php嵌套序列化输出tp5.0,ThinkPHP v5.0.x 反序列化利用链挖掘

196364

前言

前几天审计某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);

}

}

196364

简述

Thinkphp 5.0.x反序列化最后触发RCE,要调用的Request类__call方法.

但是由于这里self::$hook[$method]不可控,无法成功利用

196364

我的思路是在找其他的__call,其他魔术方法搜了一圈没有可以进一步利用.

文件:thinkphp/library/think/console/Output.php

最后选择Output类中的__call方法,这里调用block方法.后续可以当做跳板

196364

POP链分析

从头开始分析

反序列化起点:thinkphp/library/think/process/pipes/Windows.php removeFiles方法

196364

跟进removeFiles方法

跳板:file_exists方法能够触发__toString魔术方法

196364

跳板利用点:thinkphp/library/think/Model.php

Model抽象类的 __toString

196364

跟进toJson方法至toArray方法

如下图Model抽象类的toArray方法,存在三个地方可以执行__call

但是我们目的是调用Output类的__call且能够继续利用,调试后选择第三处当做调板

$item[$key] = $value ? $value->getAttr($attr) : null;

196364

分析下如何达到该行代码

$item[$key] = $value ? $value->getAttr($attr) : null;

这里直接看else分支

196364

溯源$values变量,比较关键是下面两行

$modelRelation = $this->$relation();

$value = $this->getRelationData($modelRelation);

$modelRelation值可以利用Model类中的getError方法

196364

跟进getRelationData方法,这里最后传入的$modelRelation需要Relation类型

最后返回值$values需要经过if语句判断

$this->parent && !$modelRelation->isSelfRelation() && get_class($modelRelation->getModel()) == get_class($this->parent)

全局搜索下,可以利用HasOne类

196364

最后$attr值,由$bindAttr = $modelRelation->getBindAttr();执行后的结果.

196364

跟进OneToOne抽象类getBindAttr方法,binAttr类变量可控.

196364

至此代码执行到$item[$key] = $value ? $value->getAttr($attr) : null;就能够执行Output类__call魔术方法

196364

跟进Output类block方法

196364

继续跟进writelin方法,最后会调用write方法

196364

这里$this->handle可控,全局搜索write方法,进一步利用

定位到:thinkphp/library/think/session/driver/Memcached.php

类: Memcached

196364

继续搜索可用set方法

定位到:thinkphp/library/think/cache/driver/File.php

类:File

最后可以直接执行file_put_contents方法写入shell

196364

$filename可控且可以利用伪协议绕过exit

196364

$data值比较棘手,这里有个坑,由于最后调用set方法中的参数来自先前调用的write方法

只能为true,且这里$expire只能为数值,这样文件内容就无法写shell

196364

继续执行,跟进下方的setTagItem方法

会再执行一次set方法,且这里文件内容$value通过$name赋值(文件名)

所以可以在文件名上做手脚

示例:php://filter/write=string.rot13/resource=./<?cuc cucvasb();?>

196364

POP链(图)

196364

EXP

马赛克

复现

写入文件

实战是需要找个可写目录

196364

读取文件

196364

结语

感谢@水泡泡师傅解答问题

整条POP分析下来挺有趣,希望师傅们喜欢.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值