Runbook: OT reconnaissance¶
Objective¶
Build a picture of the OT environment without generating traffic that could disrupt process control. Passive enumeration first; active scanning only where explicitly permitted and against non-critical segments.
Prerequisites¶
Explicit written confirmation that OT recon is in scope.
Confirmation of which segments can be actively scanned and at what timing and rate.
A designated safe-to-scan OT segment, separate from live production control systems, if active scanning is required.
Phase 1: Passive external discovery¶
Before touching the OT network:
# Shodan: find exposed OT devices on the organisation's IP ranges
shodan search 'org:"Target" port:502' # Modbus
shodan search 'org:"Target" port:44818' # EtherNet/IP
shodan search 'org:"Target" port:47808' # BACnet
shodan search 'org:"Target" port:102' # Siemens S7
shodan search 'org:"Target" port:4840' # OPC UA
# Censys: similar coverage, different indexing
censys search 'ip:"203.0.113.0/24" and protocols.102'
# Certificate transparency: find OT-adjacent hostnames
subfinder -d target.com -silent | grep -i 'scada\|hist\|hmi\|ics\|control\|plc'
Note every exposed OT device: IP, port, product banner, and vendor. Each is a direct attack surface if credentials are weak or authentication is absent.
Phase 2: Passive capture on accessible OT segment¶
From a foothold in the IT/OT boundary:
# Passive capture of OT protocol traffic (no packets sent)
tcpdump -i eth0 -n 'port 502 or port 20000 or port 44818 or port 47808 or port 102 or port 4840' \
-w ot-passive.pcap -s 0
# Identify communication pairs and protocols
tshark -r ot-passive.pcap -T fields -e ip.src -e ip.dst -e tcp.dstport -e udp.dstport \
| sort | uniq -c | sort -rn
From the capture, extract:
Which hosts communicate on OT protocol ports (SCADA masters, PLCs, RTUs, historians).
The register addresses that are polled and the values observed.
The timing and frequency of polling cycles.
Any write operations and the values written.
Phase 3: OPC UA and historian enumeration¶
OPC UA servers expose a browse interface that returns the full tag database without requiring writes:
# Using opcua-client-cli or python-opcua
pip install opcua
python3 -c "
from opcua import Client
c = Client('opc.tcp://<historian-ip>:4840')
c.connect()
root = c.get_root_node()
print(root.get_children())
"
For OSIsoft PI historian:
# PI Web API (if exposed)
curl -k -u 'domain\user:password' \
'https://<historian>:443/piwebapi/assetservers'
# PI OLEDB provider: enumerate tags via SQL
# SELECT * FROM PIPoint WHERE Tag LIKE '%flow%'
Phase 4: Asset mapping¶
Build a table of all discovered assets:
IP |
Hostname |
Protocol |
Vendor/Model |
Firmware |
Notes |
|---|---|---|---|---|---|
10.20.1.10 |
plc-west-01 |
EtherNet/IP |
Rockwell 1756-L85E |
v34 |
Writable tags |
10.20.1.20 |
hist-01 |
OPC UA |
AVEVA PI |
3.4.390 |
No auth |
This inventory drives every subsequent decision about targeting, protocol selection, and the scope of the demonstration.