SP LMS PHP Object Injection → Unauthenticated RCE (CVE-2026-48909)
by Amin İsayev / Proxima Cyber Security (Is4yev) · 2026-07-05
- Severity
- Critical
- CVE
- CVE-2026-48909 (GHSA-gf8c-xmwj-whrh)
- Category
- web
- Affected product
- JoomShaper SP LMS (com_splms) Joomla Learning Management System extension
- Affected versions
- 1.0.0 - 4.1.3 (fixed in 4.1.4); RCE additionally requires Joomla core < 5.2.2
- Disclosed
- 2026-07-05
- Patch status
- patched
Tags
References
Archive entry
intelseclab/poc-archiveMetadata
| Field | Value |
|---|---|
| Date Added | 2026-07-05 |
| Last Updated | 2026-07 |
| Author / Researcher | Amin İsayev / Proxima Cyber Security (Is4yev) |
| CVE / Advisory | CVE-2026-48909 (GHSA-gf8c-xmwj-whrh) |
| Category | web |
| Severity | Critical |
| CVSS Score | 9.5 (CVSS 4.0: AV:N/AC:L/AT:P/PR:N/UI:N) |
| Status | PoC |
| Tags | joomla, sp-lms, com_splms, php-object-injection, cwe-502, deserialization, unauthenticated-rce, gadget-chain |
| Related | N/A |
Affected Target
| Field | Value |
|---|---|
| Software / System | JoomShaper SP LMS (com_splms) Joomla Learning Management System extension |
| Versions Affected | 1.0.0 - 4.1.3 (fixed in 4.1.4); RCE additionally requires Joomla core < 5.2.2 |
| Language / Platform | PHP / Joomla CMS, PoC written in Python 3.10+ |
| Authentication Required | No |
| Network Access Required | Yes |
Summary
SP LMS’s cart model (components/com_splms/models/cart.php) reads the lmsOrders cookie, base64-decodes it, and passes the result directly to PHP’s unserialize() with no validation, giving an unauthenticated attacker full control over the deserialized object graph. On Joomla versions before 5.2.2, this chains into Joomla’s FormattedtextLogger gadget: the object’s __destruct() writes attacker-controlled bytes to an attacker-chosen file path via File::write(), allowing a PHP webshell to be dropped on disk. The repo ships a detection-only script (CVE-2026-48909.py) that fingerprints the vulnerable unserialize() behavior via response-status/timing differentials, and a full exploit script (CVE-2026-48909_exploit.py) that builds a filter-safe serialized payload and writes a webshell to a specified server path.
Vulnerability Details
Root Cause
components/com_splms/models/cart.php (line ~28):
| |
Joomla’s built-in FormattedtextLogger class provides a usable gadget on Joomla < 5.2.2: its __destruct() calls initFile() → File::write($path, $format), allowing arbitrary file writes with attacker-controlled content (a PHP webshell). Joomla 5.2.2 patched FormattedtextLogger::__wakeup() to close the gadget chain, but the underlying PHP Object Injection in com_splms remains regardless of Joomla core version.
Attack Vector
- Attacker crafts a base64-encoded, PHP-serialized
Joomla\CMS\Log\Logger\FormattedtextLoggerobject whosepathproperty points at a web-accessible, PHP-writable file and whoseformatproperty contains hex-encoded PHP webshell code (to survive Joomla’scmdcookie input filter, which strips+,/, and=). - Attacker sets this payload as the
lmsOrderscookie and sends a request toindex.php?option=com_splms&view=cart. unserialize()instantiates the gadget object; at the end of the request, PHP’s garbage collector invokes__destruct(), triggeringFile::write()and dropping the webshell at the chosen path.- Attacker requests the written file directly (e.g.
/tmp/x.php?c=id) to execute arbitrary OS commands.
Impact
Unauthenticated remote code execution on any Joomla site running a vulnerable SP LMS version and a pre-5.2.2 Joomla core, leading to full server compromise (webshell access, arbitrary command execution).
Environment / Lab Setup
Target: Joomla CMS < 5.2.2 with JoomShaper SP LMS (com_splms) <= 4.1.3 installed, cart endpoint reachable
Attacker: Python 3.10+ with `requests`, network access to the target's index.php?option=com_splms&view=cart endpoint
Proof of Concept
PoC Script
See
CVE-2026-48909.py(detection only, no code execution) andCVE-2026-48909_exploit.py(full RCE exploit) in this folder.poc.pngis a screenshot from the original author showing an active shell.
| |
The detection script sends a benign cookie and a serialized-stdClass probe cookie to the cart endpoint and compares status codes/response bodies/timing to infer whether unserialize() is being called. The exploit script builds a filter-safe base64 payload encoding a FormattedtextLogger gadget object, requests the cart page to trigger the deferred file write on __destruct(), then requests the written path with ?c=id to confirm shell access.
Detection & Indicators of Compromise
grep 'option=com_splms&view=cart' /var/log/apache2/access.log | grep -i 'Cookie.*lmsOrders='
find /var/www/html -newer /var/www/html/configuration.php -name '*.php' -path '*tmp*'
Signs of compromise:
- Requests to
index.php?option=com_splms&view=cartcarrying an unusually long, non-standard-lookinglmsOrderscookie value - New, unexpected
.phpfiles appearing in writable directories (tmp, cache, uploads) shortly after such a request - Outbound requests to those newly-created
.phpfiles with a?c=(or similar) command parameter
Remediation
| Action | Detail |
|---|---|
| Primary fix | Update SP LMS to >= 4.1.4 (removes the raw unserialize() call); also update Joomla core to >= 5.2.2 to eliminate the known FormattedtextLogger gadget chain |
| Interim mitigation | Do not deserialize user-controlled cookie data; if immediate patching isn’t possible, block/strip the lmsOrders cookie at the WAF/reverse-proxy layer |
References
Notes
Mirrored from https://github.com/Is4yev/CVE-2026-48909 on 2026-07-05.
| |