思路
// 析构方法入手
__destruct() --> removeFiles() --> files_exists($filename)
// 可控参数
new windows()->filename
// 绝对路径
D:\phpstudy\PHPTutorial\WWW\v5.1.37\thinkphp\library\think\process\pipes\Windows.php
file_exists()函数将参数当作字符串处理,可以触发类的__toString()魔术方法
// 寻找__toString()的调用链
__toString() --> toJson()--> toArray()
//寻找 $可控变量->方法(参数可控) 的点
$relation->visible($name);
// 可控参数
$name --> ($this->append as $key => $name)
$relation--> getAttr($key) --> getData($name) --> array_key_exists($name, $this->data) --> $this->data[$name]
// 绝对路径
D:\phpstudy\PHPTutorial\WWW\v5.1.37\thinkphp\library\think\model\concern\Conversion.php
下的$this->append
D:\phpstudy\PHPTutorial\WWW\v5.1.37\thinkphp\library\think\model\concern\Attribute.php
下的
$this->$data
// 注意,他们均为代码复用的trait,需要寻找复用了他们的类来进行利用
寻找没有visible方法的类,并且实现了__call()方法,这个方法的实现一般带着call_user_func_array
__call()-->call_user_func_array($this->hook[$method], $args)
//可控变量
$this->hook
// 绝对路径
D:\phpstudy\PHPTutorial\WWW\v5.1.37\thinkphp\library\think\Request.php
// $args为数组,且第一个参数为类实例,难以利用
array_unshift($args, $this)
故寻找Requests.php中其他可以利用的函数,filter功能经常被利用,想办法利用call_user_func()方法
filterValue(&$value, $key, $filters) --> call_user_func($filter, $value)
-->input($data = [], $name = '', $default = null, $filter = '') --> array_walk_recursive($data, [$this, 'filterValue'], $filter)
--> param($name = '', $default = null, $filter = '')
--> isAjax($ajax = false)
--> $this->param($this->config['var_ajax'])
$this->config['var_ajax']可控, 由于param()中$name可控,所以input()函数中的$name也可控,刚好input()函数中$data参数也可控(为$_GET数组)
$data = $this->getData($data, $name) --> $data = $data[$val]
// 可控参数
$this->hook
$this->config['var_ajax']
$this -> $filter
$this -> $data($_GET数组)
// 绝对路径
D:\phpstudy\PHPTutorial\WWW\v5.1.37\thinkphp\library\think\Request.php
最终的反序列利用链
在默认模块中构造利用点
POC
https://github.com/Dido1960/thinkphp/tree/master/v5.1.37/poc