🚀 欢迎来到CTF(夺旗赛)的奇妙世界!作为网络安全圈的“智力冲浪”,CTF让无数技术宅欲罢不能。对于刚入坑的小白来说,Web方向通常是最容易上手的突破口。
而在Web题里,有一个堪称“新兵训练营必刷”的经典漏洞,它不仅在CTF初级赛题中频繁露脸,在早期的真实世界代码中也屡见不鲜——这就是PHP弱类型比较漏洞。
今天,咱们就用最接地气的大白话和实战代码,带你一探究竟,顺便拿下你的第一枚Flag!
什么是PHP弱类型比较?
简单来说,PHP是一门弱类型语言。它在定义变量时不需要显式声明类型(比如它是整数、字符串还是布尔值),PHP会根据上下文自己去“猜”。
这种灵活性在写代码时很爽,但在进行安全校验时,就是安全人员的噩梦了。因为在进行相等性比较时,PHP会自动进行隐式类型转换。这就导致了一些让人大跌眼镜的“魔幻现实”。
在PHP中,有两种比较运算符:
那些年,PHP自动脑补的“名场面”
为了让你直观感受一下 == 有多任性,我们来看几行代码:
var_dump("123" == 123); // True (字符串转成了整数)var_dump("123admin" == 123); // True (PHP:开头是123,后面不认识,强行截取前截)var_dump("admin" == 0); // True (PHP:字符串开头没数字,那整个字符串就当0吧)
💡 核心逻辑: > 当一个字符串与一个数字用 == 进行比较时,PHP会尝试把字符串转换为数字。如果字符串开头是数字,就截取前面的数字;如果开头没数字,就直接算作 0。
进阶大坑:经典的“0e”漏洞(MD5碰撞)
在CTF中,最常考的就是 0e 开头的字符串。在科学计数法中,0e后面加数字 表示 $0 \times 10$ 的几次方,其值永远是 0。
如果两个不同的字符串,经过MD5加密后,结果都是以 0e 开头且后面全都是数字,那么在PHP眼中:
"0e12345..." == "0e67890..."$\rightarrow$0 == 0$\rightarrow$True!
模拟CTF实战:夺取你的Flag!
光说不练假把式,我们直接来看一道经典的CTF Web源码。题目要求很简单:绕过层层代码关卡,拿到Flag。
📋 题目源码
<?phpinclude("flag.php");highlight_file(__FILE__);if (isset($_GET['a']) && isset($_GET['b'])) { $a = $_GET['a']; $b = $_GET['b']; // 第一关:a和b不能相等,但两者的MD5值必须“相等” if ($a != $b && md5($a) == md5($b)) { echo "恭喜通过第一关!<br>"; // 第二关:从POST接收参数c,要求c不能等于0,但c和0弱相等 $c = $_POST['c']; if ($c != 0 && $c == 0) { echo "绝杀!这是你的Flag:执行成功! " . $FLAG; } else { echo "卡在最后一公里,再想想?"; } } else { echo "第一关就过不去?再瞅瞅代码。"; }}?>
🛠️ 解题思路(Payload构造)
🔓 第一关:绕过 md5($a) == md5($b)
我们需要找两个内容不同($a \neq b$),但MD5值以 0e 开头且后面全是数字的字符串。
这里提供一组CTF圈内人尽皆知的经典“魔术字符串”:
因为两者的MD5在弱类型比较下都会被当作 0,所以 0 == 0 成立!
传参方式(GET):
?a=QNKCDZO&b=240610708
🔓 第二关:绕过 $c != 0 && $c == 0
这里要求 c 本身不能是整数 0,但是和 0 进行 == 比较时要返回True。
利用我们前面讲过的知识:如果字符串开头没有数字,PHP会将其转换为 0。
所以,我们可以让 c 等于任何纯英文字符串,比如 "admin"、"abc" 或者 "flag"。
此时:
传参方式(POST):
c=admin
🎯 最终通关
在浏览器URL后面输入:
http://challenge_ip/?a=QNKCDZO&b=240610708
同时利用Postman或火狐的HackBar插件,在POST数据中带上:
c=admin
点击发送,屏幕上就会蹦出你梦寐以求的 flag{w3lc0m_t0_ctf_php_funny}!
🛡️ 代码正规军:如何防御?
看完了好玩的漏洞,作为未来的安全专家或开发大牛,我们怎么修复这个漏洞呢?
其实很简单,只需要把代码中所有的双等号(==)改成三等号(===)。
// 安全的写法if ($a !== $b && md5($a) === md5($b)) { // 这样即便MD5都是0e开头,由于类型是字符串且值不同,绝对无法绕过}
此外,在处理密码等敏感哈希比对时,建议使用PHP内置的密码学函数 password_verify() 或 hash_equals(),它们能有效防止弱类型问题及时间盲注攻击。
如果你喜欢这种实战拆解,别忘了点赞关注,下一期我们将解锁更多有趣的CTF名场面!