打开页面是一个代码审计的题目,是我不太熟悉的东西,但是没关系,我们可以学是吧,以下为源代码
<?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;
}
?>
总思路
我们先大致看一遍代码,看他需要满足怎么样的需求
先看最后这段
if($key1 && $key2){
include "Hgfks.php";
echo "You're right"."\n";
echo $flag;
}
需要key1和key2都为真,然后再输出flag,我们看看key1和key2分别需要什么条件
下面来看这段代码
$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...");
}
需要传入两个值,分别为a,b
参数a
这里有两个if判断,我们先看第一个
if(isset($a) && intval($a) > 6000000 && strlen($a) <= 3)
需要我们传入的a大于6000000,并且长度小于3,我们可以使用科学计数法来实现a=6e7来实现
参数b
第二个if判断
if(isset($b) && '8b184b' === substr(md5($b),-6,6))
需要b参数经过md5计算后,后六位字符串为8b184b,我们写一个脚本跑一下,看是多少
可以看出是53724,以下为脚本,可以复制使用
import hashlib
for i in range(1000000):
m2 = hashlib.md5()
m2.update(str(i).encode())
if m2.hexdigest()[-6:] == "8b184b":
print(i)
break
这样我们key1就已经搞定了,接下来我们来看看key2怎么操作
参数c
$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(is_array($c) && !is_numeric(@$c["m"]) && $c["m"] > 2022)
首先我们得先传入一个数组为c,然后用is_numeric判断c[“m”]是不是数字,并且把判断取反,这里的意思就是,不能是数字,然后c[“m”]需要大于2022
is_numeric函数如果整个 expression 的运算结果为数字,则 IsNumeric 返回 True;否则返回 False
意思就是:如果是数字,返回True,但题目有个感叹号,代表取反,变为Flase。所以我们不能让$c[“m”]为数字
这里我就想到了可以使用php的弱比较来绕过,比如2023a
然后看下一段
if(is_array(@$c["n"]) && count($c["n"]) == 2 && is_array($c["n"][0]))
意思是$c[“n”]必须为数组,并且这个数组的长度为2,并且$c[“n”][0]也是数组,现在大致的样子就是$c={“m”:“2023a”,“n”:[[1,2],a,b,c]}
我们继续往下面看
$d = array_search("DGGJ", $c["n"]);
$d === false?die("no..."):NULL;
从$c[“n”]中查找DGGJ,如果查找到了便返回True没找到便返回False,此处必须满足,否则die,我们再往下看
foreach($c["n"] as $key=>$val){
$val==="DGGJ"?die("no......"):NULL;
}
$key2 = 1;
使用foreach循环$c[“n”],如果循环到了DGGJ就die,这里肯定跟上面就矛盾了,这里肯定是要绕过的,肯定是有绕过方法的
array_search()绕过:
array_search()与in_array()一样,类型会进行强制转换
所以如果我们传入的是$c[“n”]=0时,那么array_search(“DGGJ”,$c[“n”]),就相当于"DGGJ"==0,这个等式是成立的
所以我们可以用0和DGGJ来作比较,因为0==“DGGJ”,但当判断0==="DGGJ"时为false,所以可以绕过
于是便有了最终的payload
?a=6e7&b=53724&c={“m”:“2023a”,“n”:[[],0]}
得到最终的flag