Hash Attack

常见的Hash函数的攻击方法主要有

  • 暴力攻击:不依赖于任何算法细节,仅与Hash值长度有关;

  • 生日攻击法(Birthday Attack):没有利用Hash函数的结构和任何代数弱性质,只依赖于消息摘要的长度,即Hash值的长度。

  • 中点交会攻击法(Meet-In-The-Middle):是生日攻击的一种变形,不比较Hash值,而是比较中间变量。这种攻击主要适用于攻击具有分组链结构的Hash方案。

  • 密码分析:依赖于具体算法的设计缺点。

暴力攻击

HashCat 工具 可以说是目前最好的基于 CPU 和 GPU 破解 Hash 的软件,相关链接如下

HashCat 官网

HashCat 简单使用

哈希长度拓展攻击(hash length extension attacks)

介绍

基本定义如下,源自维基百科

哈希长度扩展攻击(Hash Length Extension Attacks)是指针对某些允许包含额外信息的加密散列函数的攻击手段。该攻击适用于在消息与密钥的长度已知的情形下,所有采取了 H(key ∥ message) 此类构造的散列函数。MD5和SHA-1 等基于 Merkle–Damgård 构造的算法均对此类攻击显示出脆弱性。

这类哈希函数有以下特点

  • 消息填充方式都比较类似,首先在消息后面添加一个1,然后填充若干个0,直至总长度与 448 同余,最后在其后附上64位的消息长度(填充前)。

  • 每一块得到的链接变量都会被作为下一次执行hash函数的初始向量IV。在最后一块的时候,才会将其对应的链接变量转换为hash值。

一般攻击时应满足如下条件

  • 我们已知 key 的长度,如果不知道的话,需要爆破出来

  • 我们可以控制 message 的消息。

  • 我们已经知道了包含 key 的一个消息的hash值。

这样我们就可以得到一对(messge,x)满足x=H(key ∥ message)虽然我们并不清楚key的内容。

攻击原理

这里不妨假设我们我们知道了 hash(key+s) 的 hash 值,其中 s 是已知的,那么其本身在计算的时候,必然会进行填充。那么我们首先可以得到 key+s 扩展后的字符串 now,即

now=key|s|padding

那么如果我们在 now 的后面再次附加上一部分信息extra,即

key|s|padding|extra

这样再去计算hash值的时候,

  1. 会对 extra 进行填充直到满足条件。

  2. 先计算 now 对应的链接变量 IV1,而我们已经知道这部分的 hash 值,并且链接变量产生 hash 值的算法是可逆的,所以我们可以得到链接变量。

  3. 下面会根据得到的链接变量 IV1,对 extra 部分进行哈希算法,并返回hash值。

那么既然我们已经知道了第一部分的 hash 值,并且,我们还知道 extra 的值,那么我们便可以得到最后的hash值。

而之前我们也说了我们可以控制 message 的值。那么其实 s,padding,extra 我们都是可以控制的。所以我们自然可以找到对应的(message,x)满足x=hash(key|message)。

例子

似乎大都是web里面的,,不太懂web,暂时先不给例子了。

工具

如何使用请参考github上的readme。

hash算法设计有误

一些自定义的hash算法可能是可逆的。

Hashinator

题目的逻辑很简单,从一个知名的密码字典"rockyou"挑选出一个password,并且使用多种hash算法随机的哈希32轮。我们需要从最后的hash结果中破解出原始的password

分析

题目采用的hash算法有:md5sha1blakescrypt。 关键的代码如下:

  1. 程序首先通过从rockyou.txt中随机抽取一个password,作为加密的明文。

  2. 然后根据抽取的password的长度,生成一个长度为128 - len(password)salt

  3. 从之前列举的4种hash算法中抽取,组成32轮的哈希运算。

  4. 根据之前得到的passwordsalt计算出最后给我们的password_hash

很明显,我们不可能通过逆向hash算法来完成题目。 我们知道所有的可能的明文,首先考虑能否通过构造彩虹表来完成穷举。但是注意到generate_salt()函数中,saltpassword的长度组合超过了128byte的长度,并且被注释了

so,只能无奈放弃。

那这样的话,只存在一种可能,也即算法可逆。查看calculate_hash()函数的具体实现,可以发现如下可疑的代码:

重新梳理一下我们知道的信息:

  1. hash_rounds中保存了32轮,即每轮要使用的hash函数句柄。

  2. final_hash是最后给我们的hash结果。

  3. hash_rounds中的内容也会在生成之后打印给我们。

  4. 我们希望得到interim_saltinterim_hash在第一轮的值。

  5. interim_saltinterim_hash的长度均为64byte。

仔细观察一下interim_saltinterim_hash的计算方法,可以发现它是可逆的。

interim_hash1=interim_hash2hash_rounds[i](interim_salt3)interim\_hash_1 = interim\_hash_2 \oplus hash\_rounds[i](interim\_salt_3)

这行代码里,我们已知 $interim_hash_1$ 和 $interim_salt_3$,由此可以推出$interim_hash_2$的值,而$interim_hash_2$则是上一轮的interim_hash。 以此方法逆推32次,则可以得到最初的passwordsalt

具体的解密脚本为:

原hash算法

Last updated