◇ OpenCyber Academy
Technologist · Chapter 12 · English

Chapter 12 — OT, IoT and cyber-physical security: data flows

Open, free learning for anyone who wants to protect people and technology. No account is required to read this text or its worked answers.

Chapter 12 — OT, IoT and cyber-physical security: data flows

Lesson map

Lesson 12 published. Map, example, EX034.

flowchart TD
  N0["Learning outcomes"]
  N1["12.1 The flow matrix"]
  N2["12.2 Unapproved flows"]
  N3["12.3 Approved but unused"]
  N4["12.4 From comparison to change"]
  N5["Synthesis"]
  N0 --> N1 --> N2 --> N3 --> N4 --> N5
  N5 --> EX["Worked example"]
  EX --> Q["Exercise EX034"]

Logical drawing

flowchart LR
  N0["Learning outcomes"]
  N1["12.1 The flow matrix"]
  N2["12.2 Unapproved flows"]
  N3["12.3 Approved but unused"]
  N4["12.4 From comparison to change"]
  N5["Synthesis"]
  N0 --> N1 --> N2 --> N3 --> N4 --> N5 --> Q["EX034"]
[Learning outcomes]
    |
    v
[12.1 The flow matrix]
    |
    v
[12.2 Unapproved flows]
    |
    v
[12.3 Approved but unused]
    |
    v
[12.4 From comparison to change]
    |
    v
[Synthesis]
    |
    v
[Worked example] --> [Exercise EX034]

Learning outcomes

You will (1) write an approved flow matrix; (2) compare observed flows with it; (3) interpret unapproved and unused approved flows; and (4) turn the comparison into firewall changes.

12.1 The flow matrix

A flow matrix lists every permitted conversation: source, destination, port and purpose. It is the conduit table of Chapter 8 made precise enough to test. NCS has four approved flows: HMI-C to each PLC on Modbus/TCP 502, the historian polling PLC-R1, and GW-LOG to the vendor cloud on 443.

"""Lab 12: compare observed synthetic flows with the approved flow matrix."""
approved = {("HMI-C", "PLC-R1", 502), ("HMI-C", "PLC-R2", 502), ("GW-LOG", "CLOUD-LOG", 443), ("HIST", "PLC-R1", 502)}
observed = [("HMI-C", "PLC-R1", 502), ("GW-LOG", "CLOUD-LOG", 443), ("OFFICE-7", "PLC-R2", 502),
            ("HIST", "PLC-R1", 502), ("GW-LOG", "PLC-R1", 502)]
for f in observed:
    print(f"{f[0]:8} -> {f[1]:9} :{f[2]:<4} {'approved' if f in approved else 'UNAPPROVED'}")
print("approved but not seen:", sorted(approved - set(observed)))

Run with python3 lab_flows.py. Verified output:

HMI-C    -> PLC-R1    :502  approved
GW-LOG   -> CLOUD-LOG :443  approved
OFFICE-7 -> PLC-R2    :502  UNAPPROVED
HIST     -> PLC-R1    :502  approved
GW-LOG   -> PLC-R1    :502  UNAPPROVED
approved but not seen: [('HMI-C', 'PLC-R2', 502)]

The lab compares those four approved flows with five observed conversations.

The two unapproved rows, OFFICE-7 talking to PLC-R2 and GW-LOG reaching PLC-R1, are the ones to investigate first, while the unseen HMI-C to PLC-R2 flow may simply not have occurred during the capture. Chapter 27 later shows that the list was missing the historian's polling of PLC-R2, an approved flow nobody had written down.

12.2 Unapproved flows

OFFICE-7 talking Modbus to PLC-R2 is exactly what rule 9 allowed. It might be an engineer's spreadsheet macro, or malware. Either way it is a path from the office to a compressor controller. GW-LOG talking to PLC-R1 is stranger: the logger gateway has no reason to speak Modbus. It could be a vendor "integration" feature or a sign of compromise.

Priya traced both. OFFICE-7 ran an energy report macro reading compressor run hours from PLC-R2; the logger vendor confirmed an unused "PLC integration" feature on GW-LOG, enabled by default, which was disabled.

12.3 Approved but unused

HMI-C → PLC-R2 did not appear. Perhaps the window was short; perhaps the HMI reads PLC-R2 through PLC-R1. Unused approvals are candidates for removal after checking with operations — fewer open paths, less to defend.

Chapter 27 shows the risk of reading this too quickly. The observation window also missed the historian polling PLC-R2, so the flow matrix listed HIST → PLC-R1 only. When the new rule set went live, HIST stopped receiving PLC-R2 tags within four minutes and Priya rolled back. An approved-but-unseen flow is a question for operations and the vendors, not proof the flow is unused.

12.4 From comparison to change

Each unapproved flow gets an owner and a decision: approve with justification (and update the matrix), or block. Blocking happens in a planned window with operations informed, because a "mystery" flow may turn out to be something the plant needs.

Priya's two decisions: OFFICE-7's energy macro was moved to read run hours from the historian replica in the DMZ, and office → control was blocked in the 20 March maintenance window after the switch; GW-LOG's "PLC integration" feature was disabled with the logger vendor's agreement, and the flow disappeared without a firewall change.

Worked example (synthetic NCS)

Priya asks the office: OFFICE-7 runs an energy report macro that reads compressor run hours directly from PLC-R2. She proposes reading the same values from the historian replica in the DMZ instead, then blocking office → control. For GW-LOG → PLC-R1 she contacts the logger vendor, who confirms an unused "PLC integration" feature enabled by default; it is disabled and the flow disappears.

Synthetic case — Northgate Cold Storage. Flows and explanations are invented.

Errors and limits

Observation windows miss monthly or seasonal flows such as defrost schedules or end-of-month reports. Ports do not prove protocol; a flow on 502 may not be Modbus.

Exercises

Synthesis

Comparing observed flows with an approved matrix finds the paths nobody intended, and each one ends in an owned decision.

Continue studying — chapter 12 of 30

← Chapter 11 (draft) · Course chapter index · Chapter 13 (draft) →