访问靶机,初始页面如图所示:
看上去像是SQL注入,尝试注入后并没有反应,F12查看源码,看到其中存在提示:Hint: select * from 'admin' where password=md5($pass,true)
因此需要找到使password=md5($pass, true)
返回值为true的$pass。
md5函数的用法:
参数 | 描述 |
---|---|
string | 必需 |
raw | 可选,raw为true,16位二进制形式;raw为false,32位二进制形式 |
根据SQL注入的经验,只要md5的返回值为’xxx’ or ‘1xxxxx’(根据MySQL规则,只要以数字开头,返回值就为true,并且纯数字不需要使用引号),就可以使返回值为true。存在一个最常用的pass:ffifdyop,其对应的32位md5码为276f722736c95d99e921722cf9ed621c
,转换为ASCII编码后为'or'6<trash>
*(
同样查看网页源代码,可以看到存在提示:
1
2
3
4
5
6
7
<!--
$a = $GET['a'];
$b = $_GET['b'];
if($a != $b && md5($a) == md5($b)){
// wow, glzjin wants a girl friend.
-->
要求通过get方式上传a和b两个变量,要求a!=b并且md5(a) == md5(b)。PHP中==表示弱等于,在进行比较时,会先将两边的变量转换成相同的类型,而以0e开头的数字/字符会被视为科学计数法,无论e后跟随的字符是什么都会被视为0,因此只要传递两个md5码均为0e开头的字符串作为变量即可。有两个常用的QNKCDZO和s214587387a,作为参数构建payload:/levels91.php?a=QNKCDZO&b=s214587387a
,进入下一关。
这一关给出的提示为:
1
2
3
4
5
6
7
8
9
<?php
error_reporting(0);
include "flag.php";
highlight_file(__FILE__);
if($_POST['param1']!==$_POST['param2']&&md5($_POST['param1'])===md5($_POST['param2'])){
echo $flag;
}
与上一关不同的地方在于,这里使用了===,即强等于进行判断。上面提到的绕过弱等于的办法不适用于强等于,因此需要采用其他绕过办法。
PHP的md5函数存在这样一个特性,如果输出的参数为数组,那么会返回NULL,因此只要使用POST方法传递两个不同的数组,即可获得最后的flag。使用hackbar构造POST请求,得到最终的flag:
REFERENCE
[BUUOJ记录] [BJDCTF2020]Easy MD5 - Ye’sBlog - 博客园 (cnblogs.com)
PHP弱类型hash比较缺陷 - Ye’sBlog - 博客园 (cnblogs.com)
BUUCTF BJDCTF2020 Easy MD5 详解 - junlebao - 博客园 (cnblogs.com)