easyphp

说起来是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,印象更加深刻

在做题时,我们可以将代码截取出来,利用本地环境传入数据,然后查看代码回显并对错误代码进行调试

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值