前言
前几天审计某cms基于ThinkPHP5.0.24开发,反序列化没有可以较好的利用链,这里分享下挖掘ThinkPHP5.0.24反序列化利用链过程.该POP实现任意文件内容写入,达到getshell的目的
环境搭建
Debian
apache2+mysql+ThinkPHP5.0.24+php5.6
文件:application/index/controller/Index.php
namespace appindexcontroller;
class Index
{
public function index($input='')
{
echo "Welcome thinkphp 5.0.24";
echo $input;
unserialize($input);
}
}
简述
Thinkphp 5.0.x反序列化最后触发RCE,要调用的Request类__call方法.
但是由于这里self::$hook[$method]不可控,无法成功利用
我的思路是在找其他的__call,其他魔术方法搜了一圈没有可以进一步利用.
文件:thinkphp/library/think/console/Output.php
最后选择Output类中的__call方法,这里调用block方法.后续可以当做跳板
POP链分析
从头开始分析
反序列化起点:thinkphp/library/think/process/pipes/Windows.php removeFiles方法
跟进removeFiles方法
跳板:file_exists方法能够触发__toString魔术方法
跳板利用点:thinkphp/library/think/Model.php
Model抽象类的 __toString
跟进toJson方法至toArray方法
如下图Model抽象类的toArray方法,存在三个地方可以执行__call
但是我们目的是调用Output类的__call且能够继续利用,调试后选择第三处当做调板
$item[$key] = $value ? $value->getAttr($attr) : null;
分析下如何达到该行代码
$item[$key] = $value ? $value->getAttr($attr) : null;
这里直接看else分支
溯源$values变量,比较关键是下面两行
$modelRelation = $this->$relation();
$value = $this->getRelationData($modelRelation);
$modelRelation值可以利用Model类中的getError方法
跟进getRelationData方法,这里最后传入的$modelRelation需要Relation类型
最后返回值$values需要经过if语句判断
$this->parent && !$modelRelation->isSelfRelation() && get_class($modelRelation->getModel()) == get_class($this->parent)
全局搜索下,可以利用HasOne类
最后$attr值,由$bindAttr = $modelRelation->getBindAttr();执行后的结果.
跟进OneToOne抽象类getBindAttr方法,binAttr类变量可控.
至此代码执行到$item[$key] = $value ? $value->getAttr($attr) : null;就能够执行Output类__call魔术方法
跟进Output类block方法
继续跟进writelin方法,最后会调用write方法
这里$this->handle可控,全局搜索write方法,进一步利用
定位到:thinkphp/library/think/session/driver/Memcached.php
类: Memcached
继续搜索可用set方法
定位到:thinkphp/library/think/cache/driver/File.php
类:File
最后可以直接执行file_put_contents方法写入shell
$filename可控且可以利用伪协议绕过exit
$data值比较棘手,这里有个坑,由于最后调用set方法中的参数来自先前调用的write方法
只能为true,且这里$expire只能为数值,这样文件内容就无法写shell
继续执行,跟进下方的setTagItem方法
会再执行一次set方法,且这里文件内容$value通过$name赋值(文件名)
所以可以在文件名上做手脚
示例:php://filter/write=string.rot13/resource=./<?cuc cucvasb();?>
POP链(图)
EXP
马赛克
复现
写入文件
实战是需要找个可写目录
读取文件
结语
感谢@水泡泡师傅解答问题
整条POP分析下来挺有趣,希望师傅们喜欢.