PHP序列化、反序列化漏洞超全总结
字数 1828 2025-08-19 12:41:52
PHP序列化与反序列化漏洞全面解析
一、基础概念
1. 序列化与反序列化简介
序列化是将数据转化为可逆数据结构的过程,反序列化则是将序列化字符串还原为原始对象的过程。PHP中使用:
serialize():将对象格式化为有序字符串unserialize():将字符串还原为对象
主要用于数据传输和存储,如session缓存、cookie等。
2. 序列化格式解析
$user = array('xiao','shi','zi');
echo serialize($user);
// 输出:a:3:{i:0;s:4:"xiao";i:1;s:3:"shi";i:2;s:2:"zi";}
格式说明:
a:3:数组,3个元素i:0:整型索引0s:4:"xiao":字符串,长度4,值"xiao"
类序列化示例:
class test {
public $a = "xiaoshizi";
public $b = "laoshizi";
}
// 输出:O:4:"test":2:{s:1:"a";s:9:"xiaoshizi";s:1:"b";s:8:"laoshizi";}
访问控制修饰符影响:
- protected:变量名前加
\x00*\x00 - private:变量名前加
\x00类名\x00
3. 关键魔术方法
| 方法 | 触发时机 |
|---|---|
__construct() |
对象实例化时 |
__wakeup() |
执行unserialize()前 |
__sleep() |
执行serialize()前 |
__destruct() |
对象销毁时 |
__toString() |
对象被当作字符串使用时 |
__invoke() |
对象被当作函数调用时 |
二、反序列化漏洞利用技术
1. PHP7.1+类属性不敏感
PHP7.1+对protected/private属性不敏感,可省略\x00前缀直接反序列化。
例题:[网鼎杯2020青龙组]AreUSerialz
- 绕过is_valid()检查不可打印字符
- 将protected改为public属性
- 构造payload读取flag.php
class FileHandler {
public $op = 2;
public $filename = "php://filter/read=convert.base64-encode/resource=flag.php";
public $content;
}
2. 绕过__wakeup (CVE-2016-7124)
影响版本:
- PHP5 < 5.6.25
- PHP7 < 7.0.10
利用方式:序列化字符串中对象属性个数大于实际个数时跳过__wakeup执行。
例题:[极客大挑战2019]PHP
- 发现备份文件www.zip
- 构造payload绕过__wakeup
- 修改属性数量为更大值
O:4:"Name":3:{s:14:"%00Name%00username";s:5:"admin";s:14:"%00Name%00password";i:100;}
3. 正则绕过技术
- 加号绕过:
O:+4:"test"... - 数组包裹:
serialize(array($a)) - 16进制表示:
S:4:"\00*\00\61"代替s:4:"\x00*\x00a" - 引用绕过:使两个属性始终相等
4. 字符逃逸漏洞
当序列化后数据进行过滤替换时可能导致结构破坏。
字符增多情况
- 计算需要逃逸的字符串长度
- 构造足够数量的触发词使后续内容成为有效属性
字符减少情况
- 计算到下一个可控变量的距离
- 构造payload使过滤后格式正确
例题:
// 过滤将Firebasky替换为更长的Firebaskyup
FirebaskyFirebasky...";s:8:"password";s:5:"yu22x";}
三、对象注入漏洞
当unserialize参数可控且存在危险魔术方法时可能造成任意对象注入。
利用条件:
- unserialize参数可控
- 存在含危险魔术方法的类
四、PHAR反序列化
1. PHAR文件结构
- stub:标识头,如
<?php __HALT_COMPILER();?> - manifest:元数据,存储序列化信息
- contents:压缩内容
- signature:签名
2. 利用方法
$phar = new Phar("test.phar");
$phar->setStub("<?php __HALT_COMPILER();?>");
$phar->setMetadata($maliciousObj);
$phar->addFromString("test.txt", "test");
触发函数:
- file_exists()
- file_get_contents()
- 各种文件处理函数
3. 绕过技术
- 改变协议:
compress.zlib://phar:// php://filter/resource=phar:// - 修改文件头:添加GIF/PNG等文件头
- 修改扩展名:伪装为其他格式文件
五、Session反序列化
1. 处理引擎差异
| 引擎 | 存储格式 |
|---|---|
| php | `键名 |
| php_serialize | 序列化数组 |
| php_binary | 长度+键名+序列化值 |
2. 利用方式
- 使用php_serialize引擎存入
|序列化payload - php引擎会将
|后内容反序列化
3. session.upload_progress利用
通过文件上传进度机制注入session:
<form action="target.php" method="POST" enctype="multipart/form-data">
<input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="|序列化payload" />
<input type="file" name="file" />
</form>
例题:Jarvis OJ-PHPINFO
- 利用上传进度机制注入session
- 构造payload读取目录和文件内容
- 利用不同处理器差异触发反序列化
|O:5:\"OowoO\":1:{s:4:\"mdzz\";s:36:\"print_r(scandir(dirname(__FILE__)));\";}
防御建议
- 不要反序列化不可信数据
- 使用JSON等更安全的序列化格式
- 严格检查反序列化输入
- 限制危险魔术方法的使用
- 保持PHP环境更新