1. 工业IoT设备资产发现与指纹识别
为什么资产发现要“被动+主动”两条腿走路
工厂网络里大量设备是“哑设备”:PLC、变频器、远程IO、HMI、网关,它们不会主动上报自己是谁。被动流量分析能回答“谁在跟谁说话、用什么协议、暴露了哪些端口”,但拿不到厂商和型号;主动探测能补上指纹细节,却可能打扰生产设备。因此本例采用先被动摸清拓扑与协议分布,再对关键设备做低强度主动指纹的组合策略,最终输出可核对的资产清单。
被动侧:从镜像流量里提取“设备—协议—端口”三元组
在交换机镜像口或TAP上抓包,过滤工业协议特征端口与报文特征。下面脚本用 Scapy 读取 pcap,按源IP聚合出协议、端口和报文计数,作为资产发现的被动输入。
from scapy.all import rdpcap, IP, TCP, UDP
from collections import defaultdict
# 工业协议特征端口
PORT_PROTO = {
502: "Modbus/TCP",
4840: "OPC UA",
1883: "MQTT",
8883: "MQTT/TLS",
102: "S7comm",
44818: "EtherNet/IP",
20000: "DNP3",
}
def passive_discover(pcap_path):
assets = defaultdict(lambda: {"proto": set(), "ports": set(), "pkts": 0})
for pkt in rdpcap(pcap_path):
if IP not in pkt:
continue
src = pkt[IP].src
if TCP in pkt:
dport, sport = pkt[TCP].dport, pkt[TCP].sport
elif UDP in pkt:
dport, sport = pkt[UDP].dport, pkt[UDP].sport
else:
continue
for port in (dport, sport):
if port in PORT_PROTO:
assets[src]["proto"].add(PORT_PROTO[port])
assets[src]["ports"].add(port)
assets[src]["pkts"] += 1
return assets
for ip, info in passive_discover("factory.pcap").items():
print(ip, sorted(info["proto"]), sorted(info["ports"]), info["pkts"])
运行后得到类似 192.168.10.21 ['Modbus/TCP'] [502] 1842 的记录,说明该IP在502端口上持续通信,是Modbus从站候选。被动结果只给出“协议+端口+活跃度”,厂商和型号仍未知。
主动侧:低强度指纹探测补全厂商与型号
对被动筛出的候选设备,按协议做最小化探测:Modbus 读设备标识对象(0x2B/0x0E),OPC UA 读 ServerStatus 与 BuildInfo,MQTT 观察 CONNACK 返回码与 broker 版本。下面用 pymodbus 读取 Modbus 设备标识,这是最安全的只读操作。
from pymodbus.client import ModbusTcpClient
def modbus_fingerprint(ip, port=502, unit=1):
client = ModbusTcpClient(ip, port=port, timeout=2)
if not client.connect():
return {"ip": ip, "error": "connect_failed"}
try:
# 0x2B/0x0E 读设备标识,只读,不改变设备状态
rr = client.read_device_information(unit=unit)
if rr.isError():
return {"ip": ip, "error": str(rr)}
return {
"ip": ip,
"vendor": rr.information.get(0x00, b"").decode(errors="ignore"),
"product": rr.information.get(0x01, b"").decode(errors="ignore"),
"version": rr.information.get(0x02, b"").decode(errors="ignore"),
}
finally:
client.close()
print(modbus_fingerprint("192.168.10.21"))
若设备支持标识对象,会返回厂商名、产品代码和版本;若不支持,则回退到 TCP 栈指纹(TTL、窗口大小、TCP选项顺序)和 HTTP/SNMP 横幅做辅助判断。主动探测必须限制并发与频率,避免对PLC造成连接风暴。
资产清单合并与去重
被动结果和主动结果按IP合并,冲突时以主动指纹为准,被动数据作为佐证。下表是合并后的资产清单示例(教学示例数据):
| IP | 端口 | 协议 | 厂商 | 型号/版本 | 发现方式 | 置信度 |
|---|---|---|---|---|---|---|
| 192.168.10.21 | 502 | Modbus/TCP | Siemens | S7-1200 FW4.2 | 被动+主动 | 高 |
| 192.168.10.35 | 4840 | OPC UA | Kepware | KEPServerEX 6.5 | 被动+主动 | 高 |
| 192.168.10.40 | 1883 | MQTT | 未知 | Mosquitto 2.x | 被动+横幅 | 中 |
| 192.168.10.55 | 502 | Modbus/TCP | 未知 | 未知 | 仅被动 | 低 |
置信度规则:被动+主动且标识对象返回完整=高;仅被动或仅横幅=中;只有端口命中无任何指纹=低。低置信度设备应列入下一轮重点探测名单。
探测流程与结果判读
结果验证与常见问题
- 验证方法:把清单里的IP与交换机ARP表、DHCP租约、DNS记录交叉比对,确认没有遗漏网段;对高置信度设备抽查其Web管理页或铭牌,核对厂商型号是否一致。
- 主动探测无响应:设备可能禁用了标识对象或只允许特定主站访问。此时不要反复重试,改用被动流量中的功能码分布和TCP栈指纹推断。
- MQTT设备识别难:broker可能不返回版本。可观察CONNACK返回码、主题命名风格(如
factory/line1/plc21)和客户端ID格式辅助判断。 - 安全边界:主动探测只做只读操作,禁止写线圈、改寄存器、重启设备;探测频率建议单设备不超过1次/秒,并发不超过5。
资产清单是后续所有安全工作的基线。清单不完整,后面的漏洞验证、访问控制检查都会漏掉设备。建议每季度重新跑一次被动发现,与上一版清单做差异对比。