打开也面试代码审计:
<?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.
看看有哪些条件,分别有两个条件,开始分析:
if(isset($a) && intval($a) > 6000000 && strlen($a) <= 3){//intval($a)让a的值转换成整数,检查他的值是否大雨6000000,检查a的长度是否为3,
if(isset($b) && '8b184b' === substr(md5($b),-6,
6)){ //sybsttr()函数截取最后6位的值是否为‘8b184b’
$key1 = 1;
}else{
die("Emmm...再想想");
}
}else{
die("Emmm...");
}
想到了科学记数法:
在低版本的php中,科学计数法1e9的长度为3。
为了找到b的值,需要写一个简单的简本
<?php
$b=0;
while(true){
if('8b184b' === substr(md5($b),-6,6)){
echo $b;
break;
}
$b =+1;
}
?>
通过以上的步骤拿到了a,b的值,可以构造半个payload了。第二个条件是:
$c=(array)json_decode(@$_GET['c']);//通过c传入json数据,用(array)强制转换为数组。
if(is_array($c) && !is_numeric(@$c["m"]) && $c["m"] > 2022){//检查$c是否为数组,检查$c['m']是否为数字,且$c['m']的值是否大于2022
这里的考点是在低版本的PHP中如果数字中含有字母,那么PHP会把数字当作字符串来算他的值。所以可以让$c['m']=2023c
if(is_array(@$c["n"]) && count($c["n"]) == 2 && is_array($c["n"][0])){//检查$c['m'] 是否为数组,且含有的数组的元素的数量是否为2,is_array['n'][0]检查第一个元素是是否为一个数组
$d = array_search("DGGJ", $c["n"]);//遍历$is_array['n']中是否包含DGGJ
$d === false?die("no..."):NULL;
foreach($c["n"] as $key=>$val){//遍历$c['n']中是否包含$key=>$val
$val==="DGGJ"?die("no......"):NULL;
}
$key2 = 1;
要注意的是c是json数据,详细的注释写在上面了,这里有一个矛盾的条件:
$d = array_search("DGGJ", $c["n"]);//遍历$is_array['n']中是否包含DGGJ
$d === false?die("no..."):NULL;
这里如果数组中存在DGGJ的话会执行程序。
foreach($c["n"] as $key=>$val){//遍历$c['n']中是否包含$key=>$val
$val==="DGGJ"?die("no......"):NULL;
}
如果数组中包含DGGJ的话会终止程序,想到了在低版本的php中,array_search()函数的底层逻辑是弱类型匹配(==),'DGGJ' ==0,那么就开始得到c的值。
$c = {"m" : "2023c" , "n" : [[], 0]}最后构造出来的payload是;
http://61.147.171.105:58668/?a=1e9&b=53724&c={%22m%22:%222023C%22,%22n%22:[[],0]}
就拿到flag: