1.攻防世界easyphp

进入题目页面如下

是一段PHP代码进行代码审计

php 复制代码
<?php
// 高亮显示PHP文件源代码
highlight_file(__FILE__);

// 初始化变量$key1和$key2为0
$key1 = 0;
$key2 = 0;

// 从GET请求中获取参数'a'的值,并赋值给变量$a
$a = $_GET['a'];
// 从GET请求中获取参数'b'的值,并赋值给变量$b
$b = $_GET['b'];
// 检查是否在GET请求中存在,并且将$a转换为整数后大于6000000,同时$a的字符串长度小于等于3
if(isset($a) && intval($a) > 6000000 && strlen($a) <= 3){
    // 检查变量$b是否被设置,并且$b的MD5哈希值的最后6位等于'8b184b'
    if(isset($b) && '8b184b' === substr(md5($b),-6,6)){
        // 如果上述条件都满足,将$key1的值设置为1
        $key1 = 1;
    }else{
        // 如果$b不满足条件,输出提示信息并终止脚本执行
        die("Emmm...再想想");
    }
}else{
    // 如果$a不满足条件,输出提示信息并终止脚本执行
    die("Emmm...");
}

// 从GET请求中获取参数'c'的值,使用json_decode函数将其解码为数组,并将结果强制转换为数组类型,赋值给变量$c
$c=(array)json_decode(@$_GET['c']);

// 检查$c是否为数组,并且$c数组中的键'm'对应的值不是数字类型,同时该值大于2022
if(is_array($c) && !is_numeric(@$c["m"]) && $c["m"] > 2022){
    // 检查$c数组中的键'n'对应的值是否为数组,并且该数组的元素个数为2,同时数组的第一个元素也是数组
    if(is_array(@$c["n"]) && count($c["n"]) == 2 && is_array($c["n"][0])){
        // 在$c["n"]数组中搜索值为'DGGJ'的元素,并返回其键名,赋值给变量$d
        $d = array_search("DGGJ", $c["n"]);
        // 如果没有找到值为'DGGJ'的元素,输出提示信息并终止脚本执行
        $d === false?die("no..."):NULL;
        // 遍历$c["n"]数组,检查是否有元素的值直接等于'DGGJ'
        foreach($c["n"] as $key=>$val){
            // 如果有元素的值等于'DGGJ',输出提示信息并终止脚本执行
            $val==="DGGJ"?die("no......"):NULL;
        }
        // 如果上述条件都满足,将$key2的值设置为1
        $key2 = 1;
    }else{
        // 如果$c["n"]不满足条件,输出提示信息并终止脚本执行
        die("no hack");
    }
}else{
    // 如果$c不满足条件,输出提示信息并终止脚本执行
    die("no");
}

// 检查$key1和$key2的值是否都为1,如果都为1,则表示所有条件都满足
if($key1 && $key2){
    // 包含名为'Hgfks.php'的文件
    include "Hgfks.php";
    // 输出成功提示
    echo "You're right"."\n";
    // 输出$flag变量的值
    echo $flag;
}

?>

重点看以下几行代码

php 复制代码
// 检查是否在GET请求中存在,并且将$a转换为整数后大于6000000,同时$a的字符串长度小于等于3
if(isset($a) && intval($a) > 6000000 && strlen($a) <= 3){
    // 检查变量$b是否被设置,并且$b的MD5哈希值的最后6位等于'8b184b'
    if(isset($b) && '8b184b' === substr(md5($b),-6,6)){
        // 如果上述条件都满足,将$key1的值设置为1
        $key1 = 1;


// 检查$key1和$key2的值是否都为1,如果都为1,则表示所有条件都满足
if($key1 && $key2){
    // 包含名为'Hgfks.php'的文件
    include "Hgfks.php";
    // 输出成功提示
    echo "You're right"."\n";
    // 输出$flag变量的值
    echo $flag;

可以知道当key1和key2值都为真时,输出flag

先构造$key1,通过GET传参a、b的值

$a需满足字符串长度小于等于3且值要大于6000000

常规的十进制数字表示中,要同时满足字符串长度小于等于 3 且值大于 6000000 是不可能的。但在 PHP 中,存在特殊的类型转换规则,我们可以借助科学计数法来绕过这个限制

在 PHP 里,当使用 intval() 函数转换字符串时,科学计数法表示的字符串会被正确转换为对应的整数。比如,字符串 "6e6" 代表 ,也就是 6000000。

需要大于6000000,则可以令$a的值为"7e6"、"8e6"、"9e6"等

$b的MD5哈希值的最后6位等于'8b184b'

用python写一个脚本爆破出$b的值,脚本如下

python 复制代码
import hashlib
# 目标 MD5 哈希值的最后 6 位
target_suffix = '8b184b'
# 从一个简单的字符集开始生成字符串进行尝试
charset = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
length = 1
while True:
    from itertools import product
    # 生成所有可能的长度为 length 的字符串组合
    for combination in product(charset, repeat=length):
        s = ''.join(combination)
        # 计算字符串的 MD5 哈希值
        md5_hash = hashlib.md5(s.encode()).hexdigest()
        # 检查哈希值的最后 6 位是否等于目标后缀
        if md5_hash[-6:] == target_suffix:
            print(f"找到符合条件的字符串: {s}")
            print(f"其 MD5 哈希值为: {md5_hash}")
            break
    else:
        # 如果当前长度的所有组合都没有找到符合条件的字符串,增加长度继续尝试
        length += 1
        continue
    break

可以用pycharm来执行,结果如下

得到$b的值为bDIOS

将a、b的值通过get传参,并查看输出

构造的payload为

?a=9e6&&b=bDIOS

看到输出的结果改变,key1以及构造成功,下面构造key2

重点看以下几行代码

php 复制代码
// 从GET请求中获取参数'c'的值,使用json_decode函数将其解码为数组,并将结果强制转换为数组类型,赋值给变量$c
$c=(array)json_decode(@$_GET['c']);

// 检查$c是否为数组,并且$c数组中的键'm'对应的值不是数字类型,同时该值大于2022
if(is_array($c) && !is_numeric(@$c["m"]) && $c["m"] > 2022){
    // 检查$c数组中的键'n'对应的值是否为数组,并且该数组的元素个数为2,同时数组的第一个元素也是数组
    if(is_array(@$c["n"]) && count($c["n"]) == 2 && is_array($c["n"][0])){
        // 在$c["n"]数组中搜索值为'DGGJ'的元素,并返回其键名,赋值给变量$d
        $d = array_search("DGGJ", $c["n"]);
        // 如果没有找到值为'DGGJ'的元素,输出提示信息并终止脚本执行
        $d === false?die("no..."):NULL;
        // 遍历$c["n"]数组,检查是否有元素的值直接等于'DGGJ'
        foreach($c["n"] as $key=>$val){
            // 如果有元素的值等于'DGGJ',输出提示信息并终止脚本执行
            $val==="DGGJ"?die("no......"):NULL;
        }
        // 如果上述条件都满足,将$key2的值设置为1
        $key2 = 1;

需要通过上传json形式的c来实现

外层条件
php 复制代码
if(is_array($c) && !is_numeric(@$c["m"]) && $c["m"] > 2022)
  • is_array($c):c必须是一个数组。通过 `json_decode` 解析 `_GET['c']` 得到的结果要能被强制转换为数组

  • !is_numeric(@$c["m"]):``$c 数组中的键 "m" 对应的值不能是一个数字。这里使用 @ 符号来抑制可能出现的未定义索引警告

  • $c["m"] > 2022:虽然 $c["m"] 不是数字,但在进行比较时,PHP 会尝试将其转换为数字进行比较。可以利用 PHP 的类型转换规则,使用以数字开头的字符串来满足这个条件。

由于is_numberic会将数字和数字字符串判定为真,但前导数字字符串不会以及>是弱类型比较,且是将c['m']的值与数字进行比较,我们可以直接用前导字符串来作为比较数字与2022进行比较。所以令c['m']='2025a'

键n值要满足:有且仅有两个元素的数组,第一个值为数组,第二个值要满足array_search("DGGJ", $c["n"])返回为真,同时c["n"]中又不能出现"DGGJ"。

可以利用array_search函数在比较两者是否相等时是使用的弱类型比较。由于"DGGJ"是既非数字字符串又非先导数字字符串的字符串,其在与数字进行比较时会转化为数字0。从而令c['n']的第二个值为0。(一点思考:此处若不是'DGGJ'而是其他字符串时,我们应该视情况而定,选择合适的数字)所以令c['n']=(array(1,2),0)

内层条件

复制代码
if(is_array(@$c["n"]) && count($c["n"]) == 2 && is_array($c["n"][0]))
  • is_array(@$c["n"])$c 数组中的键 "n" 对应的值必须是一个数组

  • count($c["n"]) == 2:这个数组的元素个数必须为 2

  • is_array($c["n"][0]):数组 $c["n"] 的第一个元素也必须是一个数组

所以最后构造的$c的payload为:c={"m":"2025a","n":[[1,2],0]}

最后传参a、b、c构造payload

?a=8e6&&b=bDIOS&&c={"m":"2025a","n":[[1,2],0]}

最终得到flag

相关推荐
用户962377954482 小时前
DVWA Weak Session IDs High 的 Cookie dvwaSession 为什么刷新不出来?
安全
BingoGo1 天前
当你的 PHP 应用的 API 没有限流时会发生什么?
后端·php
JaguarJack1 天前
当你的 PHP 应用的 API 没有限流时会发生什么?
后端·php·服务端
cipher2 天前
ERC-4626 通胀攻击:DeFi 金库的"捐款陷阱"
前端·后端·安全
BingoGo2 天前
OpenSwoole 26.2.0 发布:支持 PHP 8.5、io_uring 后端及协程调试改进
后端·php
JaguarJack2 天前
OpenSwoole 26.2.0 发布:支持 PHP 8.5、io_uring 后端及协程调试改进
后端·php·服务端
JaguarJack3 天前
推荐 PHP 属性(Attributes) 简洁读取 API 扩展包
后端·php·服务端
BingoGo3 天前
推荐 PHP 属性(Attributes) 简洁读取 API 扩展包
php
JaguarJack4 天前
告别 Laravel 缓慢的 Blade!Livewire Blaze 来了,为你的 Laravel 性能提速
后端·php·laravel
郑州光合科技余经理5 天前
代码展示:PHP搭建海外版外卖系统源码解析
java·开发语言·前端·后端·系统架构·uni-app·php