打开靶场 是代码审计
<?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...
对其进行代码审计
首先 key1 key2 为0 get传参两个参数a和b
参数a需要满足以下条件
intval() 函数用于获取变量的整数值 传入需要一个整数 其值要大于6000000 且长度小于3
参数b满足以下条件
MD5加密后末尾值为'8b184b'的字符串 这个可以使用脚本实现
a和b参数满足条件后 key1的值置为1
那么a参数我们就可以使用科学计数法来绕过 这样子 a的值既可以大于6000000 也保证了长度
这里的值有很多 大家可以自己搜索
我这里使用的值为a=1e7
b参数的爆破脚本如下
import hashlib
for i in range(100000):
a = hashlib.md5()
a.update(str(i).encode())
q = a.hexdigest()
if q[-6:] == "8b184b": # 判断MD5最后6位的值是否位8b184b
print(i)
跑出结果为53724 所以这里的b的值就为53724
执行完毕后 可以发现 前面已经绕过了 已经进入c参数的逻辑了 下面来看C参数的逻辑
$c=(array)json_decode(@$_GET['c']);
if(is_array($c) && !is_numeric(@$c["m"]) && $c["m"] > 2022){
//传入数组c 不能是数字 大于2022 php弱类型比较 传入2023a即可
下面的代码就是最关键的地方了
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;
两个数组元素也即是说键值有两个 d在数组c["n"]中搜索"DGGJ",如果匹配成功返回键值 数组中是键值对的形式
foreach()循环遍历数组中的每个元素;$c["n"]获取数组变量中键名为"n"的元素的值 每次循环中,将当前元素的键名赋值给key变量,将当前元素的值赋值给val变量
这是最关键的地方
既要search到 DGGJ 遍历时又不要DGGJ 但array_search()又要查找并且要有结果 这里就需要绕过了
这里用array_search函数的一个漏洞 待匹配的模式串里有0时会与字符串进行比较时,字符串也会转变为0,这样就算不出现DGGJ也可以返回1
绕过is_array和array_search函数
函数的语法给到大家
这里的true参数的意义就是为我们后面绕过做了铺垫
绕array_search函数保证非0下标元素含0就行,字符串转数字都是0
数组的第一个值较为简单 是一个数组即可
数组中的第二个值要满足array_search("DGGJ", $c["n"])返回为真,同时c["n"]中又不能出现"DGGJ"。
也就是说数组中不能有DGGJ这个字符串但是又要保证array_search函数最后返回的结果为真 因为数组中没有这个字符串 所以返回不了对应的键名 只能返回false 而我们必须让其结果为真 才可以进入下一个逻辑 下面是这个函数返回值的贴图 助于理解
所以此处利用array_search函数在比较两者是否相等时是使用的弱类型比较。又由于"DGGJ"是一个普通的字符串,其在与数字进行比较时会转化为数字0。 从而令c['n']的第二个值为0。
array_search()没有设置strict参数(如果该参数被设置为 TRUE,则函数在数组中搜索数据类型和值都一致的元素),我们就可以用0和DGGJ进行弱比较
在php中,三个等号“===”是全等比较运算符,用于比较两个操作数的值是否相等,同时检测它们的类型是否相同;只有两边的值和数据类型都相等时,运算结果才是TRUE
这里我们需要保证比较的结果为false就不会执行die语句了 如果数组中存在DGGJ进行比较结果就是true了 为true那么就执行die语句了 至此闭环成功
这里给一个弱类型比较的文章
https://www.cnblogs.com/anbus/p/10000571.html
所以最后c的传参为 c={"m":"20222a","n":[[1,2],0]}
[1,2]中的数组数据无所谓 没有也行
最终的payload如下
?a=1e7&b=53724&c={"m":"20222a","n":[[1,2],0]}
flag拿出
这道题考查的就是代码审计 以及一些函数的理解运用与绕过