- 因为hash生成机制,我们可以人为在明文中加入冗余数据,使得加密链多出一节(可控),使得当我们知道倒数第二节的数据时可以控制最终的md5值
- 如同MD5算法那般分组后与向量运算的流程被统称为Merkle–Damgård结构。
而同样使用此结构的HASH算法还有:SHA1、SHA2等
以md5算法为例子(其他的暂时不会)
MD5长度拓展攻击
引入
参考文章:浅谈HASH长度拓展攻击 - Yunen的博客 - 博客园
用一个简单例子引入
<?php
include "flag.php";
$secretKey = 'xxxxxx'; #xxx为未知内容,但长度已知为6。
$v1 = $_GET['str'];
$sign = $_GET['sign'];
$token = md5($secretKey.$v1);
if($v1 === 'test') {
die($token); #token=2df51a84abc64a28740d6d2ae8cd7b16
} else {
if($token === $sign) {
die($flag);
}
}
?>
分析:
$token变量的值 = $secretKey+$v1(可控)的md5值
当$v1的值为test时,token为2df51a84abc64a28740d6d2ae8cd7b16
当$token = $sign(可控)时给出$flag
在这一例子中,我们知道当$v1为test时,md5($secretKey.$v1)的值,那么我们就可以利用md5长度拓展攻击构造出已知最终md5值的($secretKey.$v1)
要搞懂md5长度拓展攻击,首先要知道md5摘抄算法的原理
md5摘抄算法原理
借一张图:
来源:https://xz.aliyun.com/t/2563?time__1311=n4%2Bxni0%3DG%3Di%3D0QLW405DKfSxmOv8sDBie%2FmoD
接下来细嗦一下md5算法的过程:
1、将原文数据(字符串)依照ASCII码表转换成二进制
2、将二进制数据分块,每一块512位(每个字节8bit,即包括64位字符数据)
-
当(最后一块)二进制数据长度< 448 ,填充padding(无意义占位)数据使得长度达到448,再填充入长度信息(二进制64位)至512位
-
当 448 <(最后一块)二进制数据<=512 ,填充padding数据到下一块的448位,再填充长度信息至512位
padding:即 10000000···(首位为1,其他为0)
3、使用初始md5初始向量与第一块二进制原文数据运算,得到新的向量
- 初始向量:
A=0x67452301
B=0xefcdab89
C=0x98badcfe
D=0x10325476
4、使用新的向量与第二块原文数据运算,得到新的向量,以此类推,直到算完最后一块原文数据得到最终向量,如下列向量
A=0xab45bc01
B=0x6a64bb53
C=0x23ba8afe
D=0x46847a62
5、去掉0x,将每一行的数据高低位互换
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
6、拼接起来得到最终的md5值:01bc45ab53bb646afe8aba23627a8446
ok,现在我们了解了md5算法的原理,再讲讲md5长度拓展
md5长度拓展
在之前的例子中,我们知道了当$v1为test,最终向量为
A'=0x841af52d
B'=0x284ac6ab
C'=0x2a6d0d74
D'=0x167bcde8
如图
我们可以将$v1的值改为
"test" + padding数据 + 长度数据 + "abc"
此时我们只要知道倒数第二个向量与最后一个二进制原文的计算方法我们就可以知道最终的md5值
当然我们不必需要会向量与二进制原文的计算,可以直接使用工具hashpump
得出payload
test\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\x00\x00\x00\x00\x00P\x00\x00\x00\x00\x00\x00\x00abc
因为编码原因需要把\x改为%,得到最后的payload
test%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%00P%00%00%00%00%00%00%00abc
工具hashdump
项目地址:https://github.com/miekrr/HashPump
例题:
实验吧ctf-web-让我进去(Hash长度扩展攻击)
进入题目是一个经典登录页面,于是经典抓包
直接提交不行,看到cookie中有个source=0,改为1
找到源码
点击查看代码
$flag = "XXXXXXXXXXXXXXXXXXXXXXX";
$secret = "XXXXXXXXXXXXXXX"; // This secret is 15 characters long for security!
$username = $_POST["username"];
$password = $_POST["password"];
if (!empty($_COOKIE["getmein"])) {
if (urldecode($username) === "admin" && urldecode($password) != "admin") {
if ($COOKIE["getmein"] === md5($secret . urldecode($username . $password))) {
echo "Congratulations! You are a registered user.\n";
die ("The flag is ". $flag);
}
else {
die ("Your cookies don't match up! STOP HACKING THIS SITE.");
}
}
else {
die ("You are not an admin! LEAVE.");
}
}
setcookie("sample-hash", md5($secret . urldecode("admin" . "admin")), time() + (60 * 60 * 24 * 7));
if (empty($_COOKIE["source"])) {
setcookie("source", 0, time() + (60 * 60 * 24 * 7));
}
else {
if ($_COOKIE["source"] != 0) {
echo ""; // This source code is outputted here
}
}
分析:
要使得cookie中的值getmein == md5($secret+'admin'+$password)
当$password为admin时
sample-hash=md5($secret+'admin'+$password)=571580b26c65f306376d4f64e53cb5c7
使用md5长度扩展构造payload
password=admin%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%c8%00%00%00%00%00%00%00abc
getmein=7db18a2831cdab27425f299ca09f034e
提交得到flag