首页 » NetworkSec » AWD » 正文

MD5长度扩展攻击总结

0x00: MD5算法原理:

填充+压缩

先进行消息长度的填充(padding)。填充完后,初始化的4个Magic number会和第一个64字节的Message block进行md5 compress压缩算法。压缩算法完成后,会产生新的4个Magic number。这样再进行第二个64字节Message block的md5 compress压缩算法。以此类推……直到压缩到最后64个字节的(Message block + padding),最后得到的Magic number经过hex转化就是最后的md5 hash值

**************************

术语解释:

填充:
如果输入信息的长度(字节)对64求余的结果不等于56,就需要填充使得对64求余的结果等于56。填充的方法是填充一个\x80和n个0。填充完后,信息的长度为N*64+56(字节),并且最后8个字节用来记录原始输入信息长度

Magic number:

代码中的0x67452301L, 0xefcdab89L, 0x98badcfeL, 0x10325476L这4个初始化的number(固定的)就被称为Magic number或者是md5 iv(md5 向量)

*****************************

0x01: md5长度扩展攻击:

影响的算法:使用了Merkle–Damgård construction进行数据的压缩的算法,流行算法比如MD5、SHA-1等。

当已知以下二点

  1. md5(salt+message)的值
  2. salt+message长度

我们可以在不知道salt的具体内容的情况下,计算出任意的md5(salt+message+padding+append)值,

(注:padding是 salt+message/secret 最后的填充字节, append是任意扩展字符(串)。)

因为在进行md5(salt+message+padding+append)的时候,在对append进行padding之前的Message block,和md5(salt+message)产成的Message block一样

所以,我们就能在不知道salt的情况下,只需根据md5(salt+message)的结果,逆向出最后一次的4个Magic number。

逆向算法很简单:

def compute_magic_number(self, md5str):

self.A = struct.unpack(“I”, md5str[0:8].decode(‘hex’))[0]

self.B = struct.unpack(“I”, md5str[8:16].decode(‘hex’))[0]

self.C = struct.unpack(“I”, md5str[16:24].decode(‘hex’))[0]

self.D = struct.unpack(“I”, md5str[24:32].decode(‘hex’))[0]

##############################################

//此例来源于:http://www.joychou.org/index.php/web/hash-length-extension-attack.html?utm_source=tuicool&utm_medium=referral

拿admin举例,md5经过padding后,由于只有64字节,所以只进行一轮md5 compress。压缩算法完成后,产生的新的Magic number为

A=0x292f2321LB=0xa7a5577aLC=0xe4a8943LD=0xc31f804aL

md5的加密结果是21232f297a57a5a743894a0e4a801fc3,我们将A大小端逆序一下,变成21232F29,刚好是md5的前8位。以此类推

##############################################

根据这4个Magci number,再和扩展的字符串append(此时的append要进行填充,填充的长度是len(salt+message+padding+append))进行md5 compress,最后的结果即md5(salt+message+padding+append),append表示要扩展的字符串,padding表示对salt+message长度进行padding后的结果。

就是说:

关键bug(感觉不算bug,只是这类hash算法的特性而已)就在于知道md5(salt+message)的值后可以很容易逆向出最后一次的4个Magic number。

知道了这4个magic number和salt+message的长度后,我们就可以构造padding(salt+message),这样md5(salt+message+padding(salt+message))后得出就是这4个magic number(刚好是64字节),之后md5算法再padding(append),就可以在不知道salt的情况下得到md5(salt+message+padding(salt+message)+append)。

##########################################

//此例来源于www.joychou.org/index.php/web/hash-length-extension-attack.html?utm_source=tuicool&utm_medium=referral

举个实例:
已知salt的长度为4,message为admin,md5(salt+message)的值为c7813629f22b6a7d28a08041db3e80a9,想扩展的字符串append为joychou,计算md5(salt+message+padding+append)的值,padding表示对salt+message长度进行填充后的结果

c7813629f22b6a7d28a08041db3e80a9逆向出magic number为:

A=0x292f2321L

B=0xa7a5577aL

C=0xe4a8943L

D=0xc31f804aL

先对append进行padding,padding结果用padding(append)

800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003802000000000000

长度57个字节,注意最后8个字节0x238为len(salt+message+padding+append),即568bit,71字节

再用这4个magic number对append产生的Message block进行md5 compress,最后结果为06cf5a94dcda53659f58c0f411ba0bd8

###########################################################

0x02: CTF实例cn有签名限制的读取任意文件writeup

大概代码逻辑:
if url有filepath参数且不空并且有sign参数且不空,则myreadfile($_GET[‘filepath’],$mysalt,$_GET[‘sign’]);传递文件路径,salt和签名。在myreadfile函数,执行$res=checksign($filepath,$mysalt,$sign);函数到checksign($message,$mysalt,$sign)函数里校验签名,true就getfile(),false就echo ‘sign error!’;

else 打印出mysalt的长度(int(32)),并打印出md5($mysalt.$message);的值(f3d366138601b5afefbd4fc15731692e),这里的message即文件路径。

所以要getflag就要能执行getfile(),要执行getfile()就要签名校验通过,要签名校验通过就要$sign==md5($mysalt,$message)。$message是文件路径由我们输入,$sign签名也由我们输入,所以如果知道$mysalt即SALT的值,就可以getfile()了,不过这里就是不知道SALT的值,那如何绕过呢,自然联想到md5 长度扩展攻击了……

思路:

尝试读取已知的/etc/hosts

lab1.xseclab.com/decrypt1_53a52adb49c55c8daa5c8ee0ff59befe/md5_le.php?filepath=/etc/hosts&sign=f3d366138601b5afefbd4fc15731692e

## # Host Database # # localhost is used to configure the loopback interface # when the system is booting. Do not change this entry. ## 127.0.0.1 localhost 255.255.255.255 broadcasthost ::1 localhost

尝试读取/etc/passwd

1.已知mysalt长度32,那么mysalt+/etc/hosts=4+10=14

2.已知md5(mysalt+/etc/hosts)=f3d366138601b5afefbd4fc15731692e

满足md5长度扩展攻击的二个条件。

直接用工具吧。(相关工具见文末)

Payload:lab1.xseclab.com/decrypt1_53a52adb49c55c8daa5c8ee0ff59befe/md5_le.php?filepath=%2fetc%2fhosts%80%00%00%00%00%00%00%00%00%00%00%00%00X%01%00%00%00%00%00%00%2Fetc%2Fpasswd&sign=8dcc79bf6581da3e30313a5a686261dd

显示sign error

尝试读取/etc/shadow

还是sign error

真神奇……不是说读取任意系统文件可以getflag吗?签名也是工具生成,不会错。

尝试读取/etc/hosts

Payload:lab1.xseclab.com/decrypt1_53a52adb49c55c8daa5c8ee0ff59befe/md5_le.php?filepath=%2fetc%2fhosts%80%00%00%00%00%00%00%00%00%00%00%00%00%00P%01%00%00%00%00%00%00%2Fetc%2Fhosts&sign=75221e2e5cd1cd1c7694cbd386571ffe

显示Flag is: Md5LenghtExtAttackNowYouSee

这都可以,不是说除已经告知的/etc/hosts文件外,若能读取到任意系统文件即可获取Flag吗?又神奇了……

还有看源码filepath是文件路径,最后getfile(),但是%2fetc%2fhosts%80%00%00%00%00%00%00%00%00%00%00%00%00%00P%01%00%00%00%00%00%00%2Fetc%2Fhosts这一长串是怎么识别为/etc/hosts的,又神奇了…….

 

0x03: 防御hash length extender attack

(1)使用HMAC-SHA1之类的HMAC算法

(2)针对Flickr API等将参数签名的应用来说,secret放置在 参数末尾也能防止这种攻击。如将md5($salt.$role)替换成md5($role.$salt)

 

0x04: 相关工具

https://github.com/JoyChou93/md5-extension-attack

https://github.com/iagox86/hash_extender

https://github.com/bwall/HashPump

 

0x05: 参考链接

blog.chinaunix.net/uid-27070210-id-3255947.html

www.joychou.org/index.php/web/hash-length-extension-attack.html?utm_source=tuicool&utm_medium=referral

blog.csdn.net/u011500307/article/details/24095891

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Comment