OpenCyber Academy
Engineering · Chapter 23 · English
Course code: OCA-138Chapter 23: OCA-138-C023

Chapter 23 — Critical infrastructure and sector security: threat and failure analysis

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

Lesson map

Lesson 23 published. Map, example, EX045.

flowchart TD
  N0["Learning outcomes and connection"]
  N1["23.1 Threat modelling"]
  N2["23.2 Fault trees"]
  N3["23.3 Attack trees and bow-ties"]
  N4["23.4 Combining failures and attacks"]
  N5["23.6 Practical activity: Lab 9"]
  N6["Chapter synthesis"]
  N0 --> N1 --> N2 --> N3 --> N4 --> N5 --> N6
  N6 --> EX["Worked example"]
  EX --> Q["Exercise EX045"]

Logical drawing

flowchart LR
  N0["Learning outcomes and connection"]
  N1["23.1 Threat modelling"]
  N2["23.2 Fault trees"]
  N3["23.3 Attack trees and bow-ties"]
  N4["23.4 Combining failures and attacks"]
  N5["23.6 Practical activity: Lab 9"]
  N6["Chapter synthesis"]
  N0 --> N1 --> N2 --> N3 --> N4 --> N5 --> N6 --> Q["EX045"]
[Learning outcomes and connection]
    |
    v
[23.1 Threat modelling]
    |
    v
[23.2 Fault trees]
    |
    v
[23.3 Attack trees and bow-ties]
    |
    v
[23.4 Combining failures and attacks]
    |
    v
[23.6 Practical activity: Lab 9]
    |
    v
[Chapter synthesis]
    |
    v
[Worked example] --> [Exercise EX045]

Learning outcomes and connection

After this chapter you can (1) perform threat modelling on data-flow diagrams with STRIDE and ATT&CK for ICS; (2) build fault trees and compute minimal cut sets and top-event probabilities; (3) combine failure and attack analysis — attack trees, bow-ties and consequence-driven scenarios; and (4) state the assumptions and limits of each method. It uses Chapters 7 and 22 and prepares Chapters 24, 27 and 33.

23.1 Threat modelling

Threat modelling asks, systematically, what can go wrong at each element and trust boundary of a system model. STRIDE — spoofing, tampering, repudiation, information disclosure, denial of service, elevation of privilege — is a mnemonic for threat categories applied to each data flow, process and store. MITRE ATT&CK for ICS catalogues adversary tactics and techniques observed against industrial systems, from initial access to impact (for example, manipulation of control or loss of view). Use STRIDE to generate candidate threats element by element and ATT&CK to check realism and completeness against observed behaviour.

23.2 Fault trees

A fault tree decomposes an undesired top event into combinations of basic events using AND and OR gates. A minimal cut set is a smallest set of basic events whose joint occurrence causes the top event; the list of minimal cut sets is the system's failure logic in its simplest form. Single-event cut sets are single points of failure. With independent basic-event probabilities, the top-event probability is computed exactly by enumeration for small trees, or approximately by summing cut-set probabilities (the rare-event approximation, an upper bound when probabilities are small).

23.3 Attack trees and bow-ties

An attack tree applies the same AND/OR structure to an adversary's goal; leaves are attacker actions with attributes such as cost, skill or detectability rather than probabilities. Assigning probabilities to deliberate attacks is questionable — adversaries adapt — so attack trees are often used to find the cheapest or least detectable path, then to place controls on it. A bow-tie joins causes (left), the central event, and consequences (right), showing preventive barriers before the event and mitigating barriers after it; it communicates well with operators and managers.

23.4 Combining failures and attacks

Infrastructure events mix accidental and deliberate causes: an attacker may wait for a storm, or a fault may mask an intrusion. Consequence-driven methods such as INL's CCE start from the unacceptable consequence and ask what combinations of failures and adversary actions reach it. A practical approach: build the fault tree for the consequence; mark which basic events an adversary could cause deliberately; recompute with those events set to "occurred" to see what remains as protection. Whatever remains is your real defence against a capable adversary.

23.5 Worked example: loss of hospital supply (synthetic)

Top event: St Brenna's loses supply for more than 4 h in a year. Following Chapter 22's model: path A (PS4) is lost if PS4 fails, or if feeder F2 and the PS4 generator both fail; path B is lost if the reservoir is unavailable, PS3 fails or feeder F1 fails; and the event requires both paths lost and the hospital tank failing to bridge (TANK). Lab 9 enumerates the tree with synthetic annual probabilities. There are six minimal cut sets, all of order three or four, because TANK appears in every one. The largest contributor is {G1, PS4, TANK}. The exact probability is 9.10 × 10⁻⁵ per year; the rare-event approximation gives 9.36 × 10⁻⁵.

Now the adversarial view: if an attacker can remotely stop PS3 and PS4 (no R1), both become "occurred" and the top event reduces to TANK alone — probability 0.03. Remote command authentication moves the system from a two-out-of-three-independent-failures problem to a single-point-of-failure problem. That comparison is the clearest argument for R1 in the whole dossier.

23.6 Practical activity: Lab 9

# Lab 9 - fault tree: minimal cut sets and top-event probability (synthetic annual probabilities, offline)
from itertools import product
P = {"G1": 0.10, "G2": 0.08, "GEN": 0.05, "PS4": 0.02, "PS3": 0.02, "RES": 0.01, "TANK": 0.03}
# Top: hospital loses supply > 4 h = (feed A lost AND feed B lost)
# feed A (PS4 direct) lost = PS4 OR (G2 AND GEN);  feed B (reservoir) lost = RES OR PS3 OR G1
# hospital on-site tank TANK failing (empty/contaminated) is needed too: top = A AND B AND TANK
def top(s): A = s["PS4"] or (s["G2"] and s["GEN"]); B = s["RES"] or s["PS3"] or s["G1"]; return A and B and s["TANK"]
names = list(P); exact = 0.0; cuts = []
for bits in product([0, 1], repeat=len(names)):
    s = dict(zip(names, bits)); pr = 1.0
    for n in names: pr *= P[n] if s[n] else 1 - P[n]
    if top(s):
        exact += pr
        on = frozenset(n for n in names if s[n])
        cuts.append(on)
mcs = sorted({c for c in cuts if not any(o < c for o in cuts)}, key=lambda c: (len(c), sorted(c)))
for c in mcs:
    pr = 1.0
    for n in c: pr *= P[n]
    print(sorted(c), f"{pr:.2e}")
rare = sum(eval("*".join(str(P[n]) for n in c)) for c in mcs)
print(f"rare-event approx {rare:.3e}  exact {exact:.3e}")

Expected output:

['G1', 'PS4', 'TANK'] 6.00e-05
['PS3', 'PS4', 'TANK'] 1.20e-05
['PS4', 'RES', 'TANK'] 6.00e-06
['G1', 'G2', 'GEN', 'TANK'] 1.20e-05
['G2', 'GEN', 'PS3', 'TANK'] 2.40e-06
['G2', 'GEN', 'RES', 'TANK'] 1.20e-06
rare-event approx 9.360e-05  exact 9.101e-05

The six cut sets each contain TANK, so the hospital's on-site storage appears in every route to the top event. The largest single contributor combines feeder F1, PS4 and the tank. The two probability figures differ slightly because the rare-event approximation counts overlapping cut sets twice, so it gives a small upper bound on the exact value. The adversarial reading in the worked example comes from setting PS3 and PS4 to certain failure and rerunning, which EX045 asks you to do yourself.

23.7 Common errors and limits

Lab 9 itself assumes independence, so a shared software flaw in both stations' RTUs would make its figures optimistic. Its probabilities for PS3 and PS4 failing are frequencies of random faults, so they say nothing about how likely an attacker is to stop both stations, which is why the adversarial case is handled by conditioning rather than by adding an attack probability.

Exercises — chapter 23

EX045 — Adversary-conditioned tree. Objective: quantify what authentication buys. Inputs: Lab 9. Steps: (1) set PS3 and PS4 to probability 1 (attacker can stop them remotely) and compute the top-event probability; (2) instead, set G1 and G2 to 1 (attacker can cut both feeders) and recompute; (3) interpret both. Expected evidence: numbers and 150-word interpretation. Rubric: 3 = correct numbers (0.03; and with G1=G2=1, top = P(TANK)·P(PS4 or GEN) — compute), interpretation links to controls (R1; generator independence and tank); 2 = one number wrong; 1 = not run; 0 = none.

EX046 — STRIDE on a flow. Objective: threat-model one data flow. Inputs: the gateway-to-SCADA flow (Lab 8 frames over the LTE conduit). Steps: apply each STRIDE category, name an ATT&CK for ICS technique where one fits, and state the existing or proposed control. Expected evidence: six-row table. Rubric: 3 = all six categories meaningful and controls matched (e.g., spoofing → MAC; DoS → local automatic fallback); 2 = one category vacuous; 1 = list only; 0 = none.

Chapter synthesis

Threat models generate what could go wrong at each trust boundary; ATT&CK keeps them realistic. Fault trees and minimal cut sets show failure logic and single points of failure; attack trees and bow-ties show adversary paths and barriers. Combine them by conditioning on what an adversary can cause: what remains is the defence that actually matters.

Worked answers

EX045. PS3 = PS4 = 1: top = P(TANK) = 0.03. G1 = G2 = 1: path B lost; path A lost if PS4 or GEN fails: 1 − 0.98 × 0.95 = 0.069; top = 0.03 × 0.069 = 0.00207. Interpretation: remote command authentication removes the cheapest adversary path (top falls from 0.03 to 9.1 × 10⁻⁵); if an adversary can cut both feeders, the generator and the hospital tank become the decisive barriers — maintain and test them.

EX046. Spoofing — forged frames (ATT&CK for ICS: Spoof Reporting Message) → per-station MAC. Tampering — modified values in transit → MAC. Repudiation — disputes about commands → signed or MACed logs with anchors. Information disclosure — telemetry read on the carrier network → carrier encryption plus optional payload encryption. Denial of service — jamming or flooding (Denial of Service; Block Reporting Message) → local automatic fallback, stale-station alarm, rate limits. Elevation of privilege — compromise of gateway to issue commands → gateway hardening, function-code filtering, local bounds.