1. 基本概念
序列化
将对象或数据结构转换为字符串格式,便于存储或传输。
示例:serialize($object)
→ 生成序列化字符串。
反序列化
将序列化字符串还原为原始对象或数据结构。
示例:unserialize($serializedString)
→ 重建对象。
2. 序列化字符串结构
基本语法
类型:长度:值
,例如:
常见类型标识符
a
:数组、s
:字符串、i
:整数、b
:布尔值、N
:null
3. 反序列化漏洞原理
魔术方法
PHP 在反序列化时会自动调用对象的某些魔术方法,攻击者可通过构造恶意序列化数据触发这些方法:
__wakeup()
:反序列化时触发。
__destruct()
:对象销毁时触发。
__toString()
:对象被当作字符串使用时触发。
__call()
:调用不存在的方法时触发。
漏洞触发条件
- 反序列化的参数用户可控(如从请求中直接传入)。
- 类中定义了危险操作(如文件操作、命令执行)的魔术方法。
4. 常见危险函数与场景
危险函数
eval()
、system()
、exec()
、passthru()
:命令执行。
file_put_contents()
、unlink()
:文件读写/删除。
反序列化后的对象属性被用于敏感操作。
POP链
通过组合多个类的魔术方法构造利用链,例如:
class A { function __destruct() { $this->obj->save(); }}
class B { function save() { system($this->cmd); }}
攻击者可构造 A->obj = B
,B->cmd = "恶意命令"
。
5. 漏洞利用步骤
- 寻找可利用的类:代码审计,定位包含魔术方法或危险操作的类。
- 构造恶意对象:控制类属性,串联魔术方法形成攻击链。
- 生成序列化字符串:通过
serialize()
生成 payload。 - 触发反序列化:将 payload 传递给目标程序。
6. 防御方法
输入过滤
避免直接反序列化用户输入,或对输入进行严格校验。
使用安全的数据格式
优先使用 JSON(json_encode()
/json_decode()
)替代序列化。
限制魔术方法
避免在魔术方法中执行敏感操作。
签名校验
对序列化数据进行签名,确保未被篡改。
白名单机制
使用 unserialize()
的 allowed_classes
参数限制可反序列化的类:
unserialize($data, ["allowed_classes" => ["SafeClass1", "SafeClass2"]]);
7. 实例分析
漏洞代码示例
class User {
public $name;
function __wakeup() {
if ($this->name) {
system("echo " . $this->name);
}
}
}
// 用户可控输入
$data = $_GET['data'];
unserialize($data);
攻击 Payload
$payload = serialize(new User());
$payload = str_replace('s:4:"name";N;', 's:4:"name";s:13:"hello;id;exit;"', $payload);
// 触发 system("echo hello;id;exit;")
8. 工具与资源分享
PHPGGC:自动生成 PHP 反序列化 payload 的工具。
PHPGGC下载地址:https://github.com/ambionics/phpggc
练习平台
CTF题-攻防世界平台
题目名称:
Web_php_unserialize
unseping
9. 相关 CVE
- CVE-2015-8562:Joomla 反序列化漏洞。
- CVE-2017-9841:PHPUnit 反序列化 RCE。