打开题目,是一个高亮显示的php脚本
php
<?php
highlight_file(__FILE__);
include 'flag2.php';
if (isset($_GET['name']) && isset($_POST['password'])){
$name = $_GET['name'];
$password = $_POST['password'];
if ($name != $password && md5($name) == md5($password)){
echo $flag;
}
else {
echo "wrong!";
}
}
else {
echo 'wrong!';
}
?>
这段PHP代码用于演示一个典型的安全挑战,特别是关于PHP中md5
哈希函数的特性和弱类型比较的问题。以下是逐行分析:
第1行:展示当前文件源代码
通过highlight_file(__FILE__);
展示当前文件的源代码。__FILE__
是一个特殊的预定义常量,表示当前文件的完整路径和文件名。
第2行:包含外部文件
include 'flag2.php';
引入外部文件flag2.php
。我们可以假设这个文件定义了一个名为$flag
的变量,其中包含了需要在满足特定条件下显示的敏感信息(即"flag")。
第3-17行:校验GET和POST参数
代码首先检查是否同时通过GET方法提交了name
参数和通过POST方法提交了password
参数。如果没有,输出"wrong!"。
如果两个参数都存在,分别将它们赋值给变量$name
和$password
。
条件判断和漏洞点
核心逻辑在于这个条件判断:
if ($name != $password && md5($name) == md5($password)){
echo $flag;
}
- 条件要求
$name
和$password
不相等,但它们的MD5哈希值必须相等,才会输出$flag
变量的值(即满足挑战条件)。 - 这里利用的是PHP中
md5
哈希函数的特性和弱类型比较(==
)。在某些特殊情况下,不同的输入可以产生相同的MD5哈希值长文本输出(尽管这是极为罕见的),或者在使用==
进行比较时利用PHP弱类型的特性来绕过检查。
实际上,满足这个条件的一个通常方法是利用PHP中的"魔术哈希"(Magic Hash)问题。"魔术哈希"是指一些特殊值,它们的MD5哈希值以"0e"开头,接下来是纯数字,这在PHP中会被解释为科学记数法表示的0,导致弱类型比较时等于另一个具有相同特性的哈希值。
总结
这个脚本的挑战点在于找到使得$name
和$password
的MD5哈希值在弱类型比较下相等,但这两个值本身并不相等的输入。正确的解决方式通常涉及寻找或利用已知的"魔术哈希"值。
这道题有两种解法,一种是寻找两变量值不相等,但md5后的散列值相等的一组数据,分别使用GET和POST两种请求方法传入即可得到flag。
另一种是通过数组绕过的方式。
第一种解法:md5绕过
介绍几个符合两变量值不相等,但md5后的散列值相等的数据
php
//md5加密后以0E开头,且后面均为纯数字
QNKCDZO
240610708
s878926199a
s155964671a
然后利用Hackbar传参即可得到flag。
payload:?name=QNKCDZO
POST:password=240610708
第二种方法:数组绕过
payload:?name[]=1
POST:password[]=2
PHP 中的 md5
函数在处理字符串时运行正常,但如果传入的是一个数组,md5
函数返回 NULL。在 PHP 中,当你尝试对一个数组使用 md5()
函数时,会发生类型错误,因为 md5
预期的是一个字符串。如果请求的参数是一个数组(例如通过 name[]=1
),则 $_GET['name']
和 $_POST['password']
将会是数组而不是字符串。
那么,在提及的代码逻辑中,当同时使用GET传参 ?name[]=1
和POST传参 password[]=2
时,$name
和 $password
都会成为数组。这将导致条件:
if ($name != $password && md5($name) == md5($password)){
echo $flag;
}
结果如下:
$name != $password
返回true
,因为两个数组不相等。- 由于 PHP 会对名称后带
[]
的参数自动创建数组,因此md5($name)
和md5($password)
都会尝试对数组进行哈希处理,导致它们都返回 NULL 或者产生一个警告并返回一个布尔值false
。 - 在 PHP 中,(NULL == NULL) 为
true
,(false == false) 也为true
。因此使得md5($name) == md5($password)
返回true
,而忽略了实际哈希值因为它们都是 NULL 或者 false。
因此尽管 $name
和 $password
都没有被哈希处理,但由于它们都返回了 NULL 或者 false,相等性比较因类型转换返回了 true
,从而导致它们按照代码的逻辑满足了输出 $flag
的条件。这是一个类型弱检查的问题,说明==
在 PHP 中可能会导致一些非预期的行为,尤其是当比较的值中包含非字符串类型,像是数组时。
本题完。