easyphp
开启环境,得到以下代码
php
<?php
highlight_file(__FILE__);
$key1 = 0;
$key2 = 0;
$a = $_GET['a'];
$b = $_GET['b'];
if(isset($a) && intval($a) > 6000000 && strlen($a) <= 3){
if(isset($b) && '8b184b' === substr(md5($b),-6,6)){
$key1 = 1;
}else{
die("Emmm...再想想");
}
}else{
die("Emmm...");
}
$c=(array)json_decode(@$_GET['c']);
if(is_array($c) && !is_numeric(@$c["m"]) && $c["m"] > 2022){
if(is_array(@$c["n"]) && count($c["n"]) == 2 && is_array($c["n"][0])){
$d = array_search("DGGJ", $c["n"]);
$d === false?die("no..."):NULL;
foreach($c["n"] as $key=>$val){
$val==="DGGJ"?die("no......"):NULL;
}
$key2 = 1;
}else{
die("no hack");
}
}else{
die("no");
}
if($key1 && $key2){
include "Hgfks.php";
echo "You're right"."\n";
echo $flag;
}
?> Emmm...
进行分析,发现代码通过 3 个 GET 参数(a、b、c)设置层层验证,最终若key1 和 key2 均为1,将包含Hgfks.php并输出 flag。验证流程如下:
接收a、b、c参数 → 验证a和b → 验证c → 双key均为1则输出flag
接下来分别对a、b、c进行分析
第一,对a与b进行分析,关键代码及解释如下
php
$a = $_GET['a'];
$b = $_GET['b'];
// 条件1:a存在 + 转int后>600万 + 长度≤3
if(isset($a) && intval($a) > 6000000 && strlen($a) <= 3){
// 条件2:b存在 + md5(b)的最后6位是8b184b
if(isset($b) && '8b184b' === substr(md5($b),-6,6)){
$key1 = 1;
}
}else{
die("Emmm...再想想");
}
}else{
die("Emmm...");
}
- 突破 a 的限制(核心:PHP 数值表示特性)
表面矛盾:600 万是 7 位数字(6000000),但要求strlen($a)≤3(长度≤3)。
关键特性:PHP 支持「科学计数法」表示大数字,且科学计数法字符串长度极短:
例:7e6 → 转 int 后是7000000(>600 万),strlen("7e6")=3(满足长度要求);
其他合法值:8e6、9e6、6.1e6(但6.1e6长度是 4,不符合,需选 3 位长度的)。
结论:a=7e6(最优解,长度 3,intval 后 700 万 > 600 万)。 - 突破 b 的限制(核心:MD5 后 6 位碰撞)
要求 substr(md5( b),-6,6) === '8b184b',即需找到一个字符串b,其 MD5 哈希值的最后 6 位为8b184b。
解决方法:暴力破解(遍历字符串 / 数字,计算 MD5 并匹配后 6 位)
python
import hashlib
target_suffix = "8b184b" # 目标后6位
found_b = None
# 遍历0-200000,效率高且必能找到(实测范围内有多个)
for i in range(200000):
b_str = str(i) # 明文为数字字符串(容易碰撞)
md5_hex = hashlib.md5(b_str.encode("utf-8")).hexdigest() # 计算MD5(小写)
if md5_hex[-6:] == target_suffix:
found_b = b_str
print(f"✅ 找到合法b值:{found_b}")
print(f"MD5完整值:{md5_hex}(后6位:{md5_hex[-6:]})")
break
if not found_b:
print("继续扩大范围查找...")
for i in range(200000, 500000):
b_str = str(i)
md5_hex = hashlib.md5(b_str.encode("utf-8")).hexdigest()
if md5_hex[-6:] == target_suffix:
found_b = b_str
print(f"✅ 找到合法b值:{found_b}")
print(f"MD5完整值:{md5_hex}(后6位:{md5_hex[-6:]})")
break
这里可以得到一个b值为53724
第二,对c及相关部分进行分析
验证参数 c需满足嵌套条件,c是 JSON 字符串转成的数组,核心逻辑:
php
$c=(array)json_decode(@$_GET['c']);
// 条件1:c是数组 + c["m"]非数字 + c["m"]>2022
if(is_array($c) && !is_numeric(@$c["m"]) && $c["m"] > 2022){
// 条件2:c["n"]是数组 + 长度=2 + c["n"][0]是数组
if(is_array(@$c["n"]) && count($c["n"]) == 2 && is_array($c["n"][0])){
// 条件3:c["n"]中存在"DGGJ"(松散比较)
$d = array_search("DGGJ", $c["n"]);
$d === false?die("no..."):NULL;
// 条件4:c["n"]中没有任何元素严格等于"DGGJ"
foreach($c["n"] as $key=>$val){
$val==="DGGJ"?die("no......"):NULL;
}
$key2 = 1;
}
}
- 突破 c ["m"] 的限制(核心:PHP 松散比较)
要求:!is_numeric(c["m"])(非数字/数字字符串)且c["m"])(非数字 / 数字字符串)且c["m"])(非数字/数字字符串)且c["m"] > 2022(转成数字后 > 2022)。
关键特性:PHP 中非数字字符串与数字比较时,会尝试将字符串转成数字(仅保留开头数字部分)。
例:$c["m"] = "2023abc":!is_numeric("2023abc") → true(不是纯数字字符串);("2023abc" > 2022) → true(转成数字是 2023,>2022)。
结论:c["m"] = "2023test"(任意非数字后缀的字符串,前缀数字 > 2022)。 - 突破 c ["n"] 的限制(核心:array_search 松散比较漏洞)
看似矛盾的两个条件:
条件 3:array_search("DGGJ", c\["n"\]) 找到值(返回键名,非 false); 条件 4: c["n"]中无元素严格等于"DGGJ"(===)。
array_search默认是弱比较,但在循环中却是强比较,在PHP中字符串转数字的规则是,非数字开头的字符串转数字为0,即"DGGJ"转int变为0。于是可以知道,若c\["n"\]中存在0,则array_search("DGGJ", c["n"]) → 0 == "DGGJ"返回0或对应键名,而在循环中0 = = ="DGGJ"→ false(严格比较不成立)不会 die
同时需满足:
c["n"]是数组,长度 = 2;
c["n"][0]是数组(任意子数组均可,如[])。
结论:c["n"] = [ [], 0 ](第一个元素是数组,第二个元素是 0,长度 = 2)。 - 构造完整的 c 参数
将c的数组结构转为 JSON 字符串:
{
"m": "2023test",
"n": [ [], 0 ]
}
URL 编码后(JSON 字符串中的引号需转义,或直接用单引号?不,JSON 仅支持双引号,URL 传输时需对特殊字符编码):
最终c的参数值(URL 编码后):{"m":"2023test","n":[[],"0"]} → 无需额外编码,直接传输即可(PHP 的 json_decode 可解析)。
三、最终利用方案
各参数最终值
a=7e6(满足 intval>600 万,长度 3);
b=53724(md5 后 6 位为 8b184b,实际以脚本运行结果为准);
c={"m":"2023test","n":[[],"0"]}(JSON 格式,满足所有数组和比较条件)。
尝试在目标网址后加上?a=7e6&b=53724&c={"m":"2023test","n":[[],"0"]},发现并没有返回flag等相关结果,思考哪里有问题,a与b都没问题,那就只有c有问题了。
之前的"2023test"合法,但避免极端情况(如某些 PHP 版本对后缀字符的解析差异),建议用更简洁的非数字字符串:c["m"] = "2024_abc"(前缀数字 2024>2022,后缀非数字,满足!is_numeric)。
最终访问
?a=7e6&b=53724&c={"m":"2024_abc","n":[ [], 0 ]}
最终得到结果
