庖丁解牛从mb_substr与问号拼接看WarmUp题目的精妙绕过设计在CTF竞赛中Web安全类题目常常考验选手对代码逻辑的深刻理解而非简单的工具使用。2018年HCTF的WarmUp题目就是一个典型案例它通过mb_substr和mb_strpos的函数组合构建了一个看似简单却暗藏玄机的白名单验证机制。本文将聚焦于这个核心函数链揭示其背后的精妙设计。1. 关键代码片段的行为解析让我们首先聚焦于这段看似简单却暗藏玄机的代码$_page mb_substr( $page, 0, mb_strpos($page . ?, ?) );这段代码实际上完成了三个关键操作字符串拼接$page . ?确保无论原始输入是否包含问号新字符串中必然存在至少一个问号位置查找mb_strpos在新字符串中定位第一个问号的位置子串截取mb_substr根据找到的位置截取问号前的部分这种设计产生了一个有趣的现象无论输入是hint.php还是hint.php?abc最终$_page都会是hint.php。这是因为对于hint.php拼接后变为hint.php?问号位置为8截取前8个字符即hint.php对于hint.php?abc拼接后变为hint.php?abc?第一个问号仍在8的位置函数行为对比表函数输入示例处理过程输出结果mb_strposhint.php→hint.php?查找?位置8mb_substrhint.php, 0, 8截取前8字符hint.phpmb_strposhint.php?abc→hint.php?abc?查找第一个?位置8mb_substrhint.php?abc, 0, 8截取前8字符hint.php2. 白名单验证的差异点分析题目中的安全验证分为两个关键阶段初始检查in_array($page, $whitelist)处理后检查in_array($_page, $whitelist)这种设计本意是提供灵活性允许带参数的访问如hint.php?paramvalue但却意外创造了绕过机会。关键在于初始检查直接验证原始输入是否在白名单中处理后检查验证截取后的结果是否在白名单中攻击者可以利用这个差异构造一个既能在处理后通过验证又能在文件包含时指向其他路径的输入。例如hint.php?/../../../../ffffllllaaaagggg这个输入的精妙之处在于处理阶段mb_substr截取后得到hint.php通过白名单检查包含阶段完整的路径被解析最终访问ffffllllaaaagggg文件3. 多层防御与绕过策略题目实际上设置了多层防御但每层都有其特定的处理逻辑第一层验证直接检查原始输入绕过方法直接使用白名单中的文件名第二层验证检查截取后的结果绕过方法确保问号前的部分在白名单中第三层验证URL解码后重复检查绕过方法不使用需要解码的特殊字符有效Payload结构分析白名单文件名?/任意路径/目标文件其中白名单文件名必须是source.php或hint.php?触发截取逻辑的关键字符/../../..路径回溯根据实际情况调整层数目标文件本题中为ffffllllaaaagggg4. 实战中的路径计算技巧在实际解题过程中确定需要回溯的目录层数是一个关键点。通常可以采用以下方法默认Web目录结构假设题目部署在标准Linux环境下Web根目录/var/www/html/Flag位置通常直接在/根目录下层数计算从source.php所在位置假设为/var/www/html/到根目录需要4层../因此典型Payload为?/../../../../ffffllllaaaagggg目录跳转示意图/var/www/html/source.php # 起始点 /var/www/html/ # ../ /var/www/ # ../../ /var/ # ../../../ / # ../../../../ ffffllllaaaagggg # 目标文件在实际CTF比赛中这种路径遍历的技巧不仅限于这道题目。理解其核心原理后可以应用于多种场景当遇到文件包含漏洞时首先尝试确定基础目录结构通过合理的../组合尝试访问已知或猜测的文件位置注意不同操作系统Windows/Linux的路径分隔符差异