题目源代码:
php
//代码逻辑:
include_once "flag.php";
// 包含存放 flag 的文件
ini_set("display_errors", 0);
// 关闭错误显示
// 第一步:获取查询字符串
$str = strstr($_SERVER['REQUEST_URI'], '?');
// 获取 URL 中 ? 及其后面的部分(例如 ?key1=xxx&key2=yyy)
$str = substr($str,1);
// 去掉开头的 ?,剩下 key1=xxx&key2=yyy
// 第二步:过滤机制(这也是这道题的考点之一)
$str = str_replace('key','',$str);
// 将字符串中的 'key' 替换为空(删除)
// 第三步:变量解析
parse_str($str);
// 将查询字符串解析为 PHP 变量
echo md5($key1);
// 第四步:判断条件
if(md5($key1) == md5($key2) && $key1 !== $key2){
echo $flag."取得flag";
}
1.核心考点与绕过方法
要拿到 flag,必须同时满足两个条件:
-
md5($key1) == md5($key2)(MD5 值相等) -
$key1 !== $key2(原始值不相等)
还有一考点:
代码中还有一个障碍:str_replace('key','',$str)。
考点一:PHP 弱类型比较 (Magic Hash)
代码使用了 == 进行比较,而不是 ===。 在 PHP 中,== 是弱类型比较。如果字符串看起来像科学计数法(例如 0e123456...),PHP 会将其视为浮点数 0。
因此,如果两个不同的字符串,它们的 MD5 值都是以 0e 开头,且后面全是数字,PHP 就会认为它们相等(因为 0e... 被解析为 0,0 == 0 成立)。
常见的 MD5 以 0e 开头的字符串(Magic Hash):
-
QNKCDZO -
s878926199a -
240610708
考点二:str_replace 绕过
代码中有这一行:$str = str_replace('key','',$str);。 这意味着如果你传入 ?key1=xxx,它会被处理成 1=xxx,变量名变成了 $1(非法变量名),导致无法通过判断。
绕过方法:双写绕过 既然它会删除 key,我们可以构造 kkeyey。 当程序执行 str_replace 时: kkeyey -> 删除中间的 key -> 剩下 key。
这样,经过过滤后,变量名又变回了 key。
2. 最终 Payload 构造
我们需要构造 URL 参数,使得:
-
变量名绕过过滤:
kkeyey1和kkeyey2。 -
变量值满足 MD5 弱类型比较:使用
QNKCDZO和240610708(它们值不同,但 MD5 都是0e开头)。
如何获取备份文件?
使用kali工具dirsearch扫描,即可获取备份网页(index.php.bak)
apt-get install dirsearch
dirsearch -u http://网址:端口号