◇ OpenCyber Academy
Bachelor's · Chapter 7 · English

Chapter 7 — Networks and protocols

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 7 — Networks and protocols

Lesson map

Lesson 07 published. Map, example, EX019.

flowchart TD
  N0["Learning outcomes"]
  N1["7.1 Modbus/TCP in one frame"]
  N2["7.2 No identity in the protocol"]
  N3["7.3 Reading the output"]
  N4["Synthesis"]
  N0 --> N1 --> N2 --> N3 --> N4
  N4 --> EX["Worked example"]
  EX --> Q["Exercise EX019"]

Logical drawing

flowchart LR
  N0["Learning outcomes"]
  N1["7.1 Modbus/TCP in one frame"]
  N2["7.2 No identity in the protocol"]
  N3["7.3 Reading the output"]
  N4["Synthesis"]
  N0 --> N1 --> N2 --> N3 --> N4 --> Q["EX019"]
[Learning outcomes]
    |
    v
[7.1 Modbus/TCP in one frame]
    |
    v
[7.2 No identity in the protocol]
    |
    v
[7.3 Reading the output]
    |
    v
[Synthesis]
    |
    v
[Worked example] --> [Exercise EX019]

Learning outcomes

You will (1) decode the Modbus/TCP MBAP header and function code from raw bytes; (2) distinguish read and write function codes; (3) explain why Modbus offers no authentication; and (4) state what a protocol decoder can and cannot tell an analyst.

7.1 Modbus/TCP in one frame

Modbus/TCP carries a seven-byte MBAP header — transaction identifier (2 bytes), protocol identifier (2, always zero), length (2) and unit identifier (1) — followed by the protocol data unit beginning with a one-byte function code. The Modbus Application Protocol Specification V1.1b3 defines the codes: 3 reads holding registers, 6 writes a single register, 16 writes multiple registers.

In the decoder lab, frame 2 carries function code 6 and frame 3 function code 16; both are writes, which is why the allow-list in Chapter 27 cares about the function code before the address.

7.2 No identity in the protocol

Nothing in the frame says who sent it. Any host that can open TCP port 502 to a controller can issue a write if the device accepts it. Security must therefore come from the network (segmentation, allow-listing) or from a secured variant such as Modbus/TCP Security, which wraps the protocol in TLS with certificate-based roles.

"""Lab 07: decode synthetic Modbus/TCP request headers (offline bytes only)."""
import struct
FC = {1: "read coils", 3: "read holding registers", 4: "read input registers",
      5: "write single coil", 6: "write single register", 16: "write multiple registers"}
frames = ["000100000006010300640002", "00020000000601060064012c", "000300000006011000c80001"]
for h in frames:
    b = bytes.fromhex(h)
    tid, pid, length, unit, fc = struct.unpack(">HHHBB", b[:8])
    addr, val = struct.unpack(">HH", b[8:12])
    kind = "WRITE" if fc in (5, 6, 15, 16) else "read"
    print(f"tid={tid} unit={unit} fc={fc} ({FC[fc]}) addr={addr} arg={val} -> {kind}")

Run with python3 lab_modbus.py. Verified output:

tid=1 unit=1 fc=3 (read holding registers) addr=100 arg=2 -> read
tid=2 unit=1 fc=6 (write single register) addr=100 arg=300 -> WRITE
tid=3 unit=1 fc=16 (write multiple registers) addr=200 arg=1 -> WRITE

For PLC-H, which cannot authenticate Modbus clients, this is the whole argument for Chapter 24's compensating controls: the firewall allow-list naming HMI-1 and HIST-1 as the only permitted sources is the identity check the protocol lacks. A host on the office VLAN that reaches port 502 is, to PLC-H, indistinguishable from HMI-1.

7.3 Reading the output

Frame 2 writes value 300 to register 100; frame 3 is a multiple-register write starting at 200. Notice the decoder prints the starting address and the first argument but does not know what register 100 means — that comes from the PLC's register map, which is plant documentation, not protocol.

In LDHP's register map, register 100 holds the supply temperature setpoint in tenths of a degree, so value 300 means 30.0 °C, far below the 90 °C operating point. That is the difference between "write single register" and "potential loss of heat". Maya's note adds a register-map column for exactly this reason, and marks frame 3's multiple-register write at 200 as unexplained until the map says what registers 200 onward control.

Synthetic case — Lakeside District Heating Plant. The frames in the lab were composed by hand; no device or network was contacted.

Errors and limits

Some devices use zero-based addressing and some documents use 40001-style numbering; mixing them causes off-by-one errors. Decoding traffic from a plant you are not authorised to monitor is not acceptable practice.

Exercises

Synthesis

A protocol decoder gives you structure; plant documentation gives you meaning; and segmentation, not the protocol, gives you identity.

Continue studying — chapter 07 of 40

← Chapter 06 (draft) · Course chapter index · Chapter 08 (draft) →