猫头鹰
信安舆情早知道

Hash Length Extension Attack

0x00 前言

前不久,phpwind在wooyun被爆出新漏洞——phpwindv9某前台某padding可getshell漏洞。不过wooyun还没公开,但是微信上这篇文章已经公开,并且有getshell poc。

其中在签名处,利用了md5长度扩展攻击进行绕过,导致前台获取secretkey。
这种攻击手法还是比较鸡肋,打ctf的人可能经常见过。实战中还是比较少。

刺在2012年写的Understanding MD5 Length Extension Attack这篇针对hash长度扩展攻击原理讲解的文章讲得很好,不过我在测试js代码的时候,发现最后md5加密的时候有点小问题。

本文将针对hash长度扩展攻击进行原理讲解(以md5为例)。

大概分以下几个目录:

  1. 理解md5算法
  2. 理解md5长度扩展攻击
  3. md5长度扩展攻击代码
  4. 攻击场景简单举例
  5. 漏洞修复
  6. 参考链接

0x01 理解md5算法

md5算法流程可以用下图来完美概括

1

md5算法特别简单,步骤分为两步:

  1. md5 padding
  2. md5 compress

什么是md5 padding?

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

比如admin进行md5 padding的结果为:

61646d696e800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

2800000000000000

即由以下几块组合

61646d696e :admin的hex

80:填充的\x80

50个00:为了保证信息的长度为N*64+56(字节)

2800000000000000:实际的值为0000000000000028,十进制的40,单位是bit,所以是5个字节(admin)

什么是Magic number

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

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值

配合上面的图,我相信第一次了解md5算法细节的同学仔细读应该都可以理解。

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

A=0x292f2321L

B=0xa7a5577aL

C=0xe4a8943L

D=0xc31f804aL

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

0x02 理解md5长度扩展攻击

根据上面的原理描述,当已知以下三点

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

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

以上就是对md5长度扩展攻击的描述。

因为在进行md5(salt+message+padding+m’)的时候,在对m’进行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]

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

举个实例:

已知salt的长度为4,message为admin,md5(salt+message)的值为c7813629f22b6a7d28a08041db3e80a9,想扩展的字符串m’为joychou,计算md5(salt+message+padding+m’)的值,padding表示对salt+message长度进行padding后的结果

c7813629f22b6a7d28a08041db3e80a9逆向出magic number为:

A=0x292f2321L

B=0xa7a5577aL

C=0xe4a8943L

D=0xc31f804aL

先对m’进行padding,padding结果用padding(m’)

800000000000000000000000000000000000000000000000000000000000000000000000000000000000000

000000000003802000000000000

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

再用这4个magic number对m’产生的Message block进行md5 compress,最后结果为:

06cf5a94dcda53659f58c0f411ba0bd8

为了证明和验证想法,我们正向去进行md5加密,看看padding的过程。此时需要知道salt,salt为meme

原始的urlencode后字符串为

memeadmin%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%00%00%00%00%00%00%00%00%00%00%00

H%00%00%00%00%00%00%00joychou

代码这样写:

str =

unquote(“memeadmin%80%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%0

0%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%0

0%00%00H%00%00%00%00%00%00%00joychou”)

m = md5py.md5()

print m.my_md5(str)

进行padding后

6d656d6561646d696e800000000000000000000000000000000000000000000000000000000000000000000

000000000000000000000000048000000000000006a6f7963686f75800000000000000000000000000000000

000000000000000000000000000000000000000000000000000000000000000003802000000000000

可以发现,其实只对joychou进行了padding。而且前64字节产生的magic number正是:

c7813629f22b6a7d28a08041db3e80a9算出来的

这就是md5长度扩展攻击的过程

0x03 md5长度扩展攻击代码

利用上面的逻辑,写了一个代码比较好懂的python版本

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

0x04 攻击场景简单举例

举一个ctf的实例,其实就是上面的实例翻译成了php代码

已知一组role为admin,salt长度为4,hash为c7813629f22b6a7d28a08041db3e80a9

<?php

 

$role = $_REQUEST[“role”];

$hash = $_REQUEST[“hash”];

$salt = “meme”;

 

if ($hash !== md5($salt.$role)){

echo ‘wrong!’;

exit;

}

 

if ( $role == ‘admin’){

echo ‘wrong, hash cann\’t be admin’;

exit;

}

 

echo “You are “.$role.'</br>’;

echo ‘Congradulation!’;

 

?>

利用写的脚本

python md5pad.py c7813629f22b6a7d28a08041db3e80a9 joychou 9

2

0x05 漏洞修复

很多哈希算法都存在Length Extension攻击,这是因为这些哈希算法都使用了Merkle–Damgård construction进行数据的压缩,流行算法比如MD5、SHA-1等都受影响。

个人理解中,最简单的修复方式,将md5($salt.$role)替换成md5($role.$salt)

如果理解有问题,欢迎指正。

0x06 参考链接

Understanding MD5 Length Extension Attack

phpwindv9某前台某padding可getshell漏洞

Hash长度扩展攻击及利用平台

 

*来源:JoyChou  Mottoin小编整理发布

转载请注明来自MottoIN,未经允许不得转载!MottoIN » Hash Length Extension Attack

分享到:更多 ()

评论 抢沙发

评论前必须登录!

 

MottoIN 换一个角度看安全

寻求报道联系我们