news 2026/5/20 9:26:37

PHP代码审计实战:手把手带你审计BUUCTF那道‘滑稽’的WarmUp题目

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
PHP代码审计实战:手把手带你审计BUUCTF那道‘滑稽’的WarmUp题目

PHP代码审计实战:从WarmUp题目看白名单绕过与多层防御突破

在CTF竞赛和实际渗透测试中,PHP代码审计能力往往是区分初级与中级安全研究员的关键分水岭。今天我们将以BUUCTF平台经典的[HCTF 2018]WarmUp题目为蓝本,进行一次深度代码审计实战。这道看似简单的题目实则包含了白名单验证、字符串处理函数链、URL解码漏洞等多层防御机制,是学习PHP安全审计的绝佳案例。

1. 环境搭建与初步观察

首先我们需要搭建本地测试环境来动态分析代码行为。推荐使用Docker快速构建隔离的PHP环境:

docker run -d -p 8080:80 --name warmup -v "$PWD":/var/www/html php:7.4-apache

将题目源码保存为index.php后访问http://localhost:8080,页面会显示两个关键信息:

  1. 高亮的源代码(由highlight_file(__FILE__)实现)
  2. 一个滑稽表情图片(当检查不通过时的默认输出)

关键问题定位:通过页面输出和代码逻辑可知,我们需要控制$_REQUEST['file']参数,使其通过emmm::checkFile()验证,最终实现文件包含。

2. 核心防御机制拆解

让我们聚焦emmm类的checkFile方法,这是整个题目的防御核心。该方法采用四层递进式验证:

2.1 基础类型检查层

if (!isset($page) || !is_string($page)) { echo "you can't see it"; return false; }

这一层是最基础的防御:

  • 确保$page参数存在且为字符串类型
  • 过滤了null、数组、对象等非字符串输入

2.2 直接白名单匹配层

$whitelist = ["source"=>"source.php","hint"=>"hint.php"]; if (in_array($page, $whitelist)) { return true; }

白名单设计特点:

  • 仅允许source.phphint.php两个文件
  • 使用松散比较(in_array默认不检查类型)
  • 键值对形式存储但只比较值

2.3 问号截断验证层

$_page = mb_substr( $page, 0, mb_strpos($page . '?', '?') ); if (in_array($_page, $whitelist)) { return true; }

这一层引入了多重防御:

  1. mb_strpos定位第一个问号位置
  2. mb_substr截取问号前的内容
  3. 对截取结果再次进行白名单校验

2.4 URL解码穿透层

$_page = urldecode($page); $_page = mb_substr( $_page, 0, mb_strpos($_page . '?', '?') ); if (in_array($_page, $whitelist)) { return true; }

最终防御层特点:

  • 对输入进行URL解码处理
  • 重复问号截断验证流程
  • 可能产生双重解码漏洞(服务器自动解码+手动解码)

3. 漏洞链构造与突破路径

要成功绕过所有检查,我们需要构造一个满足以下所有条件的payload:

  1. 原始输入必须是字符串
  2. 经过URL解码后,问号截断前的部分必须匹配白名单
  3. 最终包含的文件路径需要指向目标flag文件

关键突破点在于利用URL编码和服务器解码特性:

处理阶段解码行为示例输入
客户端提交原始编码source.php%253F../../../../fffflllaaaggg
服务器自动解码解码%xxsource.php%3F../../../../fffflllaaaggg
代码中urldecode()再次解码source.php?../../../../fffflllaaaggg

具体攻击步骤如下:

  1. 确定白名单文件:从代码可知source.php在允许列表中
  2. 构造多层路径穿越:使用../../../../实现目录跳转
  3. 编码关键字符:将问号编码为%253F(双重编码)
  4. 组合最终payload:
?file=source.php%253F../../../../fffflllaaaggg

4. 动态调试与验证

为了验证我们的分析,可以使用PHP内置的Web服务器进行调试:

php -S localhost:8000

然后通过cURL测试payload:

curl "http://localhost:8000/?file=source.php%253F../../../../etc/passwd"

在调试过程中,可以添加以下调试代码观察中间状态:

var_dump($_REQUEST['file']); var_dump(urldecode($_REQUEST['file'])); var_dump(mb_substr(urldecode($_REQUEST['file']), 0, mb_strpos(urldecode($_REQUEST['file']).'?', '?')));

5. 防御方案与最佳实践

从防御者角度,这道题目展示了几个常见的安全误区:

  1. 不安全的解码顺序:应在验证前完成所有解码操作
  2. 路径校验不完整:未检查最终包含路径是否在白名单目录内
  3. 依赖单一过滤机制:应采用纵深防御策略

改进后的安全方案应包含:

// 安全的文件包含检查示例 function safeInclude($file) { $whitelist = ['allowed_dir/']; $realBase = realpath('allowed_dir'); $filepath = realpath($file); if ($filepath === false || strpos($filepath, $realBase) !== 0) { return false; } return is_file($filepath); }

6. 扩展思考与变种挑战

掌握了基础绕过方法后,可以尝试以下变种挑战:

  1. 当白名单使用严格模式(in_array的第三个参数为true)时如何绕过?
  2. 如果禁用urldecode函数,还有哪些替代方案?
  3. 如何利用mb_substrmb_strpos的字符集处理特性进行绕过?

在实际审计中,类似的防御模式经常出现在:

  • 文件上传功能的白名单校验
  • 模板引擎的包含限制
  • 插件系统的模块加载

7. 工具链与自动化检测

对于大规模代码审计,可以结合以下工具提高效率:

  1. 静态分析工具

    # 使用phpcs-security-audit扫描 phpcs --standard=Security --extensions=php /path/to/code
  2. 动态模糊测试

    # 使用Radamsa生成变异payload echo "source.php" | radamsa --count 100 --output testcase-%n
  3. 自定义规则检测

    # 使用grep查找危险模式 grep -nE '(include|require)(_once)?\s*\(\s*\$_' *.php

在真实环境中,这类漏洞往往不会如此明显,需要结合上下文和业务逻辑进行深度分析。例如,我曾经遇到过一个案例,开发者使用json_decode处理用户输入后再进行文件包含,看似安全实则可以通过JSON编码构造特殊字符实现绕过。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/20 9:16:21

HoRain云--Skills skill-creator 创建 Skill

🎬 HoRain 云小助手:个人主页 ⛺️生活的理想,就是为了理想的生活! ⛳️ 推荐 前些天发现了一个超棒的服务器购买网站,性价比超高,大内存超划算!忍不住分享一下给大家。点击跳转到网站。 目录 ⛳️ 推荐 …

作者头像 李华
网站建设 2026/5/20 9:16:21

LibreDWG完全指南:如何在2025年高效处理AutoCAD DWG文件转换

LibreDWG完全指南:如何在2025年高效处理AutoCAD DWG文件转换 【免费下载链接】libredwg Official mirror of libredwg. With CI hooks and nightly releases. PRs ok 项目地址: https://gitcode.com/gh_mirrors/li/libredwg LibreDWG是一款强大的开源CAD文件…

作者头像 李华
网站建设 2026/5/20 9:11:46

移远RX500U模组的USB接口还能这么玩?从AT调试、网卡共享到ADB刷机的三种模式切换指南

移远RX500U模组的USB接口三重玩法实战手册 当你第一次拿到移远RX500U这款5G模组时,可能只把它当作普通的通信模块。但它的USB接口实际上是个功能强大的多面手——就像瑞士军刀的主刀片,通过简单配置就能切换三种完全不同的工作模式。本文将带你解锁AT命令…

作者头像 李华