在某新生赛看到的,来学习一下,参考文章:https://www.cnblogs.com/yunen/p/13624595.html

MD5算法原理

先具体看一下md5算法的原理是怎么样的然后来看一看具体的题目

这里放一张流程图:

1

整体的算法流程就是,将数据分块,每512位为一块,有一个初始序列,与第一个数据块进行运算,然后产生一个新的序列,继续与下一个数据块进行计算,以此类推。

一个512位的数据块就是64个字符的大小,对MD5来说最后一个数据块的处理分为两种情况:

  • 明文数据的二进制数据长度<=448,填充padding(无意义占位)数据使其长度为448,再添加原始明文数据的二进制长度信息(64位)使其长度为512位即可。
  • 448<明文数据的二进制数据长度<=512,填充padding数据至下一块的448位,而后再添加原始明文数据的二进制长度信息(64位)使其长度为512位即可。

这里借文章大佬的两张图:

这是第一种情况的

2

这是第二种情况的

3

上图可以知道,padding的数据的特点是首位为1,后面都是0

要注意一点长度信息位是从低位向高位的,比如上面的f0 03 00 00 00 00 00 00,即代表0x03f0,对应的十进制为1008,即为64+62=126个字符的二进制位数。

下面说一下向量串的转换

MD5有一个初始的固定向量串用来参与运算,其流程图如下:

4

然后得到的最后一个向量串再经过高低位呼唤就是我们最后的MD5的32个16进制字符,比如最后的向量串是这样的

A=0xab45bc01
B=0x6a64bb53
C=0x23ba8afe
D=0x46847a62

然后两两一组组合

ab 45 bc 01
6a 64 bb 53
23 ba 8a fe
46 84 7a 62

然后高低位互换

01 bc 45 ab
53 bb 64 6a
fe 8a ba 23
62 7a 84 46

最终拼接就得到最终的MD5值

01bc45ab53bb646afe8aba23627a8446

如同MD5算法那般分组后与向量运算的流程被统称为Merkle–Damgård结构。

而同样使用此结构的HASH算法还有:SHA1、SHA2等

哈希拓展攻击

那么知道上面的原理之后我们能干什么呢

这里来用一道题来分析一下通过这个算法流程我们能做什么事

<?php
$secret="1234567890abcde"; // This secret is 15 characters long for security!
$username="admin";
$flag="flag{test}";
$password = $_POST["password"];

if($_POST["getmein"] === md5($secret . urldecode($username . $password))){
echo "Congratulations! You are a registered user.\n<br>";
die ("The flag is ". $flag);
}else{
die("Your cookies don't match up! STOP HACKING THIS SITE.");
}
// md5(1234567890abcdeadmin)=b7271fdc3f7b4ee4f9fd6f6eb059c1f3
?>

一般哈希拓展的题目都会给我们一个已知的哈希和已知的密文长度,密文我们一般都是不知道,这里是本地所以就设置了一个方便测试,我们假装不知道。

这题就是我们知道了一个密文的哈希以及他的长度,这里1234567890abcdeadmina的哈希是b7271fdc3f7b4ee4f9fd6f6eb059c1f3,长度是20;现在我们需要传一个getmein参数和一个password参数,其中username变量和password参数会被拼接到$secret变量上面去然后进行md5,我们传的getmein就是一个哈希需要与拼接后的字符串的md5相等。

这里我们就可以利用哈希的算法流程,通过我们传递的password参数来做一些手脚了。

回想一下这个长度20的字符串是怎么进行加密的呢;这个字符串符合我们的第一种情况,长度小于等于448,那么就会padding数据到448位然后补上64位的数据长度信息,那么这些padding的信息和数据长度的信息我们都是知道,我们就可以通过传递的password参数手动padding然后出来的哈希值也是一样的。

那现在我们要传password参数,随便传一些东西他的哈希我们肯定是不知道的,但是上面说了我们可以padding数据到与他给的哈希相等,我们把这个数据块当成倒数第二个,这个哈希值我们是已知的,我们padding完之后再加一些我们指定的字符串,这些字符串就会放入下一个数据块,也就是最后一个。

现在要计算最后一个数据块的哈希的条件,数据长度上一个数据块的哈希,这两样东西都已经齐全了,那最终的哈希我们就可以预测了,这也就是所谓的哈希拓展,也就是通过已知的上一个数据块哈希,利用我们传递的参数去padding一些数据来预测下一个数据块的哈希。

这里提供两个工具

  1. hexpand:安装教程跟着这篇来:https://www.cnblogs.com/pcat/p/7668989.html。
  2. 类hexpump:https://github.com/shellfeel/hash-ext-attack?tab=readme-ov-file,因为原来的hexpump项目不见了,找到一个功能跟hexpump一样的。但是hexpump需要原始数据,现在一般不提供,原理上也不需要,所以用的会比较少

这里用hexpand工具

/hexpand -t md5 -s b7271fdc3f7b4ee4f9fd6f6eb059c1f3 -l 20 -m test # -s是我们的已知哈希;-l是密文长度;-m是我们要添加的数据,根据题目来,这里没有限制我们随意即可

5

fb66c4470d1c810edc1d77678a4299c0 //我们最终的哈希
800000000000000000000000000000000000000000000000000000000000000000000000a00000000000000074657374 //我们要添加的数据

因为这里我们是url传递还需要写个脚本加上百分号

value="800000000000000000000000000000000000000000000000000000000000000000000000a00000000000000074657374"
value2=""
for i in range(0,len(value),2):
value2+="%"+value[i]+value[i+1]
print(value2)

# 结果:%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%a0%00%00%00%00%00%00%00%74%65%73%74

然后post传递看看结果

6

可以看到我们成功拿到了flag