反序列化漏洞入门:PHP、Java 与 Python 反序列化利用链对比

引言

反序列化漏洞是 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 为例,经典利用链如下:

  1. AnnotationInvocationHandler.readObject() 触发
  2. 调用 TransformedMapcheckSetValue()
  3. 触发 InvokerTransformer.transform()
  4. 通过反射调用 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

六、防御建议

  1. 避免反序列化不可信数据:这是最根本的防御措施
  2. 使用安全的序列化格式:如 JSON、XML(注意 XXE)
  3. 签名与加密:对序列化数据进行完整性校验
  4. 白名单机制:限制可反序列化的类(Java 的 ObjectInputFilter
  5. 最小权限原则:运行应用程序的账户应具有最小权限

结语

反序列化漏洞的本质是“将数据当作代码执行”。PHP 依赖魔术方法、Java 依赖反射与第三方库、Python 依赖 pickle 的 __reduce__ 机制,三者的利用思路各有不同,但核心逻辑一致:寻找从反序列化入口到危险函数的调用路径。掌握这些差异,有助于在不同语言环境中快速定位和利用反序列化漏洞,也能更好地设计防御方案。

未经允许不得转载:任鹏个人博客 » 反序列化漏洞入门:PHP、Java 与 Python 反序列化利用链对比

赞 (0) 打赏

评论 0

取消
  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏