easyphp攻防世界详细题解

打开网站,即可看到网页的php代码,一眼就看出本题为php代码审计的题目

现在逐段来进行分析,可以看到只有当key1和key2都为1时,才会输出flag,于是本题就是要

highlight_file(__FILE__);
$key1 = 0;
$key2 = 0;//key1和key2的初始值都设为0

$a = $_GET['a'];
$b = $_GET['b'];//a和b都通过get方式来传参

if(isset($a) && intval($a) > 6000000 && strlen($a) <= 3){
//a的判断:判断是否设置了参数a,并且判断a的值是否大于6000000,a位数小于等于三位,只有三个条件都满足的时候才能执行以下语句
    if(isset($b) && '8b184b' === substr(md5($b),-6,6)){
//b的判断:判断参数b是否被设置;并且使用 md5() 函数对 $b 进行加密,并截取加密结果的最后 6 个字符

判断截取得到的加密结果是否等于字符串 '8b184b';
当两个条件都满足的时候,key1=1;

        $key1 = 1;
        }else{
            die("Emmm...再想想");
//不满足就输出"Emmm...再想想"
        }
    }else{
    die("Emmm...");
}

满足题目的a,b,c

 a的构造:

要求:a的值大于6000000,a位数小于等于三位

一看就知道要用科学计数法,这里我们构造a=7e6

b的构造:

题目要求:

使用 md5() 函数对 $b 进行加密,并截取加密结果的最后 6 个字符

判断截取得到的加密结果是否等于字符串 '8b184b';

这里要学习一下substr函数的用法(用于截取字符串的某一部分)

substr函数格式 (俗称:字符截取函数)
  格式1: substr(string string, int a, int b);
  格式2:substr(string string, int a) ;

解释:

格式1:
    1、string 需要截取的字符串 
    2、a 截取字符串的开始位置(注:当a等于0或1时,都是从第一位开始截取)
    3、b 要截取的字符串的长度

格式2:
    1、string 需要截取的字符串
    2、a 可以理解为从第a个字符开始截取后面所有的字符串。

 if(isset($b) && '8b184b' === substr(md5($b),-6,6))

判断参数b是否被设置;并且使用 md5() 函数对 $b 进行加密,并截取加密结果的最后 6 个字符

判断截取得到的加密结果是否等于字符串 '8b184b';要找到满足条件的b,我们需要写一个脚本来爆破,可以参考以下脚本:

import hashlib  # 导入Python的hashlib库,它提供了各种哈希函数,如md5,sha1,SHA256等。  
  
for i in range(100000):  # 循环从0到99999,总共100000次。  
    m = hashlib.md5()  # 创建一个新的md5哈希对象,每次循环都会创建新的哈希对象。  
    m.update(str(i).encode())  # 将当前的数字i转化为字符串并编码为字节,然后更新哈希对象m。这一步是计算md5哈希的关键步骤。  
    h = m.hexdigest()  # 从哈希对象m中获取十六进制的哈希值,并赋值给变量h。  
    if h[-6:] == "8b184b":  # 检查h的最后6个字符是否为"8b184b"。如果是,则执行下面的代码。  
        print(i)  # 打印当前的数字i。  
        break  # 结束循环。

然后找个在线网站运行一下,即可爆破出相应的b的值,b=53724;

 最后来看看c的构造,c最麻烦

看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");
}

这是一段PHP代码,其主要功能是接收一个来自GET请求的JSON字符串,并对其进行解码,然后进行一系列的检查。以下是对该代码的逐行解析:

  1. $c=(array)json_decode(@$_GET['c']);

这行代码的作用是:

  • @$_GET['c']:获取GET请求中键名为'c'的参数值,但在这里使用了@操作符,意味着如果有错误发生,它不会抛出错误,而是静默失败。
  • json_decode():对获取到的JSON字符串进行解码,将其转换为PHP对象或数组。
  • (array):将解码后的结果强制转换为数组类型。
  1. if(is_array($c) && !is_numeric(@$c["m"]) && $c["m"] > 2022){

这行代码的作用是:

  • is_array($c):检查变量$c是否是一个数组。
  • !is_numeric(@$c["m"]):检查$c数组中的键名为"m"的元素是否不是数字。这里再次使用了@操作符。
  • $c["m"] > 2022:检查"m"键的值是否大于2022。

如果上述所有条件都满足,那么会执行花括号中的代码。

  1. if(is_array(@$c["n"]) && count($c["n"]) == 2 && is_array($c["n"][0])){

这行代码的作用是:

  • is_array(@$c["n"]):检查$c数组中的键名为"n"的元素是否是一个数组。
  • count($c["n"]) == 2:如果"n"键的值是一个数组,那么检查其元素数量是否为2。
  • is_array($c["n"][0]):检查"n"键的第一个元素是否也是一个数组。

如果上述所有条件都满足,那么会执行花括号中的代码。

  1. $d = array_search("DGGJ", $c["n"]);

这行代码的作用是在"n"键的数组中搜索"DGGJ"这个值,并返回其索引位置。如果找不到,返回false。

  1. $d === false?die("no..."):NULL;

这是一个三元操作符,它检查$d是否等于false,也就是在"n"键的数组中是否没有找到"DGGJ"。如果没有找到,则输出"no..."并终止执行。否则,返回null。
6. foreach($c["n"] as $key=>$val){ ... }

这是一个foreach循环,它会遍历"n"键的数组中的每一个元素。如果发现任何一个元素的值等于"DGGJ",则输出"no......"并终止执行。
7. $key2 = 1;

这行代码将变量$key2的值设置为1。但在后续的代码中并没有使用到这个变量。
8. }else{ die("no hack"); }

这是上述if条件的else部分,如果上述所有的条件检查都没有通过,那么会执行这里的代码,输出"no hack"并终止执行。
9. }else{ die("no"); }

这是最外层的if条件的else部分,如果最开始对变量$c的检查没有通过,那么会执行这里的代码,输出"no"并终止执行。

 

$c=(array)json_decode(@$_GET['c']);
/*@$_GET['c']:获取GET请求中键名为'c'的参数值,但在这里使用了@操作符,意味着如果有错误发生,它不会抛出错误,而是静默失败。
json_decode():对获取到的JSON字符串进行解码,将其转换为PHP对象或数组。
(array):将解码后的结果强制转换为数组类型。*/

if(is_array($c) && !is_numeric(@$c["m"]) && $c["m"] > 2022)
/*is_array($c):检查变量$c是否是一个数组。
!is_numeric(@$c["m"]):检查$c数组中的键名为"m"的元素是否不是数字。这里再次使用了@操作符。
$c["m"] > 2022:检查"m"键的值是否大于2022。*/
{
    if(is_array(@$c["n"]) && count($c["n"]) == 2 && is_array($c["n"][0]))
    /*is_array(@$c["n"]):检查$c数组中的键名为"n"的元素是否是一个数组。
count($c["n"]) == 2:如果"n"键的值是一个数组,那么检查其元素数量是否为2。
is_array($c["n"][0]):检查"n"键的第一个元素是否也是一个数组。*/

    {
        $d = array_search("DGGJ", $c["n"]);//这行代码的作用是在"n"键的数组中搜索"DGGJ"这个值,并返回其索引位置。如果找不到,返回false。
        $d === false?die("no..."):NULL;//这是一个三元操作符,它检查$d是否等于false,也就是在"n"键的数组中是否没有找到"DGGJ"。如果没有找到,则输出"no..."并终止执行。否则,返回null。
        foreach($c["n"] as $key=>$val)
        {
            $val==="DGGJ"?die("no......"):NULL;
        }//这是一个foreach循环,它会遍历"n"键的数组中的每一个元素。如果发现任何一个元素的值等于"DGGJ",则输出"no......"并终止执行。
        $key2 = 1;
    }else{
        die("no hack");
    }
}else{
    die("no");
}//这是最外层的if条件的else部分,如果最开始对变量$c的检查没有通过,那么会执行这里的代码,输出"no"并终止执行

 m的构造:

不是数字且大于2022,我们随便构造m=2023a即可;

n的构造:

Array_search():查找数组中的元素并返回其下标。
元素n的下标是DGGJ
但是如果n的下标是DGGJ,程序就会终止。。。。。。
那必须是绕过它才行,那该怎么绕啊

这array_search()在查找元素的时候是进行弱类型比较,而在PHP里字符串==0是成立的,即“DGGJ"==0是成立的,因此,要保证在c["n"]中有0,即可绕过array_search的判断。

 构造为?a=7e8&b=53724&c={"m":"2023a","n":[[],0]}

flag

 You're right cyberpeace{4bc0c536b369be07b6e17d8d6f1b7693}

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值