打开页面是一个代码审计的题目,是我不太熟悉的东西,但是没关系,我们可以学是吧,以下为源代码

<?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
在这里插入图片描述

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐