Skip to article
Back to BlogVARDAR FIELD NOTE

Understanding Modbus Security: Why the Protocol Cannot Defend Itself

Modbus has no authentication, no integrity checking, and no session state. Here is what that means on the wire, and how to detect abuse of it.

Every list of OT protocol vulnerabilities opens with the same observation: Modbus has no authentication. This is true, and it is also the least interesting thing about it. Modbus was published by Modicon in 1979 to move register values between a controller and a handful of devices over a serial line that a person could physically see. There were no adversaries in the threat model because there was no network. Judged against its own requirements, the protocol is a success. It is small, deterministic, trivially implementable on a microcontroller with a few kilobytes of ROM, and it still works in plants built four decades apart.

The problem is not that Modbus is broken. The problem is that it was lifted onto TCP/IP in the late 1990s essentially unchanged, and the assumptions that made it safe on an RS-485 bus did not travel with it. What CISOs need is not another reminder that the protocol lacks security features. It is a precise understanding of which properties are missing, what an attacker can do with each one, and what evidence those actions leave behind.

What Is Actually on the Wire

A Modbus TCP request is small enough to describe completely. It opens with a seven byte MBAP header: a transaction identifier that the client uses to match responses, a protocol identifier that is always zero, a length field, and a unit identifier. Then comes one byte of function code and the payload. That is the entire protocol.

The function codes are where the power sits, and they divide cleanly. Function code 3 reads holding registers. Function code 4 reads input registers. Codes 1 and 2 read coils and discrete inputs. These run continuously in every plant, thousands of times an hour, and they change nothing.

Then there are the codes that write. Function code 5 forces a single coil. Code 6 writes a single register. Codes 15 and 16 write multiple coils and multiple registers in one shot. Code 8 is diagnostics, and its subfunctions include restarting communications and forcing a device into listen only mode, where it processes requests and answers none of them. Code 43 reports device identification, which is how an attacker learns the vendor, product code, and firmware revision of everything answering on the segment.

Four structural properties follow from this design, and each maps to a distinct attacker capability.

There is no identity. Nothing in the frame says who sent it. A server that receives a well formed write from any source on the segment executes it, because from the protocol's point of view there is no other option. Authorization is not weak, it is absent.

There is no integrity beyond transport. Serial Modbus carries a CRC. Modbus TCP dropped it and relies on the TCP checksum, which detects corruption and not tampering. Anything positioned in the path can rewrite a setpoint in flight and the receiver has no way to notice.

There is no confidentiality. Register values, function codes, and device identification move in cleartext. A passive listener learns the full register map of a process simply by watching the poll loop run.

There is no session. Modbus TCP has no login, no state, and no notion of a conversation that began. Each request stands alone, which means replay is not an attack technique so much as a normal operation performed twice.

The most dangerous function codes are not exotic. A single well formed function code 6 request, eleven bytes on the wire, is sufficient to change a process setpoint on most Modbus servers. No exploit, no vulnerability, no CVE. The protocol working exactly as specified.

What Abuse Looks Like in Practice

The gap between "no authentication" and an actual incident is filled by reconnaissance, and reconnaissance is the noisiest phase.

An attacker landing on an OT segment does not know the register map. Register layouts are engineering decisions specific to each site: which holding register holds a pump speed setpoint, which coil enables a valve, where the safety interlocks live. Finding out means asking, and asking means reading addresses that do not exist.

Modbus answers those questions with exception responses. Exception code 0x02, illegal data address, is returned when the requested register is outside the server's map. Code 0x01, illegal function, comes back when the device does not implement that function code. In normal operation a mature plant produces almost none of these, because the polling configuration was validated at commissioning and has not changed since. A host generating a run of 0x02 exceptions across a widening address range is enumerating, and there is no benign explanation for it.

The same pattern applies to the unit identifier. On a Modbus TCP gateway fronting a serial subnet, the unit ID selects which downstream device receives the request. A client sweeping unit IDs 1 through 247 is mapping the serial side of that gateway, and gateways are attractive precisely because they sit at a boundary where segmentation usually stops.

Reconnaissance is followed by capability that is worth taking seriously. The INCONTROLLER toolset disclosed by CISA in 2022, also tracked as PIPEDREAM, included components able to scan for and interact with Schneider Electric controllers over Modbus, alongside modules targeting Omron devices and OPC UA servers. That is the shape of the modern threat: not a Modbus exploit, but tooling that speaks the protocol fluently and uses its legitimate functions to accomplish an objective on the process.

Why the Secure Version Did Not Solve This

The Modbus Organization published a security specification in 2018 that wraps Modbus TCP in TLS on port 802, using X.509 certificates for mutual authentication and carrying a role identifier in the client certificate for authorization. It is a competent design that addresses identity, integrity, and confidentiality in one move.

Adoption in the field is close to negligible, and the reason is not vendor negligence. TLS requires a certificate lifecycle: issuance, distribution, rotation, revocation, and a trusted time source on every endpoint. The installed base consists of controllers with no real time clock, no capacity for certificate storage, twenty year service lives, and change windows measured in hours per year. A device commissioned in 2011 will still be running in 2031, and it will still be speaking Modbus in cleartext on port 502.

Any security program that depends on the protocol being replaced is planning against a timeline that will not arrive. The realistic position is that unauthenticated Modbus is a permanent condition of the environment, and controls have to be built around that fact rather than in anticipation of its removal.

Building Controls Around a Protocol That Cannot Help You

IEC 62443 handles this honestly. The standard's system requirements for identification, authentication, and communication integrity in 62443-3-3 cannot be met by Modbus itself, so the framework moves the burden to zones and conduits: the protocol is untrusted, therefore the boundary around it carries the control. That framing is correct and it is where segmentation work should be aimed.

Segmentation alone, though, only constrains where Modbus can travel. It says nothing about whether the Modbus inside a zone is legitimate, and the majority of consequential actions in an OT incident happen inside a zone the attacker has already reached.

This is where the determinism of industrial traffic becomes an asset rather than a liability. A Modbus poll loop is one of the most predictable things on any network. A given client reads a fixed set of register ranges from a fixed set of servers at a fixed interval, with jitter measured in milliseconds, using the same three or four function codes, for years. The behavioral envelope is narrow enough that deviation is measurable rather than debatable, which is the opposite of the situation in enterprise IT.

Detecting that deviation requires decoding, not counting. Flow telemetry such as sFlow or NetFlow will tell you that host A talked to host B on port 502 and how much data moved. It will not tell you that the function code changed from 3 to 16, and that distinction is the entire signal. Full packet inspection from a SPAN or mirror port is what separates a routine read from a controller write, and it is the collection method that makes the following checks possible.

Concrete checks worth running against Modbus traffic: writes from a client that has only ever read; function code 8 diagnostics from any source; register ranges outside the commissioned map; exception code 0x02 in bursts; unit ID sweeps at gateways; role reversal, where a device that has only ever answered requests begins issuing them; and poll intervals that shift outside their historical envelope.

The Practical Position

Modbus will not be fixed, and treating that as the headline finding of an assessment wastes the assessment. The protocol's lack of authentication is a fixed environmental constant, like the fact that a pump has inertia.

What is not constant is whether anyone can answer three questions about the Modbus in their own plant. Which hosts are permitted to issue write function codes, and does the network enforce it. What the commissioned register map is for each critical controller, and what happens when something reads outside it. Whether the poll loops that have run unchanged for years would be noticed the day they change.

Those questions are answerable without replacing a single device. They just require watching what the devices actually do on the wire, which is the one thing Modbus, for all its silence on identity, reports with complete honesty.