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

重要特性

  1. 序列化只保存对象的成员变量,不保存方法
  2. 反序列化时,底层代码以;作为字段分隔,以}作为结尾
  3. 反序列化根据长度判断内容,长度不对应会报错

0x03 反序列化漏洞原理

漏洞产生条件

  1. 反序列化参数用户可控
  2. 服务器未对反序列化内容进行过滤
  3. 存在可利用的魔术方法

关键魔术方法

魔术方法 触发条件
__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';
}

利用原理

  1. 利用filter函数将'bb'替换为'ccc',使字符串变长
  2. 精心构造payload使多出的字符闭合原序列化字符串并添加恶意内容

利用步骤

  1. 构造name值为bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";s:4:"pass";s:6:"hacker";}
  2. 序列化后经过filter替换,多出的字符将闭合原序列化字符串并修改pass值

类型2:字符串减少导致的字符逃逸

典型例题:[0CTF 2016]piapiapia

漏洞分析

  1. 代码中存在filter函数将敏感词替换为'hacker'
  2. 替换导致字符串长度减少,可利用此特性构造逃逸

利用步骤

  1. 计算需要逃逸的字符数
  2. 构造nickname包含特定数量的敏感词,使替换后字符减少
  3. 利用减少的空间注入恶意序列化内容

4. Phar反序列化漏洞

漏洞原理
Phar文件的元数据(metadata)部分会被反序列化,攻击者可构造恶意Phar文件触发反序列化

利用条件

  1. 存在文件操作函数如file_exists()、fopen()等
  2. 可上传Phar文件或能控制Phar文件路径

利用方式

  1. 构造恶意Phar文件
  2. 通过文件操作函数触发Phar元数据反序列化

0x05 防御措施

  1. 不要反序列化不可信数据
  2. 使用白名单验证反序列化类
  3. 对序列化数据进行签名验证
  4. 使用php.ini配置限制:
    • unserialize_callback_func设置回调函数
    • allow_url_includeallow_url_fopen设为Off
  5. 更新PHP版本修复已知漏洞

0x06 总结

PHP反序列化漏洞危害严重,攻击者可利用其执行任意代码、文件操作等。理解序列化格式、魔术方法触发条件和各种绕过技巧是挖掘和防御此类漏洞的关键。开发中应严格验证反序列化输入,避免使用危险函数,并及时更新PHP版本修复已知漏洞。

PHP反序列化漏洞全面解析与实战指南 0x01 前言 PHP反序列化漏洞是Web安全中常见且危害较大的漏洞类型。本文将从基础概念入手,逐步深入讲解四种常见的PHP反序列化漏洞类型,包括简单反序列化漏洞、__ wakeup绕过、字符逃逸漏洞等,并结合CTF例题进行实战分析。 0x02 反序列化基础概念 序列化与反序列化 序列化(serialize)是将对象转换为可存储或传输的字符串的过程,反序列化(unserialize)则是将字符串重新转换为对象的过程。 序列化字符串结构解析 序列化字符串格式为: O:对象名长度:"对象名":对象属性个数:{s:属性名长度:"属性名";s:属性值长度:"属性值";...} 公有属性(public):直接显示属性名 保护属性(protected):属性名前添加 %00*%00 私有属性(private):属性名前添加 %00类名%00 重要特性 序列化只保存对象的成员变量,不保存方法 反序列化时,底层代码以 ; 作为字段分隔,以 } 作为结尾 反序列化根据长度判断内容,长度不对应会报错 0x03 反序列化漏洞原理 漏洞产生条件 反序列化参数用户可控 服务器未对反序列化内容进行过滤 存在可利用的魔术方法 关键魔术方法 | 魔术方法 | 触发条件 | |---------|---------| | __ construct() | 创建新对象时调用 | | __ destruct() | 对象销毁时调用 | | __ wakeup() | 反序列化时调用 | | __ toString() | 对象被当作字符串使用时 | | __ sleep() | 对象被序列化前调用 | | __ get()/__ set() | 访问/设置未定义属性时 | | __ invoke() | 以函数方式调用对象时 | | __ call()/__ callStatic() | 调用不存在的方法/静态方法时 | 0x04 反序列化漏洞类型与实例 1. 简单反序列化漏洞 漏洞代码示例 : 利用方式 : 构造payload控制输出内容: 2. __ wakeup绕过(CVE-2016-7124) 漏洞特征 : 当序列化字符串中表示对象属性个数的值大于真实的属性个数时,会跳过__ wakeup()的执行 漏洞代码示例 : 利用方式 : 构造payload将对象属性个数改为大于实际值: 3. 反序列化字符逃逸 类型1:替换修改导致字符串变长 漏洞代码示例 : 利用原理 : 利用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版本修复已知漏洞。