thinkphp6手册_ThinkPHP 6.x反序列化POP链(二)

论坛 期权论坛 编程之家     
选择匿名的用户   2021-6-2 15:45   70   0

环境准备

安装ThinkPHP 6.0

composer create-project topthink/think=6.0.x-dev v6.0

修改application/index/controller/Index.php Index类的代码

class Index{   public function index()  {       $payload = unserialize(base64_decode($_GET['payload']));       return 'ThinkPHP V6.x';  }}

开启ThinkPHP6调试

将根目录.example.env更改为.env,文件中添加:APP_DEBUG = true

POP链分析

__destruct()

依旧是全局搜索 __destruct() ,我们查看在 /vendor/league/flysystem-cached-adapter/src/Storage/AbstractCache.php 中的__destruct

e9caa54b0b9b5190826135f8818ff9b1.png

使 $this->autosave = false 可以触发 $this->save()

CacheStore

AbstractCache是一个抽象类,我们使用find usages寻找继承它的类

be3e7d78e34068ef289090960f46a1e5.png

/vendor/topthink/framework/src/think/filesystem/CacheStore.php 中的 CacheStore 类继承了 AbstractCache 类,并实现了 save() 方法

a2f23b392fac91bc74371e6868604ed7.png

save() 方法中涉及 getForStorage() 方法,我们跟进此方法

getForStorage()

回到 AbstractCache.php 中我们找到了 getForStorage() 方法,继续跟进 cleanContents()

0d0cd2af0d4d29674aa3abe5b04a5249.png

cleanContents()

array_flip对数组反转,array_intersect_key取数组交集

9059998d8e4990814c5a7350bb9f8195.png

然后函数会将 $contents 返回给 getForStorage() 中的 $cleaned ,经过 json_encode 后返回给前面的 save() 方法

60a55a7f5238ded3c827652c179c2e58.png

$contents 变量接收函数返回值后,进入下面了逻辑,此时$this->store是可控的,我们可以调用任意类的set方法,如果这个指定的类不存在set方法,就有可能触发__call()。当然也有可能本身的set()方法就可以利用。

Notice:在对象中调用一个不可访问方法时,__call()会被调用。有关 __call() 方法的详细说明,参见php手册https://www.php.net/manual/zh/language.oop5.overloading.php#object.call

set()

060a328dfbcd8a8cc49ed02f7d6d2e12.png

我们利用在File类中的 set() 方法

762f374f7a3485a6e774dfcae81e82bb.png

serialize()方法

此处有两种利用方法,我们先分析利用 serialize() 方法的POP链

4c91eb189f6f8da70022de71ad5abbdc.png

$this->options\['serialize'][0]可控,可以执行任意函数,参数为$data

我们从set()方法中可知,$data 来源于 $value 的传值,在继续从CacheStore 中可知 $value 来源于 $contents

json_encode后的数据,由此我们需要使json_encode后的数据被当作代码执行。

此时需要注意一个问题

f70bf8f51e71eef8bf08605587c0ab6e.png

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:3875789
帖子:775174
精华:0
期权论坛 期权论坛