一篇文章带你了解反序列化漏洞
字数 1141 2025-08-15 21:31:25

PHP反序列化漏洞详解

一、序列化与反序列化基础

1. 基本概念

  • 序列化(serialize): 将对象的状态信息转换为可以存储或传输的形式的过程。在PHP中,序列化将对象转换为字符串形式。

  • 反序列化(unserialize): 将序列化后的字符串重新转换为对象状态信息的过程。

2. 序列化示例

class test {
    var $test = "MSKJ";
    function __destruct(){
        //echo $this->test;
    }
}

$obj = new test();
$ser = serialize($obj);
echo $ser;

输出结果:

O:4:"test":1:{s:4:"test";s:4:"MSKJ";}

二、PHP魔术方法

魔术方法在特定情况下会被自动调用,与反序列化相关的重要魔术方法包括:

  1. __construct(): 对象创建(new)时自动调用,但unserialize()时不会自动调用
  2. __destruct(): 对象销毁时自动执行
  3. __wakeup(): 使用unserialize时自动调用
  4. __sleep(): 使用serialize时自动调用
  5. __toString(): 把类当作字符串使用时触发
  6. __invoke(): 当脚本尝试将对象调用为函数时触发

三、反序列化漏洞原理

反序列化漏洞产生的原因是应用程序在处理对象、魔术函数以及序列化相关问题时存在缺陷。当传给unserialize()的参数可控时,攻击者可以注入恶意payload,在反序列化时触发对象中的魔术方法,从而执行恶意代码。

四、漏洞示例分析

1. 基础示例

class convent {
    var $warn = "No hacker.";
    function __destruct(){
        eval($this->warn);
    }
    function __wakeup(){
        foreach(get_object_vars($this) as $k => $v) {
            $this->$k = null;
        }
    }
}

$cmd = $_POST['cmd'];
unserialize($cmd);

2. 魔术方法执行顺序

在反序列化时,魔术方法的执行顺序为:

  1. __wakeup() (如果存在)
  2. __destruct() (对象销毁时)

3. 绕过__wakeup()的方法

当反序列化字符串中表示的对象属性数量大于实际数量时,可以绕过__wakeup()的执行:

原始序列化字符串:

O:7:"convent":1:{s:4:"warn";s:10:"No hacker.";}

修改为(将属性数量从1改为2):

O:7:"convent":2:{s:4:"warn";s:10:"phpinfo();";}

五、漏洞利用步骤

  1. 构造恶意类,在__destruct()__wakeup()等方法中插入恶意代码
  2. 序列化该对象
  3. 修改序列化字符串中的属性数量以绕过__wakeup()
  4. 将恶意序列化字符串通过可控参数传递给unserialize()

六、防御措施

  1. 不要反序列化不可信的数据
  2. 使用白名单验证输入
  3. 限制反序列化类
  4. 使用__wakeup()__destruct()方法进行安全检查
  5. 更新PHP版本,修复已知漏洞

七、CTF题目实战分析

给定题目代码:

highlight_file(__FILE__);
error_reporting(0);
class convent {
    var $warn = "No hacker.";
    function __destruct(){
        eval($this->warn);
    }
    function __wakeup(){
        foreach(get_object_vars($this) as $k => $v) {
            $this->$k = null;
        }
    }
}
$cmd = $_POST['cmd'];
unserialize($cmd);

利用步骤:

  1. 构造payload将$warn设置为phpinfo();
  2. 绕过__wakeup()方法
  3. 通过POST传递payload

最终payload:

O:7:"convent":2:{s:4:"warn";s:10:"phpinfo();";}

八、总结

PHP反序列化漏洞是一种危险的漏洞类型,攻击者可以通过精心构造的序列化字符串触发魔术方法中的恶意代码。理解序列化/反序列化过程、魔术方法的执行顺序以及绕过技术是防御此类漏洞的关键。开发者应始终对反序列化操作保持警惕,并实施严格的安全措施。

PHP反序列化漏洞详解 一、序列化与反序列化基础 1. 基本概念 序列化(serialize) : 将对象的状态信息转换为可以存储或传输的形式的过程。在PHP中,序列化将对象转换为字符串形式。 反序列化(unserialize) : 将序列化后的字符串重新转换为对象状态信息的过程。 2. 序列化示例 输出结果: 二、PHP魔术方法 魔术方法在特定情况下会被自动调用,与反序列化相关的重要魔术方法包括: __construct() : 对象创建(new)时自动调用,但unserialize()时不会自动调用 __destruct() : 对象销毁时自动执行 __wakeup() : 使用unserialize时自动调用 __sleep() : 使用serialize时自动调用 __toString() : 把类当作字符串使用时触发 __invoke() : 当脚本尝试将对象调用为函数时触发 三、反序列化漏洞原理 反序列化漏洞产生的原因是应用程序在处理对象、魔术函数以及序列化相关问题时存在缺陷。当传给unserialize()的参数可控时,攻击者可以注入恶意payload,在反序列化时触发对象中的魔术方法,从而执行恶意代码。 四、漏洞示例分析 1. 基础示例 2. 魔术方法执行顺序 在反序列化时,魔术方法的执行顺序为: __wakeup() (如果存在) __destruct() (对象销毁时) 3. 绕过__ wakeup()的方法 当反序列化字符串中表示的对象属性数量大于实际数量时,可以绕过 __wakeup() 的执行: 原始序列化字符串: 修改为(将属性数量从1改为2): 五、漏洞利用步骤 构造恶意类,在 __destruct() 或 __wakeup() 等方法中插入恶意代码 序列化该对象 修改序列化字符串中的属性数量以绕过 __wakeup() 将恶意序列化字符串通过可控参数传递给unserialize() 六、防御措施 不要反序列化不可信的数据 使用白名单验证输入 限制反序列化类 使用 __wakeup() 或 __destruct() 方法进行安全检查 更新PHP版本,修复已知漏洞 七、CTF题目实战分析 给定题目代码: 利用步骤: 构造payload将 $warn 设置为 phpinfo(); 绕过 __wakeup() 方法 通过POST传递payload 最终payload: 八、总结 PHP反序列化漏洞是一种危险的漏洞类型,攻击者可以通过精心构造的序列化字符串触发魔术方法中的恶意代码。理解序列化/反序列化过程、魔术方法的执行顺序以及绕过技术是防御此类漏洞的关键。开发者应始终对反序列化操作保持警惕,并实施严格的安全措施。