哈希(Hash)长度扩展攻击

先来看一下md5算法的实现框图
在这里插入图片描述
以实现字符串abcde的md5的值的计算为例
切换到win

  1. 在winhex中打开并输入如下内容
    在这里插入图片描述
    2.对消息进行补位,使得位长mod512得值为448,即len(message) % 512 == 448(单位为bit)。补位的方式为二进制情况下数据后面加上1,然后多个0,直到满足上述等式,事实上10000000(B)=80(hex),所以体现在winhex中,数据后面跟的是80和多个0
    填充完毕后如图阴影部分
    在这里插入图片描述
    448bit等于56byte,在整个块(共64byte)倒数第8个byte开始,填的是补位之前的消息长度,abcde,为5个byte,5*8=40bit,转为16进制为28,然后填充7byte的0x00
    填充如下
    在这里插入图片描述
    接下来用这64byte的数据进行计算
    与初始化向量进行,初始化向量为固定值
    A 01 23 45 67 0x67452301
    B 89 AB CD EF 0xEFCDAB89
    C FE DC BA 98 0x98BADCFE
    D 76 54 32 10 0x10325476
    进行复杂的函数运算后得到abcde的md5值
    ab56b4d92b40713acc5af89985d4b786
    在这里插入图片描述
    以上是md5算法的流程

而在攻击者进行长度扩展攻击时,比如追加内容为“append“,则按照同样会的方法对其进行填充,再利用上一次运算出的值处理后作为初始向量进行函数运算,最终实现无需secret(salt)便能得到签名。

注:
针对初始向量的值的处理是这样的,正常情况下是写死的,即上文提到的
A 01 23 45 67 0x67452301
B 89 AB CD EF 0xEFCDAB89
C FE DC BA 98 0x98BADCFE
D 76 54 32 10 0x10325476
而当进行攻击时,ABCD会被替换为已知的数据对应的md5值,如在abcde这个例子中,得到的md5值为ab56b4d92b40713acc5af89985d4b786
8位为一组,得ab56b4d9,2b40713a, cc5af899,85d4b786
按照小端格式进行处理,分别赋值给A,B,C,D
可得
A d9 b4 56 ab
B 3a 71 40 2b
C 99 f8 5a cc
D 86 b7 d4 85

实际上对以下算法都能实现hash长度扩展攻击,包括md4,md5,ripemd-160,sha-0,sha-1,sha-256,sha-512等,此次针对最常见的md5的hash长度扩展攻击进行讲解。

条件:

  1. secret(salt)为“secret”(攻击者未知)
  2. 数据为“data”(攻击者已知)
  3. 应用采用md5算法,签名算法是hash(secret||data)(||为拼接符,可以为空),已知一个对应项为
    hash(secret || data) = 6036708eba0d11f6ef52ad44e8b74d5b(攻击者已知)
    在这里插入图片描述
  4. 追加字符为”append”(攻击者攻击时使用)

流程为:服务器向攻击者发送数据和签名(即攻击者知道条件2,3),攻击者只需要知道secret(salt)的长度(在CTF比赛中可能会给出,但是实际情况下可能需要通过遍历等方法获取)以及采用的算法,就可以附加追加的数据并为数据生成有效的签名。

可能还是有点懵圈,简单说,就是攻击者现在知道应用给出的一对数据和签名的对应值,只要再知道采用的算法,和secret(salt)的长度就可以生成有效签名进行攻击。为什么这算是攻击呢?因为正常情况下,需要知道secret(salt)才可以生成有效签名,可是在现在的情况下,攻击者无需知道secret(salt)便可以生成有效签名。

接下来看看具体攻击的逻辑。
先看服务端是如何实现的。
切换到kali
在这里插入图片描述
编译
在这里插入图片描述
运行
在这里插入图片描述
通过这段逻辑可以看到,服务器将会检查我们发送的针对签名6ee582a1669ce442f3719c47430dadee
的数据(生成时需要secret(salt)。现在再来看看攻击者是如何生成该签名的。
如何在不实际访问secret(salt)的情况下计算上面显示的数据的签名呢?
首先,我们需要看一下我们要处理的内容:数据、追加内容,md5(secret || data)。
我们需要定义一个新函数md5’,它使用与md5相同的算法,但其起始状态是md5(secret || data)的最终状态,即签名。 一旦我们有了这个签名,我们只需计算md5’(追加内容),该函数的输出就是我们的最终的哈希值。
代码实现如下:
在这里插入图片描述
编译
在这里插入图片描述
提示没有显示声明,只是报了一个warning,没事,继续
执行
在这里插入图片描述
我们可以看到得到的结果与服务器应用相同。不同的是,我们根本没有使用secret(salt)
回顾下代码,我们一开始开始创建MD5_CTX结构,就像服务器部分的代码一样。 然后我们采用64个‘A’的MD5。 我们采用’A’的完整(64字节)块的MD5来确保除了散列本身的状态之外的任何内部值都设置为我们期望的值。(其实用其他值进行填充也是可以的)
然后,在完成之后,我们将c.A,c.B,c.C和c.D替换为签名中的值:6036708eba0d11f6ef52ad44e8b74d5b(这个值就是前面应用给出的,就是下图的值)
在这里插入图片描述
这使得MD5_CTX结构处于与最初完成时相同的状态,并且意味着我们散列的任何其他内容(在本例中为append)将产生与我们以正常方式对其进行哈希处理时相同的输出。
我们在设置状态变量之前对值使用htonl(),因为MD5 - 是小端模式(little-endian ) ,以小端模式输出它的值。
由上得到了
md5(secret || data || append): 6ee582a1669ce442f3719c47430dadee

换个角度来理解,切换到win
切换到windows,打开winhex,新建file
在这里插入图片描述
输入已知的数据secretdata
在这里插入图片描述
按照填充的规则进行填充
在这里插入图片描述
拆开字符串来看,secret(salt)就是secret,数据为data,从80 00…到50之前,为从0x80开始的一共46byte的填充,0x50是小端的位长。

如果攻击者添加追加内容的话,填充如下:
在这里插入图片描述
计算这一块的hash这两种办法,一是直接使用md5算法进行计算(服务端程序采用),二是通过从第一个块结束开始,使用我们已经从签hash中获知的状态,并从该状态开始对追加内容进行hash(攻击者程序采用)

先看服务端的
我们实际上只是将数据发送给服务端,而不是secret(salt)+数据,secret(salt)在服务器进行处理时会自动加上
所以数据应该是这样子的
在这里插入图片描述
服务器应用会自动添加secret(salt)
在这里插入图片描述
并且进行hash得到
6ee582a1669ce442f3719c47430dadee

在这里插入图片描述在这里插入图片描述在这里插入图片描述
在这里插入图片描述

安装完毕后输入hashpump即可使用

在这里插入图片描述
分别输入已知hash、数据、长度、以及追加内容即可得到
在这里插入图片描述
结果中的6ee582a1669ce442f3719c47430dadee正是在实验步骤二攻击者在未知secret的情况下生成的md5

了解了攻击产生的原理,相应的防护手段也就不难理解

1.可以将消息摘要的值再进行消息摘要,这样就可以避免用户控制message了。也就是HMAC算法。该算法大概来说是这样:MAC =hash(secret + hash(secret + message)),而不是简单的对密钥连接message之后的值进行哈希摘要。具体HMAC的工作原理有些复杂,但你可以有个大概的了解。重点是,由于这种算法进行了双重摘要,密钥不再受本文中的长度扩展攻击影响。HMAC最先是在1996年被发表,之后几乎被添加到每一种编程语言的标准函数库中。
2.将secret放置在消息末尾也能防止这种攻击。比如 hash(m+secret),希望推导出 hash(m + secret||padding||m'),由于自动附加secret在末尾的关系,会变成hash(m||padding||m'||secret)。现在的附加值可以看作是m'||secret,secret值不知道,从而导致附加字符串不可控,hash值也就不可控,因而防止了这种攻击。

6 参考
1.《白帽子讲web安全》中的"Understanding MD5 Length Extension Attack"一节
2.所有讲hash长度扩展攻击的文章必会引用的资料 https://blog.skullsecurity.org/2012/everything-you-need-to-know-about-hash-length-extension-attacks
3.绿盟博客使用python实现相关原理的参考 http://blog.nsfocus.net/hash-length-extension-attack/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值