md5绕过汇总

函数介绍

在php语言中,md5() 函数用于计算字符串的 MD5 散列。例如:

1
2
3
4
5
6
<?php
$str = "Hello World!";
echo md5($str); //默认输出 32 字符十六进制数
echo "<br>";
echo md5($str,TRUE); //输出原始 16 字符二进制格式
?>

相关漏洞

php弱比较

1
2
3
4
5
6
7
8
9
10
<?php
$a = $_GET['a'];
$b = $_GET['b'];

if ($a != $b && md5($a) == md5($b)) {
die("Success!");
} else{
die("Failed!");
}
?>

若两个字符经过MD5加密后的值为 0e 开头的字符串,在php弱比较中会被认为是科学计数法,表示为0*10的若干次方,结果为零,判定为相等。

下列字符串在经过MD5加密后形成值为 0e 开头的字符串。

1
2
3
4
5
6
QNKCDZO
240610708
s878926199a
s155964671a
s214587387a
s1091221200a

下列字符串在经过MD5和二次MD5加密后均形成值为 0e 开头的字符串。

1
2
3
CbDLytmyGm2xQyaLNhWn
770hQgrBOjrcqftrlaZk
7r4lGXCH2Ksu2JNT3BYM

检验代码

1
2
3
4
5
6
<?php
$str = "CbDLytmyGm2xQyaLNhWn";
echo md5($str);
echo "<br>";
echo md5(md5($str));
?>

下列本身为 0e 开头字符串在经过MD5加密后可以再次形成值为 0e 开头的字符串。
0e215962017(验证有误?)

php强比较

1
2
3
4
5
6
7
8
9
10
<?php
$a = $_GET['a'];
$b = $_GET['b'];

if ($a !== $b && md5($a) === md5($b)) {
die("Success!");
} else{
die("Failed!");
}
?>

md5()函数无法处理数组,如果传入的为数组,虽然会产生报错,但仍会返回NULL,所以两个数组经过加密后得到的均为NULL,在php强比较中判断为相等。

MD5碰撞

1
2
3
4
5
6
7
8
9
10
<?php
$a = (string)$_GET['a'];
$b = (string)$_GET['b'];

if ($a !== $b && md5($a) === md5($b)) {
die("Success!");
} else{
die("Failed!");
}
?>

由于增加了一个转为字符串的强制类型转换,传数组的方法将不可行,这里就需要进行MD5碰撞,使用 Fastcoll 可以生成指定前缀的两个内容不同但是MD5值相同的文件。

新建一个head.txt写入指定前缀内容并保存,将这个文件拖到fastcoll.exe上,相当于使用fastcoll打开它,fastcoll会自动在同一目录下生成两个二进制文件,这两个文件内容不同但是MD5值相同。

也可以使用命令运行该程序。
fastcoll.exe -p head.txt -o 1.txt 2.txt

写程序读取文件内容并转化为url编码,转化编码的目的是生成的文件中存有不可见字符,以便于进行后续的传参工作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php 
function readmyfile($path){
$fh = fopen($path, "rb");
$data = fread($fh, filesize($path));
fclose($fh);
return $data;
}
echo '二进制md5加密 '. md5( (readmyfile("1_msg1.txt")));
echo "</br>";
echo 'url编码 '. urlencode(readmyfile("1_msg1.txt"));
echo "</br>";
echo '二进制md5加密 '.md5( (readmyfile("1_msg2.txt")));
echo "</br>";
echo 'url编码 '. urlencode(readmyfile("1_msg2.txt"));
echo "</br>";
?>

构造sql注入攻击语句

当目标网站使用如下查询语句时,可以通过特殊字符串进行MD5加密后形成万能密码从而产生注入攻击。
select * from 'admin' where password=md5($pass,true)

这个特殊字符串就是 ffifdyop ,在进行MD5加密后的值为276f722736c95d99e921722cf9ed621c, 对应的ascii字符串为 'or'6�]��!r,��b ,这个字符串前几位刚好是' or '6
而 Mysql 会将 hex 转成 ascii 解释,因此拼接之后的形式是select * from 'admin' where password='' or '6<乱码>,相当于select * from 'admin' where password='' or 1,即sql万能密码,能够绕过 md5() 函数。

其它

对于题目的更多要求,可以自行编写 php 或者 python 脚本将特殊字符串的内容跑出来。