easyphp-江苏工匠杯

题目:

 

<?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;
}

?> Emmm...

源码分析

highlight_file(__FILE__);
这行代码将当前 PHP 文件的内容高亮显示。通常用于代码审计或教学

$key1 = 0;  
$key2 = 0;
这里定义了两个变量 $key1 和 $key2 并初始化为 0。这两个变量将用于后续的条件检查

$a = $_GET['a'];  
$b = $_GET['b'];
从 URL 的 GET 参数中获取 a 和 b 的值。

if(isset($a) && intval($a) > 6000000 && strlen($a) <= 3){  
    ...  
}else{  
    die("Emmm...");  
}
如果 $a 存在,其整数值大于 6000000,且长度小于等于 3,则进入第一个条件块。否则,输出 "Emmm..." 并终止脚本。

isset()

isset() 是一个语言结构,用于检测变量是否已设置并且非 NULL。如果变量存在并且值不是 NULL,则返回 TRUE,否则返回 FALSE。

intval()

intval() 函数用于获取变量的整数值。它尝试将变量转换为整数类型。如果变量是字符串,它会解析字符串直到遇到一个非数字的字符为止,并返回解析到的数字。如果变量是一个布尔值,则返回 1(对于 TRUE)或 0(对于 FALSE)。如果变量是 NULL,则返回 0。如果变量不存在,则返回 0。

if(isset($b) && '8b184b' === substr(md5($b),-6,6)){  
    $key1 = 1;  
}else{  
    die("Emmm...再想想");  
}
如果 $b 存在,并且其 MD5 哈希值的最后 6 个字符是 '8b184b',则将 $key1 设置为 1。否则,输出 "Emmm...再想想" 并终止脚本。

substr(string $string, int $start, int $length = null): string
$string 是要从中提取子串的原始字符串。
$start 是子串开始的位置。如果是正数,则从字符串的开头开始计数;如果是负数,则从字符串的结尾开始计数。
$length 是可选参数,表示子串的长度。如果省略或设置为 null,则返回从 $start 开始到字符串末尾的所有字符。
在表达式 substr(md5($b), -6, 6) 中:

md5($b) 首先计算变量 $b 的 MD5 哈希值。MD5 是一种常用的哈希算法,它接受一个字符串作为输入,并返回一个固定长度的 32 字符长的十六进制数字字符串。
substr(md5($b), -6, 6) 然后从 MD5 哈希值的最后一个字符开始,向前取 6 个字符作为子串。这里 -6 作为 $start 参数意味着从字符串末尾向前数第 6 个位置开始。然而,$length 参数也被设置为 6,这意味着即使从倒数第 6 个位置开始,实际上最多也只能取到字符串的末尾,因为不可能从某个位置开始取超过该位置到字符串末尾的字符数。
因此,这个表达式实际上是从 MD5 哈希值的最后 6 个字符中取子串。由于 $length 是 6,且 $start 也是从倒数第 6 个位置开始,所以实际上它直接返回了 MD5 哈希值的最后 6 个字符。

$c=(array)json_decode(@$_GET['c']);  
if(is_array($c) && !is_numeric(@$c["m"]) && $c["m"] > 2022){  
    ...  
}else{  
    die("no");  
}
首先,尝试将 GET 参数 c 解码为 JSON 数组。然后,检查 $c 是否为数组,$c["m"] 是否为非数字,并且 $c["m"] 的值是否大于 2022。如果所有条件都满足,则进入条件块。否则,输出 "no" 并终止脚本

if(is_array(@$c["n"]) && count($c["n"]) == 2 && is_array($c["n"][0])){  
    ...  
}else{  
    die("no hack");  
}
检查 $c["n"] 是否为数组,其长度是否为 2,以及 $c["n"][0] 是否也为数组。如果满足这些条件,则进入条件块。否则,输出 "no hack" 并终止脚本。

$d = array_search("DGGJ", $c["n"]);  
$d === false?die("no..."):NULL;  
foreach($c["n"] as $key=>$val){  
    $val==="DGGJ"?die("no......"):NULL;  
}  
$key2 = 1;
首先,使用 array_search 函数查找 $c["n"] 中是否存在 "DGGJ"。如果找不到,输出 "no..." 并终止脚本。然后,遍历 $c["n"],如果找到值为 "DGGJ" 的元素,输出 "no......" 并终止脚本。如果所有这些检查都通过,将 $key2 设置为 1。

$d === false ? die("no...") : NULL; 这行代码做了以下事情:

检查变量 $d 是否严格等于(===false。这里的严格等于不仅比较值,还比较变量的类型。如果 $d 严格等于 false,则执行 die("no...")。这会导致脚本终止,并输出字符串 "no..."。如果 $d 不严格等于 false,则执行 NULL。在这种情况下,实际上什么都不会发生,因为 NULL 在这里是一个无操作(no-op)。

foreach($c["n"] as $key=>$val){    
    $val==="DGGJ"?die("no......"):NULL;    
}  
$key2 = 1;
foreach($c["n"] as $key=>$val):
这行代码遍历 $c["n"] 数组。对于数组中的每个元素,$key 会被赋值为当前元素的键,$val 会被赋值为当前元素的值。
$val==="DGGJ"?die("no......"):NULL;:
对于数组中的每个 $val 值,代码检查它是否严格等于(===)字符串 "DGGJ"。
如果 $val 严格等于 "DGGJ",则执行 die("no......")。这会导致脚本立即终止,并输出字符串 "no......"。
如果 $val 不严格等于 "DGGJ",则执行 NULL。这实际上是一个无操作(no-op),因为 NULL 在这里不会产生任何效果。
$key2 = 1;:
这行代码在 foreach 循环外部,将变量 $key2 的值设置为 1。
综上所述,这段代码的主要目的是检查 $c["n"] 数组中的每个值,如果找到任何值严格等于 "DGGJ",则立即终止脚本并输出 "no......"。如果数组中没有值严格等于 "DGGJ",则脚本会继续执行,并将 $key2 设置为 1。

需要注意的是,尽管在 foreach 循环中使用了 $key 变量,但在这段代码中并没有对 $key 进行任何操作或使用。如果 $key 的值对于后续代码不重要,那么它可能是不必要的。此外,$key2 的赋值是在循环之外进行的,这意味着无论循环中的情况如何,$key2 的值最终都会是 1。

if($key1 && $key2){  
    include "Hgfks.php";  
    echo "You're right"."\n";  
    echo $flag;  
}
如果 $key1 和 $key2 都为 1,则包含 "Hgfks.php" 文件,并输出 "You're right" 和 $flag 变量的值。

CTF_Web:php弱类型绕过与md5碰撞 - 简书 (jianshu.com)

playload构造:

a要大于6000000,且a的长度要小于等于3,科学计数法a=9e9(9*10^9)

bMD5加密后字符串的后六位等于“8b184b”

直接上脚本

import hashlib  
  
def md5_suffix_match(number, suffix):  
    """检查给定数字的MD5哈希值是否以指定的后缀结尾"""  
    md5_hash = hashlib.md5(str(number).encode('utf-8')).hexdigest()  
    return md5_hash[-6:] == suffix  
  
def find_number_with_md5_suffix(start, end, suffix):  
    """在指定范围内查找具有指定MD5后缀的数字"""  
    for number in range(start, end + 1):  
        if md5_suffix_match(number, suffix):  
            return number  
    return None  # 如果没有找到匹配项,则返回None  
  
# 设置你想要的后六位  
suffix = '8b184b'  
  
# 设置搜索范围(可以根据需要调整)  
start = 1  # 开始搜索的数字  
end = 10**9  # 结束搜索的数字(可以根据需要设置更大的值,但要注意时间限制)  
  
# 尝试找到符合条件的数字  
result = find_number_with_md5_suffix(start, end, suffix)  
if result is not None:  
    print(f"Found number: {result}, with MD5 suffix: {suffix}")  
else:  
    print("No number found with the specified MD5 suffix in the given range.")

跑出来53724

 c要是json格式的字符串,而且key为m的value不能为数字而且要大于数字2022

 当字符串与数字相比会把字符串强制转换成整型

如"123abc"转换成123

"abc"会转换成0

跟==和===一样的

所以m为"9999abc"

n是一个包含二个元素的数组

先假设c=[[1],[2]]因为之前的下面这段代码

$d = array_search("DGGJ", $c["n"]);
        $d === false?die("no..."):NULL;
        foreach($c["n"] as $key=>$val){
            $val==="DGGJ"?die("no......"):NULL;
        }

互相矛盾如果有DGGJ不行

只能从array_search()下手

在 PHP 中,array_search() 函数用于在数组中搜索一个特定的值,并返回对应的键名。如果找不到该值,则返回 false。这个函数特别适用于关联数组,但也可以用于索引数组。

函数的语法如下:

php

array_search(value, array, strict)
  • value:必需。指定要搜索的值。
  • array:必需。指定要搜索的数组。
  • strict:可选。如果设置为 true,则使用严格比较(类型和值都必须匹配)。默认是 false,表示使用非严格比较。

 这里默认false,在 PHP 中,array_search() 函数使用弱比较(非严格比较)时,会尝试将不同类型的值进行类型转换以便进行比较。这种类型转换在某些情况下可能会导致意料之外的结果。

当你使用 array_search() 函数并传入一个整数(如 0)和一个包含字符串的数组时,PHP 的弱比较机制会尝试将整数和字符串之间进行类型转换和比较。由于字符串 'DGGJ' 在转换为数字时会被解释为 0(因为字符串以非数字字符开头,所以其数字值被认为是 0),整数 0 和字符串 'DGGJ' 在弱比较下被认为是相等的。

这种行为是由于 PHP 的类型转换规则导致的。在 PHP 中,当使用 == 运算符进行比较时,如果操作数类型不同,PHP 会尝试将它们转换为相同的类型,然后再进行比较。对于字符串和数字之间的比较,PHP 会尝试将字符串转换为一个数字。如果字符串以一个或多个有效的数字字符开头,那么这些数字字符将被解析为数字值。如果字符串以非数字字符开头,那么整个字符串将被解析为 0

因此,在 array_search(0, array('DGGJ')) 的情况下,'DGGJ' 字符串被转换为数字 0,然后 0 和 0 被认为是相等的,所以函数返回了 'DGGJ' 在数组中的键名(如果存在的话)。

所以n=[[1],0]

c={"m":"9999abc","n":[[1],0]}

所以playload

/?a=1e9&b=53724&c={"m":"9999abc","n":[[1],0]}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值