Industrial Protocols
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
# 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.100Write Operations
Siemens S7comm
Proprietary protocol for Siemens S7 PLCs. Port 102 (ISO-TSAP). Very common in manufacturing and utilities.
# 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 trafficEtherNet/IP (CIP)
Common Industrial Protocol over Ethernet. Used by Allen-Bradley/Rockwell PLCs. Port 44818.
# 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.100DNP3 (Distributed Network Protocol)
Common in utilities (power, water). Port 20000. Supports authentication in DNP3-SA (Secure Authentication).
# 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 injectionOPC UA
Modern protocol with built-in security. Port 4840. Supports authentication and encryption.
# 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 suitesBACnet (Building Automation)
Building automation protocol. Port 47808 (UDP). Controls HVAC, lighting, access control.
# 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 dataPROFINET
Siemens industrial Ethernet standard. Layer 2 protocol using Ethernet frames directly.
# 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 manipulationProtocol 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
# 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