1. 从BuyFlag题目看PHP弱类型比较的陷阱第一次看到这个CTF题目时我差点笑出声来。FLAG NEED YOUR 100000000 MONEY这个提示实在太直白了但真正解题时才发现处处是坑。这个题目完美展示了PHP弱类型比较的魔幻特性很多新手开发者经常在这里栽跟头。先来看题目给出的关键代码片段if (isset($_POST[password])) { $password $_POST[password]; if (is_numeric($password)) { echo password cant be number; } elseif ($password 404) { echo Password Right!; } }这段代码看似简单实则暗藏玄机。它先用is_numeric()检查密码是否为数字但又要求密码的值等于404。这就像要求一个人不能是学生但必须有学生证一样矛盾。不过PHP的弱类型比较给了我们可乘之机。我尝试用404a作为密码时神奇的事情发生了is_numeric(404a)返回false因为这不是纯数字404a 404返回true因为PHP会尝试将字符串转为数字比较这种特性在实际开发中经常导致安全问题。比如验证码检查时如果使用弱比较输入123abc可能会被当作123通过验证。我在一次渗透测试中就利用这个漏洞绕过了某网站的验证码系统。2. 深入理解PHP的类型转换机制要彻底搞懂这个漏洞我们需要了解PHP的类型转换规则。PHP在弱比较()时会自动进行类型转换这个特性虽然方便但也带来了安全隐患。当字符串与数字比较时PHP会尝试从左到右提取字符串中的数字部分。例如404a → 404a404 → 040e4 → 40e会被当作字母而非科学计数法这种转换规则导致了很多反直觉的结果123abc 123 // true abc123 0 // true 0e123 0e456 // true都转换为0在实际审计中我总结了几个常见的危险场景密码哈希比较时如果使用弱比较0e123和0e456会被认为相等用户权限检查时字符串1admin可能被当作数字1通过验证支付金额验证时100USD可能被当作100处理3. 绕过is_numeric()的多种姿势回到题目我们需要同时满足两个条件不是纯数字绕过is_numeric弱比较等于404利用特性除了原文章提到的404a还有更多绕过方法404%20URL编码空格404.0.0小数点0x194十六进制404e0科学计数法404%00空字节截断我在实际测试中发现不同PHP版本对这些输入的处理略有差异。例如在PHP 7.4中is_numeric(404e0) // true is_numeric(0x194) // false而PHP 8.0后十六进制表示法默认不被is_numeric()接受。这种版本差异在CTF比赛中经常被用作考点。4. 科学计数法在数字比较中的应用题目第二部分要求我们传递一个很大的金额100000000。直接传这个数字会被提示Number length is too long。这时候科学计数法就派上用场了。科学计数法1e8表示1×10⁸正好等于100000000。但题目检查的是字符串长度而1e8只有3个字符完美绕过长度限制。不过这里有个坑点题目实际要求金额必须大于等于100000000。我最初尝试1e8时失败了因为1e8 100000000 // true但题目源码可能是用strcmp比较这时需要password404amoney1e9这样既满足金额要求又保持较短的字符串长度。在实际支付系统中这种科学计数法绕过可能导致严重的业务逻辑漏洞。5. 数组传参绕过strcmp的技巧最精彩的部分是绕过strcmp检查。strcmp本意是比较两个字符串但如果传入数组会怎样题目可能的源码if (strcmp($_POST[money], $flag) 0) { echo $Flag; }当传入money[]0时$_POST[money]变成数组strcmp遇到非字符串参数会返回NULLNULL 0在弱比较下为true这种数组绕过方法在以下场景也适用md5(array()) → NULLsha1(array()) → NULLstrpos(str, array()) → NULL我在审计某CMS时曾发现其密码重置功能使用strcmp比较token通过数组传参直接绕过了验证。6. 实战中的综合应用技巧综合以上知识点完整的解题步骤应该是修改Cookie: user1普通用户→学生用户POST传递password404a绕过is_numeric和弱比较POST传递money[]0数组绕过strcmp用cURL可以这样实现curl -X POST \ -d password404amoney[]0 \ -H Cookie: user1 \ http://example.com/buyflag在实际渗透测试中这类漏洞往往需要组合利用。比如先通过弱类型比较绕过身份验证再用数组绕过关键操作检查。我建议开发者在进行敏感操作检查时使用严格比较检查参数类型是否匹配对输入进行严格过滤7. 防御措施与最佳实践针对这类漏洞我总结了几个防御方案类型严格检查if (is_int($input) $input 404)使用filter_var过滤$password filter_var($_POST[password], FILTER_VALIDATE_INT);哈希比较安全写法if (hash_equals($stored_hash, $user_input_hash))关闭错误提示避免信息泄露ini_set(display_errors, 0);在最近参与的一个金融项目审计中我们发现系统多处使用了弱比较。通过建议改为严格比较避免了潜在的千万级资金风险。