Industrial Protocols

Enumeration

ICS environments use specialized protocols designed for reliability and real-time communication, often with minimal security features. Understanding these protocols is essential for effective testing.

Modbus

The most common ICS protocol. Simple, no authentication, widely supported. Used in nearly all industrial sectors.

Variants

  • Modbus RTU - Serial (RS-232/485)
  • Modbus ASCII - Serial, human readable
  • Modbus TCP - Ethernet, Port 502

Security Issues

  • • No authentication
  • • No encryption
  • • No integrity checking
  • • Easily spoofable

Modbus Function Codes

Code Function Risk
0x01 Read Coils Info disclosure
0x03 Read Holding Registers Info disclosure
0x05 Write Single Coil Control manipulation
0x06 Write Single Register Control manipulation
0x0F Write Multiple Coils Mass control manipulation
0x10 Write Multiple Registers Mass control manipulation
0x2B Read Device Identification Fingerprinting

Modbus Testing

bash
# Using pymodbus
pip install pymodbus

# Read holding registers
python3 << 'EOF'
from pymodbus.client import ModbusTcpClient
client = ModbusTcpClient('192.168.1.100', port=502)
client.connect()

# Read registers 0-9
result = client.read_holding_registers(0, 10, unit=1)
print(f"Registers: {result.registers}")

# Read coils
coils = client.read_coils(0, 10, unit=1)
print(f"Coils: {coils.bits}")

# Device identification
device_id = client.read_device_information()
print(f"Device: {device_id}")

client.close()
EOF

# Using modbus-cli
pip install modbus-cli
modbus read 192.168.1.100 holding_register 0 10
modbus read 192.168.1.100 coil 0 10

# Nmap script
nmap -sV -p 502 --script modbus-discover 192.168.1.100

Write Operations

Never perform write operations on production ICS systems. Writing to registers/coils can cause physical damage, safety incidents, or process disruption.

Siemens S7comm

Proprietary protocol for Siemens S7 PLCs. Port 102 (ISO-TSAP). Very common in manufacturing and utilities.

bash
# S7 enumeration with Nmap
nmap -p 102 --script s7-info 192.168.1.100

# Returns:
# - Module type
# - Serial number  
# - Plant identification
# - Module name
# - Firmware version

# Using snap7 library
pip install python-snap7

python3 << 'EOF'
import snap7
from snap7.util import get_string

client = snap7.client.Client()
client.connect('192.168.1.100', 0, 1)  # IP, rack, slot

# Get CPU info
info = client.get_cpu_info()
print(f"Module: {info.ModuleTypeName}")
print(f"Serial: {info.SerialNumber}")

# Read data block
db_number = 1
data = client.db_read(db_number, 0, 100)
print(f"DB{db_number}: {data.hex()}")

client.disconnect()
EOF

# S7 password cracking (if protected)
# Use s7-brute-offline with captured traffic

EtherNet/IP (CIP)

Common Industrial Protocol over Ethernet. Used by Allen-Bradley/Rockwell PLCs. Port 44818.

bash
# Using pycomm3 for Allen-Bradley PLCs
pip install pycomm3

python3 << 'EOF'
from pycomm3 import LogixDriver, CIPDriver

# Generic CIP info
with CIPDriver('192.168.1.100') as plc:
    info = plc.get_plc_info()
    print(f"Vendor: {info['vendor']}")
    print(f"Product: {info['product_name']}")
    print(f"Revision: {info['revision']}")

# For ControlLogix/CompactLogix
with LogixDriver('192.168.1.100') as plc:
    # Get all tags
    tags = plc.get_tag_list()
    for tag in tags[:10]:
        print(f"Tag: {tag['tag_name']} Type: {tag['data_type']}")
    
    # Read a tag
    result = plc.read('MyTag')
    print(f"Value: {result.value}")
EOF

# Nmap enumeration
nmap -p 44818 --script enip-info 192.168.1.100

DNP3 (Distributed Network Protocol)

Common in utilities (power, water). Port 20000. Supports authentication in DNP3-SA (Secure Authentication).

bash
# DNP3 enumeration with Nmap
nmap -p 20000 --script dnp3-info 192.168.1.100

# Using dnp3-python
pip install dnp3-python

# DNP3 Wireshark analysis
# Filter: dnp3
# Look for:
# - Function codes
# - Data objects
# - Unsolicited responses

# Common attacks:
# - Replay captured commands
# - Inject false data
# - Disable unsolicited reporting

# DNP3 Secure Authentication (SA)
# Check if authentication is enabled
# If not, protocol is vulnerable to command injection

OPC UA

Modern protocol with built-in security. Port 4840. Supports authentication and encryption.

bash
# Using opcua-client-gui
pip install opcua-client

# Or use asyncua library
pip install asyncua

python3 << 'EOF'
import asyncio
from asyncua import Client

async def main():
    url = "opc.tcp://192.168.1.100:4840"
    async with Client(url=url) as client:
        # Get server info
        print(f"Server: {await client.get_server_node()}")
        
        # Browse root
        root = client.get_root_node()
        children = await root.get_children()
        for child in children:
            print(f"Node: {child}")
        
        # Read a variable
        node = client.get_node("ns=2;i=2")
        value = await node.read_value()
        print(f"Value: {value}")

asyncio.run(main())
EOF

# Security modes:
# - None (no security)
# - Sign (message signing)
# - SignAndEncrypt (full security)

# Common issues:
# - Anonymous access enabled
# - Self-signed certificates accepted
# - Weak cipher suites

BACnet (Building Automation)

Building automation protocol. Port 47808 (UDP). Controls HVAC, lighting, access control.

bash
# Using BAC0 library
pip install BAC0

python3 << 'EOF'
import BAC0

# Start BACnet/IP network
bacnet = BAC0.lite()

# Discover devices (WhoIs)
devices = bacnet.whois()
for device in devices:
    print(f"Device: {device}")

# Read device properties
device_id = 1234
# Read Present Value of Analog Input 0
value = bacnet.read(f'{device_id} analogInput 0 presentValue')
print(f"Temperature: {value}")

# Read all points from device
# device = BAC0.device('192.168.1.100', device_id, bacnet)
# print(device.points)
EOF

# Nmap BACnet script
nmap -sU -p 47808 --script bacnet-info 192.168.1.100

# Common attacks:
# - Write to setpoints (temperature, schedules)
# - Disable alarms
# - Manipulate access control
# - Read sensitive building data

PROFINET

Siemens industrial Ethernet standard. Layer 2 protocol using Ethernet frames directly.

bash
# PROFINET operates at Layer 2
# Uses Ethernet frames with EtherType 0x8892

# Discovery with DCP (Discovery and Configuration Protocol)
# Sends broadcast to identify PROFINET devices

# Using Wireshark
# Filter: pn_dcp or pn_io

# PROFINET tools:
# - Siemens PRONETA
# - Wireshark with PROFINET plugins

# Common issues:
# - No authentication
# - Name spoofing
# - Configuration manipulation

Protocol Comparison

Protocol Port Auth Encryption Primary Use
Modbus TCP 502 Universal ICS
S7comm 102 ⚠️ Optional Siemens PLCs
EtherNet/IP 44818 Allen-Bradley PLCs
DNP3 20000 ⚠️ SA optional ⚠️ SA optional Utilities
OPC UA 4840 ✅ Built-in ✅ Built-in Modern ICS
BACnet 47808 ⚠️ SC optional ⚠️ SC optional Building automation

Protocol Analysis with Wireshark

bash
# Wireshark ICS protocol filters
modbus                    # Modbus TCP
s7comm                    # Siemens S7
enip                      # EtherNet/IP
cip                       # Common Industrial Protocol
dnp3                      # DNP3
bacnet                    # BACnet
opcua                     # OPC UA
profinet                  # PROFINET (pn_io, pn_dcp)

# Useful display filters
modbus.func_code == 6     # Write Single Register
s7comm.param.func == 0x05 # S7 Write Var
enip.command == 0x006f    # EtherNet/IP Send RR Data

# Extract interesting data
# Statistics > Protocol Hierarchy
# Statistics > Conversations
# File > Export Objects