反序列化漏洞复现
字数 1552 2025-08-18 11:39:22
ThinkPHP 5.1.37 反序列化漏洞分析与复现
一、漏洞概述
本文详细分析ThinkPHP 5.1.37版本中的反序列化漏洞,该漏洞允许攻击者在满足特定条件下实现远程代码执行(RCE)。
二、利用条件
- 存在一个内容完全可控的反序列化点
- 例如:
unserialize(可控变量)
三、环境搭建
- 从GitHub下载ThinkPHP 5.1.37版本
- 修改
composer.json文件 - 在包含
composer.json的目录下执行命令:composer install
四、漏洞分析
1. 漏洞触发点
- 入口点为
unserialize()函数 - 框架中存在
file_exists函数触发类__toString方法的有趣特性 - 在
windows.php文件中存在被动触发点,在对象销毁时会触发
2. 关键调用链
-
__toString魔术方法触发- 当对象以字符串形式被执行时,包含
__toString魔术方法的类会被执行 - 重点利用
think\model\concern\Conversion类的__toString方法
- 当对象以字符串形式被执行时,包含
-
toArray()方法分析__toString最终落脚点在toArray()方法- 关键代码:
$this->getAttr($name) $relation值可控,因为:$this->append可赋值$this->data完全可控(通过payload构造)
-
getData()方法跳转$key可控(来自$this->data[$key])- 最终形式:
$可控类->visible(可变变量) - 通过此可调用
visible方法和__call魔术方法
-
__call魔术方法利用- 选择
request.php中的魔术函数 $this->hook可控(通过payload构建)- 利用
call_user_func_array()函数调用任意类方法
- 选择
-
RCE漏洞点
- 位于
request类的input方法中 - 存在
call_user_func($filter,$data)调用点 - 直接调用
input方法会报错,需要寻找其他调用路径:param方法调用inputisAjax和isPjax方法调用param
- 位于
-
参数控制
- 通过
getFilter方法构建$filter赋值(如system函数) $data可通过GET传值赋值array_walk_recursive参数可控filterValue函数中:value参数对应data的值filters为payload中构建的系统函数(如system)
- 通过
五、漏洞复现步骤
-
构建反序列化入口点
-
构造恶意payload:
- 控制
$this->data和$this->append - 设置
$this->hook为可利用的类方法 - 配置
$filter为系统函数(如system) - 通过GET参数传递要执行的命令(如
whoami)
- 控制
-
触发流程:
- 反序列化触发
__destruct - 调用
__toString - 跳转至
toArray和getAttr - 触发
__call魔术方法 - 最终执行
call_user_func实现RCE
- 反序列化触发
六、漏洞修复建议
- 严格控制反序列化参数的值
- 使用白名单方式过滤反序列化内容
- 更新到最新版本(官方已修复此漏洞)
七、技术要点总结
- 反序列化漏洞入口点为
unserialize() - 利用
file_exists触发__toString - 通过
toArray()和getAttr()方法控制执行流 __call魔术方法实现方法调用跳转- 最终通过
call_user_func实现任意代码执行
八、流程图
unserialize()
↓
__destruct()
↓
file_exists() → __toString()
↓
toArray() → getAttr()
↓
visible() → __call()
↓
call_user_func_array()
↓
param() → input()
↓
call_user_func($filter, $data) → RCE