Hash长度扩展攻击

作者: const27 分类: All,杂七杂八的安全问题 发布时间: 2020-08-16 20:05

刚刚学习了CBC翻转字节和padding oracle attack,感觉蛮有意思,这个hash长度拓展感觉也有密码学的味道在里面,学习学习

一开始觉得很难,但是get到点后就豁然开朗了。

1 byte=8 bit

hash算法

Merkle–Damgård构造

易受hash长度扩展攻击的算法有 SHA系列与MD系列,因为他们都是基于Merkle–Damgård构造。具体它是怎么结构,从下文的MD5算法可以感受到

MD5算法

分组

MD5算法里,会先设置好一个一个的分组,每个组的大小是512bit或者说是64bytes。

每个组都包含2个部分:
1.数据区,占56bytes来记录需要被加密的字符串数据,当数据无法填满数据区时,会进行”补位”操作(请看下文解释)
2.长度描述符区,用于记录“非补位”数据的大小,占8个byte,其值为该组数据区种非补位数据的bit大小的16进制值。
比如非补位数据是admin,其占5个byte,40个bit,40的十六进制是28,所以其值会是28。
然后这个值会以一种叫做小端存储的方式记录到长度描述符区。
(非补位数据指该组的非填充的数据,即真正需要被加密的字符串)

补位

很简单,若某个组的数据长度小于56byte,该组的数据区不会被占满,那么就会自动补位来使数据区被填满。

其规则是在数据后先添加一个80字节,然后再用00字节填充完整个数据区。

分组与补位小结

再更进一步的了解MD5算法前,需要更加深刻地理解一下分组与补位,不然稍后的理解会非常困难。

假设我们有字符串admin需要被md5加密,那分组会是怎样的呢?
首先数据区会有admin。

其次我们需要把数据区填满

然后我们需要把长度描述符区添上,因为这里的非补位数据是admin,5byte长,40bit,40的十六进制是28.所以长度描述符添上后就是这样👇

至此,应该能懂分组和补位了吧

加密流程

这里放张自己画的加密流程的图

字符串先分组,然后第一组与初始链进行复杂数学运算得到链1.
注意,这里的初始链是固定的,每个MD5运算的初始链都是固定的,其值就是图中所记录的。也就是说,无论对什么数据进行MD5加密,其初始链都是

0x67452301
0xefcdab89
0x98badcfe
0x10325476

ok。第一组数据与初始链进行复杂运算得到链1,然后链1与第二组数据进行复杂运算得到链2,如此往复,直到倒数第二条链与最后一组数据进行复杂运算得到最后一条链(链final)

然后链final进行高低位转换就得到最终hash,那么什么是高低位转换?

如果final链是

  1. A=0x20f4847a
  2. B=0x42e6abf8
  3. C=0xf9097423
  4. D=0x51a8dad4

那么其hash便是 7a84f420f8abe642237409f9d4daa851

hash长度扩展攻击

基础知识掌握了,就开始了解这个重头戏了。

以一道题为切入点(改了一下实验吧的一道题)

Your cookies don't match up! STOP HACKING THIS SITE. <?php
include "flag.php";
//$secret="XXXXXXXXXXXXXXX"; This secret is 15 characters long for security!
$username="admin";
$password = $_POST["password"];
if($_POST["getmein"] === md5($secret . urldecode($username . $password))){
    if(is_numeric(strpos($password,"abc"))){
    echo "Congratulations! You are a registered user.\n";
    die ("The flag is ". $flag);
    }
}else{
    echo("Your cookies don't match up! STOP HACKING THIS SITE.");
}
highlight_file(__FILE__);
echo(md5($secret . urldecode($username . "admin")));
?> 93a5e7bea9c040065617b1a62ffc3d72

从中我们可以得知secret长度是15,md5($sercet.”adminadmin”)=93a5e7bea9c040065617b1a62ffc3d72
题目的意思很明显,我们需要传两个参数getmein和password使得
getmein=md5($secret.”admin”.password),且password包含abc字符

那么这就是hash长度扩展攻击经典的使用典例,即:
知道salt长度(这里secret变量的长度)
知道一组被加密字符串长度小于56的样本( md5($sercet.”adminadmin”) 的值)
即可知道某个值与salt一起被MD5加密后的hash

那这种攻击是如何实现的呢?
首先我们知道了一组样本,即等于我们知道了该样本的final链(高低位变换)。
同时我们知道了salt长度,即等于我们可以构造出该分组。
那么如果我们又构造出一个新的分组,同时其上一个组是已知样本,那么与新分组进行复杂运算的就是已知样本的final链。
已知样本的final链,新分组的待加密字符串,即可通过复杂运算,高低位变换获得最终hash。
故新分组待加密字符串的hash值是可以预测的。
这,就是hash长度扩展攻击的原理。
可能还是云里雾里的,那就看如何解题吧。

因为已知salt长度,那么可以预测一下样本的分组的情况
因为salt+adminadmin的长度是25,那么其bit就是200,转换为16进制就是c8.
那么假设salt字符全为x(仅仅是个假设而已,别想太多了),该分组的情况

那么我们可以传参
password=admin%80%00*30abc
其中abc以前的字符会在被MD5运算的时候分配到前一个组,然后通过运算获得链1,这个链1就是我们已知样本的final链了。
然后我们就可以预知,这个final链与abc进行复杂运算,高低位变换得到的hash了。然后再把这个hash赋值给openmein,这个题就做出来了。

好的,大致原理就是这样了。
这时候可以自行写脚本来找到某明文对应的MD5密文,或者使用工具:hashpump.

这里就说说hashpump吧,目前编程能力很弱,不能自行编写很好的脚本。
(安装方法就不细说了,网上都有)

依次输入我们已知的信息,就可以得到最终的hash值以及对应的加密字符串
传参过去

完事(注意要用%来表示不可显字符,比如\x00发包时就要写成%00)

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!

Leave a Reply

Your email address will not be published. Required fields are marked *

标签云