php反序列化完整总结
字数 1874 2025-08-25 22:59:02
PHP反序列化漏洞全面解析与实战指南
0x01 前言
PHP反序列化漏洞是Web安全中常见且危害较大的漏洞类型。本文将从基础概念入手,逐步深入讲解四种常见的PHP反序列化漏洞类型,包括简单反序列化漏洞、__wakeup绕过、字符逃逸漏洞等,并结合CTF例题进行实战分析。
0x02 反序列化基础概念
序列化与反序列化
序列化(serialize)是将对象转换为可存储或传输的字符串的过程,反序列化(unserialize)则是将字符串重新转换为对象的过程。
// 序列化示例
class class1 {
public $a = "1";
protected $b = "ThisB";
private $c = "ThisC";
}
$test = new class1();
echo serialize($test);
// 输出: O:6:"class1":3:{s:1:"a";s:1:"1";s:4:" b";s:5:"ThisB";s:9:"class1c";s:5:"ThisC";}
序列化字符串结构解析
序列化字符串格式为:
O:对象名长度:"对象名":对象属性个数:{s:属性名长度:"属性名";s:属性值长度:"属性值";...}
- 公有属性(public):直接显示属性名
- 保护属性(protected):属性名前添加
%00*%00 - 私有属性(private):属性名前添加
%00类名%00
重要特性
- 序列化只保存对象的成员变量,不保存方法
- 反序列化时,底层代码以
;作为字段分隔,以}作为结尾 - 反序列化根据长度判断内容,长度不对应会报错
0x03 反序列化漏洞原理
漏洞产生条件
- 反序列化参数用户可控
- 服务器未对反序列化内容进行过滤
- 存在可利用的魔术方法
关键魔术方法
| 魔术方法 | 触发条件 |
|---|---|
| __construct() | 创建新对象时调用 |
| __destruct() | 对象销毁时调用 |
| __wakeup() | 反序列化时调用 |
| __toString() | 对象被当作字符串使用时 |
| __sleep() | 对象被序列化前调用 |
| __get()/__set() | 访问/设置未定义属性时 |
| __invoke() | 以函数方式调用对象时 |
| __call()/__callStatic() | 调用不存在的方法/静态方法时 |
0x04 反序列化漏洞类型与实例
1. 简单反序列化漏洞
漏洞代码示例:
class A{
var $test = "demo";
function __destruct(){
echo $this->test;
}
}
$a = $_GET['test'];
$a_unser = unserialize($a);
利用方式:
构造payload控制输出内容:
http://127.0.0.1/test.php?test=O:1:"A":1:{s:4:"test";s:5:"hello";}
2. __wakeup绕过(CVE-2016-7124)
漏洞特征:
当序列化字符串中表示对象属性个数的值大于真实的属性个数时,会跳过__wakeup()的执行
漏洞代码示例:
class A{
var $target = "test";
function __wakeup(){
$this->target = "wakeup!";
}
function __destruct(){
$fp = fopen("shell.php","w");
fputs($fp,$this->target);
fclose($fp);
}
}
$test = $_GET['test'];
$test_unseria = unserialize($test);
利用方式:
构造payload将对象属性个数改为大于实际值:
O:1:"A":2:{s:6:"target";s:10:"hacker.php";}
3. 反序列化字符逃逸
类型1:替换修改导致字符串变长
漏洞代码示例:
function filter($str){
return str_replace('bb', 'ccc', $str);
}
class A{
public $name = 'aaaa';
public $pass = '123456';
}
利用原理:
- 利用filter函数将'bb'替换为'ccc',使字符串变长
- 精心构造payload使多出的字符闭合原序列化字符串并添加恶意内容
利用步骤:
- 构造name值为
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";s:4:"pass";s:6:"hacker";} - 序列化后经过filter替换,多出的字符将闭合原序列化字符串并修改pass值
类型2:字符串减少导致的字符逃逸
典型例题:[0CTF 2016]piapiapia
漏洞分析:
- 代码中存在filter函数将敏感词替换为'hacker'
- 替换导致字符串长度减少,可利用此特性构造逃逸
利用步骤:
- 计算需要逃逸的字符数
- 构造nickname包含特定数量的敏感词,使替换后字符减少
- 利用减少的空间注入恶意序列化内容
4. Phar反序列化漏洞
漏洞原理:
Phar文件的元数据(metadata)部分会被反序列化,攻击者可构造恶意Phar文件触发反序列化
利用条件:
- 存在文件操作函数如file_exists()、fopen()等
- 可上传Phar文件或能控制Phar文件路径
利用方式:
- 构造恶意Phar文件
- 通过文件操作函数触发Phar元数据反序列化
0x05 防御措施
- 不要反序列化不可信数据
- 使用白名单验证反序列化类
- 对序列化数据进行签名验证
- 使用php.ini配置限制:
unserialize_callback_func设置回调函数allow_url_include和allow_url_fopen设为Off
- 更新PHP版本修复已知漏洞
0x06 总结
PHP反序列化漏洞危害严重,攻击者可利用其执行任意代码、文件操作等。理解序列化格式、魔术方法触发条件和各种绕过技巧是挖掘和防御此类漏洞的关键。开发中应严格验证反序列化输入,避免使用危险函数,并及时更新PHP版本修复已知漏洞。