进入题目页面如下
尝试提交XSS攻击以及sql注入
并没有回显,尝试无果,用burp suite抓取响应包查看一下,右键→拦截→拦截响应
在响应中找到了响应头
Hint:select * from ‘admin’ where password =md5($pass,ture)
给出提示MD5
SQL 查询语句的提示,原始的查询语句 select * from ‘admin’ where password =md5($pass,true) (注意:MD5 函数第二个参数在不同数据库意义不同,在 MySQL 里 MD5() 函数只接受一个参数)
这个 SQL 语句的目的是从名为 admin 的表中查询出 password 字段值等于对变量 $pass 进行 MD5 哈希处理后结果的所有记录。
SQL 注入风险
原理:如果在实际应用中,$pass 是用户输入的内容,且没有经过严格的过滤和转义,可以通过构造特殊的输入来改变 SQL 语句的原意,从而实现 SQL 注入攻击。
<?php
$pass = $_GET['pass'];
$sql = "SELECT * FROM admin WHERE password = MD5('$pass')";
// 执行 SQL 查询
?>
可以构造如下的 pass 参数:
' OR '1'='1
最终的 SQL 语句会变成:
SELECT * FROM admin WHERE password = MD5('' or '1'='1')
由于 '1'='1' 永远为真,这个查询会返回 admin 表中的所有记录,可能借此绕过登录验证或者获取敏感信息。
当'or'后的值为True时,可实现SQL注入
md5函数
md5 函数通常用于计算输入字符串的 MD5 哈希值。md5(string, raw) 这种形式的函数调用中,string 是需要进行哈希计算的输入字符串,而 raw 是一个布尔类型的参数,用于指定返回的哈希值的格式。
string:这是必需的参数,代表要进行 MD5 哈希计算的原始字符串数据。可以是任意长度的文本信息,例如用户密码、文件内容等。
raw:这是一个可选参数,不同编程语言对该参数的处理和含义可能有所不同,但一般来说:
当 raw 为 true 或者类似表示真的值时,函数会返回原始的 128 位(16 字节)二进制格式的哈希值。
当 raw 为 false 或者类似表示假的值时,函数会返回以 32 位十六进制字符串形式表示的哈希值。
在 PHP 里,md5()
函数的第二个参数用于指定是否返回原始二进制数据
<?php
// 待哈希的字符串
$string = "Hello, World!";
// 返回 32 位十六进制字符串形式的哈希值
$hexHash = md5($string, false);
echo "十六进制哈希值: ". $hexHash. "\n";
// 返回原始二进制形式的哈希值
$binaryHash = md5($string, true);
echo "二进制哈希值长度: ". strlen($binaryHash). " 字节\n";
?>
在上述代码中,当第二个参数为 false
时,得到的是常见的 32 位十六进制字符串;当为 true
时,得到的是 16 字节的二进制数据。
看了大佬的博客才继续下去,附上链接
[BUUOJ记录] [BJDCTF2020]Easy MD5 - Ye'sBlog - 博客园
大佬说
ffifdyop字符串md5加密后若raw参数为True时会返回 'or'6<trash> (<trash>
只要第一位是非零数字会被判定为True
<trash>会在MySQL将其转换成整型比较时丢掉
后端的SQL语句
select * from `admin` where password=''or'6<trash>'
直接输入ffifdyop,点击提交
进入下一个界面
ctrl+u查看源代码
看到注释中的关键信息
这里使用了==弱比较
比较操作符分为强比较和弱比较,以 PHP 为例来详细讲解弱比较 ==
的情况。当在代码里使用 md5(string, raw)
配合 ==
弱比较
PHP 中 ==
弱比较规则
在 PHP 里,==
是弱比较操作符,它在比较时会进行类型转换,然后再比较值是否相等。
var_dump(0 == "abc"); // 输出: bool(true)
这是因为在使用 ==
比较时,PHP 会尝试将字符串 "abc"
转换为数字,转换结果为 0
,所以与整数 0
比较时结果为 true
。
md5()
和 ==
可能出现的问题
在某些情况下,当使用 md5()
函数计算哈希值并使用 ==
进行比较时,可能会因为弱比较的特性产生意外结果。
哈希值以 0e
开头的情况
部分字符串经过 MD5 哈希后的结果会以 0e
开头,在科学计数法中,0e
后面跟着的数字表示 0 乘以 10 的多少次方,结果始终为 0。当使用 ==
比较两个以 0e
开头的 MD5 哈希值时,PHP 会将它们当作科学计数法表示的数字进行比较,从而认为它们相等。
$str1 = "240610708";
$str2 = "QNKCDZO";
$md5_1 = md5($str1);
$md5_2 = md5($str2);
var_dump($md5_1 == $md5_2); // 输出: bool(true)
echo "MD5 of str1: ". $md5_1. "\n"; // 输出: 0e462097431906509019562988736854
echo "MD5 of str2: ". $md5_2. "\n"; // 输出: 0e830400451993494058024219903391
在上述代码中,$str1
和 $str2
是不同的字符串,但它们的 MD5 哈希值以 0e
开头,使用 ==
比较时结果为 true
。
重要代码解释
<?php
// 从 GET 请求中获取参数 a 的值并赋值给变量 $a
$a = $_GET['a'];
// 从 GET 请求中获取参数 b 的值并赋值给变量 $b
$b = $_GET['b'];
// 检查 $a 不等于 $b 并且它们的 MD5 哈希值相等
if ($a != $b && md5($a) == md5($b)) {
// 若条件满足,执行这里的代码
echo "找到了满足条件的 a 和 b!";
} else {
// 若条件不满足,执行这里的代码
echo "未找到满足条件的 a 和 b。";
}
?>
以下是可以绕过该条件判断的示例输入:
?a=240610708&b=QNKCDZO
这两个字符串不同,但它们的 MD5 哈希值分别是:
md5(240610708)
的结果是 0e462097431906509019562988736854
md5(QNKCDZO)
的结果是 0e830400451993494058024219903391
在 PHP 的弱比较下,这两个哈希值会被判定为相等。
得到这个页面
进行代码审计
<?php
// 关闭所有 PHP 错误报告,避免将错误信息暴露给用户,增强安全性,但也可能掩盖一些潜在问题
error_reporting(0);
// 引入 flag.php 文件,该文件中通常定义了敏感信息,如 flag 值
include "flag.php";
// 高亮显示当前 PHP 文件(即包含此代码的文件)的源代码,方便开发者调试或展示代码结构
highlight_file(__FILE__);
// 检查 POST 请求中 param1 和 param2 两个参数的值是否不相等,并且它们的 MD5 哈希值是否严格相等(值和类型都相等)
if($_POST['param1']!==$_POST['param2']&&md5($_POST['param1'])===md5($_POST['param2'])){
// 如果上述条件满足,则输出 flag.php 文件中定义的 $flag 变量的值
echo $flag;
}
由于 MD5 算法存在哈希碰撞的问题,也就是可以找到两个不同的输入,它们经过 MD5 计算后得到相同的哈希值。不过代码中使用了 ===
进行严格比较,这要求不仅哈希值的内容相同,类型也要相同,所以利用以 0e
开头的 MD5 值在弱比较下相等这种方法在这里行不通。
但实际上可以利用 MD5 对数组不做处理的特性来绕过这个判断。当 md5()
函数的参数为数组时,它会返回 NULL
。
md5数组绕过
1. 原理概述
在许多编程语言里,当使用 MD5 函数对数组进行处理时,其行为可能并非如预期对数组元素进行哈希计算,而是会产生一些特殊结果,利用这些特殊结果可以绕过基于 MD5 哈希值比较的验证机制,这就是 MD5 数组绕过。以 PHP 语言为例,下面详细介绍其原理、示例及防范措施。
2. PHP 中 MD5 对数组的处理
在 PHP 里,md5()
函数是用于计算字符串的 MD5 哈希值的。当传入的参数是数组时,md5()
函数不会对数组元素进行哈希计算,而是直接返回 NULL
。
<?php
$array1 = [1, 2, 3];
$array2 = [4, 5, 6];
$hash1 = md5($array1);
$hash2 = md5($array2);
var_dump($hash1); // 输出: NULL
var_dump($hash2); // 输出: NULL
if ($hash1 === $hash2) {
echo "两个数组的 MD5 哈希值相等";
} else {
echo "两个数组的 MD5 哈希值不相等";
}
?>
在上述代码中,$array1
和 $array2
是不同的数组,但对它们使用 md5()
函数计算哈希值时,结果都为 NULL
,所以在进行严格比较 $hash1 === $hash2
时,结果为 true
。
构造 POST 请求
可以通过构造一个包含两个不同数组的 POST 请求来绕过判断条件。
payload
param1[]=1¶m2[]=2
用hackbar工具POST传参
最终得到flag