Concluded·6 Aug 2026 · 6 min read
Reading a plant from its names: what vocabulary five protocols leak
tcpdump 4.99.4 · tshark 4.6.7 · eclipse-mosquitto 2.0.22 · Modbus TCP · EtherNet/IP · S7comm · MQTT · OPC UA
The rest of this series watched people write to plants they did not own. This one watches somebody read, and only read. No packet goes back onto the wire. The question is what a person learns from a capture when all they are allowed to do is listen, and the answer turns out to depend far more on how modern the protocol is than on how much traffic crossed the tap.
Five captures, all from an isolated lab, all against equipment under my own control. The same five the scorecard used. This time they are lined up not by whether a write went through, but by how much each one explains itself to a stranger.
The rig, and the axis
Capture with tcpdump 4.99.4 on the bridge the traffic crossed, which stands in for a
mirror port on a real switch. Decode with tshark 4.6.7 and, where a protocol carries
plain text, with strings. Nothing was captured on a routable segment, and nothing here
is a walkthrough for doing this to somebody else's plant. The finding is a ranking and a
fix.
The axis is confidentiality, but not the usual reading of it. The interesting loss is not that a value is readable. It is that the wire tells you what the value is for. A number is a fact about the plant. A name is the plant's own account of itself.
Numbers first, at the bottom
Modbus is the floor, and it is the floor for the same reason it was the ceiling of the write risk: it is a protocol from 1979 with no room in it for a name. The register map reads out cleanly, but it reads out as numbers.
tshark -r modbus.pcap -d tcp.port==5020,mbtcp -Y modbus \
-T fields -e modbus.func_code -e modbus.reference_num | sort -uThe hostile write from the first lab lands on holding register ten. What the capture never says is that register ten is a pump speed, because that fact lives in the client software and never crosses the wire. An observer walks away knowing the plant has registers and what they hold this second, and knowing nothing about what any of them are for.
S7comm sits one step up and is nearly as quiet. It gives away structure rather than vocabulary, the numbered data block and the offset, but a search of the capture for anything readable comes back empty.
strings -n 4 s7.pcap | grep -iE '[a-z]{4,}' # -> (empty)The block has a number, not a name.
Where the names begin
EtherNet/IP is the first protocol in the set that carries human words, and it does not guard them at all. You do not need a protocol dissector to find them. A plain text search of a twenty-one-frame capture returns them in the clear.
strings -n 4 enip.pcap | grep -E 'MOTOR_CMD|SETPOINT'That is a different kind of loss from a leaked value. The values were already readable. The names tell the observer which of those values matter, and they do it in the plant's own words.
The modern server introduces itself
OPC UA is where the introduction becomes a full one. The server on the bench offers two doors on the same endpoint, an unprotected one and an encrypted one, and everything below came through the unprotected door while the encrypted read of the same value left no readable trace at all.
Search that session for the word pump, in any casing, and it appears twenty-nine times.
strings opcua.pcap | grep -i pump | sort | uniq -c 8 pumpserver0 server identity
7 opc.tcp://opcua-plc:4840/pump/ network endpoint (with one variant frame)
7 urn:pumpserver application URI (with one variant frame)
3 pumpclient0 / urn:pumpclient0 the other client on the bus
2 Pump OPC UA Server product name
1 http://pump.lab vendor namespace URI
1 Pump node browse name
It is not one node named twenty-nine times. It is a set of distinct disclosures: the server's product, its network address, its application and namespace identifiers, its node names, and the identity of the other client already talking to it.
None of that is a flaw in OPC UA. Every one of those strings is there to make the server
discoverable and self-describing, which is precisely what you want from it. The flaw is
the door that was left open, and closing it is a configuration flag. Turn on
SecurityMode=Sign&Encrypt, and all twenty-nine occurrences leave the wire together.
The whole plant, in a topic tree
The top of the ladder is the Unified Namespace, and it is at the top for the most uncomfortable reason in the piece: it earns its place by being good. A UNS is built to be human-readable, hierarchical and self-explaining, so that anyone new to the site can look at the tree and understand the plant. When the broker underneath it has no transport encryption, that same tree explains the plant to anyone on the segment.
tshark -r mqtt.pcap -Y 'mqtt.msgtype==3' -T fields -e mqtt.topic \
| tr ',' '\n' | sort -u | wc -l # 26 distinct topicsTwenty-six distinct topics came off this broker, and the strings alone rebuild the site.
Read it top to bottom with no values attached and you have an operator, a site, and an asset that is a tank. Two pumps, each reporting running state, speed, hours and fault, and the words duty and mode beside them make it a lead and a standby rather than two pumps run together. A valve with separate command and position, so it modulates. A full mass balance in level, volume, inflow, outflow and a totaliser. A four-level alarm scheme, and the start, stop and trip setpoints. That is a piping and instrumentation diagram, assembled from names, before a single payload is opened.
The shape of it
Put the five on a chart and the diagonal is empty. The protocol that will accept any write gives up the least about itself, and the stack that defends its writes best gives up the most about what those writes mean.
The write risk climbed as the protocols aged backward toward Modbus. The reconnaissance risk climbs the other way, toward the modern and the well-designed, because legibility and confidentiality are in tension and the good stack chose legibility on purpose.
The fix is not "rename your tags"
The wrong instinct is to make the names cryptic. That fights the entire reason a Unified Namespace exists, it does not survive anyone correlating a few values, and it trades a real control for a comforting one. The names are not the problem. They are a symptom, and the thing they are a symptom of is an unencrypted transport.
So the fix is the transport. Where the protocol can defend itself, let it: OPC UA sign and encrypt, and broker TLS, take the vocabulary off the wire and let you keep every descriptive name behind it. Where the protocol cannot, which is the cleartext fieldbuses, the defence is the one the rest of this series keeps arriving at, that a tap must not be possible on that segment in the first place. And treat a descriptive name as a disclosure only in relation to the boundary it crosses in the clear. The same name is a leak on an open conduit and good engineering inside an encrypted zone.
This is the confidentiality reading of the thesis this series has carried since the first Modbus post: the protocol was never the control, the network was. The blog companion, your namespace is a floor plan, tells the same finding through the reader rather than the wire.
Reproducing this
Every command here runs against a saved capture, so the reading half needs no lab. The
eclipse-mosquitto broker is 2.0.22 and the Modbus simulator is the one from the first
lab; the EtherNet/IP, S7comm and OPC UA simulators ran on a throwaway stack that has since
been torn down, so those three package versions are not pinned here. If you reproduce it,
pin them yourself and expect small differences in what the dissectors name things. Then
line your own protocols up on the same ladder. The useful surprise is usually the same
one: the parts of the stack you are proudest of are the parts that explain the plant most
clearly to a stranger.
Newsletter
New essays, by email.
SCADA, cloud, AI, and the plant floor — a short email when something new is published. No noise, unsubscribe anytime.