thinkphp6.0反序列化利用链

本来想审一下thinkphp5.2的链子,但找不到了害,找了几个用thinkphp5.2的博客代码也该过了,就直接上6.0吧,反正差的也不多。

分析

thinkphp6比5改了好多好多,审计之前我还是仔细的看了一下开发手册。

第一步还是全局搜索__destruct方法,这里可用的是vendor/topthink/think-orm/src/Model.php

image-20200211213523261

这里的$this->lazySave是简单可控的

image-20200211213640085

可用的方法在updateData,首先我们要避免上面的return false,

1.$this->isEmpty()返回值为 false

2.$this->trigger('BeforeWrite')返回值为true

3.要把$this->exists设为true

image-20200211213841597

这里`$data设置为一个非空的数组就行了,就行儿

image-20200211214641533

这里的$this->withEvent是简单可控的,设为false就可以了

再看一下触发的updateData方法

image-20200211215521136

首先要保证不被return,就是要保证这个$data的输出是一个非空数组

h
1
$data = $this->getChangedData();

image-20200211220735918

这里的$this->force是简单可控的,只要设为true,就可以返回之前一件设为非空数组的$data

然后看下面的checkAllowFields方法

image-20200211221719905

我们要触发的地方是$this->db()方法,所以要$this->field空,且$this->schema也空,啥都不做就是空的。

image-20200211222353850

而这里调用的db方法中用到了.的拼接,只要把$this->name或者$this->suffix设为下一个类对象,就可以出发__toString方法了。

这里用到的还是Conversion类中的__toString->toJson->toArray一条,然后就到了getAttr方法了

image-20200211223412418

首先这里的$this->visible$this->relation都是可控的,然后接下去

image-20200211224319794

image-20200211224347609

这里就出现了动态函数调用。这里的$this->withAttr是简单可控。

这里可以利用\Opis\Clsure方法可以序列化匿名函数,我们这样

1
2
$function = function(){@eval($_GET['yds']);};
$closure = new \Opis\Closure\SerializableClosure($function);

这样就可以成功getshell

exp

1
这是一条美丽的马赛克

image-20200211235240427

成功执行system(‘ls’)

pop链

image-20200211235748909