写在前面:最近练习了一些CTF中关于md5绕过的题目,总结了几种思路,本质没有太大变化,就是各种组合绕过,也是比较考察基础的,前段时间太摆烂了,好久没有更新了,革命尚未成功,同志仍需努力!!!
关于md5
md5是一种信息摘要算法(目标是用于证明原文的完整性),其本质也是一种哈希函数,一种被广泛使用的密码散列函数,任意长度的数据算出的md5值的长度都是固定的,md5码具有高度的散列性,没有规律可循,哪怕辕信息只有一点变化,那么md5码也会发生巨大的变化,常用于验证文件的完整性,数据库存储密码,数字签名等。
md5具有不可逆性,但是通过MD5碰撞,还是有一定可能逆向出来的,(推荐一个在线md5破解网站:md5在线破解网站)
PHP 类型比较
松散比较(运算符):使用两个等号 == 比较,只比较值,不比较类型。严格比较(全等运算符):用三个等号 === 比较,除了比较值,也比较类型。详细了解可以参考菜鸟教程,很详细了。
PHP 0e漏洞
PHP在处理哈希字符串时,会利用”!=”或”==”来对哈希值进行比较,它把每一个以”0E”开头的哈希值都解释为0(当成科学计数法进行处理),所以如果两个不同的密码经过哈希以后,其哈希值都是以”0E”开头的,那么PHP将会认为他们相同,都是0。
PHP在攻击者可以利用这一漏洞,通过输入一个经过哈希后以”0E”开头的字符串,即会被PHP解释为0,如果数据库中存在这种哈希值以”0E”开头的密码的话,他就可以以这个用户的身份登录进去,尽管并没有真正的密码。
PHP md5()函数
语法:md5(string,raw)
参数 | 描述 |
---|---|
string | 必需。规定要计算的字符串。 |
raw | 可选。规定十六进制或二进制输出格式: TRUE - 原始 16 字符二进制格式 FALSE - 默认 32 字符十六进制数 |
具体使用方法,可以参考菜鸟教程
松散比较类型
题目一
题目如下:<?phpheader("Content-Type:text/html;charset=utf-8");show_source(__FILE__);include('flag.php');$md5 = $_GET['md5'];if($md5 == md5($md5)){ echo 'GET_FLAG'.$flag;}else{ echo 'md5校验失败...';}?> md5校验失败...
题目分析:
题目中要求一个字符串与md5加密后的值相等,通过上面PHP 0e漏洞的原理,也就将此题转化成 ==>寻找一个字符串(0e开头)加密后(还是0e开头),弱比较相等。
payload:?md5=0e215962017
此题可解:
题目二
题目如下:<?phpheader("Content-Type:text/html;charset=utf-8");show_source(__FILE__);include('flag.php');$username = $_GET['username'];$password = $_GET['password'];if($username != $password){ if(md5($username) == md5($password)){ echo 'GET_FLAG:'.$flag; }else{ echo 'md5校验出错...'; }}else{ echo '用户名密码不能相等!';}?> 用户名密码不能相等
题目分析: 题目中,要求两个字符串值不能相等,但是两个字符串经过md5加密后的值需要相等,通过上面PHP 0e漏洞的原理,也就将此题转化成 ==> 寻找两个值加密后以0e开头,且0e后面是纯数字的字符串即可,可以使用Python写个程序或者直接在网上搜。
240610708 0e462097431906509019562988736854 314282422 0e990995504821699494520356953734 571579406 0e972379832854295224118025748221QLTHNDT 0e405967825401955372549139051580 QNKCDZO 0e830400451993494058024219903391 EEIZDOI 0e782601363539291779881938479162 TUFEPMC 0e839407194569345277863905212547 UTIPEZQ 0e382098788231234954670291303879
此题可解: 严格比较类型
题目一
题目如下:<?phpheader("Content-Type:text/html;charset=utf-8");show_source(__FILE__);include('flag.php');$username = $_GET['username'];$password = $_GET['password'];if($username != $password){ if(md5($username) === md5($password)){ echo 'GET_FLAG:'.$flag; }else{ echo 'md5校验出错...'; }}else{ echo '用户名密码不能相等!';}?> 用户名密码不能相等!
题目分析: 全等运算符“===”,既比较值又比较类型,题目中“!=”意思为“不等于”,具体可查看菜鸟教程关于“!=”说明,值不相等时返回“ture”,也就是说两个参数值要不相等,两个参数在md5加密后全相等,也就是说两个参数在md5加密后不仅值相等类型也要一致,此时就无法利用PHP 0e漏洞了,需要别的方法绕过。
可以利用md5在加密字符串时会warining,输出结果为NULL,传入两个数组,这样就能使两个参数在md5加密后的类型是一致的。
payload:?username[]=1&password[]=2
此题可解:catf1ag{nlLU5FRGzI98ZuDyCYwq4KG4iZqIVEmp}
SQL注入+md5
(此题考察了SQL注入+md5各种绕过)
题目如下:题目分析:随便输入内容。点击提交没有任何回显,想到查看网页源代码,是否会有线索解题,在源代码中看到“header”,考虑可以尝试抓包查看HTTP头,这里推荐一个好用的在线工具(在线查看HTTP/HTTPS响应消息头)。
通过抓包(如下图),发现“Hint”处存在一个SQL语句“select * from 'admin' where password=md5($pass,true)”,这里通过上面对PHP md5()函数的解释,md5($pass,true)为true时,返回的是原始 16 字符二进制格式,这时可以通过输入ffifdyop进行绕过。
ffifdyop绕过原理:
ffifdyop经过md5加密后是:276f722736c95d99e921722cf9ed621c
在转换字符串是:'or'6<乱码> 即 'or'66�]��!r,��b
利用方法:
select * from admin where password=''or'6<乱码>'
就相当于构成永真式,即万能密码,实现SQL注入
select * from admin where password=''or 1
输入提交后,返回了新的页面(如下图)。
查看网页源代码。
<!--$a = $GET['a'];$b = $_GET['b'];if($a != $b && md5($a) == md5($b)){-->
这里通过代码审计:
传入参数a和b不能相等,两个参数经过md5加密后值相等。可以参考上面的松散比较类型进行绕过。提交参数后,页面刷新(如下图)。
好家伙,又要绕过,需要传入参数param1和param2,需要满足两个参数不相等,md5加密后值和类型都相等,可以参考上面的严格比较类型进行绕过(数组)。需要注意的是这里需要使用POST传参,这里推荐工具:HackBar。
题目得解:flag{2223418e-1d21-4436-95cb-4050c0ffc7a4}
题目练习平台
Catf1agCTF - 综合训练平台(前面几道题目)
BUUCTF在线评测http://www.catf1ag.cn/mainBUUCTF在线评测(最后一题[BJDCTF2020]Easy MD51)