解题关键:
读懂并逐渐理解php脚本
解题过程:
网站显示php脚本内容如下,首先对代码进行一个简单的分析。
这段代码是一个简单的 PHP 脚本,它接受两个 GET 参数:`a` 和 `b`,以及一个名为 `c` 的 JSON 字符串。让我来解释一下:
1. `highlight_file(__FILE__);`:这会在页面上显示当前 PHP 文件的源代码,所以你可能在浏览器中看到了这个 PHP 文件的代码。
2. 接着是对 `$_GET['a']` 和 `$_GET['b']` 的检查:
- `$_GET['a']` 必须存在,且是一个大于 6000000 且长度不超过 3 的整数。
- `$_GET['b']` 也必须存在,并且经过 MD5 加密后的结果的最后 6 位必须是 '8b184b'。3. 然后是对 `$_GET['c']` 的处理,它被当作 JSON 解码。如果满足以下条件:
- 是一个数组。
- 不是一个数字。
- 数组中包含一个键为 "m" 的值大于 2022。
- 数组中有一个名为 "n" 的键,其值是一个包含两个元素的数组,第一个元素也是一个数组,且第一个元素中包含字符串 "DGGJ"。4. 最后如果条件满足,则包含另一个文件 "Hgfks.php",然后输出一个变量 `$flag` 的值。
这段代码看起来像是一个简单的安全性检查,确保传入的参数满足一定的条件才会继续执行,并且最后可能会包含一个文件并输出一个叫做 `$flag` 的变量。
解a:
isset()
函数的作用是用来检查一个变量是否已经设置并且非NULL。它接受一个或多个参数,每个参数可以是一个变量、数组元素或者对象属性。如果变量已经设置且不为NULL,则isset()
函数返回true
,否则返回false
。
intval()
函数将尝试将输入值转换为整数。它会尝试截取字符开始的数字(忽略前导空格),直到遇到非数字字符为止,并返回转换后的整数值。如果输入值不能转换为整数,intval()
函数将返回 0(如果不是数字开头)或者最大整数值(如果数值过大)。$value1 = "12345";
$result1 = intval($value1); // 结果为 12345$value2 = "42.5";
$result2 = intval($value2); // 结果为 42$value3 = "abc123";
$result3 = intval($value3); // 结果为 0,因为以非数字开头$value4 = "123abc";
$result4 = intval($value4); // 结果为 123,因为从数字部分开始到非数字停止$value5 = "12345678901234567890";
$result5 = intval($value5); // 结果为 PHP 最大整数值,超出整数表示范围我们可以尝试使用科学计数法使得数字经过intval()后大于6000000的并且长度不超过3
因此a=1e8,或者1e9
解b:
接着分析b,通过python中的hashlib找到经过 MD5 加密后的结果的最后 6 位必须是 '8b184b'的数值,代码如下:
import hashlib
import random
target_suffix = '8b184b'
# 随机生成字符串进行 MD5 加密,直到找到结果的后 6 位匹配目标值
while True:
random_str = str(random.getrandbits(16)) # 生成随机字符串
md5_hash = hashlib.md5(random_str.encode()).hexdigest()
if md5_hash[-6:] == target_suffix:
print(f"原始字符串:{random_str}")
print(f"MD5 加密后的结果:{md5_hash}")
break
运算过后得到b为53724
解c:
依次了解以下c脚本中各个函数的作用
is_numeric()
是 PHP 中的一个内置函数,其作用是判断一个变量是否为数字或数字字符串。具体来说:
- 如果变量是一个数字(无论是整数、浮点数、正数、负数等),
is_numeric()
返回true
。- 如果变量是一个数值型的字符串(如 "123"、"3.14"),
is_numeric()
也会返回true
。- 如果变量是非数值型的字符串、布尔值、数组、对象、NULL 等,
is_numeric()
则返回false
。
$c=(array)json_decode(@$_GET['c']);
:从 GET 请求参数中取得名为c
的参数值并尝试将其解析为 JSON 格式,然后将解析后的结果转换为数组。
is_array($c) && !is_numeric(@$c["m"]) && $c["m"] > 2022
:如果$c
是数组,且数组中的键名为m
的值不是数字、且大于 2022,则进入下一层判断,所以这里我们可以令m前端为比2022大的数最后加上一个字母,比如2088a
if(is_array(@$c["n"]) && count($c["n"]) == 2 && is_array($c["n"][0]))
:判断数组中键名为n
的值是否也是一个数组,并且数组长度为 2,并且第一个元素也是数组,即n的格式为一个任意数组加上后续元素,比如[[1,2,3],?]。
$d = array_search("DGGJ", $c["n"]);
$d === false ? die("no...") : NULL;
在数组$c["n"]
中查找值为 "DGGJ" 的元素,将结果赋给$d
。如果在$c["n"]
中找不到 "DGGJ",则输出字符串 "no..." 并终止脚本。
foreach($c["n"] as $key=>$val)$val === "DGGJ" ? die("no......") : NULL;
遍历数组$c["n"]
中的值。如果数组中有值等于 "DGGJ",则输出字符串 "no......" 并终止脚本。与4相矛盾,因此我们必须要绕过其中一个选择array_search()进行绕过,因为当字符与数字进行匹配比较的时候会被转换成数字,因此使字符串的部分为0可以绕过该函数。
c的组成要使用json编码{"m":"2088a","n":[1,2,3,],0]}
61.147.171.105:63018/?a=1e9&b=53724&c={"m":"2088a","n":[[1,2,3],0]}
得到flag
总结:
理解php脚本,学会绕过漏洞函数