hash(哈希)长度扩展攻击
b站的书写体验不得不让人称道啊
到目前为止我还没有遇到过这种攻击(可能是攻击过于古老),但是我觉得还是值得拿出来研究一下的。
问题来源:诸如md5或者sha1的一些hash加密的加密原理层的缺陷导致了漏洞,具体为:当md5加密参数存在用户可控变量时 (md5(secret+args); args可控)时 , 用户可以用过控制args变量来来控制最后的加密结果md5(....)而不需要知道secret值。
多说无益,来点题目(这里以php为例:)

分析一下代码,在开始之前我根据时间戳定义了一个长度为15的随机secret,然后从文件中读取静态的secret。接下来判断是否存在user字段cookie,如果没有初始化user为admin,hash为secret和admin的md5值。最后主要逻辑段判断是否存在cookie,如果存在进入验证,如果user字段的值等于admin,则终止,不等于的话继续判断secret和cookie中的user的md5值是否强等于cookie中hash的字段值。
可以很明显的从题目中分析出几点:
md5(secret+cookie.user)要等于hash
secret未知
已知条件:md5(secret+"admin") 但是user不能传admin && len(secret) = 15
这里可以引入hash长度扩展攻击,但我们要先理解消息摘要算法的实现。这里拿 md5 算法举例。
md5加密过程分为补位,补长度和计算消息摘要,下面分条阐述,并以加密abc为实例
1.补位:把原始消息化为bit字节单位的数据,然后后面补上10000....(n个0)使得最后len(message) % 512 == 448 ,这里的len测的是message的bit位数, 然后补100
关于单位:8bit (比特)= 1 bytes(字节),深入一点讲,这里的message的length等于把abc转换为bytes类型然后转换为整数来测试他的二进制最高位,懂得都懂我也不赘述

'abc'的bit长度为23,然后补到448

2.补长度
把刚刚得到的数据补到64 字节,根据进制转换,64bytes = 512bits 刚刚是448bits,也就是说还少了64bits也就是8bytes,bytes数和字符数等价,但是这里注意的是补位过后,第 57 个字节储存的是补位之前的消息长度,abc
是 3 个字母,也就是 3 个bytes字节,24 bit,换算成 16 进制为 0x18,也就是57位需要我们补上0x18然后再补7个随意字符。
后面查阅了下文档,发现也可以用64位表示出初始字符串的长度,这样就不用再补7个字符了,就直接就完成了补完8个bytes(字节)。
注意:因为前面所有的全都是补数据,所以可以以8为组整拆分数据分别化为bytes数据

到这里为止数据已经构造完成了,至于为什么这么构造,原因是为满足后面处理中对信息长度的要求,要求信息长度为512的整数倍
3.计算消息摘要
对消息进行分组以及padding后,MD5算法开始依次对每组消息(填充好的消息按照64字节分组)进行压缩,经过64轮数学变换。这个过程中,一开始会有定义好的初始化向量,为4个中间值,初始化向量不是随机生成的,是标准里定义死的,是的,你没看错,这是“硬编码”!

引用了道哥文章里的话,太精辟了就直接拿过来了,总结来说就是md5的计算是固定数据的轮计算。
最后一轮产生的链变量经过高低位互换(如:aabbccdd -> ddccbbaa)后就是我们计算出来的 md5 值。
Hash长度扩展攻击
Length Extension 的理论基础,就是将已知的压缩后的结果,直接拿过来作为新的压缩输入。在这个过程中,只需要上一次压缩后的结果,而不需要知道原来的消息内容是什么。 ---道哥永远滴神!
攻击目的:在未知secret并且知道一段由包含secret加密的结果的情况下通过控制可控变量得到md5(secret+可控)的值
攻击原理:带上我个人的一点理解来说,先再赘述下md5加密原理,在我们padding全部结束之后进行消息摘要,经过64轮计算之后,把加密结果(4段)分别逆序然后拼接起来作为密文输出。在我们得到这段密文之后,如果下次加密还是用的上次加密相同的密文并且密文后接了可控数据,我们就可以利用可控量进行手动填充原始数据使其达到正常加密前两步padding后的结果(给出密文的那次加密),又因为是分组加密,所以每组的加密结果互不干涉(这也就是ECB的诟病),所以我们可以手动添加(控制)最后一组明文,并根据上一次加密的结果逆向再和库中固定的加密轮密钥来演算出我们新添加的一组明文的加密结果,进而推出最后的新密文,演算细节不详细展开,不然快变成密码学而不是web了。
回到题目,我们现在有了md(secret+"admin")的值,要求md5(secret+cookie.user) === hash , 已知密文的一段md5 + 新的验证里由可控字段user,完全满足hash扩展攻击的条件。
攻击流程:
查看cookie取出初次加密的md5值

这里使用hashpump构造user并计算hash,把\x替换成浏览器可识别数据类型%

md5: 9d9096a97e358bbeddd3533c8d0f9c29
user:admin%80%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%a0%00%00%00%00%00%00%00feng
不急着打,先分析下user数据,就如上文我所说的一样,先按照得到已知密文的初始明文构造数据并填充到满足可以进行消息摘要的明文,然后再随意构造一段明文,最后的根据已知密文并填充数据计算最后的新md5结果是hashpump帮我们完成的。
然后将数据替换掉

刷新下页面

攻击成功
如何修复?
加密可控消息
md5(secret + md5($_COOKIE['user']))
大型攻击案例
phpwind 利用哈希长度扩展攻击进行getshell
https://www.leavesongs.com/PENETRATION/phpwind-hash-length-extension-attack.html
参考链接
http://blog.chinaunix.net/uid-27070210-id-3255947.html
https://blog.skullsecurity.org/2012/everything-you-need-to-know-about-hash-length-extension-attacks
hashpump下载
https://github.com/bwall/HashPump
write by@feng2020
3630 0648 2483 2480 2092 4502 0x62 4541