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:整型索引0
  • s: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

  1. 发现备份文件www.zip
  2. 构造payload绕过__wakeup
  3. 修改属性数量为更大值
O:4:"Name":3:{s:14:"%00Name%00username";s:5:"admin";s:14:"%00Name%00password";i:100;}

3. 正则绕过技术

  1. 加号绕过O:+4:"test"...
  2. 数组包裹serialize(array($a))
  3. 16进制表示S:4:"\00*\00\61"代替s:4:"\x00*\x00a"
  4. 引用绕过:使两个属性始终相等

4. 字符逃逸漏洞

当序列化后数据进行过滤替换时可能导致结构破坏。

字符增多情况

  • 计算需要逃逸的字符串长度
  • 构造足够数量的触发词使后续内容成为有效属性

字符减少情况

  • 计算到下一个可控变量的距离
  • 构造payload使过滤后格式正确

例题:

// 过滤将Firebasky替换为更长的Firebaskyup
FirebaskyFirebasky...";s:8:"password";s:5:"yu22x";}

三、对象注入漏洞

当unserialize参数可控且存在危险魔术方法时可能造成任意对象注入。

利用条件

  1. unserialize参数可控
  2. 存在含危险魔术方法的类

四、PHAR反序列化

1. PHAR文件结构

  1. stub:标识头,如<?php __HALT_COMPILER();?>
  2. manifest:元数据,存储序列化信息
  3. contents:压缩内容
  4. 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. 绕过技术

  1. 改变协议
    compress.zlib://phar://
    php://filter/resource=phar://
    
  2. 修改文件头:添加GIF/PNG等文件头
  3. 修改扩展名:伪装为其他格式文件

五、Session反序列化

1. 处理引擎差异

引擎 存储格式
php `键名
php_serialize 序列化数组
php_binary 长度+键名+序列化值

2. 利用方式

  1. 使用php_serialize引擎存入|序列化payload
  2. 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

  1. 利用上传进度机制注入session
  2. 构造payload读取目录和文件内容
  3. 利用不同处理器差异触发反序列化
|O:5:\"OowoO\":1:{s:4:\"mdzz\";s:36:\"print_r(scandir(dirname(__FILE__)));\";}

防御建议

  1. 不要反序列化不可信数据
  2. 使用JSON等更安全的序列化格式
  3. 严格检查反序列化输入
  4. 限制危险魔术方法的使用
  5. 保持PHP环境更新
PHP序列化与反序列化漏洞全面解析 一、基础概念 1. 序列化与反序列化简介 序列化是将数据转化为可逆数据结构的过程,反序列化则是将序列化字符串还原为原始对象的过程。PHP中使用: serialize() :将对象格式化为有序字符串 unserialize() :将字符串还原为对象 主要用于数据传输和存储,如session缓存、cookie等。 2. 序列化格式解析 格式说明: a:3 :数组,3个元素 i:0 :整型索引0 s:4:"xiao" :字符串,长度4,值"xiao" 类序列化示例: 访问控制修饰符影响: 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 2. 绕过__ wakeup (CVE-2016-7124) 影响版本: PHP5 < 5.6.25 PHP7 < 7.0.10 利用方式 :序列化字符串中对象属性个数大于实际个数时跳过__ wakeup执行。 例题:[ 极客大挑战2019]PHP 发现备份文件www.zip 构造payload绕过__ wakeup 修改属性数量为更大值 3. 正则绕过技术 加号绕过 : O:+4:"test"... 数组包裹 : serialize(array($a)) 16进制表示 : S:4:"\00*\00\61" 代替 s:4:"\x00*\x00a" 引用绕过 :使两个属性始终相等 4. 字符逃逸漏洞 当序列化后数据进行过滤替换时可能导致结构破坏。 字符增多情况 计算需要逃逸的字符串长度 构造足够数量的触发词使后续内容成为有效属性 字符减少情况 计算到下一个可控变量的距离 构造payload使过滤后格式正确 例题: 三、对象注入漏洞 当unserialize参数可控且存在危险魔术方法时可能造成任意对象注入。 利用条件 : unserialize参数可控 存在含危险魔术方法的类 四、PHAR反序列化 1. PHAR文件结构 stub :标识头,如 <?php __HALT_COMPILER();?> manifest :元数据,存储序列化信息 contents :压缩内容 signature :签名 2. 利用方法 触发函数 : file_ exists() file_ get_ contents() 各种文件处理函数 3. 绕过技术 改变协议 : 修改文件头 :添加GIF/PNG等文件头 修改扩展名 :伪装为其他格式文件 五、Session反序列化 1. 处理引擎差异 | 引擎 | 存储格式 | |------|----------| | php | 键名|序列化值 | | php_ serialize | 序列化数组 | | php_ binary | 长度+键名+序列化值 | 2. 利用方式 使用php_ serialize引擎存入 |序列化payload php引擎会将 | 后内容反序列化 3. session.upload_ progress利用 通过文件上传进度机制注入session: 例题:Jarvis OJ-PHPINFO 利用上传进度机制注入session 构造payload读取目录和文件内容 利用不同处理器差异触发反序列化 防御建议 不要反序列化不可信数据 使用JSON等更安全的序列化格式 严格检查反序列化输入 限制危险魔术方法的使用 保持PHP环境更新