SCADA / modbus /
root authored on 16 Jun 2022
..
misc playing with modbus day #1 2 years ago
GRFICS_0-99_Modbus.xls playing with modbus day #1 2 years ago
GRFICS_bang.png useful scripts and make GRFICS go bang! 2 years ago
GRFICS_bang.py useful scripts and make GRFICS go bang! 2 years ago
README.md update readme 2 years ago
enum_all.py read only mode added for safety 2 years ago
monitor_muiltiple.py playing with modbus day #1 2 years ago
set_coil.py useful scripts and make GRFICS go bang! 2 years ago
set_reg.py useful scripts and make GRFICS go bang! 2 years ago
test_coil_true.py playing with modbus day #1 2 years ago
test_hold_int.py playing with modbus day #1 2 years ago
README.md

MODBUS

Modbus scripts

in this folder

  • enum_all.py, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values!
  • monitor_multiple.py, monitor several modbus addresses with a configurable interval and pretty colours
  • set_coil.py, set a specific coil value, loop option available
  • set_reg.py, set a specific register value, loop option available
  • GRFICS_bang.py, GRFICS PoC to destroy the chemical plant via modbus.

recommendations:

  • https://github.com/sourceperl/mbtget, Simple perl script for make some modbus transaction from the command line.

Enumerate SCADA Modbus slave ids (sids) and collects their device information.

when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default.

nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 <host>

mbtget

read coils: 
mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip]

read registers
mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip]

enumerate coils:
for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done

enumerate registers:
for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done

polling values over time (assume 5 is changing):
for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done

enum_all.py

$> python enum_all.py -r 0 3 -i 127.0.0.1
******************************
Reading Coils Status - 0x01
100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s]
Writing Coil Status - 0x05
******************************
Reading Holding Registers - 0x03
100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s]
Writing Holding Status - 0x06
100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s]
******************************
Reading Discrete Input - 0x02
100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s]
******************************
Reading Input Registers - 0x04
100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s]
******************************
Check the output Excel File - Modbus_Output.xls

monitor_multiple.py

$> python monitor_muiltiple.py -h
usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]]
                            [-ho [HOLD [HOLD ...]]]
                            [-di [DISCRETE [DISCRETE ...]]]
                            [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT]
                            [-t TIMEOUT]
optional arguments:
  -h, --help                    show this help message and exit
  -co [COIL [COIL ...]]         list of addresses
  -ho [HOLD [HOLD ...]]            list of addresses
  -di [DISCRETE [DISCRETE ...]]    list of addresses
  -in [INPUT [INPUT ...]]        list of addresses
  -i IPADDRESS                    Input IP Address
  -p PORT                         Port Number
  -t TIMEOUT                    request every X seconds

$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1
### watch list ###
coils: (7)[0, 1, 3, 4, 5, 6, 8]
hold reg: (7)[0, 1, 2, 3, 4, 5, 6]
Total = 14
------------------
[coils:[0][1][0][0][0][0][0]][hold regs:[   13][  666][     ][     ][     ][     ][     ]]

set_coil.py

$> python set_coil.py -h
usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT]

optional arguments:
  -h, --help            show this help message and exit
  -i IPADDRESS, --ipaddress IPADDRESS
                        Input IP Address
  -p PORT, --port PORT  Port Number
  -c COIL, --coil COIL  Coil Number
  -tr, --true           True if set
  -l, --loop            loop on
  -t TIMEOUT, --timeout TIMEOUT
                        request every X seconds

$> python set_coil.py -i 192.168.95.2 -c 5 -tr

set_reg.py

$> python set_reg.py -h
usage: set_reg.py [-h] -i IPADDRESS [-p PORT] -r REG -v VAL [-l] [-t TIMEOUT]

optional arguments:
  -h, --help            show this help message and exit
  -i IPADDRESS, --ipaddress IPADDRESS
                        Input IP Address
  -p PORT, --port PORT  Port Number
  -r REG, --reg REG     Register Number
  -v VAL, --val VAL     Register Value
  -l, --loop            loop on
  -t TIMEOUT, --timeout TIMEOUT
                        request every X seconds

GRFICS_bang.py

GRFICS PoC screenshot