说起来是easy但是,代码审计对于我来说有点小难
唯一觉得好的地方是因为基本上每一步都有回显,可以依照回显一步步注入
<?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;
}
?>
代码审计1
先忽略变量c,先把a和b执行完
这段代码是一个简单的PHP脚本。它有两个输入参数$a和$b,这些参数应该通过GET请求从URL中获取。
代码检查$a是否被设置,并且它的整数值大于6000000,并且它的长度不超过3个字符。
如果条件满足,代码将检查$b是否被设置,并且其MD5哈希的后6个字符是'8b184b'。如果条件满足,$key1将被赋值为1。
如果任何条件不满足,代码将使用die()函数输出相应的错误消息并终止脚本的执行。
解题步骤1
这里我们采取科学计数法1e3绕过intval和strlen函数
然后使用一段python脚本计算出变量b的MD5值
import hashlib
#导入hashlib模块
for i in range(100000):
if hashlib.md5(str(i).encode('utf-8')).hexdigest()[-6:] == '8b184b':
#利用模块的MD5方法对字符串i进行编码,注意哈希之前必须要规定字符串编码类型,最后转化为16进制输出
#输出结果取取倒数的6位字符,进行对比
print(i)
print(hashlib.md5(str(i).encode('utf-8')).hexdigest())
观察回显数据,说明变量a,b注入成功
代码审计2
继续看变量c的部分
首先,将GET请求中的参数c解码为一个数组,并将其赋值给变量$c。此处使用了@符号,表示对可能出现的错误进行忽略。
然后,代码进行了一系列的条件判断和操作:
首先将c变量进行json解码,并转换为一个array数组
判断$c是否是一个数组,并且$c["m"]不是一个数字,并且$c["m"]大于2022。
如果满足以上条件,则继续判断$c["n"]是否是一个数组,且长度为2,并且$c["n"][0]也是一个数组。
如果满足以上条件,则使用array_search函数在$c["n"]数组中搜索值为"DGGJ"的元素,并将结果赋值给变量$d。如果找到了匹配的值,则继续执行;如果没有找到,输出"no..."并终止程序。
接下来,使用foreach循环遍历$c["n"]数组中的每个元素,如果某个元素的值等于"DGGJ",则输出"no......"并终止程序。否则,将变量$key2赋值为1。
如果$key1和$key2都存在且为真,则输出flag
解题步骤2
根据代码审计,我们得知变量c需要传入的是一个json型的数据,并会自动转换为一个数组
is_numeric函数
is_numeric函数用来检测是否为纯数字或数字字符串
利用php字符串与数字相比较的性质:
我们得知一个字符串在没遇到字符前都是可以跟数字进行比较的,所以我可以在传入的数的最后添加任意字符就可以绕过字符比较
在php8之后好像就不允许这样了绕过is_numeric函数
当看到回显不是no就说明绕过成功
根据第二个if语句,在数组n中创建一个包含数组
接着将数组n中的第二个参数设置为DGGJ
根据回显为no......,说明绕过成功
接下来就有点麻烦了,因为接着运用了一个foreach循环将数组n的键和值分别传入key和val两个变量,如果在其中检测到DGGJ字符串就回显no......退出循环
去查了一下,array_scarch函数是查找第一次出现的位置,如果找到了就返回键值,本来想着将数组和字符串DGGJ的位置换一个变成
"n":["DGGJ",[1,2,3]]
是前面还有对变量c第一个元素为数组的检测
还想着将DGGJ字符串放到第一个数组里去,变成
"n":[["DGGJ",2,3],2]
但是检测无法进入到数组中,连第一个搜索字符串都过不了
然后想到了编码绕过,将传入的数据进行url编码试试
还是不行,最后查看了wp,得知忽略了一个及小的东西:
array_search函数
就是array_search函数的执行逻辑其实就是对数组中的数据进行比较,如果满足相等就返回下标索引
php8之前字符串与数字进行比较的性质:
字符串和数字一起比较,会将字符串先转化为数字0再进行比较
所以,我们可以直接将DGGJ字符串替换为0就可以注入成功
虽然做的有点慢,但是是自己慢慢做出来的,没有直接查看wp,印象更加深刻
在做题时,我们可以将代码截取出来,利用本地环境传入数据,然后查看代码回显并对错误代码进行调试