ThinkPHP v5.1.x 反序列化 分析
环境准备
Thinkphp 5.1.38
写入反序列化点
漏洞复现
exp:
<?php |
get任意传参
漏洞分析
以__destruct为入口
全局搜索
thinkphp\library\think\process\pipes\Windows.php
两个函数
close()进行关闭连接操作
removefiles()
可以任意文件删除 exp:
<?php |
用到了 file_exists
函数会将参数当作字符串来进行处理,可以用来触发__toString
全局搜索 __toString
thinkphp\library\think\model\concern\Conversion.php
trait Conversion
跟进toJson()
跟进toArray()
摘取部分代码
// 追加属性(必须定义获取器) |
append 可控所以 key 与 name可控,relation是通过 getRelation
获得,跟进
thinkphp\library\think\model\concern\RelationShip.php
trait RelationShip
这里肯定 要求返回空
也就是if和elseif都不进入
接着 进入getAttr
thinkphp\library\think\model\concern\Attribute.php
trait Attribute
返回值为 return $value;
跟进getData
因为上面 三个都是trait
,全局搜索找一个同时继承三个triat的子类
thinkphp\library\think\Model.php
abstract class Model 抽象类
先找一下实现类
\thinkphp\library\think\model\Pivot.php
回到 $relation->visible([$attr]);
利用有两条路走
- visible方法中存在利用
- 触发__call方法
全局寻找visible方法,三处无利用点,尝试寻找_call方法
thinkphp\library\think\Request.php
$this->hook[$method]
可控 $args
可控
但是存在
array_unshift($args, $this); |
本来 $args 作为命令参数可控,由于 array_unshift()向数组插入新元素时会将新数组的值将被插入到数组的开头
,导致参数不可控
那么尝试再去调用其他方法 且参数可控
在Thinkphp的Request类中还有一个filter功能,事实上Thinkphp多个RCE都与这个功能有关。我们可以尝试覆盖filter的方法去执行代码
利用点肯定是这里
$value = call_user_func($filter, $value); |
但是两个参数都不可控,就去向上找谁调用了filterValue
看看能不能控制传入filterValue的参数
找到这个类的input方法:
$data依旧不可控,继续往上寻找调用input的函数,找到 param
$name依旧不可控,接着往上寻找isAjax()
$this->config[‘var_ajax’] 可控
在 isAjax
函数中,我们可以控制$this->config['var_ajax']
,意味着 param
函数中的$name
可控。param函数中的 $name
可控就意味着 input函数中的 $name
可控。
倒着梳理一下
在 input中$this->param
是通过与 get传参进来的参数进行合并 传入input中的$data
再看input中的这三句
$data = $this->getData($data, $name); |
$data = $this->getData($data, $name)
$name就是$this->config['var_ajax']
即 $data=$data[$name]
$filter = $this->getFilter($filter, $default)
$filter=''
进入else分支 返回$this->filter也就是可控的
$this->filterValue($data, $name, $filter)
$data可控 $filter 可控 成功rce