Hash长度拓展攻击
参考:
https://xz.aliyun.com/t/10602?time__1311=CqjxRGiteiq05DK5YIx7Ki%3DoQet6QHW4D#toc-1
https://ciphersaw.me/2017/11/12/hash-length-extension-attack/#0x00-%E5%89%8D%E8%A8%80
hash长度拓展攻击,概括一下就是由于hash的生成机制使得我们可以人为的在原先的明文基础上添加新的拓展字符,从而使得原本的加密链变长,进一步控制加密链的最后一节,使得我们得以控制最终的结果。
这里首先给出一个相关demo:
1 |
|
在这个例子中,我们需要使得变量$token
与我们输入的sign参数满足一致才会输出flag。
而由于我们无法知道变量$secretKey
的内容,所以无法得到$token
的值,故而看似是没有办法获取到flag的死局,而这时便轮到我们的拓展攻击来大显身手了。
md5算法过程

md5算法是512位一组的,也就是64字节一组,见下面的例子:

由64个a和3个b组成,这里的64个a其二进制长度为512位,已经符合一个md5分组,后面的bbb是下一个分组了。
对于md5算法,我们需要将原始数据分块处理,以512个二进制数据为一块。”最后“一块的处理分为以下两种情况:
- 明文数据的二进制数据长度<=448,填充padding(无意义占位)数据使其长度为448,再添加原始明文数据的二进制长度信息(64位)使其长度为512位即可。
- 448<明文数据的二进制数据长度<=512,填充padding数据至下一块的448位,而后再添加原始明文数据的二进制长度信息(64位)使其长度为512位即可。
情况一:


这里其实64个字符a组成了一个md5分组,剩下的32个字符b作为下一个md5分组,然后需要进行填充。
进行填充的方式就是在二进制下第一个补1,后面的依次补0 。但是在这里咱们是以十六进制形式在010里演示的,而对于十六进制来说,一个十六进制字符对应4个二进制字符,所以对于010里面数据来说,10000000(2)==80(16),补充上去就是:

然后后面依次补0,知道填满448位为止,得到最终补位结果为:

然后还需要补位8个字节,原始明文为64个a和32个b,共96个字符,768位,转换为十六进制就是300。

情况二:


补位就不展示了,跟上面的情况一是同理的。
对于MD5算法来说,有一串初始向量如下:
1 | A=0x67452301 |
这串初始向量的值是固定的,作为与第一块数据运算的原始向量。
当这串向量与第一块数据块运算之后,得到了一串新的向量值,这串新的向量值接着与第二块数据块参加运算,直到最后一块数据块。

而最后的MD5值就是这最后的向量串经过如下转换的结果。
如向量串:
1 | A=0xab45bc01 |
再进行高低位互换,得到如下数据:
1 | 01 bc 45 ab |
最终拼接得到MD5值:01bc45ab53bb646afe8aba23627a8446
。
回首demo
然后回到先前那个例子:
对于MD5值:2df51a84abc64a28740d6d2ae8cd7b16
。我们可以根据MD5与向量互转规则,将MD5转成md5($secretKey + "test")
的最终向量值(A’、B’、C’、D’):
1 | A'=0x841af52d |

这时候我们修改$v1
变量的内容为:
1 | "test" + [0x80 + (0x0)*45] + [0x50 + 0x0*7] + "abc" |
则上述过程则被延续成下图所示:
而对于上述运算过程来说,我们知道了倒数第二个向量串的内容和最后一个数据块,这样一来,最终的MD5值我们也可以自己通过MD5算法计算出来了。
利用工具exploit
hash-ext-attack-master
hashpump
