@shaobaobaoer
2018-03-06T04:02:34.000000Z
字数 6161
阅读 1783
CTF
1月份的时候(当自己完全是个小白的时候),做到了哈希长度扩展攻击的题目,那时候一点也不会,也没人教自己,看解析也看不懂。
今天花了点时间,终于搞明白了。
参考网站
https://blog.skullsecurity.org/2012/everything-you-need-to-know-about-hash-length-extension-attacks
想做一个脚本小子的话,直接翻到最后吧
但是该会的还是要会的吧
说什么理论,我不是很喜欢,单刀直入说个例题,这是实验吧的题目,也是我当初死活没搞懂的题目
<?php$flag = "flag{flag is here}";$secret = "aaaaabbbbbccccc"; // 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}}?>
md5哈希扩展攻击,都有一个普遍的规律,我们需要知道字符串的长度
username和password不能都没admin,有个cookie叫getmein其需要等于md5(secret+username+password)的值。
- 1.首先$secret变量我们不知道,但是我们知道它的长度
- 2.从下面setcookie函数我们可以通过sample-hash这个变量拿到md5($secret+”admin”+”admin”)的md5值
- 3.我们登陆成功的条件,username==admin&&password!=admin 并且我们要cookie getmein的值等于md5($secret+username+password)
MD5最神奇的地方,就是无论多长的东西,都给你整成一定长度的东西。
MD5算法最重要的就是补位,md5的加密算法的具体算法,非常的复杂。但是过程的话,在此简略写一下
补位
转换成16进制后,对消息进行补位操作,当字符串不满 448 bit时候,将它们补 0 加到 448 bit,然后加上80表示填充开始。注意是位而不是字符串长度,若是说字符串长度的话 应该是 56 的长度 (按照ascii)
补位的时候也是小端绪的。就是本来应该是0000...长度(16)。啥是小端绪的话,看看下面的就行。
补上初始长度
在57字节之后是存储的字符串长度。紧跟在57位后面,并计算成16位。不包含填充字符串的长度,注意是比特数而不是字符串的长度。(十进制下,长度*8)后面继续用0b00补齐成64位。
计算摘要
利用初始变量进行计算,最后输出结果,MD5初始链变量(magic number):
其中的计算过程太过于繁杂了。总之经过一次消息摘要后,上面的链变量将会被新的值覆盖,而最后一轮产生的链变量经过高低位互换(如:aabbccdd -> ddccbbaa 这个很关键)后就是我们计算出来的 md5 值。
MD5不管怎么加密,每一块加密得到的密文作为下一次加密的初始向量IV,这一点也很关键
找了半天,找到了一张图,我一看就明白了很多

举个栗子
let secret = "secret"let data = "data"let H = md5()let signature = hash(secret || data) = 6036708eba0d11f6ef52ad44e8b74d5blet append = "append"
那么在md5计算后就是这样子的

具体参数如下所示
"secret" = secret"data" = data80 00 00 ... — The 46 bytes of padding, starting with 0x8050 00 00 00 00 00 00 00 — The bit length in little endian
具体 $SECRET 的情况下,得知了其 hash 值,以及我们有一个可控的消息。而我们得到的 hash 值正是最后一轮摘要后的经过高地位互换的链变量。我们可以想像一下,在常规的摘要之后把我们的控制的信息进行下一轮摘要,只需要知道上一轮消息产生的链变量。
那么这个应该如何实现呢?
···
为了方便理解,我们把之前的那个题目重新写一下
<?php$SECRET="123456";$auth = "I_L0vE_L0li";if (isset($_COOKIE["auth"])) {$hsh = $_COOKIE["hsh"];if ($hsh !== md5($SECRET . $_COOKIE["auth"])) {die("F4ck_U!");}} else {setcookie("auth", $auth);setcookie("hsh", md5($SECRET . $auth));die("F4ck_U!");}die("I_aM_A_L0li_dA_Yo~");?>
通过获取cookie中 hsh的值,我们就能得到 hsh =
自己动手写个函数,或者用手算一下,可以得到下一轮的链变量就是:
然后进行补位。因为 $SECRET 的长度是 6,我们用 6 个 a 来填补一下,紧跟着就是 auth 的值。然后我们把消息补到 448 bit。接着进行补长度。
得到如下参数:
secret_admin = "aaaaaaI_L0vE_L0li" + '\x80' + '\x00' * 38 + '\x88' + '\x00' * 7 + "whaleCTF"
然后,md5的加密中,这个东西会被填补成 512*2 bit 的东西,当然,我们需要计算的只是后面的东西,也就是"whaleCTF"+填充的东西。
转换成16进制,也就是:
之后就看以开展我们的哈希长度扩展攻击了,将这个16进制数作为第二轮中的输入,并将s1,s2,s3,s4作为初始的链变量。我们就能够得到 一个新的hsh为 57105e676f1e378fe5d6435d3a285c8a
之后就是就题目论事了。那我们这道题目而言,我们需要的是
$hsh !== md5($SECRET . $_COOKIE["auth"])
所以说
57105e676f1e378fe5d6435d3a285c8a== md5(xxxxxx+"I_L0vE_L0li" + '\x80' + '\x00' * 38 + '\x88' + '\x00' * 7 + "whaleCTF")
(注意url编码)
是成立的,所以只要在cookie中输入
得到flag

那么对于实验吧的这道题目的?其实也是一样的。源码在上面
我们获取了sample_hash为
那么,下一轮变量的IV就是
payload就是如下
secret_admin = "aaaaabbbbbcccccadminadmin" + '\x80' + '\x00' * 30 + '\xc8' + '\x00' * 7 + "admin"
对于这道题目而言,只要将username=admin,password="admin" + '\x80' + '\x00' * 30 + '\xc8' + '\x00' * 7 + "admin" URL编码 post提交
··· PS:实验吧这道题好像被宕了,不知道咋回事

url: http://daka.whaledu.com/web/web44/
源码
<?phpecho "已知一组role为root,salt长度为6,hash为a0566a65f9d6bfd9abf2c116ef1ca2af,想要扩展的字符串是whaleCTF"."<br>";$flag = "**********";$role = $_REQUEST["role"];$hash = $_REQUEST["hash"];$salt = "***********"; //The length is 6if ($hash !== md5($salt.$role)){echo 'wrong!';exit;}if ( $role == 'root'){echo 'no no no !, hash cann\'t be root';exit;}//echo "You are ".$role.'</br>';echo 'Congradulation! The flag is'.$flag;?>
攻击过程。md5pad.py 哈希值 扩展的字符串 原始盐加上信息的长度(10)
md5-extension-attack/md5pad.py" a0566a65f9d6bfd9abf2c116ef1ca2af whaleCTF 10
Payload: '\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\x00whaleCTF'
Payload urlencode: %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%00whaleCTF
md5: aab9a3180e92bd4126d56011b672711f
然后post提交数据即可
本文中的部分知识也是来自该作者的博客,全英文的,耐下心子看很好理解。
https://github.com/iagox86/hash_extender
利用方法也相当得方便
root@ninthdevil:~/桌面/Cknife/hash_extender# ./hash_extender -d I_L0vE_L0li -a whaleCTF -l 6 -f md5 -s d607a0da7fd77724621092333d8fdee8 --out-data-format htmlType: md5Secret length: 6New signature: 57105e676f1e378fe5d6435d3a285c8aNew string: I%5fL0vE%5fL0li%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%88%00%00%00%00%00%00%00whaleCTF
个人感觉比上面那个好用,因为上面那个输入的参数有些多,实际上输入盐加原来字符的长度是不是就够了呢?
https://github.com/JoyChou93/md5-extension-attack
python md5pad.py [hash] [padding] [len(salt+message)]
> md5-extension-attack/md5pad.py" a0566a65f9d6bfd9abf2c116ef1ca2af whaleCTF 10> Payload: '\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\x00whaleCTF'> Payload urlencode: %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%00whaleCTF> md5: aab9a3180e92bd4126d56011b672711f