thinkphp 5.1.x 反序列化漏洞分析.md
利用链1
1  |  | 
存在__destruct()方法

跟进removeFiles(),file_exists在处理filename时会当成字符串处理,只要让构造$this->files为包含类的数组就可以调用__toString()

1  |  | 
存在_toString()

toJson()
调用toArray()

toArray()
需要让$this->visible为空,$this->hidden为空,调用getAttr()。$data由$this->data和$this->merge合并而成。

getAttr()满足条件isset($this->withAttr[$fieldName])即可命令执行,参数可控
1  |  | 

getData(),需要满足第二个条件$this->data数组中存在$name键,即可返回$this->data[$name]

1  |  | 
Loader::parseName
parseName会把大写字母转为小写并在前面加上_,如A变成_a,不影响payload的构造

函数名为$closure = $this->withAttr[$fieldName];,$fieldName来源于经过Loader::parseName函数处理的getAttr()函数参数$name,而getAttr()函数参数等于$data的键名$key,$data由$this->data和$this->merge合并而成。最终等于$this->withAttr[$key]。让数组$this->withAttr与$this->data有相同的键名即可
执行命令:$value=$this->getData($name),$name为getAttr()参数,在getData()函数中只要满足array_key_exists($name, $this->data)就会返回$this->data[$name],$name为传入参数等于键值$key,最终等于$this->data[$key]。
利用
构造exp
1  |  | 

利用链2
前面的触发点都一样,区别在toArray()这里
toArray()
调用_call()方法,首先遍历数组$this->append,当键值$name为数组时满足is_array($name)。让$relation等于类名即可触发_call()
在这之前按需要满足3个条件
1  |  | 

getRelation()
满足array_key_exists($name, $this->relation)就会返回$this->relation[$name]。$name就是$this->append数组中的键名。需要让$this->relation[$name]等于空才能满足!$relation执行下面的语句。

getAttr()返回$value,也就是经过getData()处理的参数$key

getData(),$name就是$this->append数组中的键名$key,最终返回$this->data[$name],让它等于一个存在__call()方法且不存在visable()方法的类即可调用__call

1  |  | 
__call(),由于array_unshift()会修改参数数组,造成执行命令不可控,所以没办法直接利用这个call_user_func_array,只能寻找新的利用点

filterValue()函数中存在call_user_func,但是$value不可控,不能直接利用

input()函数中调用了filterValue(),参数不可控不能直接利用

param()函数调用input(),执行$this->input($this->param, $name, $default, $filter);,参数仍不可控。

isAjax()调用param(),参数$this->config['var_ajax']可控,这样param()函数中的$name参数可控,这样input()函数中的$name可控。param()函数可以接收$_GET数组赋值给$this->param,这样input()函数的前两个参数$this->param和$name都可控了

回到input()函数,传入filterValue()函数的第一个参数$data和第三个$filter是执行命令的关键。$data等于$this->getData($data,$name),两个函数参数就是input()传入的参数$this->param和$name。而$filter等于$this->getFilter($filter, $default);

getData(),最终$data = $data[$val] = $data[$name],也就是$this->param[$this->config['var_ajax']]

getFilter(),$filter来源于$this->filter

利用
构造exp
1  |  | 

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!