thinkphp_5.1.39反序列化分析
[toc]
环境搭建
thinkphp5.1.39
php7.3
从网上下载好源码,打开 application\index\controller\Index.php 文件写入如下代码:
打开框架的debug模式,配置好phpstorm+chrome的调试模式,便可以开始了。
反序列化
搜索 __destruct() 方法,和thinkphp5.0.x一样,还是在 Windows类中
跟进 removeFiles()
这里的 file_exists() 中的参数是可控的,其参数会被当做字符串处理,可以触发 __toString() 方法,搜索一下这个方法,很快就找到了,在 vendor\phpspec\prophecy\src\Prophecy\Argument\Token\ExactValueToken.php 文件下的 ExactValueToken 类中有一个可以利用的函数。
这里的 $this->util->stringify($this->value) 两个参数都是可控的,是可以完美触发 __call() 的地方,然后搜索一下__call(),在 Request 类中
__call方法的第一个参数是调用的那个不存在的方法,在这里也就是 stringify ,第二个参数以数组的方式传递,数组中的值是调用不存在方法时传递的参数。
在这里 $this->hook 是可控的,但是 array_unshift会把 $this 放到 $args 数组的第一个元素,我们只能
1 | call_user_func_array([$obj,"任意方法"],[$this,任意参数]) |
这样很难直接执行我们想要的函数,但是Thinkphp作为一个web框架,
Request类中有一个特殊的功能就是过滤器 filter(ThinkPHP的多个远程代码执行都是出自此处)
我们只能想办法通过调用别的方法来达到我们想要的结果,然后也是在 Request 类中找到了 filterValue 方法
这里可以调用 call_user_func 来执行任意函数,需要找一个调用 filterValue 的点,发现 input 方法符合条件
1 | public function input($data = [], $name = '', $default = null, $filter = '') |
但是这里的参数不可控,需要再寻找input参数可控的点,在 param() 中
1 | public function param($name = '', $default = null, $filter = '') |
这里只有 $this->param 是可控的,$filter 为空,需要再寻找调用 param() 的点,
这里 isAjax() 参数时可控的,并且 param() 的参数 $this->config\['var_ajax'\]
也是可控的,那这样 param() 中 $name也是可控的,再看 input() 方法
1 | public function input($data = [], $name = '', $default = null, $filter = '') |
$data 来自 getData() 方法, $filter 来自 getFilter() ,先看一下 getData()
这里 $data = $data[$val] = $data[$name] ,而 $name 是可控的,所以我们的 $data 也是可控的,
再看一下 getFilter()
$filter = $filter ?: $this->filter;,也是可控的。
所以在 input()中调用 filterValue() 方法时的参数 $data 和 $filter 都是可控的,也就是 filterValue() 中我们调用 call_user_func 时的参数,这样整条pop链就算构造完成了。
POC
1 | <?php |
执行成功
- Post Title: thinkphp_5.1.39反序列化分析
- Post Author: Katharsis
- Post Link: http://yoursite.com/2020/09/16/thinkphp-5-1-39/
- Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
1.thinkphp6反序列化链
2.thinkphp5.0.24反序列化pop链分析
3.ciscn2019 laravel反序列化利用链
4.代码审计之——PHP-Audit-Labs