CTF Web 入门:从[HCTF 2018]WarmUp看PHP白名单绕过的2种核心技巧
在CTF Web安全竞赛中,PHP代码审计是常见的挑战类型。本文将以经典题目[HCTF 2018]WarmUp为例,深入剖析两种关键的PHP白名单绕过技巧,帮助初学者建立系统化的解题思路。
1. 题目背景与代码分析
首先我们查看题目提供的核心代码片段:
class emmm { public static function checkFile(&$page) { $whitelist = ["source"=>"source.php","hint"=>"hint.php"]; if (!isset($page) || !is_string($page)) { echo "you can't see it"; return false; } if (in_array($page, $whitelist)) { return true; } $_page = mb_substr($page, 0, mb_strpos($page.'?', '?')); if (in_array($_page, $whitelist)) { return true; } $_page = urldecode($page); $_page = mb_substr($_page, 0, mb_strpos($_page.'?', '?')); if (in_array($_page, $whitelist)) { return true; } echo "you can't see it"; return false; } }这段代码实现了一个白名单校验机制,主要功能点包括:
- 定义白名单
$whitelist,仅允许访问source.php和hint.php - 通过
in_array()检查输入是否在白名单中 - 使用
mb_substr()和mb_strpos()处理带参数的URL - 对输入进行URL解码后再次检查
2. 关键PHP函数解析
2.1 mb_substr与mb_strpos组合
这两个函数在处理多字节字符时特别重要:
| 函数 | 描述 | 危险用法示例 |
|---|---|---|
mb_substr() | 安全的多字节字符串截取 | mb_substr($input, 0, mb_strpos($input.'?', '?')) |
mb_strpos() | 返回字符串在另一字符串中首次出现的位置 | 可能被用于构造特殊路径 |
典型利用场景:
// 当输入为"source.php?../../../../flag"时 $_page = mb_substr($page, 0, mb_strpos($page.'?', '?')); // $_page = "source.php"2.2 in_array函数特性
in_array()函数用于检查值是否存在于数组中:
// 严格模式关闭时存在类型转换问题 in_array("1", ["a", 1, "b"]); // 返回true2.3 urldecode的双重解析
PHP会对GET参数自动进行一次URL解码,手动调用urldecode()可能导致双重解码:
原始输入: source.php%253f../../flag 第一次解码: source.php%3f../../flag 第二次解码: source.php?../../flag3. 第一种绕过技巧:字符串截断
利用mb_substr和mb_strpos的组合特性,我们可以构造特殊路径绕过检查:
构造原理:
- 在文件名后添加
?字符 - 利用截断获取白名单通过的前缀
- 附加实际要访问的路径
- 在文件名后添加
Payload示例:
/source.php?../../../../ffffllllaaaagggg操作步骤:
- 检查
source.php?的前缀source.php在白名单中 include实际加载的是source.php?../../../../ffffllllaaaagggg- 服务器解析时会忽略
?后的路径参数
- 检查
注意:这种技巧依赖于服务器对包含路径的特殊处理方式,不同环境可能有差异。
4. 第二种绕过技巧:双重URL编码
利用URL解码特性构造特殊输入:
构造原理:
- 对关键字符
?进行双重编码(%253f) - 第一次自动解码为
%3f - 第二次
urldecode()解码为?
- 对关键字符
Payload示例:
/source.php%253f../../../../ffffllllaaaagggg代码执行流程:
$_page = urldecode("source.php%253f../../flag"); // 变为"source.php%3f../../flag" $_page = mb_substr($_page, 0, mb_strpos($_page.'?', '?')); // 截取后变为"source.php"
5. 防御方案对比
针对这类白名单绕过,开发者可以采取以下防护措施:
| 防护措施 | 有效性 | 实现复杂度 |
|---|---|---|
使用realpath()解析路径 | ★★★★★ | 中等 |
严格模式in_array(..., true) | ★★★☆☆ | 简单 |
禁用危险函数如include | ★★★★★ | 高 |
| 白名单完整路径校验 | ★★★★☆ | 中等 |
6. 实战思维导图
以下是面对类似白名单校验时的通用解题思路:
确定白名单内容
- 查找
in_array或白名单数组定义 - 确认允许访问的基础文件
- 查找
分析校验逻辑
- 检查字符串处理流程
- 识别可能的截断点
尝试绕过方法
- 参数附加法(添加
?或#) - 路径遍历(
../) - 编码混淆(双重URL编码)
- 参数附加法(添加
验证包含结果
- 测试文件包含是否成功
- 检查错误信息获取线索
7. 扩展训练建议
为了巩固这些技巧,建议尝试以下练习:
- 修改题目代码,使两种绕过方法都失效
- 在Docker环境中搭建类似题目
- 研究其他CTF题目中的白名单绕过案例
- 编写自动化检测脚本识别这类漏洞
掌握这些核心技巧后,面对大多数PHP白名单校验场景都能快速找到突破点。在实际CTF比赛中,灵活组合多种技巧往往能解决更复杂的挑战。