[BUUOJ记录] [BJDCTF2020]Easy MD5
各种关于md5的Bypass操作,都是基本操作,考察数组绕过、弱类型比较绕过以及md5($password,true) ByPass
1、利用md5($password,true)实现SQL注入
F12或者Burp抓取响应头可以看到Hint,也就是后端处理的SQL语句:
select * from 'admin' where password=md5($pass,true)
突破点在md5($pass,true)这里,先来看看md5函数的用法:
可以看到这里的raw参数是True,意为返回原始16字符二进制格式。
也就是说如果md5值经过hex转成字符串后为 'or'+balabala这样的字符串,则拼接后构成的SQL语句为:
select * from `admin` where password=''or'balabala'
当'or'后面的值为True时,即可构成万能密码实现SQL注入,这里我们需要知道的是MySQL的一个特性:
在mysql里面,在用作布尔型判断时,以1开头的字符串会被当做整型数。要注意的是这种情况是必须要有单引号括起来的,比如password=‘xxx’ or ‘1xxxxxxxxx’,那么就相当于password=‘xxx’ or 1 ,也就相当于password=‘xxx’ or true,所以返回值就是true。当然在我后来测试中发现,不只是1开头,只要是数字开头都是可以的。
当然如果只有数字的话,就不需要单引号,比如password=‘xxx’ or 1,那么返回值也是true。(xxx指代任意字符)
select * from `admin` where password=''or'1abcdefg' ---> True select * from `admin` where password=''or'0abcdefg' ---> False select * from `admin` where password=''or'1' ---> True select * from `admin` where password=''or'2' ---> True select * from `admin` where password=''or'0' ---> False
只要'or'后面的字符串为一个非零的数字开头都会返回True,这就是我们的突破点。
我们可以通过这个脚本来获得满足我们要求的明文:
<?php for ($i = 0;;) { for ($c = 0; $c < 1000000; $c++, $i++) if (stripos(md5($i, true), '\'or\'') !== false) echo "\nmd5($i) = " . md5($i, true) . "\n"; echo "."; } ?> //引用于 http://mslc.ctf.su/wp/leet-more-2010-oh-those-admins-writeup/
这里提供一个最常用的:ffifdyop,该字符串md5加密后若raw参数为True时会返回 'or'6<trash> (<trash>其实就是一些乱码和不可见字符,这里只要第一位是非零数字即可被判定为True,后面的<trash>会在MySQL将其转换成整型比较时丢掉)
所以如果这里我们输入ffifdyop,后端的SQL语句会变成:
select * from `admin` where password=''or'6<trash>' ---> True
成功构成SQL注入,我们在本题直接输入ffifdyop即可进入下一关
2、PHP md5弱类型比较
进入第二关后右键查看源代码可以从注释中得到后端PHP的一部分源码:
$a = $GET['a']; $b = $_GET['b']; if($a != $b && md5($a) == md5($b)){ // wow, glzjin wants a girl friend.
可以看到,赵师傅又在征婚了 这里要求a和b明文值不同,但md5值相同,注意这里是两个等于号,是弱相等,所以我们可以利用PHP的弱类型比较突破,寻找两个明文不同但md5值为"0exxxxx"的字符串,可以参考我之前的一篇文章:https://www.cnblogs.com/yesec/p/12232075.html
这里直接提供两个QNKCDZO和s214587387a,用GET传值直接过关
3、数组绕过
进入第三关给出了源码:
<?php error_reporting(0); include "flag.php"; highlight_file(__FILE__); if($_POST['param1']!==$_POST['param2']&&md5($_POST['param1'])===md5($_POST['param2'])){ echo $flag; }
可以看到依旧是md5比较,但是不同于第二关,这一关是“===“强相等,很明显2中的方法没办法通过
刚才推荐的那一片文章里文末也提到了这种方法,这里需要知道的是PHP的一些特性:
md5(array()) = null
sha1(array()) = null
ereg(pattern,array()) = null vs preg_match(pattern,array) = false
strcmp(array(), "abc") = null
strpos(array(),"abc") = null
引用自 https://blog.csdn.net/q1352483315/article/details/89469928
md5()函数无法处理数组,如果传入的为数组,会返回NULL,所以两个数组经过加密后得到的都是NULL,也就是相等的。
所以直接POST传入param1[]=1¶m2[]=2即可得到Flag:
[ * ]博客中转载的文章均已标明出处与来源,若无意产生侵权行为深表歉意,需要删除或更改请联系博主: 2245998470[at]qq.com