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;
}
}
}
?>

审计代码可知:
我们需要以GET形式传递3个值,其中 v1 != v2 ,if中的第二个判断条件用的是 ==,我们可以利用 “0x” == “0a” 的判断结果为1,所以只找出经过加密后的两个md5值以0开头,接下去以都相同的值,直到遇到的字母的两个字符串相等 v3 == flag

一、PHP处理0e开头md5时hash字符串漏洞

PHP在处理哈希字符串时,会利用”!=”或”==”来对哈希值进行比较,它把每一个以”0E”开头的哈希值都解释为0,所以如果两个不同的密码经过哈希以后,其哈希值都是以”0E”开头的,那么PHP将会认为他们相同,都是0。 例如:v1=s878926199a&&v2=s155964671a

二、md5函数特性

根据md5函数特性,用两个值不同但不可进行md5的数据类型,如果使用一个不可md5的数据类型传入的话那么md5函数将返回false,这个也是返回值
例如: v1[]=1&&v2[]=2

三、strcmp()

1
2
3
4
5
int strcmp ( string $str1 , string $str2 )
参数 str1第一个字符串。str2第二个字符串。
如果 str1 小于 str2 返回 < 0;
如果 str1 大于 str2 返回 > 0;
如果两者相等,返回 0。

传入的期望类型是字符串类型的数据,但是如果我们传入非字符串类型的数据的时候,这个函数将会有怎么样的行为呢?实际上,当这个函数接受到了不符合的类型,这个函数将发生错误,但是在5.3之前的php中,显示了报错的警告信息后,将return 0 !!!! 也就是虽然报了错,但却判定其相等了。这对于使用这个函数来做选择语句中的判断的代码来说简直是一个致命的漏洞,当然,php官方在后面的版本中修复了这个漏洞,使得报错的时候函数不返回任何值。

1
2
3
4
5
6
7
8
9
10
11
<?php
$password="***************"
if(isset($_POST['password'])){

if (strcmp($_POST['password'], $password) == 0) {
echo "Right!!!login success";n
exit();
} else {
echo "Wrong password..";
}
?>

只要我们$_POST[‘password’]是一个数组或者一个object即可,但是上一个问题的时候说到过,只能上传字符串类型,那我们又该如何做呢
我们只需将payload构造成 password[]=admin 即可

所以该题的绕过方式为:
?v1[]=1&&v2[]=2&&v3[]=3
?v1=s878926199a&&v2=s155964671a&&v3[]=1 都可