Abandoning Abstractions: Manually Crafting EtherNet/IP Packets Almost Broke Me
By RUGERO Tesla ( @404Saint ). There is a persistent illusion in Industrial Control Systems (ICS) security research: that high-level libraries, abstraction frameworks, or protocol tooling give you a real understanding of Operational Technology (OT) behavior. They don’t. They hide the architecture. Determined to understand what actually happens when a Programmable Logic Controller (PLC) receives a control-plane command, I built an EtherNet/IP and Common Industrial Protocol (CIP) sandbox from scratch. No Scapy. No protocol wrappers. Just raw sockets, a Linux loopback interface, a cpppo simulator, and a passive monitoring tool ( enip_monitor.py ) capturing traffic in real time. It looked clean on paper. Then I reached the application layer. And things stopped behaving like theory. The Reality of the “Industrial Abstraction Layer” If you come from Modbus or traditional IT networking, you’re used to linear memory spaces—fixed registers, predictable offsets, and flat addressing. EtherNet/IP and CIP discard that model entirely. Instead, they introduce a structured object system wrapped inside multiple encapsulation layers: +-----------------------------------------------------------+ | EtherNet/IP Encapsulation Header (24 bytes) | | → Session control, commands (0x0065, 0x006F) | +-----------------------------------------------------------+ | Common Packet Format (CPF) | | → Routing, addressing, and transport segmentation | +-----------------------------------------------------------+ | CIP Application Layer | | → Service codes (0x4C, 0x4D, 0x10, etc.) | +-----------------------------------------------------------+ To communicate with a PLC at the wire level, your code must: Establish a session using RegisterSession (0x0065) Wrap all subsequent requests in SendRRData (0x006F) Encode routing information inside CPF structures Construct symbolic or logical paths for the CIP Message Router Ensure strict byte alignment across nested payload layers A single mistake in any layer b