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
- EX043 — Applying the offset. A PLC log line reads 10:04:10. What is the corrected time?
Show marking criteria
Rubric: 3 = 10:05:25; 2 = correct direction, arithmetic slip; 1 = subtracts; 0 = none. - EX044 — Labelling timeline entries. Label O, I or A: (a) "CV-11 moved to 80 % at 10:02:45", (b) "the valve move was automatic control action", (c) "no other host wrote to PLC-H".
Show marking criteria
Rubric: 3 = O, I, A; 2 = two right; 1 = one; 0 = none. - EX045 — Custody fields. List five fields of a custody record for the exported PLC log.
Show marking criteria
Rubric: 3 = five relevant fields including hash; 2 = four; 1 = no hash; 0 = none.
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) →