Fork me on GitHub

哈希扩展攻击继续分析

最近看到了好多针对de1ctf ssrfme题目分析,顺便把之前没搞明白的哈希长度扩展攻击写一下

链接这篇文章讲的很仔细了,分析一下文章中的栗子

师傅给的代码

md5的过程

  1. MD5 padding

如果输入信息的长度(字节)对64求余的结果不等于56,就需要填充使得对64求余的结果等于56。填充的方法是填充一个x80和xx个0。填充完后,信息的长度为N*64+56(字节),并且最后8个字节用来记录原始输入信息长度

  1. MD5 compress
    这个算法直接到网上找就行

所以MD5的过程就是:

先进行消息长度的填充(padding)。填充完后,初始化的4个Magic number会和第一个64字节的Message block进行md5 compress压缩算法。压缩算法完成后,会产生新的4个Magic number。这样再进行第二个64字节Message block的md5 compress压缩算法。以此类推……直到压缩到最后64个字节的(Message block + padding),最后得到的Magic number经过hex转化就是最后的md5 hash值

比如md5(‘admin’),由于padding之后只有64个字节,所以只进行一轮的md5 compress 得到的密文就是:

21232f297a57a5a743894a0e4a801fc3

我们可以从密文推导出4个magic number:

1
2
3
4
A=0x292f2321L
B=0xa7a5577aL
C=0xe4a8943L
D=0xc31f804aL

这个关系就是大小端转化一下

md5长度扩展的攻击过程

知道如下三个值:

  1. md5(salt+message)的值
  2. message内容
  3. salt+message长度

我们可以根据md5(salt+message)的值逆向出最后的四个magic number

1
2
3
4
5
def compute_magic_number(self, md5str):
self.A = struct.unpack("I", md5str[0:8].decode('hex'))[0]
self.B = struct.unpack("I", md5str[8:16].decode('hex'))[0]
self.C = struct.unpack("I", md5str[16:24].decode('hex'))[0]
self.D = struct.unpack("I", md5str[24:32].decode('hex'))[0]

这个四个magic number去和m做一下次的md5 compress

再理解一下

继续又看了一篇师傅的文章,想要好好梳理一下哈希扩展攻击

师傅是以sha1算法为例讲解的: sha1的流程如下:

sha1算法和md5很相似,也有最初的四个IV,并且是确定的(这是一种很不好的方法但是也是一种无奈的举动)

一个不足64位的字符串会被padding至64位,并且由于只有一个分组,所以只需要一轮运算即可

我们在前一次64位padding之后的字符串的基础上加入一些字符,sha1(salt+padding+add_data) 首先这里肯定是要分成两组的,前一组加密后的内容已经知道了,同时产生的新的IV会参与下一次的复杂的数学运算

而这些IV是能够从第一组的密文中得知的,这就导致下一组加密后的内容实际上我们也可以知道的

《白帽子讲web安全》上提到,如何利用长度扩展攻击:

LengthExtension 使得可以在原文之后附加任意的值,并计算出新的hash值,最常见的地方就是签名

  1. 错误的签名校验算法
    参数连接时没有使用分隔符,本来是?a=1&b=2&c=3在签名算法中简单地变成了a1b2c3

于是攻击者可以伪造参数?a=1b2c3[...padding....]&b=4&c=5

最终在签名算法中连接时变成了a1b2c3[...padding...]b4c5

  1. 附加任意的参数

  2. HPP

最简单的防护就是将secret放置在参数的末尾

举例

大师傅给的栗子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php

$role = $_REQUEST["role"];
$hash = $_REQUEST["hash"];
$salt = "meme";

if ($hash !== md5($salt.$role)){
echo 'wrong!';
exit;
}

if ( $role == 'admin'){
echo 'wrong, hash cann\'t be admin';
exit;
}

echo "You are ".$role.'</br>';
echo 'Congradulation!';

?>

已知role为admin,salt的长度为4,hash值为:c7813629f22b6a7d28a08041db3e80a9

我们可以在role后面附加任意的数据使得第一个if被绕过

用大师傅的脚本:

python md5pad.py c7813629f22b6a7d28a08041db3e80a9 joychou 9

当然也可以这样:

1
2
3
4
5
6
7
$ hashpump                                                                                                                        
Input Signature: c7813629f22b6a7d28a08041db3e80a9
Input Data: admin
Input Key Length: 9
Input Data to Add: joychou
06cf5a94dcda53659f58c0f411ba0bd8
admin\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\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00p\x00\x00\x00\x00\x00\x00\x00joychou

注意第三次输入的数据长度是包括salt在内的

参考

深入理解hash长度扩展攻击(sha1为例)
Hash Length Extension Attack