MD5哈希(hash)长度扩展攻击

0x01 MD5加密原理

简单介绍下分成下面几步

  • 分组,先将二进制字符串以512位(64字节)为一组,然后再把每组分为16个子分组(每子分组32位,也就是4字节)
  • 填充,分两步填N64+56字节,填充规则是,二进制的话是先填充一个1,后面全填为0,十六进制是先填充一个8,后面全填0,直到长度满足N64+56

  • 第二步的填充:再填充8字节,这样最后的数据就是(N+1)*64字节。

  • 接下来假设原始为abcd,对一个分组的子分组进行一系列神奇的运算,得出新的abcd,然后这个新的abcd又和下一个分组进行神奇的运算,以此类推,最后就会得出一个128位加密后的值,用16进制来表示也就是我们看到的32位的md5。

0x02 加盐(salt)原理

管理员把用户密码的md5值存储在数据库,但攻击者常常把一些常用字符串生成md5字典,通过比较网站数据库密码的md5值得到真正的密码。为了加强安全,管理员又通过加盐(salt)的方式来存储密码数据,具体措施是自定义一个字符串,这个字符串谁都看不到。当用户进行注册的时候,把md5(salt+密码)的值进行存储,以后用户每次登陆都在后台把用户输入的密码加盐再md5加密与数据库进行比较。这样攻击者不知道盐是什么,很难通过爆破的方式来获取密码。

0x02 MD5长度扩展攻击原理

哈希长度扩展攻击
hash的MD5对数据进行加密的时候,是分组进行加密。

MD5加密的时候会有四个初始向量IV,对第一组数据加密的时候利用的就是四个初始向量,不同的是,在对第二组数据进行加密的时候,使用的并不是四个初始向量,而是将前一组加密后的密文作为下一组的初始向量。

哈希长度扩展攻击便是利用这个特性来实现的。

扩展攻击实现的条件

  • 知道Salt的长度
  • 要知道一个由salt加密后的md5值
  • 知道$data的值(未加盐的明文)

0x03 简单的md5长度扩展攻击题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
include "secret.php";
@$username=(string)$_POST['username'];
function enc($text){
global $key;
return md5($key.$text);
}
if(enc($username) === $_COOKIE['verify']){
if(is_numeric(strpos($username, "admin"))){
die($flag);
}
else{
die("you are not admin");
}
}
else{
setcookie("verify", enc("guest"), time()+60*60*24*7);
setcookie("len", strlen($key), time()+60*60*24*7);
}
show_source(__FILE__);

从源码可以得到以下内容:

  • enc(“guest”)的值为78cfc57d983b4a17e55828c001a3e781
  • $key的长度为46

题目的关键代码

1
2
3
4
if(enc($username) === $_COOKIE['verify']){
if(is_numeric(strpos($username, "admin"))){
die($flag);
}

这段代码要求我们输入的username在经过enc函数加密之后,与$_COOKIE[‘verify’]的值相等,并且username中必须含有admin。

看到这里,我们就可以想到来利用哈希长度扩展来帮我们解决这个问题。

而且题目给予我们的信息,刚好满足哈希长度扩展攻击的要求。

操作

这里我们使用HashPump这个工具

安装

1
2
3
4
5
git clone https://github.com/bwall/HashPump
apt-get install g++ libssl-dev
cd HashPump
make
make install

使用说明

1
2
3
4
Input Signature: 已知的hash值,这里是$_COOKIE['verify']的值
Input Data: 上面的hash值解密后的字符串,这里是guest。
Input Key Length: $key的长度
Input Data to Add: 想要添加的数据,由于题目要求要含有admin,所以这里是admin。

使用

1
2
3
4
5
6
7
➜  HashPump hashpump
Input Signature: 78cfc57d983b4a17e55828c001a3e781
Input Data: guest
Input Key Length: 46
Input Data to Add: admin
5f585093a7fe86971766c3d25c43d0eb
guest\x80\x00\x00\x00\x00\x98\x01\x00\x00\x00\x00\x00\x00admin

然后我们将得到的hash值去替换数据包中$_COOKIE[‘verify’]的值,然后post提交username=guest%80%00%00%00%00%98%01%00%00%00%00%00%00admin即可。

0x04 序列化md5长度扩展攻击题

此题来自jarvis oj flag在管理员手中吗?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<!DOCTYPE html>
<html>
<head>
<title>Web 350</title>
<style type="text/css">
body {
background:gray;
text-align:center;
}
</style>
</head>

<body>
<?php
$auth = false;
$role = "guest";
$salt =
if (isset($_COOKIE["role"])) {
$role = unserialize($_COOKIE["role"]);//要先将cookie里的role序列化
$hsh = $_COOKIE["hsh"];
if ($role==="admin" && $hsh === md5($salt.strrev($_COOKIE["role"]))) { //需要先提前把cookie里的role取反
$auth = true;
} else {
$auth = false;
}
} else {
$s = serialize($role);
setcookie('role',$s);
$hsh = md5($salt.strrev($s));
setcookie('hsh',$hsh);
}
if ($auth) {
echo "<h3>Welcome Admin. Your flag is
} else {
echo "<h3>Only Admin can see the flag!!</h3>";
}
?>

</body>
</html>

这个比上一题复杂了多,有两个难点:

  • 不知道salt的长度
  • 序列化问题

序列化问题自己搭环境写,比如:

1
2
3
4
5
<?php
$s = 'guest';
$b= serialize($s);
print(strrev($b));
?>

salt的长度一个个蒙,不过写脚本比较简便,前提是你有代码能力

网上看到的有脚本的wp链接,https://cloud.tencent.com/developer/article/1038017

然后上HashPump工具

1
2
3
4
5
6
Input Signature: 3a4727d57463f122833d9e732f94e4e0
Input Data: ;"tseug":5:s
Input Key Length: 12
Input Data to Add: ;"nimda":5:s
fcdc3840332555511c4e4323f6decb07
;"tseug":5:s\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc0\x00\x00\x00\x00\x00\x00\x00;"nimda":5:s

替换cookie即可得到flags
image

文章目录
  1. 1. 0x01 MD5加密原理
  2. 2. 0x02 加盐(salt)原理
  3. 3. 0x02 MD5长度扩展攻击原理
    1. 3.1. 扩展攻击实现的条件
  4. 4. 0x03 简单的md5长度扩展攻击题
    1. 4.1. 操作
  5. 5. 0x04 序列化md5长度扩展攻击题
,