ThinkPHP 5.1反序列化利用链学习


安装环境

下面2个都要下载 framework think 并且将framework下载好后的framework-5.1.37改名为为thinkphp放到think-5.1.37文件夹中 我是直接在sublime中运行think文件调试的

__destruct

在刚刚改名的文件夹中搜索能被反序列化触发的点__destruct(因为在主文件中,此文件夹中的内容已被当做基础文件加载) 其中Unix.phpConnection.php 中的__desctruct都是直接close了,跟了一下没有发现可利用的点
Process.php跟到了proc_get_status()要取一个resource值,传入不了 然后跟到isRunning()函数中,有个字符串比较 不过!==/===无法触发__toString() (!=/==可以,因为!==/===是先判断的类型,类型不同直接返回false了)

最后只能跟Windows.php __destruct()中有个$this->removeFiles(); 乍一看可以看出有个任意文件删除,不过file_exists()会把参数作为字符串处理,所以导致可触发__toString() 如果将$filename传入一个对象,就会先调用该类__toString方法

__toString

搜索__toString() 当一个对象被当作字符串对待的时候,会触发这个方法

think/model/concern/Conversion.php

Conversion.php跟到toArray() 那么如进一步利用呢 可以在流程比较多的toArray()中寻找到一个$可控变量->方法(参数可控)来触发某个类的__call方法 toArray()函数中部分如下所示: 其中192行的$relation->visible($name); 首先$this->append可控,所以$key,$name可控,再跟$relation,测试可知$relation在188行执行后还是为NULL 进入190行的条件判断,$relation通过$this->getAttr($key)获取 于是跟到think/model/concern/Attribute.php 由于这里的$this->data可控,容易构造任意返回值 那么就满足了$relation$name可控,可以构造一个类传入 接着就需要找类是否有可利用的visible方法, 或者没有visible方法,但有可利用的__call方法

__call

搜索__call 该方法在调用的方法不存在时会自动调用,程序仍会继续执行下去。

think/Request.php

不过在执行call_user_func_array()前有个array_unshift()函数把本类对象$this放在数组变量$args的第一个 只能执行call_user_func_array(可控, [$this,array('0'=>[可控数组])]) 直接这样好像并没什么好方法构造RCE,这条路走太不通,换条路 call_user_func_array()第一个参数为数组且该数组第一个参数为一个对象或类名时,可调用该类中的方法 函数名可控,可以找找当前类有无可触发RCE的函数 跟到input() 有个array_walk_recursive()函数 而其中的filterValue函数 可以将传入的$filters作为回调函数执行 $filters参数由$filter = $this->getFilter($filter, $default);而来 跟入getFilter() 由于传入的$filter'',is_null()判断为false,$this->filter可控,故$filters可控 只要$data可控便可以RCE了 但是由于不能控制上文所提到的$args,直接调用input()是不行的 所以可以继续寻找不受$args影响的函数进一步调用input() input()中有个很关键的$name = (string) $name; 这里默认传入的$name是一个object,强制类型转换会报错,无法继续执行,这里才搞明白为啥参考文章中都用的param() 因为isAjax()isPjax()中调用param()时,传入param()的第一个参数(传入input()的第二个参数)也就是$name可控,不会被报错终止 设置为

最终即可RCE

 

触发

先生成反序列化并url编码的字符串后再在think文件中执行unserialize(urldecode())

任意文件删除

触发__toString

由于think\model\concern\Conversion()是由trait定义的 在写poc时需要注意找到继承此的类think/Model.php 可以发现Model也是一个抽象类,反序列化时也会报错,从而找到继承Model的非抽象类think/model/Pivot.php

控制relation和name触发__call

printf测试及调用类中方法

RCE

 

参考链接

1.挖掘暗藏ThinkPHP中的反序列利用链 2.ThinkPHP5.1.X反序列化利用链