hash原理(以MD5为例)
原理浅析
MD5算法输入消息以512bit的分组为单位处理(sha1、sha256也是如此),共64字节。然后对每个分组进行一次“加密”,前一次的“加密”结果会作为这一次“加密”的输入,最后一次“加密”结果即为最终MD5值。不足64字节的分组需要进行补位,也就是字节填充。
补位原则:首先将需要hash的字符串进行分组,即字符串长度(以字节为单位)整除64,最后一组不足56字节的进行字节填充。填充的第一个字节为0x80,其他均为0x00。剩下的8个字节用来表示原字符串的长度。
举个例子
现在需要加密字符串:hash_length_extend_attack
,共25字节。
该字符串不足56字节,需进行补位。第一个字节为0x80,其余为0x00,填充至56位。
最后8个字节为原字符串的长度描述符(以bit为单位),25字节共200bit,120转十六进制为0xc8。由于MD5的存储为小端位序。例如0x12345678存为0x78563412。
hash长度扩展攻击原理
若md5($salt.string1)
已知,则在salt未知的条件下可以求出md5($salt.string1+padding+stirng2)
。
证明:因为md5($salt.string1)=md5($salt.string1+padding
,因此md5($salt.string1+padding+stirng2)
即为用md5($salt.string1)
对$string2+padding
进行一次“加密”。
工具:hashpump
安装:
1 | git clone https://github.com/bwall/HashPump |
用法:
1 | root@kali:~/HashPump# hashpump |
下面结合两个具体题目来实现攻击
题目一:salt长度已知
题目链接:http://www.shiyanbar.com/ctf/1848
username和password输入admin、admin。响应出现:
1 | If you have the correct credentials, log in below. If not, please LEAVE. |
查看源码,无任何提示。于是抓包分析。发现:
1 | Cookie: sample-hash=571580b26c65f306376d4f64e53cb5c7; source=0; Hm_lvt_34d6f7353ab0915a4c582e4516dffbc3=1553478983,1554089005,1554300942,1554380508; Hm_cv_34d6f7353ab0915a4c582e4516dffbc3=1*visitor*130458%2CnickName%3AKANGEL; Hm_lpvt_34d6f7353ab0915a4c582e4516dffbc3=1554380518; PHPSESSID=615uqh2qr9s16pr67f9bhs9ur6 |
cookie中有hash值,有source。将source=0
改为source=1
,发现源码:
1 | $flag = "XXXXXXXXXXXXXXXXXXXXXXX"; |
熟悉的味道,要注意的是$salt = %secret."admin"
,长度为20:
1 | $salt.string1 = $secret.urldecode("admin"."admin") |
现在利用hashpump计算md5($secret.urldecode("admin"."admin").padding."kangel")
,其中$password="admin".padding."kangel"
1 | Input Signature: 571580b26c65f306376d4f64e53cb5c7 |
于是构造cookie:
1 | getmein=04dd497abe8ae2d3c5a7775c2056850e |
构造post,需要将\x
替换为%
:
1 | username=admin |
flag:CTF{cOOkieS_4nd_hAshIng_G0_w3LL_t0g3ther}
题目二:salt长度未知
题目链接:http://web.jarvisoj.com:32778/
查看源码,无提示。
抓包分析,发现cookie中包含信息:
1 | Cookie: UM_distinctid=167a58b007e9-03c00e05130083-143d7240-100200-167a58b007f190; role=s%3A5%3A%22guest%22%3B; hsh=3a4727d57463f122833d9e732f94e4e0 |
既然无任何源码信息,用源码泄露工具扫一波,发现:
1 | http://web.jarvisoj.com:32778/index.php~ |
漏洞朔源:一般网站管理员在日常维护中,总会把网站源码给备份一下,防止网站出现问题时,能马上的恢复使用,不过一般的管理员安全意识不高,在备份的时候,会使用一些常见的压缩备份名以及文件名,而且不光使用常见的备份名字,大部分的管理还会把备份好的源码直接放在网站根目录里。因此很容易被攻击者利用。
该文件为index.php备份文件,先将文件名该文index.php.swp,再使用vim进行恢复
1 | vim -r index.php.swp |
得到源码:
1 |
|
熟悉的味道,首先要满足$role==="admin"
,对“admin”进行序列化得到;"nimda":5:s
,而字节填充和strrev()刚好利用unserialize()的%00截断漏洞:
漏洞分析:
1 | $salt = $salt //长度未知 |
现在用hashpump计算md5($salt.strrev($_COOKIE["role"]))
,salt长度对hash值计算无影响,假设为10
1 | Input Signature: 3a4727d57463f122833d9e732f94e4e0 |
得到cookie中的hsh:fcdc3840332555511c4e4323f6decb07
,对padding值进行反转,将\x
替换为%
,进行URL编码:
1 | role=s%3a5%3a"admin"%3b%00%00%00%00%00%00%00%b0%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%80s%3a5%3a"guest"%3b |
利用burp进行爆破,最多64次,这里取salt长度为10,11,12,13,14,15作为演示,选取%b0%00%00%00%00%00
1 | %b0%00%00%00%00%00 |