news 2026/9/20 15:44:38

Modbus协议取证实战:从流量抓包到事件溯源

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Modbus协议取证实战:从流量抓包到事件溯源

1. 项目概述与整体思路拆解

如果你负责工厂自动化系统的安全巡检,或者在做工控安全相关的应急响应,那么Modbus协议你一定绕不开。这套诞生于1979年的串行通信协议,到今天仍然是PLC、HMI、变频器、传感器之间最主流的通信方式之一。我经常跟团队里的新人说,Modbus之于工业控制系统,就像HTTP之于Web应用——它足够简单、足够老,也因此足够普及。

这次整理的学习笔记,核心解决一个实际问题:当工业现场出现异常通信,比如某个PLC在深夜主动改写保持寄存器、某台上位机向所有从站广播写命令,我该怎么从抓包到复盘,完整地还原事件经过。换句话说,不只要看懂Modbus报文,还要掌握围绕Modbus做流量取证和内存取证的整套方法。

笔记面向的人群很明确:刚接触工控安全的乙方工程师、工厂里的自动化运维骨干,以及想从IT取证转型OT取证的同事。我会把协议格式拆到字节级别,再结合真实场景演示抓包、解析、溯源、关联分析的操作步骤。

2. Modbus协议核心细节解析

想做好取证,先要把协议本身吃透。Modbus的报文结构不复杂,但恰恰因为简单,很多设备在实现时会“偷懒”,比如该填的字节长度不填对、功能码用得模棱两可。这些细节在现场都是重要线索。

2.1 协议设计思路与适用场景

Modbus是主从架构,也就是一主多从。主站发起请求,从站响应,从站之间不直接通信。这个设计决定了取证时的一个重点:你只需要盯住主站和被操作的从站之间的对话,尤其关注主站发往从站的写入类请求。

整个协议在OSI模型里非常“扁平”,Modbus RTU和ASCII直接跑在物理串口上,Modbus TCP则是把协议报文封装进TCP/IP,固定使用502端口。这种扁平设计的好处是解析简单、实现成本低,对单片机那点资源非常友好;坏处是几乎没有加密、没有认证、没有会话完整性校验,这在安全取证角度反而成了“好事”——报文内容直接可读、可回放、可伪造,你抓到什么就是什么。

2.2 三种传输变体的选择逻辑

Modbus家族里最常见的三种变体分别是RTU、ASCII和TCP,它们的区别不止是传输层不同,报文内部格式也略有差异。

变体传输载体报文特征典型场景
Modbus RTURS232 / RS485 串口二进制紧凑,帧间隔≥3.5字符时间,带CRC16校验工厂车间DCS、小型PLC网络
Modbus ASCIIRS232 / RS485 串口每个字节转成两个ASCII字符,带LRC校验老旧设备、无线数传电台
Modbus TCP以太网在RTU基础上增加MBAP头,无CRC现代SCADA、大型产线网络

我实际遇到的项目里,老旧产线仍有大量RTU在跑,特别是RS485总线好几公里拉到大门口的流量计、水泵房。RS485是半双工差分信号,总线上的报文实时性很强,取证时通常要在PLC网关侧或者串口服务器的抓点才能完整体现“谁在跟谁说话”。

2.3 报文格式逐字节拆解

先说Modbus RTU的报文结构。一帧典型的请求报文长这样:

从站地址(1字节) + 功能码(1字节) + 数据段(N字节) + CRC16(2字节)

举个例子,主站要读取从站地址为1的设备的保持寄存器,起始地址0x0000,读取2个寄存器:

01 03 00 00 00 02 C4 0B

拆开看:

  • 01:从站地址
  • 03:功能码,读保持寄存器
  • 00 00:起始寄存器地址,高字节在前
  • 00 02:要读的寄存器数量
  • C4 0B:CRC16校验码,低字节在前

这个例子看着简单,但取证时必须注意寄存器地址的字节序。Modbus协议规定多字节字段用大端序(高字节在前),但不少老设备的实现并不规范,有的寄存器值会按小端存储,如果你不校验功能码对应的数据含义,很容易把读取到的值算错。

Modbus TCP则在RTU请求前面加了7字节的MBAP头,用于事务标识、协议标识和长度:

事务标识(2字节) + 协议标识(2字节) + 长度(2字节) + 单元标识(1字节) + 功能码 + 数据

协议标识固定为0,如果抓包里出现非0的协议标识,那就不是标准的Modbus流量,多半是某种私有封装,这也是取证时值得留意的异常信号。

2.4 功能码分类与取证优先级

Modbus功能码主要分三类:位操作、寄存器操作和文件记录操作。从取证角度,我最看重的是带“写”操作的功能码。

功能码含义取证价值
0x01读线圈
0x03读保持寄存器中,可看出是否被批量读取
0x05写单个线圈高,能定位精确写入时间
0x06写单个寄存器高,最常见的人为篡改入口
0x0F写多个线圈高,批量变更状态
0x10写多个寄存器高,重灾区,常用于参数覆盖
0x14读文件记录
0x15写文件记录高,少见但影响大

而0x08功能码下的子功能码0x00(回环测试)常被用来做连通性探测。在恶意样本中,攻击者也会先发送回环诊断请求确认目标在线,这算是攻击前的试探信号。抓包时一旦看到大量源IP相同、目标为502端口的诊断请求,就值得跟进了。

2.5 异常响应与错误码的价值

当从站收到非法请求或执行失败时,会返回异常帧。异常帧的构成是:

从站地址 + (功能码 | 0x80) + 异常码 + CRC

看到功能码带了0x80的返回包,说明从站拒绝了请求。异常码的含义也要记住几个:

  • 01:非法功能码,说明该设备根本不支持这个功能,比如给只读设备发写命令
  • 02:非法数据地址,说明寄存器地址越界
  • 03:非法数据值,说明请求中的数值超出允许范围
  • 04:从站设备故障
  • 06:从站设备忙
  • 10:网关路径不可用

取证时异常码特别有用。假如一晚上出现了几十条异常码02和03的记录,说明有人或某个程序在盲扫寄存器地址,这种“暴力排查”行为明显区别于值班人员正常点检。

3. 取证实操全流程记录

协议搞明白了,接下来进入实操。这一部分完全来自我在真实项目里跑过的流程,从流量采集到报文解析,再到内存和USB外围取证,每一步都有可以直接照抄的命令和思路。

3.1 流量采集点选择与基础准备

Modbus取证的第一步不是打开Wireshark,而是想清楚在哪个位置抓包。

如果现场是Modbus TCP,最简单的办法是在核心交换机上做端口镜像,把PLC网段和上位机网段的流量全部镜像到取证笔记本。没有条件做镜像,也可以用串接TAP设备,但搞生产网络时尽量不要中断现有链路,我一般优先建议端口镜像。

如果是Modbus RTU/RS485,抓包点比较麻烦。一种做法是在PLC侧串口上用串口服务器做旁路监听,另一种是直接用带RS485接口的USB转串口工具搭一个探测点,把A/B差分信号并接出来,注意共地。还有更省事的方案,用支持Modbus RTU的协议分析仪,直接挂在总线上就能解析。

抓包工具的选择上,Wireshark是最顺手的。它对Modbus协议做了完整的解析,且会自动识别502端口,即使没有配置任何自定义解析规则,也能直接看到Modbus TCP报文。如果是RTU原始二进制流,可以先抓成PCAP文件,再用Wireshark的“Decode As”功能强制解析为Modbus RTU。

3.2 Wireshark与TShark解析实战

用Wireshark打开PCAP后,过滤器是核心操作。我最常用的几个:

modbus modbus && modbus.func_code == 0x10 modbus && modbus.func_code == 0x06 tcp.port == 502 && ip.src == 192.168.1.10

如果要在服务器上批量处理大量PCAP,则用TShark更高效。提取全部Modbus写请求的报文,用一条命令就能搞定:

tshark -r capture.pcap -Y "modbus.func_code == 0x10" -T fields \ -e frame.time -e ip.src -e ip.dst -e tcp.srcport -e tcp.dstport \ -e modbus.regnum -e modbus.qty -e modbus.value

这条命令会输出时间、源IP、目的IP、端口、寄存器起始地址、寄存器数量和写入值。提取出来的字段已经足够支撑时间线重建。我在一个项目中就是靠这条命令从三天、上百个GB的PCAP里筛出了同一条从站地址在凌晨被反复写入0x0001的完整时间线,最后定位到一台临时接入产线网络的笔记本。

Wireshark还有一个容易被忽略的功能:右键任意Modbus报文,选择“Follow TCP Stream”,可以看到这个TCP连接里的全部Modbus交互。这个视图比逐条报文快得多,适合快速判断一次请求和响应的对应关系——注意TCP连接上的请求响应不总是严格匹配,尤其是存在重传时,要结合Seq和Ack来对应。

3.3 案例复盘:一次疑似异常写寄存器事件

下面用一个虚拟但典型的案例走一遍完整分析过程。

场景:某水处理厂中控室报警,2号送水泵变频器在凌晨03:12被远程修改了运行频率设定值,导致管网压力骤降。上位机操作日志显示03:12没有人工操作记录,怀疑有异常写入。

拿到PCAP后,我按下面的顺序排查:

先看整体流量概况。用Wireshark的统计功能,按对话排序,找出502端口流量最大的IP对,快速定位通信双方。

然后过滤Modbus写功能码,重点是0x06和0x10,看目标是哪个寄存器。结果发现03:12:08.433有一条来自192.168.30.50的报文,功能码0x10,目标寄存器40005(地址0x0004),写入值0x1F40,换算成十进制就是8000,正好对应变频器的8000转。时间点与报警时间吻合。

继续看这条报文的“前奏”。过滤目标IP为变频器PLC的512端口的所有TCP包,发现02:58开始有三次连接异常中断,遗留了若干个TCP SYN重传。这三次重传很关键——它暗示连接不稳定,可能是中间路由断过、也可能是攻击者手动调整参数时的网络波动,而不能直接视为攻击行为,需要结合其他日志做关联。

最后提取全部Modbus异常帧。结果在03:10到03:15之间出现了多次0x02异常码,均为读保持寄存器时超出了实际寄存器范围,说明写入者在尝试定位寄存器地址范围。

综合三条线索,可以这样叙事:某IP在03:10左右开始扫描目标PLC寄存器地址空间,03:12定位到40005后立即执行写入操作,随后快速断开连接。整个过程自动化特征明显,与人工值班操作模式不符。

3.4 内存取证扩展:找到协议通信的“主人”

流量取证解决了“网络层面发生了什么”,但如果目标是“哪个进程在操作Modbus”,就需要转向内存取证。

在Windows工控上位机上,如果怀疑有恶意进程或未知软件在发起Modbus请求,我一般会做这几件事:

用内存镜像取证工具做进程列表和网络连接的关联分析。我常用Volatility 2,配合可视化GUI工具(比如Volatility Workbench)操作更直观。如果需要分析Windows 10/11或Server 2016之后系统的内存镜像,建议直接上Volatility 3,因为Volatility 2对较新的系统结构支持有限。

拿到镜像后,先用netscan插件列出所有TCP连接:

volatility -f image.mem --profile=Win7SP1x64 netscan

重点过滤本地或远程端口为502的记录,直接定位到持有Modbus TCP连接的PID。拿到PID之后,用pslist或者psscan查看这个进程的可执行路径和启动参数。如果是生产环境中从未见过的第三方软件,优先级立刻提上来。

这里有一个经验:侦查阶段很多恶意程序会伪装成系统进程的名字,但你查路径会发现执行文件在临时目录或者用户下载目录。所以不要只看进程名,一定要验证可执行文件路径。

另外,Volatility的cmdline插件能看进程启动的命令行。Modbus主站工具很多是带参启动的,命令行里往往直接烙有目标IP、端口、轮询间隔,这个信息对溯源极其重要。我见过一个案例,恶意脚本通过计划任务定时调用mbpoll 192.168.50.21 -r 40005 -0 8000写入变频器参数,整个操作记录在进程命令行里一目了然。

如果内存镜像里找不到进程,但确认存在异常通信,就要检查驱动模块和隐藏进程。用modscandevicetree对比异常项,这种招数一般用在更隐蔽的样本上,日常排除“普通误操作”用不到这么深。

3.5 USB设备取证与时间线串联

很多工控现场的事件都与临时接入的U盘、USB转串口线有关。取证时经常有人问“使用过的USB序列号怎么查”,这其实有固定套路。

Windows系统里,每个USB设备首次连接时会在注册表留下记录,核心路径有三个:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USBSTOR HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\DeviceClasses

展开USBSTOR之后,会看到很多类似Disk&Ven_Kingston&Prod_DataTraveler&Rev_1.00的子键,再往下一层就是该设备的序列号。每个序列号对应一个具体的U盘硬件。如果再往下看FriendlyNameParentIdPrefixContainerID,则能还原设备生产厂商、型号和物理标识。

在内存取证中,同样的信息可以通过字符串搜索提取。用Volatility的strings插件配合搜索关键词USBSTOR或设备厂商名,可以定位到内存里的USB枚举记录。不过内存里的注册表键值不一定完整,最好的办法是对比多个镜像再下结论。

USB取证的价值在于把网络事件和物理接触关联起来。比如通过Modbus流量定位到攻击源IP是一个内网工位,但工位IP可以随便改。而USBSTOR里的序列号则是唯一的、与物理U盘一一对应的,再结合门禁刷卡记录或监控录像,就能形成完整的证据链。

3.6 报告输出与证据固定

取证到最后一定要产出报告,但报告不是把PCAP里的报文贴一遍就完事。

我习惯按这个框架来组织:

  • 事件概述:什么时间、什么设备、什么问题
  • 网络拓扑与采集点:在哪里抓的包、为什么选这个点
  • 关键证据列表:异常报文的十六进制、时间戳、源目的IP/端口
  • 时间线:从扫描、写入到断开的完整过程
  • 关联分析:内存进程、USB设备与网络行为的对应关系
  • 结论与建议:判断事件性质,给出加固措施

写报告的过程中要同步固定证据。PCAP文件、内存镜像、注册表导出的快照都要计算SHA256哈希,记录在报告附录里。这一步是行业规范,也是保护取证人自己的护身符——后续出现争议时,能证明证据没有被篡改过。

4. 常见问题与排查技巧实录

4.1 抓包环节的典型“坑”

  • 抓到了流量却看不到Modbus解析:很多现场抓包时用的是交换机镜像口,但VLAN标签没去掉,Wireshark把被看作普通以太网帧,解析不出来。对策是把镜像口设置成Trunk模式,抓包时在Wireshark里选择“VLAN”解析。
  • 502端口不是Modbus:有些私有系统默认也用502端口,但内容并不是标准Modbus。这种情况要结合报文内容和协议标识进行判断,不能一刀切认定“502=Modbus”。
  • RTU抓包时序错乱:RS485总线是半双工,多个设备同时发送时会产生碰撞,串口抓包工具容易捕获到乱序帧。对策是抓包时启用DTR/RTS信号控制,或者直接用带硬件时间戳的协议分析仪。如果你发现报文里帧间隔忽大忽小且CRC频繁校验失败,大概率是抓包时序乱了而不是总线故障。

4.2 协议解析中的常见陷阱

字节序是最容易翻车的地方。Modbus多字节字段遵循大端序,但很多设备厂商在应用层会把寄存器值对调字节,导致Wireshark显示的寄存器值与真实物理量不一致。排查时要先查设备的寄存器映射表,确认按“大端”还是“小端”解释,再对照数值量程做换算。我曾经因为没查映射表,把一组正常数据判定成了异常,差点做出错误结论。

另一个陷阱是功能码重定义。Modbus规范允许厂商在特定范围内自定义功能码,尤其是0x41到0x48之间的编码,不同厂商含义不同。取证时看到功能码不在标准码表里,不要急着标异常,先找到对应设备的Modbus通信手册。

4.3 内存取证的快速排查顺序

如果现场时间紧张,只够做一个动作,我会优先跑netscan。这个插件能直接呈现镜像里的TCP连接状态,502端口的连接一看便知。之后如果时间允许,再按pslistcmdlinedlllist的顺序往下追溯。追踪优先级是“网络连接先定 PID,PID 再定位进程,进程再关联启动命令行”,这样三级递进不容易迷失。

在实际操作里,很多工控上位机装的是Windows 7 Embedded或Windows Server 2008 R2,对应Volatility 2的Win7SP1x64配置。如果你需要分析的是较新的Windows 10 22H2,请用Volatility 3,运行速度快很多,对应的命令变成了windows.netscan.NetScan

4.4 常见问题速查表

现象可能原因对策
抓包后无Modbus报文端口镜像未配置VLAN调整Switch Trunk配置,或改抓镜像口
目标从站不响应写请求寄存器地址越界或功能码不支持对照寄存器映射表检查
大量异常码02/03存在寄存器扫描行为关联源IP与时间,排查扫描来源
进程命令行中有mbpoll等工具异常自动化脚本操作比对计划任务和启动时间,识别持久化机制
USB序列号在注册表查不全系统日志被清理,或设备类型特殊用内存字符串搜索二次验证
RTU帧CRC频繁错误抓包混乱或硬件故障换硬件抓包点,关闭省电模式

4.5 时间线重建的两个原则

做Modbus取证时,时间轴是所有结论的骨架。两个原则必须守住:

第一,统一时间基准。PCAP里的时间是抓包终端的时间,内存镜像里的系统时间是受害者机器的时间,两者可能存在分钟级偏差。取证时必须先校准基准,方法是对比NTP日志、开机时间或已知固定事件的报文时间,否则“先扫描后写入”的结论可能是错的。

第二,区分“记录时”与“发生时”。上位机操作日志记录的是操作产生的时刻,而网络流量的时间戳才是动作真正抵达PLC的时刻。两者相差一个网络延迟,正常情况下毫秒级,但如果网络拥塞,可能差到秒级。报告中要单独标注这两个时间来源,不能混用。

5. 关于取证工具链的几点个人心得

工具永远是辅助,思路才是核心。我见过有人拿了一堆取证软件,却连一个最简单的功能码0x06报文都解释不清楚,也有人只用一个Wireshark,就把整个事件复现得明明白白。所以最后再分享三条工具选型的经验。

5.1 流量侧工具组合与使用频率

我电脑上长期保留三个工具,按使用频率排序:Wireshark(日常解析与过滤)、TShark(批量处理与自动化提取)、scapy(写临时脚本来做报文回放和流量生成)。

scapy虽然不在传统取证工具列表里,但它在验证“某条报文能否在目标设备上重复产生相同效果”时极其好用。比如你想确认一条写寄存器命令是否真的能修改变频器转速,就在测试环境用scapy重放相同Payload,观察设备行为是否一致。这能帮助验证攻击路径的可行性,从而提升报告的说服力。

5.2 内存取证工具的版本选择

Volatility 2和Volatility 3不能互相替代。Volatility 2胜在插件生态丰富、社区资料多,特别是对老系统的支持更好;Volatility 3胜在跨平台、对新系统支持好,但插件数量还在积累。我的习惯是:拿到一个镜像,先用Volatility 3跑一遍快速扫描,再用Volatility 2做深度分析,两个工具交给我的结果一致时,才认为这个结论可靠。

如果有图形化操作需求,Volatility Workbench可以作为Volatility 2的GUI前端,内存镜像一拖进去就能选Profile和插件,对不熟悉命令行的人友好很多。

5.3 自动化提取脚本的取舍

处理大量PCAP时,我一般会写一个Python脚本,用pyshark或者scapy来做自动化提取。核心逻辑是:读文件→按IP和功能码过滤→输出CSV。但这里有一个陷阱,用scapy加载非常大、成千上万条的PCAP时,内存占用会爆炸,导致解析速度极慢。如果文件太大,建议直接用tshark的命令行过滤输出CSV,或者用数据库分段存储,不要试图一次全量加载。

有经验的取证人员会把“尽量少改动原始数据”作为原则。任何转换、提取、过滤操作都在副本上进行,原PCAP永远保留一份不加任何处理的版本,并计算哈希归档。这条习惯帮我避免过好几次麻烦——有一次分析到一半发现自己的过滤脚本有个bug,如果原始副本被覆盖了,整个报告就得推倒重来。

6. 写在最后的实操体会

说实话,Modbus协议本身的技术含量不算高,真正难的是把它放到真实工业场景里理解。进到现场你会遇到掉线的从站、乱写的寄存器地址、奇怪的自定义功能码,还有那些打着“保密”旗号不给你寄存器映射表的设备厂商。这时候光会背协议格式是不够的,你得能跟产线老师傅聊清楚工况,再结合抓包结果判断“这是故障还是人为”。

我个人在实际操作中最常用的方法,是先在测试环境搭一套与现场一致的Modbus环境,用模拟从站接受数据,再用PCAP里的真实报文逐条回放,观察哪些命令会被重放出来、哪些会被从站拒绝。这个方法在多个项目里帮我缩小了嫌疑范围。

最后再分享一个小技巧:做Modbus取证时,最好把每次采集的时间、地点、设备、采集工具版本记录下来,哪怕是随手记在手机备忘录里。因为很多案件或审计项目在几个月后才会展开质证,届时如果没有这些原始记录,拿到手的PCAP就像没有来源的孤证,说服力大打折扣。

Modbus协议的取证是一个典型的“懂协议才懂攻击、懂攻击才懂取证”的领域。把每一个功能码、每一段字节序、每一条异常响应都吃透,再配合流量、内存、USB日志的交叉验证,面对大多数工业现场安全事件你都能理出头绪。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/20 15:42:55

如何高效阅读招股说明书?以光迅科技为样本的拆解指南

简介:光迅科技首次公开发行股票招股说明书PDF,面向证券投研、行业分析及金融教学场景,适合需要上市公司原始披露文件的投资者、研究员与学生,尤其适用于光电行业公司IPO案例研究。压缩包内为单份PDF电子书,共1个文件&a…

作者头像 李华
网站建设 2026/9/20 15:41:55

chezmoi Keeper 模板函数详解:在模板中安全获取 Keeper 密钥数据

chezmoi Keeper 模板函数详解:在模板中安全获取 Keeper 密钥数据 【免费下载链接】chezmoi Manage your dotfiles across multiple diverse machines, securely. 项目地址: https://gitcode.com/gh_mirrors/ch/chezmoi keeper、keeperDataFields 与 keeperFi…

作者头像 李华
网站建设 2026/9/20 15:40:30

PL-300备考指南:一套练习数据通关Power BI实操

简介:微软商业智能PL-300认证练习数据包,面向备考PL-300认证的开发者、数据分析师以及希望提升数据可视化能力的职场人士。资源源于官方练习场景,覆盖数据连接、数据清洗、数据建模、DAX表达式、交互式报表、仪表板开发和行级安全性等核心考点…

作者头像 李华
网站建设 2026/9/20 15:39:49

CentOS 7下mitmproxy部署与系统集成指南

1. 环境准备与依赖安装在CentOS 7系统上部署mitmproxy前,需要确保基础环境完备。我推荐使用Miniconda作为Python环境管理器,它能有效解决多版本Python和依赖隔离的问题。以下是具体操作步骤:1.1 系统基础依赖安装首先更新系统并安装编译工具链…

作者头像 李华