在工控安全现场待久了,你迟早会撞上EtherNet/IP(习惯上也有人写成Ethernet/IP)。不管是在汽车零部件厂评估一条PLC产线,还是排查HMI和PLC之间通信时好时坏的问题,EtherNet/IP报文都会高频出现在你的抓包里。它是ODVA维护的工业以太网协议,在罗克韦尔自动化(AB)体系里几乎是默认标配,很多日系、欧系设备也支持它。很多刚转入工控安全的人一听到CIP协议栈、对象模型就头大,其实它没想象中那么玄乎:底子是标准以太网,上面跑的是面向对象的CIP协议,通信方式主要就两种——显式消息和隐式消息。理解这两条主线,再去看攻击面、审计点、防护手段,思路就顺了。这篇文章就按我实际做项目时的思路,从协议原理、风险场景、抓包审计、落地防护到常见坑位,系统梳理一遍。
1. 先搞清楚EtherNet/IP到底是个什么协议
1.1 工业以太网里的三大流派
工控网络里说到工业以太网,经常被拿出来对比的通常是三个:PROFINET、EtherCAT、EtherNet/IP。它们都用标准以太网做物理层,但上层协议差异很大。PROFINET是西门子体系的地盘,设备发现靠DCP,实时通信走的是RT/IRT那套;EtherCAT是倍福带起来的,主站发一帧报文,从站“在飞行中”读取和插入数据,靠分布式时钟保证同步;EtherNet/IP则走了另一条路——把上层CIP协议完整搬到TCP/IP之上,HMI、PLC、IO模块、变频器、机器人控制器之间全用标准的以太网报文交互。
这三个流派的安全侧重点完全不同。PROFINET要关注DCP协议、LLDP、实时通道;EtherCAT要注意主从拓扑和过程数据被篡改的可能;EtherNet/IP要盯的是44818端口上的CIP命令、2222端口上的周期性IO数据,以及CIP对象模型暴露出的资产信息。如果你服务的客户里外资工厂、汽车产线、物流仓储比较多,EtherNet/IP的出镜率会非常高。国内很多汽车焊装线、总装线,底层就是AB的PLC加EtherNet/IP网络,所以做资产梳理、做风险排查,这个东西绕不过去。
1.2 EtherNet/IP = 标准以太网 + CIP
EtherNet/IP的关键在于“IP”不是指Internet Protocol,而是Industrial Protocol,全称是EtherNet/Industrial Protocol。它把CIP(Common Industrial Protocol,通用工业协议)作为应用层,承载在标准TCP/UDP之上。CIP最早并不是为以太网设计的,它源自DeviceNet、ControlNet那套体系,后来被移植到以太网上,形成了EtherNet/IP。打个比方,TCP/IP就像城市道路,EtherNet/IP是道路上的标准厢式货车,CIP则是车厢里的标准化货架。做安全的人关心的是:货车能不能被冒充?货架上的东西能不能被人偷看或篡改?
CIP的设备模型很统一:任何设备都是“对象”的集合,每个对象有类、实例、属性、服务。这种设计带来一个安全上的事实——只要掌握了CIP读写规则,就可以跨厂商对设备做操作,不区分是AB还是第三方设备。这也意味着,网络里一旦混入一个恶意节点,它对整个厂区EtherNet/IP设备的“理解成本”非常低。
1.3 为什么安全人员必须啃协议细节
很多做传统IT安全的同事刚接触工控网络,习惯用“扫端口+看版本”的方式做评估,这在EtherNet/IP场景里远远不够。等保2.0的工控扩展要求、IEC 62443的落地检查,都会明确提到“应对工业控制协议进行深度分析”和“对非授权指令进行检测”。你不能只会看“44818端口开着”就完了,你得能回答:这个端口上跑的是什么服务、谁在访问、是否建立了会话、有没有出现Set类的写指令、IO报文周期是否正常。
而且,EtherNet/IP的漏洞利用、异常检测、白名单规则编写,全都建立在协议细节之上。防火墙如果不认CIP,就只能按IP+端口做黑白名单,很多攻击流量照样能混过去。所以下面我会花不少篇幅讲协议本身,这不是学院派掉书袋,是做审计和防护的基本功。
2. 协议核心:CIP对象模型与两种消息
2.1 “设备=对象的集合”这个模型
CIP把每个设备都抽象成多个对象。对象由类(Class)、实例(Instance)、属性(Attribute)三层结构描述,外部通过“服务”(Service)对属性进行读取或写入。比如一个简单的IO模块,它会有Identity对象(设备身份信息)、Assembly对象(IO数据集合)、Connection Manager对象(连接管理)等。每个对象都有固定的类ID,比如:
- Identity对象,类ID 0x01,存放厂商ID、设备类型、产品代码、序列号、固件版本
- Message Router对象,类ID 0x02,负责消息路由
- Assembly对象,类ID 0x04,应用数据的主要载体
- Connection Manager对象,类ID 0x06,负责显式和隐式连接的生命周期管理
在抓包里,你会看到“路径”这个概念,它是CIP用来定位对象的。例如路径0x20 0x04 0x24 0x69 0x30 0x03代表“类ID 4、实例ID 105、属性ID 3”的一个对象属性。类ID、实例ID、属性ID都是数值化的,这给安全检测带来便利,因为防火墙可以做字段级过滤:只允许读属性、禁止写属性,在技术上是可行的。
2.2 显式消息:TCP 44818上的请求与响应
显式消息用于非实时通信,比如工程站读取PLC程序、诊断设备状态、读写标签数据。它跑在TCP 44818端口,是典型的请求/响应模型。流程大致是:客户端先发RegisterSession(注册会话)报文,服务端返回会话句柄,后续再通过SendRRData把CIP命令打包发送。Wireshark里能看到完整的封装头(Encapsulation Header)和CIP数据段。
显式消息里经常出现的服务码有:0x0E(Get_Attribute_Single,读取单属性)、0x10(Set_Attribute_Single,写单属性)、0x4C(Read Tag,读取标签)、0x4D(Write Tag,写标签)、0x01(Get_Attribute_List,读属性列表)等。安全审计时,我建议重点关注Set/Write类服务码,因为它们直接改变设备行为。举个例子,一个HMI正常巡检时只读IO数据,如果抓包发现某个IP频繁向PLC发Write Tag指令,那就值得查一查是不是有异常行为。
2.3 隐式消息:UDP 2222上的周期性IO
隐式消息是EtherNet/IP的实时通道,用于PLC与IO模块、HMI与PLC之间周期性交换过程数据。它走UDP 2222端口,通常是一个预先建立的连接,由Connection Manager负责协商RPI(Requested Packet Interval,请求包间隔)。数据格式是固定的,不带请求/响应语义,强调的是低延迟和可预测性。正因为这种流量“周期性”非常明显,所以在安全监控里很容易建模。
但隐式消息也有自己的风险点:报文是明文,且没有认证机制。攻击者只要进入网络,就能监听IO数据,甚至伪造源IP向PLC发预编译好的隐式报文,直接改写设定值或让执行机构动作。而且这类报文的长度和内容相对固定,普通防火墙很难识别“这个值合理不合理”,只能靠业务侧规则来做深度检测。
3. 风险视角:攻击者会从哪些点下手
3.1 明文通信等于信息裸奔
EtherNet/IP从设计之初就把功能放在首位,没有为安全性留太多余地。CIP报文里的设备身份信息、程序标签名、工艺参数,全都以明文形式在网络上传输。这意味着只要有人能接入网络,无论是物理插网线、连了生产WiFi,还是攻破了一台边缘设备,他就能通过抓包获得整个产线的“底细”,比如PLC型号、固件版本、标签命名规则。这些信息会进一步帮助攻击者精准选择漏洞、构造恶意指令。
在一次产线排查中我见过类似情况:工程站到PLC的通信被镜像到一个临时排查口上,抓了一小时包,不仅看到了IO周期数据,连某台设备的序列号和固件都清清楚楚。如果这些流量落到恶意分子手里,他们不需要物理接触设备,就能完成摸底。
3.2 无认证写操作,离“搞停机”只差一条指令
EtherNet/IP的大多数设备不会校验“谁在给我发指令”。只要网络可达、CIP会话建立成功,任何节点都可以发起写请求。常见的破坏行为包括:向PLC发送Set指令修改设定值、向设备发送Reset指令重启、通过Download指令下载恶意配置。更麻烦的是,很多老固件的PLC即使设置了程序保护口令,口令校验也只存在于上层组态软件,CIP层面的写操作未必会被拦截。
所以我在做安全加固时,跟前端运维同事强调最多的一句话是:不要指望PLC自身能挡住恶意写操作,必须在网络层把“谁有权限写”这件事管起来。这也是为什么防火墙的CIP深度解析、白名单机制在工控场景里比什么都重要。
3.3 资产枚举等于给攻击者画了张地图
EtherNet/IP有一个非常方便的能力:向网段内发送ListIdentity广播,所有支持CIP的设备都会返回自己的身份信息。类似地,ListServices可以列举设备支持的服务。这个机制本来是方便工程软件自动发现设备的,但对攻击者来说,这就是现成的资产测绘工具。扫一遍广播域,设备型号、厂商ID、固件版本全拿到手,再对照漏洞库,打哪里、怎么打,思路很清晰。
作为防守方,我建议定期做同样的资产盘点,用攻击者的视角检查网络里到底有哪些EtherNet/IP设备、存不存在未收录的“黑户”设备。下面第4节我会给一个可复现的盘点方法。
3.4 拒绝服务比数据窃密更致命
在传统IT里,数据泄露是头号担心;但在工控里,最怕的是“业务不可用”。EtherNet/IP设备在资源上通常很有限,连接表、会话数都有上限。攻击者可以快速建立大量TCP连接,或者发大量UDP报文冲击设备的CIP协议栈,让PLC的通信处理器过载,导致正常的HMI轮询超时、IO丢包甚至CPU停机。这类攻击无需漏洞,只要协议本身支持大量连接就能实现,所以防御上必须靠网络层的连接数限制、流量限速和异常会话检测。
4. 实操:从抓包到资产盘点,一次完整的安全审计
4.1 抓包位置和准备工作
做EtherNet/IP审计之前,先确定抓包位置,这个很关键。最常见的做法是交换机镜像口,把核心交换机上连PLC、HMI、工程站的端口流量镜像到审计笔记本。如果现场有工业防火墙或分流器,也可以从它的镜像口取流。还有一个必须注意的点:抓包时机。生产高峰期的流量最真实,但也最容易影响业务;建议先在低峰期做一轮摸底,再在运维窗口做深度抓包。
准备工具方面,Wireshark是主力,另外准备一台装了Scapy的Linux笔记本,用于主动资产发现。如果条件允许,还可以带一台工业交换机做小范围测试环境,避免在真实产线上做太多实验。无论哪种方式,都建议先把抓包文件命名、时间戳、对应的PLC柜号和交换机端口记录清楚,不然事后复盘会一头雾水。
4.2 Wireshark快速定位EtherNet/IP流量
打开抓包文件后,可以直接在过滤栏输入:
tcp.port == 44818,看显式消息udp.port == 2222,看隐式消息ethernetip或cip,按协议解析层过滤
Wireshark对CIP的支持已经比较完善,会自动把封装头、CIP路径解析成可读结构。我最常用的操作是:先按IP排序,看哪些设备在互相通信;然后取一条RegisterSession报文,展开封装头,确认会话建立过程;再随机看几条CIP请求,找到服务码和路径,判断这条连接是在读数据还是在写数据。
如果你想快速从一份大抓包文件里提取所有CIP设备身份,可以直接用统计功能里的“Protocol Hierarchy”或“Conversations”,把EtherNet/IP流量和端到端会话两层信息结合起来看。这样既能知道“谁在和谁说话”,又能知道“传输层用了什么端口”。
4.3 用Scapy做CIP设备盘点
主动发现CIP设备,最常用的是ListIdentity广播。下面这段脚本可以往目标网段发一个ListIdentity请求,并打印返回设备的IP和身份信息。注意:这是在你自己有授权的网络里做资产梳理用的,千万别对着没授权的生产网乱扫。
from scapy.all import * import struct def build_list_identity(): # EtherNet/IP封装头,共20字节,小端序 # 命令0x0063表示ListIdentity,长度0,会话、状态、上下文、选项全为0 return struct.pack("<HHI8xI", 0x0063, 0, 0, 0) def parse_identity(data): if len(data) < 2: return None item_count = struct.unpack("<H", data[:2])[0] offset = 2 for _ in range(item_count): if offset + 4 > len(data): break type_id, length = struct.unpack("<HH", data[offset:offset+4]) offset += 4 if type_id == 0x00B1: # CIP Identity数据项 if offset + length > len(data): break vendor_id, dev_type, prod_code, rev = struct.unpack("<HHHH", data[offset:offset+8]) status, serial = struct.unpack("<HI", data[offset+8:offset+14]) name_len = data[offset+14] name = data[offset+15:offset+15+name_len].decode("utf-8", "replace") return vendor_id, dev_type, prod_code, rev, status, serial, name offset += length return None def scan(target_cidr): # 需要替换成自己的网卡和网段 pkt = Ether(dst="ff:ff:ff:ff:ff:ff") / IP(dst=target_cidr) / \ UDP(sport=44818, dport=44818) / Raw(load=build_list_identity()) ans, _ = srp(pkt, timeout=3, iface="eth0", verbose=0) for sent, recv in ans: if recv.haslayer(Raw): result = parse_identity(recv[Raw].load) if result: vendor_id, dev_type, prod_code, rev, status, serial, name = result print(f"{recv[IP].src}: vendor={vendor_id}, type={dev_type}, " f"prod={prod_code}, rev={rev}, name={name}") if __name__ == "__main__": scan("10.10.20.255")注意目标地址这里写的是广播地址,实际扫描时可以直接填网段广播地址,也可以对设备逐个单独发。响应解析部分做了简化,如果遇到结构特殊的设备,建议用Wireshark打开对应报文做交叉验证。我在真实项目里发现,部分老设备不会响应广播ListIdentity,只会回复定向请求,这时候就需要结合供应商工具进行补充盘点。
4.4 输出一份能推动整改的审计报告
资产盘点不是终点,最终要落到报告上。我常用的表格字段包括:设备IP、MAC地址、厂商、设备类型、序列号、固件版本、开放端口、发现时间、风险等级。风险等级我一般这样定义:生产网络直接暴露、存在可写CIP服务但无访问控制、固件版本存在已知漏洞、不在资产台账中的“黑户设备”等。风险等级高的设备,对应到整改建议时不能只说“抓紧升级”,要给出具体的处置路径,比如先做网络隔离、限制源IP,再排计划升级固件。
报告里最好附上几份关键抓包截图,尤其是异常CIP请求和未识别会话的截图,方便网络和自动化团队定位问题。审计的目的不是“抓谁的小辫子”,而是让所有相关方看到当前状态,推动改进。
5. 落地防护:从架构到设备,一层层加上去
5.1 用IEC 62443的区域与通道思路隔离EtherNet/IP
做EtherNet/IP防护,我最推荐的顶层框架是IEC 62443(国内也有对应的工控信息安全标准转化)。这个标准里的“区域与通道”概念非常实用:把功能相近、安全级别相近的资产放在同一个区域里,区域之间用通道连接,通道上做访问控制。比如一条产线里,PLC、HMI、IO模块、机器人控制器可以放在“产线控制区”,工程站放在“工程维护区”,上层MES、ERP放在“企业IT区”。EtherNet/IP通信只允许在控制区和维护区内部发生,跨区访问必须经过工业防火墙,并且只放行业务必需的协议和端口。
这样做的好处是,即使某台HMI被攻破,攻击者也不能直接横向跳到其他产线,更碰不到企业IT系统。相比“一台防火墙挡在全厂门口”的粗放做法,区域划分能把爆炸半径压到最小。
5.2 协议白名单:允许读,禁止写
针对EtherNet/IP,光有IP+端口白名单是不够的,要做CIP协议层的深度白名单。现在主流的工业防火墙基本都能解析CIP,识别服务码、类ID、实例ID。我实际部署时喜欢做一套“业务基线”:
- 工程站对PLC:允许读标签、在线监控、上传下载,但下载操作要求严格审批并通过临时策略放行
- HMI对PLC:只允许读IO数据、写报警确认类标签,禁止修改设定值
- PLC对IO模块:只允许隐式消息,UDP 2222端口,按既定RPI周期通信
- 其他设备之间:默认拒绝
这套白名单建议先在监控模式下运行一两周,把业务流量基线抓全、看明白之后,再切成强制模式。否则一上来就阻断,很容易把正常业务搞挂。
5.3 流量监控:抓异常,不只看告警
监控EtherNet/IP流量,建议重点关注几类异常:
- 新增设备:网络里出现从未见过的IP/MAC,尤其是尝试发ListIdentity或RegisterSession的设备
- 连接数量突增:某个IP突然建立大量TCP连接到PLC,可能是扫描或DoS的前兆
- 写操作异常:在非业务时段出现大量Write Tag、Set Attribute等操作
- IO周期变化:流量周期性突然变化,可能意味着IO连接被篡改或设备状态异常
- 非标路径的CIP访问:访问了业务基线上不存在的类ID或实例ID
这些检测如果靠人工看日志会累死,建议把镜像流量接到工控IDS或SIEM里,用规则做自动化告警。我自己的经验是,阈值刚开始别设太紧,先磨合一两周,再逐步收敛,避免被正常业务误报淹没。
5.4 设备侧加固和CIP Security的现状
设备层面的加固同样不能落下。能关的端口就关,能改的默认口令就改,CPU的运行/编程模式切换权限要收口,工程软件的升级补丁要及时打。对于EtherNet/IP,有些新设备开始支持CIP Security(基于TLS/DTLS对CIP通信加密和认证),但坦白说,现网设备普及率还不高,老设备更多要靠网络侧防护来兜底。所以新项目选型时,可以优先考虑支持CIP Security的设备,存量设备则通过区域隔离和协议白名单来降低风险。
另外,一定要做好配置备份。PLC程序和网络配置文件定期备份到离线位置,避免设备故障或遭受攻击后无法快速恢复。备份本身也是安全事件应急响应的基础条件。
6. 常见问题与避坑指南
6.1 常见问题速查表
| 现象 | 可能原因 | 排查与处置 |
|---|---|---|
| 抓包看不到44818端口流量 | 抓包位置不对、流量被VLAN隔离、设备修改了端口 | 检查交换机镜像配置,用IP+MAC维度做会话统计 |
| PLC能ping通,但CIP连接建立失败 | CPU处于停止状态、连接数耗尽、固件限制 | 查看CPU状态,重启工程软件,必要时重启PLC通信模块 |
| 防火墙放行44818/2222后HMI仍连不上PLC | 只放了单方向策略,隐式消息回包被拦 | 同时放行PLC到HMI的UDP 2222回程,并保证组播可达 |
| ListIdentity只返回少量设备 | 设备关闭广播响应、跨VLAN、老固件机制不同 | 改为定向发送,结合供应商工具做补充发现 |
| DPI设备偶尔丢包,HMI时断时续 | 深度检测对CIP报文处理开销大,或多个会话被误判 | 调整DPI规则,业务流量单独放行,避免“一刀切” |
| 设备出现写操作但无告警 | 监控规则只查了端口,没查服务码 | 在规则里增加CIP服务码和路径匹配 |
6.2 我踩过的一些坑
先在运维窗口做主动扫描这件事,我强调多少遍都不过分。有一回我在一个项目上做ListIdentity广播,因为目标网段里接了上百台设备,广播风暴和响应报文瞬时冲击了一段时间,结果某台老PLC的通信模块直接报错,产线上HMI开始闪烁。后来我们改成了逐台定向扫描、限制发包速率,才彻底消停。做资产盘点一定要“温柔”,尤其是对上了岁数的设备,宁慢勿快。
另一个坑是抓包记录写得不够细。早期我抓完包回到办公室,看着一堆pcap文件,经常想不起来这是哪个车间、哪个交换机端口、什么时间段。后来我养成习惯:抓包前先在记事本里写三行——时间、地点、交换机端口;抓完包马上复制一份到带日期的目录里。这个习惯帮我省了很多返工时间。
还有一个容易被忽略的问题:调试用的临时抓包口、临时放行策略,活动结束后没有及时拆除。这些临时通道往往会变成安全的缺口。现在我每次项目收尾,都会列一个“临时措施清单”,逐项确认关闭和回收,避免留下尾巴。
最后想说的是,EtherNet/IP本身并不复杂,复杂的是它身处生产环境,任何误操作都会直接影响业务。做安全的人要敬畏这一点:先保住业务,再谈安全;先看清基线,再做封禁。这样你在车间里才会被老师傅信任,后面推进工作也会顺利很多。