记录hardphp这道题复现过程,学习了Php-Parse进行混淆和解混淆和Session机制的另一种利用方式,如有不足,希望师傅们批评指正。
0x01 解混淆
拿到题目源码 ,是下图的格式,需要解混淆。
比赛结束后看了zsh师傅发的文章,知道正解是用Php-Parser来解混淆,文章里提出了一种通过Parse来进行代码混淆的方式,Parser是可以用来对php代码进行语法分析的工具,可以将php代码解析成抽象语法树,然后遍历语法树修改树上的节点,最后再将修改后的语法树转换为php代码。这样就可以达到一个混淆代码的作用。遍历抽象语法树需要用到Node visitors ,其相关用法如下图,去这里Walking the AST详细看下,可能更好理解。
然后看题目中混淆代码的大致规则,可以看到每个php文件前面都是类似这样的结构
1 | $GLOBALS['�����']=unserialize(base64_decode('xxxxxxxxxxxxxxx')); |
可以知道$GLOBALS['�����']
为一个数组,首先反向解出$GLOBALS['�����']
如下图
可以看出$GLOBALS['�����'][1]
仍为一串base64编码的字符串,$GLOBALS['�����'][2]
为base64_docode
,$GLOBALS['�����'][2]
为unserialize
,$GLOBALS['�����'][3]
之后的值都为int型整数,然后分析上面代码的的第二句
1 | $GLOBALS[$GLOBALS['�����'][0]]=$GLOBALS['�����'][3]($GLOBALS['�����'][2]($GLOBALS['�����'][1])); |
将值代入后可以得出
1 | $GLOBALS[$GLOBALS['�����'][0]]=unserialize(base64_decode($GLOBALS['�����'][1])); |
我们解出$GLOBALS[$GLOBALS['�����'][0]]
如下图
$GLOBALS[$GLOBALS['�����'][0]]
仍然为数组,里面的值有字符串和int值;
然后分析上面代码的第三句
1 | $GLOBALS[$GLOBALS['�����'][0]][$GLOBALS['�����'][4]+($GLOBALS['�����'][5]-$GLOBALS['�����'][6])] |
将其中内容简写后如下图所示:
就是取$GLOBALS[$GLOBALS['�����'][0]]
数组中,对应索引为后面三个值相加减后的结果的值。然后我们开始解混淆,
1 | function decode ($beforeFilename,$afterFilename){ |
的图片,在首页可以得到图片在服务器上的文件名,
然后编写exp
1 |
|
然后发送两遍,第二遍触发反序列化
然后在/img/upload/文件夹下生成shell.php,然而并不能利用,因为在upload文件夹下有.htaccess文件
1 | php_flag engine off; |
禁止了php文件执行,那么只能寻找include之类的文件包含来利用了,然后发现core.php中有类自动加载器,并且有include文件包含。
然后寻找那里有使用了未定义的类,
每个接口差不多都有一个$v2变量的getTime()静态方法的调用,$v2来源于$_SESSION[‘data’]中数据的反序列化,如果$v2为一个字符串,就可以调用字符串对应的类的静态方法,那么这里如果$v2为一个未定义的类,就会触发前面的类加载器,包含shell。然后伪造session的data。
另外也可以发送
1 | username=aaa&password=aaa&HTTP_X_FORWARDED_FOR[',data%3dconcat('data|O:5:"shell":0:{}')%23']=123 |
本地测试后,这种方式不是通过$v2调用静态方法触发的,猜测是在unserialize时接收的参数是一个类对象,然后触发的类自动加载器。
之后访问/?s=img/upload就可以得到shell了。
参考链接