bsmali4 发布的文章

哈希长度扩展攻击学习总结

菜的扣脚,学习到这里,还是想做个总结和记录吧。这都是很多师傅和大佬玩剩下的,但是对于菜鸟的我来说,刚学习到这里的时候,还是感觉接触到了一片新天地。
看名字高大上,在查阅了一些资料之后,还没想象中的难到无法入手。
1.先从md5加密过程说起
MD5是一个安全的散列算法,输入两个不同的明文不会得到相同的输出值,根据输出值,不能得到原始的明文,即其过程不可逆;所以要解密MD5没有现成的算法,只能用穷举法,把可能出现的明文,用MD5算法散列之后,把得到的散列值和原始的数据形成一个一对一的映射表,通过比在表中比破解密码的MD5算法散列值,通过匹配从映射表中找出破解密码所对应的原始明文。
以上为官话,下面我们可以具体到一个字符串123,来讲讲它的具体加密过程

822419A1-AB54-4DD2-BAA6-C507EFD557C2.png

首先将123拆分成单个字符,1对应的ascii码是49,2是50,3是51(10进制),具体可以去查其ascii码表,将其转成16进制31,32,33
DCA668FB-C059-4CAC-9F0F-748B701980B8.png

补位操作
由于最后的长度要对512取模(求余)的值为448。换句话说,也就是448/8=56字节(B)。对于上面的字符123来说,它的长度是3位,也就是3字节,对应的也就是3x8=24b(比特)。我们对于不足56字节的先补到56字节,再后面补56-3=53位(ps:1B( 字节)对应的是8b(比特),这就是我们上面说要补到448位,因为448=56x8)。但是补的话不是乱补的,第一个位置我们要补二进制的10000000(7个0,刚好8位)。对应的16进制也就是80,然后后面依次补00,直到补满到56位
4E7A9DC6-B54E-4412-9687-62B835DE0897.png

DC4B4966-5186-4F6B-BAD6-25EC888D89F9.png

补完之后就是64位了。
计算消息摘要
在完成补位之后再来做的操作,计算消息摘要的时候,有一个默认的初始链变量,用来参与第一轮的计算,初始链变量为:
A=0x67452301 B=0xefcdab89 C=0x98badcfe D=0x10325476
如果想了解更多具体的计算细节,可以参考百度或者看看道哥的文章
http://blog.chinaunix.net/uid-27070210-id-3255947.html
但是我们去做长度扩展攻击的时候,不需要了解太多的细节(如果你学有余力,当然可以去学习,在这里不太需要)我们知道经过多轮的消息摘要之后,上面的4个初始链变量最终高低位互换之后,再组合变成我们的最终密文。
比如123对应的md5密文是202cb962ac59075b964b07152d234b70
那么最终那四个链变量就是:
A=0x62b92c20(202cb962高低位互换之后的结果,202cb962就是密文的前8位,下面依次类推)
B=0x5b0759ac
C=0x15074b96
D=0x704b232d
算法所带来的问题
这四个链变量,一直是存在算法的计算过程中的。每次上一次算法过后最终的链变量,变成一下一个算法链变量的初始值。看道哥的一张图,你就明白什么意思了。
要加密的明文是 0.12204316770657897
C74371A4-29D7-4ECF-9C25-9B897C7C0B44.png

最终的链变量就是上面的h1,h2,h3,h0了,只不过我们是16进制,他这里是转成10进制了。
那么加密0.12204316770657897...axis is smart!呢
1D620522-F64C-4A09-BACF-8F0A23F19FA8.png

可以看到在计算过程中是有0.12204316770657897对应的四个最终链变量的。那么问题就随之而来,既然我们用到了上一步的链变量,那么我们是不是可以这样假设。比方说我们知道了 $key最终的密文,也就是知道了$key最终的链变量,我们可以通过推算的方式知道$key + admin( 任意字符)的密文,这里我们不需要知道$key的明文是多少。我们只需要知道$key的最终密文,就可以推算出$key123xxx(任意字符),原因很简单嘛,因为计算的时候用到了$key的链变量嘛,但是我们还必须知道$key的长度,为什么?为了补位,补位的长度不能乱补。
这里再引用 freebuf一个网友的回答,简单易懂
E0A33990-5D9C-4FE9-9295-5A7A868AEA26.png

攻击方式
下面会给大家展示两个攻击方式,
在这里假设知道$key的密文为secretdata(这是secretdata的密文,假设我们不知道$key是secretdata,我们可以求出123....(前面补满64位)admin的密文)
E99DBB30-6862-4AC4-91C1-246F614A96F4.png

1.c语言版
#include <stdio.h>
#include <openssl/md5.h>
int main(int argc, const char *argv[])
{
int i;
unsigned char buffer[MD5_DIGEST_LENGTH];
MD5_CTX c;

MD5_Init(&c);
MD5_Update(&c, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 64);

c.A = htonl(0x6036708e); /* <-- This is the hash we already had */
c.B = htonl(0xba0d11f6);
c.C = htonl(0xef52ad44);
c.D = htonl(0xe8b74d5b);

MD5_Update(&c, "append", 6); /* This is the appended data. */
MD5_Final(buffer, &c);
for (i = 0; i < 16; i++) {
  printf("%02x", buffer[i]);
}
printf("\n");
return 0;

}
上面这段代码就是secretdata....(和前面一起补满64位 )append之后的密文了。注意前面必须补满到64位,具体怎么补,可以看最开始我拿123作为例子的操作,应为他是64一轮的计算哦。
第二种方式HashPump
首先去github上下载这个工具
https://github.com/bwall/HashPump
安装编译
$ git clone https://github.com/bwall/HashPump.git
$ apt-get install g++ libssl-dev
$ cd HashPump
$ make
$ make install
这里有一个ctf题目
这里有一个ctf题目

题目提示 md5($secret."adminadmin")的值为571580b26c65f306376d4f64e53cb5c7 但是我们并不知道$secret具体是多少,怎么做?我们可以这样考虑password我们必须要提交,提交多少无所谓,根据我们的知识,我们现在知道md5($secret.”adminadmin")=571580b26c65f306376d4f64e53cb5c7 最终提交password后组合后的形式是md5($secret.”admin”.$password),如果我们让$password=admin...(补齐64位)xxx(任意字符)。我们就可以推算出它的结果了。

CA465716-A8EA-47CB-A427-0A1D5D37BA94.png

root@a20180f6b450:/HashPump# ./hashpump
Input Signature: 571580b26c65f306376d4f64e53cb5c7(知道的密文)
Input Data: admin(将会作为password的一部分)
Input Key Length: 20(15位密文+admin刚好20位)
Input Data to Add: bsamli4
5db717fb0c59feba1add76e17112deed
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\xc8\x00\x00\x00\x00\x00\x00\x00bsamli4
提交的时候将x\替换成%,那么我们最终提交的是
answer=5db717fb0c59feba1add76e17112deed&password=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%c8%00%00%00%00%00%00%00bsamli4
这里要想一想,我们提交完之后,加密前变成 $key.’admin’.’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%c8%00%00%00%00%00%00%00bsamli4’。注意这里$key.’admin’.’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%c8%00%00%00%00%00%00%00’刚好是64位,为什么我们前面用的Input Key Length是20,这下大家应该明白了吧
实际利用场景
大家可以去参考p牛的文章,真的很nice,
https://www.leavesongs.com/PENETRATION/phpwind-hash-length-extension-attack.html
利用这个方法搞phpwind,屌吧,膜拜吧。
还有 freebuf的文章页不错了,模拟了一种利用场景,简直666

好像图片不是高清的,大家下载原件吧。写的不好,不要喷我,不然我会喷回去的。

http://www.freebuf.com/articles/web/31756.html

参考资料
http://www.freebuf.com/articles/web/31756.html
http://www.freebuf.com/articles/web/69264.html
https://www.leavesongs.com/PENETRATION/phpwind-hash-length-extension-attack.html
https://github.com/bwall/HashPump
http://blog.chinaunix.net/uid-27070210-id-3255947.html
https://blog.skullsecurity.org/2012/everything-you-need-to-know-about-hash-length-extension-attacks
http://www.2cto.com/Article/201405/298779.html