OpenCyber Academy
Bachelor's · Chapter 15 · English
Course code: OCA-114Chapter 15: OCA-114-C015

Chapter 15 — Evidence and measurement

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 15 published. Map, example, EX043.

flowchart TD
  N0["Learning outcomes"]
  N1["15.1 Clocks disagree"]
  N2["15.2 What the corrected timeline shows"]
  N3["15.3 Chain of custody"]
  N4["15.4 Observation, inference, assumption"]
  N5["Synthesis"]
  N0 --> N1 --> N2 --> N3 --> N4 --> N5
  N5 --> EX["Worked example"]
  EX --> Q["Exercise EX043"]

Logical drawing

flowchart LR
  N0["Learning outcomes"]
  N1["15.1 Clocks disagree"]
  N2["15.2 What the corrected timeline shows"]
  N3["15.3 Chain of custody"]
  N4["15.4 Observation, inference, assumption"]
  N5["Synthesis"]
  N0 --> N1 --> N2 --> N3 --> N4 --> N5 --> Q["EX043"]
[Learning outcomes]
    |
    v
[15.1 Clocks disagree]
    |
    v
[15.2 What the corrected timeline shows]
    |
    v
[15.3 Chain of custody]
    |
    v
[15.4 Observation, inference, assumption]
    |
    v
[Synthesis]
    |
    v
[Worked example] --> [Exercise EX043]

Learning outcomes

You will (1) correct for clock offset when combining logs; (2) preserve the chain of custody for exported evidence; (3) distinguish observation, inference and assumption in a timeline; and (4) state measurement uncertainty.

15.1 Clocks disagree

Controllers, HMIs and historians often keep independent clocks, and a PLC without network time can drift by minutes per month. Before sequencing events, measure the offset — for instance, by comparing a known event (an operator's setpoint change) in both logs — and record how it was measured.

"""Lab 15: align two synthetic logs with a measured clock offset."""
from datetime import datetime, timedelta
hmi = [("2026-03-02T10:00:07", "operator changed SP TT-101 to 95"), ("2026-03-02T10:02:40", "alarm TT-101 HI")]
plc = [("2026-03-02T09:58:52", "SP write accepted"), ("2026-03-02T10:01:30", "valve CV-11 to 80%")]
offset = timedelta(seconds=75)  # measured: PLC clock is 75 s behind the reference
ev = [(datetime.fromisoformat(t), "HMI", m) for t, m in hmi] + [(datetime.fromisoformat(t) + offset, "PLC", m) for t, m in plc]
for t, src, m in sorted(ev):
    print(t.time(), src, m)

Run with python3 lab_clock.py. Verified output:

10:00:07 HMI operator changed SP TT-101 to 95
10:00:07 PLC SP write accepted
10:02:40 HMI alarm TT-101 HI
10:02:45 PLC valve CV-11 to 80%

At LDHP the known event was an operator's setpoint change on HMI-1 at 10:00:07, which also appears in PLC-H's log as "SP write accepted". Matching the two gave an offset of 75 seconds, with an uncertainty of about two seconds from the logs' resolution.

15.2 What the corrected timeline shows

After adding the measured 75-second offset, the PLC's "SP write accepted" lines up with the HMI entry at 10:00:07, which supports the hypothesis that the write came from HMI-1. Without correction the PLC event appears 75 seconds before the operator acted — a sequence that might be misread as an external write followed by an operator reaction.

The correction changes the story, not just the numbers. A manager reading the uncorrected logs could conclude that someone outside the control room wrote the setpoint and the operator then reacted, which would trigger a security incident. The corrected timeline shows an ordinary operator change, provided the offset assumption holds.

15.3 Chain of custody

For each exported file record who exported it, from which system, when, by what method, and its SHA-256 hash. Store the original read-only and work on copies. This is how a timeline becomes evidence a manager, insurer or court can rely on.

For Maya's timeline, the record would read: HMI-1 event log, exported by the shift engineer at 11:20 with the read-only account, SHA-256 recorded; PLC-H diagnostic log, exported from EWS-1 by the control engineer, SHA-256 recorded; both originals stored read-only on the investigation share, and Maya's corrected timeline built only from copies. If an insurer later asks whether the PLC log was edited, the hash answers it.

15.4 Observation, inference, assumption

Label each timeline entry. "PLC log line at 09:58:52 local PLC time" is an observation. "The write originated from HMI-1" is an inference. "The PLC clock offset was constant all morning" is an assumption. Mixing them is the most common flaw in incident reports.

Maya's table adds a label column for exactly this. Her offset row is marked A, because "75 s ± 2 s, measured by matching the 10:00:07 setpoint change" relies on the offset staying constant from 09:30 to 10:30. If someone later finds a PLC clock adjustment at 10:15, only the rows that depend on that assumption need revisiting.

Worked example (synthetic LDHP)

Maya's table has three columns — corrected time, source, statement — plus a fourth for the label (O/I/A). The offset row reads: "Offset 75 s ± 2 s, measured by matching the 10:00:07 HMI setpoint change to the PLC acceptance message (A: offset constant during 09:30–10:30)."

Synthetic case — Lakeside District Heating Plant. Log lines and the offset are invented.

Errors and limits

One matched event gives one offset measurement; drift during the period may make it wrong later. Time zones and daylight-saving shifts are a separate error source.

Exercises

Synthesis

Evidence in OT is only as good as its clocks, its custody record and its honesty about what was seen versus concluded.

Continue studying — chapter 15 of 40

← Chapter 14 (draft) · Course chapter index · Chapter 16 (draft) →

Worked answers

EX043. 10:04:10 + 75 s = 10:05:25 reference time.

EX044. (a) O — it is a logged observation (after correction); (b) I — inferred from the controller's logic and timing; (c) A — an assumption unless the network capture covering the period was reviewed.

EX045. Exporter's name, source system and export method, date and time of export, SHA-256 hash of the file, storage location of the read-only original (plus any later transfers with signatures).