哈希扩展攻击继续分析
最近看到了好多针对de1ctf ssrfme题目分析,顺便把之前没搞明白的哈希长度扩展攻击写一下
链接这篇文章讲的很仔细了,分析一下文章中的栗子
师傅给的代码
md5的过程
- MD5 padding
如果输入信息的长度(字节)对64求余的结果不等于56,就需要填充使得对64求余的结果等于56。填充的方法是填充一个x80和xx个0。填充完后,信息的长度为N*64+56(字节),并且最后8个字节用来记录原始输入信息长度
- MD5 compress
这个算法直接到网上找就行
所以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’),由于padding之后只有64个字节,所以只进行一轮的md5 compress 得到的密文就是:
21232f297a57a5a743894a0e4a801fc3
我们可以从密文推导出4个magic number:
A=0x292f2321L
B=0xa7a5577aL
C=0xe4a8943L
D=0xc31f804aL
这个关系就是大小端转化一下
md5长度扩展的攻击过程
知道如下三个值:
- md5(salt+message)的值
- message内容
- salt+message长度
我们可以根据md5(salt+message)的值逆向出最后的四个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]
这个四个magic number去和m做一下次的md5 compress
再理解一下
继续又看了一篇师傅的文章,想要好好梳理一下哈希扩展攻击
师傅是以sha1算法为例讲解的: sha1的流程如下:

sha1算法和md5很相似,也有最初的四个IV,并且是确定的(这是一种很不好的方法但是也是一种无奈的举动)
一个不足64位的字符串会被padding至64位,并且由于只有一个分组,所以只需要一轮运算即可
我们在前一次64位padding之后的字符串的基础上加入一些字符,sha1(salt+padding+add_data) 首先这里肯定是要分成两组的,前一组加密后的内容已经知道了,同时产生的新的IV会参与下一次的复杂的数学运算
而这些IV是能够从第一组的密文中得知的,这就导致下一组加密后的内容实际上我们也可以知道的
《白帽子讲web安全》上提到,如何利用长度扩展攻击:
LengthExtension 使得可以在原文之后附加任意的值,并计算出新的hash值,最常见的地方就是签名
- 错误的签名校验算法
参数连接时没有使用分隔符,本来是?a=1&b=2&c=3在签名算法中简单地变成了a1b2c3
于是攻击者可以伪造参数?a=1b2c3[...padding....]&b=4&c=5
最终在签名算法中连接时变成了a1b2c3[...padding...]b4c5
-
附加任意的参数
-
HPP
最简单的防护就是将secret放置在参数的末尾
举例
大师傅给的栗子:
<?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!';
?>
已知role为admin,salt的长度为4,hash值为:c7813629f22b6a7d28a08041db3e80a9
我们可以在role后面附加任意的数据使得第一个if被绕过
用大师傅的脚本:
python md5pad.py c7813629f22b6a7d28a08041db3e80a9 joychou 9
当然也可以这样:
$ hashpump
Input Signature: c7813629f22b6a7d28a08041db3e80a9
Input Data: admin
Input Key Length: 9
Input Data to Add: joychou
06cf5a94dcda53659f58c0f411ba0bd8
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\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00p\x00\x00\x00\x00\x00\x00\x00joychou
注意第三次输入的数据长度是包括salt在内的