引言
反序列化漏洞是 Web 安全领域中危害极大的一类漏洞。自 2015 年 Java Apache Commons Collections 反序列化漏洞引爆安全圈以来,PHP、Python 等语言的反序列化利用链也相继被安全研究者深入挖掘。理解不同语言反序列化漏洞的共性与差异,对于漏洞挖掘和防御都具有重要意义。
一、序列化与反序列化的基本概念
序列化(Serialization)是将对象转换为可存储或传输的字节流/字符串的过程;反序列化(Deserialization)则是将字节流/字符串还原为对象的过程。
当应用程序接收了不可信的序列化数据并对其进行反序列化时,攻击者可以构造恶意数据,在反序列化过程中触发非预期的对象方法调用,最终实现任意代码执行、文件读写、命令执行等攻击效果。
二、PHP 反序列化
2.1 魔术方法机制
PHP 反序列化的核心在于魔术方法(Magic Methods)。当 unserialize() 被调用时,如果类中定义了以下魔术方法,它们会在特定时机被自动触发:
__wakeup():反序列化时自动调用__destruct():对象被销毁时调用__toString():对象被当作字符串使用时调用__get()/__set():访问不可访问属性时调用__call():调用不可访问方法时调用
2.2 利用链构造思路
PHP 反序列化利用链(POP Chain)的构造思路是:从入口魔术方法出发,寻找属性可控且能调用其他方法的“跳板”,最终到达危险函数(如 system()、eval()、file_put_contents() 等)。
class A {
public $cmd;
public function __destruct() {
eval($this->cmd);
}
}
// 构造 payload
$obj = new A();
$obj->cmd = 'phpinfo();';
echo serialize($obj);
// 输出: O:1:"A":1:{s:3:"cmd";s:10:"phpinfo();";}
2.3 特点总结
- 语言层面无内置安全机制:PHP 的
unserialize()不会限制可反序列化的类 - 利用链依赖魔术方法:需要目标类中存在可触发的魔术方法
- 属性可控性强:通过序列化字符串可以直接控制对象属性值
- 典型漏洞:Typecho、Laravel、WordPress 插件中的反序列化漏洞
三、Java 反序列化
3.1 反射机制与 readObject
Java 反序列化通过 ObjectInputStream.readObject() 实现。利用链的核心在于反射机制和 readObject() 方法的重写。
3.2 经典利用链:Commons Collections
以 Commons Collections 3 为例,经典利用链如下:
AnnotationInvocationHandler.readObject()触发- 调用
TransformedMap的checkSetValue() - 触发
InvokerTransformer.transform() - 通过反射调用
Runtime.getRuntime().exec()执行命令
// 核心利用代码示意
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod",
new Class[]{String.class, Class[].class},
new Object[]{"getRuntime", new Class[0]}),
new InvokerTransformer("invoke",
new Class[]{Object.class, Object[].class},
new Object[]{null, new Object[0]}),
new InvokerTransformer("exec",
new Class[]{String.class},
new Object[]{"calc.exe"})
};
3.3 特点总结
- 依赖第三方库:利用链通常依赖 Commons Collections、Fastjson、Jackson 等库
- 反射是核心:通过反射绕过访问控制,调用任意方法
- 利用链复杂但威力大:可实现任意代码执行
- Java 17+ 增加了安全限制:
ObjectInputFilter等机制对反序列化进行了约束 - 典型漏洞:WebLogic、Shiro、Fastjson
四、Python 反序列化
4.1 pickle 模块的危险性
Python 的 pickle 模块在反序列化时会执行 __reduce__() 方法返回的指令。攻击者可以通过构造恶意 __reduce__() 方法实现任意命令执行。
import pickle
import os
class Exploit:
def __reduce__(self):
return (os.system, ('whoami',))
payload = pickle.dumps(Exploit())
# 反序列化时执行 whoami
pickle.loads(payload)
4.2 利用链构造
Python 反序列化利用链通常通过以下方式构造:
__reduce__方法:直接返回可调用对象和参数__reduce_ex__方法:类似__reduce__,优先级更高eval+__import__:通过内置函数执行任意代码
class RCE:
def __reduce__(self):
return (eval, ("__import__('os').system('id')",))
4.3 特点总结
- pickle 本身设计不安全:官方文档明确说明不要反序列化不可信数据
- 利用链构造简单直接:通过
__reduce__即可实现 RCE - 常见于 Web 框架:Flask session 反序列化、Django session 等
- 典型漏洞:Flask SECRET_KEY 泄露导致的 session 伪造
五、三种语言反序列化对比
| 对比维度 | PHP | Java | Python |
|---|---|---|---|
| 核心机制 | 魔术方法 | 反射 + readObject | __reduce__ |
| 利用链依赖 | 魔术方法 + 属性可控 | 第三方库 + 反射 | pickle 模块 |
| 构造难度 | 中等 | 较高 | 较低 |
| 语言内置防护 | 无 | Java 17+ 有过滤机制 | 无(pickle 设计如此) |
| 常见入口 | unserialize() |
readObject() |
pickle.loads() |
| 典型漏洞 | Typecho、Laravel | Shiro、Fastjson | Flask Session |
六、防御建议
- 避免反序列化不可信数据:这是最根本的防御措施
- 使用安全的序列化格式:如 JSON、XML(注意 XXE)
- 签名与加密:对序列化数据进行完整性校验
- 白名单机制:限制可反序列化的类(Java 的
ObjectInputFilter) - 最小权限原则:运行应用程序的账户应具有最小权限
结语
反序列化漏洞的本质是“将数据当作代码执行”。PHP 依赖魔术方法、Java 依赖反射与第三方库、Python 依赖 pickle 的 __reduce__ 机制,三者的利用思路各有不同,但核心逻辑一致:寻找从反序列化入口到危险函数的调用路径。掌握这些差异,有助于在不同语言环境中快速定位和利用反序列化漏洞,也能更好地设计防御方案。
未经允许不得转载:任鹏个人博客 » 反序列化漏洞入门:PHP、Java 与 Python 反序列化利用链对比

