反序列化漏洞复现
字数 1552 2025-08-18 11:39:22

ThinkPHP 5.1.37 反序列化漏洞分析与复现

一、漏洞概述

本文详细分析ThinkPHP 5.1.37版本中的反序列化漏洞,该漏洞允许攻击者在满足特定条件下实现远程代码执行(RCE)。

二、利用条件

  • 存在一个内容完全可控的反序列化点
  • 例如:unserialize(可控变量)

三、环境搭建

  1. 从GitHub下载ThinkPHP 5.1.37版本
  2. 修改composer.json文件
  3. 在包含composer.json的目录下执行命令:composer install

四、漏洞分析

1. 漏洞触发点

  • 入口点为unserialize()函数
  • 框架中存在file_exists函数触发类__toString方法的有趣特性
  • windows.php文件中存在被动触发点,在对象销毁时会触发

2. 关键调用链

  1. __toString魔术方法触发

    • 当对象以字符串形式被执行时,包含__toString魔术方法的类会被执行
    • 重点利用think\model\concern\Conversion类的__toString方法
  2. toArray()方法分析

    • __toString最终落脚点在toArray()方法
    • 关键代码:
      $this->getAttr($name)
      
    • $relation值可控,因为:
      • $this->append可赋值
      • $this->data完全可控(通过payload构造)
  3. getData()方法跳转

    • $key可控(来自$this->data[$key]
    • 最终形式:$可控类->visible(可变变量)
    • 通过此可调用visible方法和__call魔术方法
  4. __call魔术方法利用

    • 选择request.php中的魔术函数
    • $this->hook可控(通过payload构建)
    • 利用call_user_func_array()函数调用任意类方法
  5. RCE漏洞点

    • 位于request类的input方法中
    • 存在call_user_func($filter,$data)调用点
    • 直接调用input方法会报错,需要寻找其他调用路径:
      • param方法调用input
      • isAjaxisPjax方法调用param
  6. 参数控制

    • 通过getFilter方法构建$filter赋值(如system函数)
    • $data可通过GET传值赋值
    • array_walk_recursive参数可控
    • filterValue函数中:
      • value参数对应data的值
      • filters为payload中构建的系统函数(如system

五、漏洞复现步骤

  1. 构建反序列化入口点

  2. 构造恶意payload:

    • 控制$this->data$this->append
    • 设置$this->hook为可利用的类方法
    • 配置$filter为系统函数(如system
    • 通过GET参数传递要执行的命令(如whoami
  3. 触发流程:

    • 反序列化触发__destruct
    • 调用__toString
    • 跳转至toArraygetAttr
    • 触发__call魔术方法
    • 最终执行call_user_func实现RCE

六、漏洞修复建议

  1. 严格控制反序列化参数的值
  2. 使用白名单方式过滤反序列化内容
  3. 更新到最新版本(官方已修复此漏洞)

七、技术要点总结

  1. 反序列化漏洞入口点为unserialize()
  2. 利用file_exists触发__toString
  3. 通过toArray()getAttr()方法控制执行流
  4. __call魔术方法实现方法调用跳转
  5. 最终通过call_user_func实现任意代码执行

八、流程图

unserialize()
    ↓
__destruct()
    ↓
file_exists() → __toString()
    ↓
toArray() → getAttr()
    ↓
visible() → __call()
    ↓
call_user_func_array()
    ↓
param() → input()
    ↓
call_user_func($filter, $data) → RCE
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() 方法 关键代码: $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 方法调用 input isAjax 和 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 实现任意代码执行 八、流程图