资讯动态

Modbus协议取证实战:从流量分析到内存痕迹排查

发布时间:2026/9/14 3:31:11 来源:尧图企业网站定制
记不清具体是从哪一天开始我的日常工作里就离不开Modbus了。做了几年安全事件处置和电子数据取证尤其是接触工控环境之后我愈发确认一个事实在工业控制系统领域Modbus协议就像国民级基础设施一样无处不在。水处理厂、变电站、楼宇自控、生产车间的PLC、HMI、电表、传感器几乎都能看到它的身影而且很多设备一跑就是十几年不换。但恰恰是这样一个承载着核心生产业务的协议在设计之初几乎没有考虑任何安全问题。它有清晰的帧结构、完善的功能码体系但没有任何认证、加密或权限控制。谁在网络里能碰到它谁就能直接读写寄存器。对做安全的人来说理解Modbus协议是基本功能不能在事件发生后把Modbus流量、主机痕迹、内存镜像里的线索串成一条可信的证据链才是真正拉开差距的地方。这篇笔记是我自己学习Modbus协议及取证方法的完整记录。我会从协议本身的结构讲起到流量抓包分析、内存取证、主机痕迹排查再手把手带你把Modbus Poll和Modbus Slave搭成一套可复现的实验环境。适合刚接触工控安全的入门者也适合正在准备安全事件处置、电子数据取证相关工作的朋友做参考。1. Modbus协议核心知识拆解1.1 为什么是Modbus工业现场的事实标准Modbus诞生于1979年最初是Modicon后来的施耐德电气为其PLC产品设计的一种串行通信协议。让我印象最深的是它的开放策略协议规范完全公开任何厂商、任何开发者都可以免费使用和实现。在那个工业总线群雄并起的年代这一招直接让Modbus成了事实标准。它之所以能延续到今天在我看来有三点原因实现简单。整个协议的核心就是地址、功能码、数据、校验这几个部分一个8位单片机就能跑起来。硬件成本低。基于RS-232、RS-485或者以太网就能工作其中RS-485两线制可以挂32个从站组网成本很低。生态成熟。从PLC、仪表到组态软件几乎所有工控设备都内置了Modbus支持。需要强调的是Modbus的普及度本身就是一个安全劣势。攻击者不需要学习私有协议只要会用Wireshark抓包再对照公开的Modbus协议文档就能直接构造恶意报文。做过工控安全评估的朋友应该都有体会现场扫一圈用Modbus功能码03读一下保持寄存器设备状态全暴露了——没有任何阻拦。1.2 Modbus RTU与Modbus TCP的帧格式拆解Modbus协议在传输层上可以分为两种最常见的变体基于串行链路的Modbus RTU和基于以太网的Modbus TCP。两者的数据模型是一致的但帧封装方式完全不同。Modbus RTU帧格式如下从站地址1字节取值范围0-2470为广播地址1-247为从站地址。功能码1字节指示要执行的操作。数据N字节具体数据内容根据功能码而定。CRC16校验2字节对前面所有字节做循环冗余校验。RTU有一个特殊要求每帧之间必须保持3.5个字符时间的静默间隔。这个间隔如果太短接收方会认为是一帧连续数据太长则会判断为帧超时。实际调试串口时这个时序问题很容易踩坑尤其是用USB转串口线的时候延迟不稳定会导致经常性通信失败。Modbus TCP帧则在RTU基础上增加了一个MBAP头事务处理标识符2字节用于匹配请求和响应。协议标识符2字节Modbus固定为0x0000。长度字段2字节表示剩余字节数。单元标识符1字节等同于RTU的从站地址用于网关转发时标识最终从站。功能码1字节和数据N字节与RTU一致。Modbus TCP默认使用502端口这也是取证时最重要的流量特征之一。RTU帧里的CRC16在TCP帧中不再需要因为TCP本身有校验和与可靠传输机制MBAP头里的长度字段也解决了粘包分包问题。理解这个区别对抓包分析很有用你看TCP流的时候不要继续找CRC字节否则会把响应末尾的多余数据误认为负载。1.3 常用功能码与识别特征Modbus的功能码整体分为位操作和字操作两大类。做取证时我习惯先快速判断流量中的功能码立刻知道攻击者或异常操作者在做什么功能码名称操作对象取证关注点01读线圈输出位查看设备状态02读离散输入输入位查看外部开关量03读保持寄存器输出寄存器最常见的读操作04读输入寄存器输入寄存器读取模拟量数据05写单个线圈输出位单点启停控制06写单个寄存器保持寄存器修改单个参数0F15写多个线圈输出位批量启停控制1016写多个寄存器保持寄存器批量参数修改从取证角度写操作功能码05、06、0F、10是重中之重。攻击者如果想破坏或篡改工控过程绝大多数情况下是通过写功能码下发的。我在实际分析中会先用Wireshark过滤modbus.func_code 16看看有没有批量写寄存器的行为再结合时间判断是否异常。2. 取证视角下的Modbus痕迹体系2.1 流量层面的痕迹Modbus取证最直接的证据来源就是网络流量。在工控现场流量抓取点一般选择交换机的镜像端口、工业防火墙的旁路接口或者在网关设备上做流量复制。Modbus TCP流量特征非常明显固定源或目的的502端口、MBAP头中协议标识符为0、长度字段合理、数据区不含标准文件头。用Wireshark打开pcap文件如果大量出现Modbus/TCP协议标识基本可以确定这是工控网络流量。流量层取证的关注点包括谁在主动连接502端口。通常主站是固定的上位机IP一旦出现陌生IP发起扫描就要重点关注。谁在超大批量读取寄存器。这可能是扫描行为攻击者想快速获取全部点位状态。谁在非工作时间执行写操作。凌晨两三点对PID参数做修改这个时间点本身就说明问题。是否存在功能码错误响应。比如从站返回异常码02非法数据地址可能说明攻击者在盲目探测寄存器区间。Wireshark里的Statistics - Conversations可以快速统计通信双方的连接数、包数和字节数。我一般会先看端口502的会话列表找出通信量最大的IP对然后再深入追踪流。2.2 主机与内存层面的痕迹工控环境中有大量Windows主机例如工程师站、HMI、数据采集服务器。这些主机上运行着组态软件、OPC客户端、Modbus Poll等测试工具一旦发生安全事件主机上的痕迹往往比流量还丰富。主机痕迹主要包括进程信息正在运行或历史上运行过的进程特别是Modbus相关工具。网络连接进程对应的TCP连接恢复出远端IP和端口。工程文件组态软件的工程目录中可能保存着点位表、脚本程序。日志记录Windows事件日志、PowerShell操作日志、RDP登录记录。注册表与启动项自启动程序、服务配置。如果现场情况不允许直接操作原机或者主机已经关机就需要做内存取证。内存镜像里保存着进程、网络连接、命令输入等大量瞬态信息。Volatility中的netscan插件就是专门用来扫描内存镜像中网络连接对象的它可以恢复出进程对应的本地地址、远端地址、连接状态和PID这是我在内存取证中使用频率最高的插件之一。2.3 现场设备与日志痕迹PLC本身一般没有日志功能尤其老型号的Modbus从站设备你把它重启一下内部寄存器状态就全部恢复默认了。所以要取PLC里的当前值必须在设备断电前通过上位机读取。这个操作要非常谨慎因为连接PLC读寄存器也有可能导致某些程序逻辑变化最好在工艺窗口期操作。现场真正有价值的日志痕迹包括上位机历史数据库。很多数据采集系统会把实时数据存入数据库包含点位值变化的时间戳能复原案发前后的状态变化。HMI操作记录。部分HMI软件有操作审计记录了操作员点击了哪些按钮、切换过哪些画面。DCS或SCADA系统的报警事件记录通常是Event Log形式。边缘网关的转发日志记录了对下Modbus轮询和对上MQTT/OPC UA转发的情况。3. 搭建Modbus取证实验环境3.1 工具选型与许可说明要学习Modbus协议分析和取证光看书是不够的必须动手搭一套环境自己抓包看帧。最常用的模拟工具是Modbus Poll主站模拟和Modbus Slave从站模拟。一个充当上位机不停读数据一个充当PLC响应请求中间用Wireshark抓包整个过程清晰直观。这里要特别说明一下工具授权问题。Modbus Poll和Modbus Slave官方提供评估版本可以正常使用大部分功能但评估版有使用时间限制比如21天后需要注册。网上流传的各种注册码和破解文件我完全不建议使用——首先法律风险不言而喻其次工控环境中工具一定要可控可信从非官方渠道下载的软件本身就可能携带恶意代码。如果你需要长期使用可以向官方购买授权价格并不离谱。如果不想花钱也有不错的免费替代方案Modpoll命令行工具简单直接的Modbus主站请求工具。Python的pymodbus库和minimalmodbus库可以自己写脚本模拟任意主站和从站行为。谷哥的Eximo已经不再更新或FreeModbus开源协议栈可以自己编译一个从站。Wireshark自带modbus解析器抓包分析不用额外付费工具。我的建议是初学者先用Modbus Poll/Slave评估版入门因为图形界面直观配置参数可以点选能帮你快速理解主从交互流程。后面写自动化分析脚本时再用pymodbus。3.2 主从站连接配置实操第一步准备环境。一台Windows电脑安装Modbus Poll、Modbus Slave和Wireshark。如果只有一台电脑可以通过Modbus Poll连接本机的Modbus Slave走TCP回环地址127.0.0.1或者走虚拟串口对。第二步配置Modbus Slave为从站。打开软件后选择Setup - Slave Definition或直接点击新建关键配置如下Slave ID默认填1表示从站地址。Function选择03读保持寄存器。Address起始地址填0Quantity填10读10个寄存器。View选择Word或Hex格式显示寄存器值。我在从站里手动设置几个有含义的寄存器值比如地址0为温度100.5地址1为压力2.34方便后面抓包时对照数据。第三步配置Modbus Poll为主站。打开软件后选择Connection - Connect连接方式选TCP/IP填入127.0.0.1和502端口如果走串口就选RTU填串口号、波特率9600、数据位8、停止位1、无校验。然后设置读寄存器Slave ID1。Function03。Address0。Quantity10。点击OK后如果一切正常Modbus Poll的主界面会显示从站返回的10个寄存器值并且按设定的轮询周期自动刷新。这一步连不通时常见的报错是Connection failed原因多半是从站ID不一致、端口被占用或Windows防火墙拦截了502端口的入站连接。第四步启动Wireshark抓包。选择回环接口或者实际使用的物理网卡设置过滤条件tcp.port 502 || modbus然后让Modbus Poll和Slave跑几秒。你会在抓包列表里看到大量的Modbus/TCP协议包。3.3 流量抓取与理解打开一个请求包展开Modbus协议层你能看到非常清晰的层次结构。比如请求包中MBAP头包含事务ID、协议ID、长度随后是单元ID、功能码03、起始地址0x0000、寄存器数量0x000A。响应包则会返回字节计数和寄存器数据例如Byte Count: 20后面跟20个字节的数据换算成10个16位寄存器值。把响应数据和Modbus Slave界面里的寄存器值对照你会发现完全一致这就是最能加深印象的一次练习。我通常会保留这套实验拓扑作为后续取证练习的基础。需要模拟攻击行为时可以让Modbus Poll对从站执行写操作功能码06或16把正常的寄存器值篡改掉同时在Wireshark中记录全过程。这样你就有了一个完整的、含恶意操作的pcap样本。4. Modbus流量取证实战分析4.1 关键过滤表达式在流量取证中Wireshark过滤表达式的熟练程度直接影响效率。下面是我常用的一组Modbus过滤语句modbus显示出所有Modbus协议包。tcp.port 502按端口过滤抓取Modbus TCP通信。modbus.func_code 3只看功能码03的读保持寄存器请求。modbus.func_code 16只看功能码16的写多个寄存器请求。modbus.func_code 6只看功能码06的写单个寄存器请求。modbus.exception_code只看异常响应的包。modbus modbus.word_cnt 100筛选出读取或写入寄存器数量超过100的包可能是扫描行为。如果需要更复杂的分析可以用tshark命令行。例如统计pcap中所有Modbus功能码的分布tshark -r capture.pcap -Y modbus -T fields -e modbus.func_code | sort | uniq -c统计完成后你能看到整个流量中以读功能码03为主还是混入了大量写功能码。正常轮询场景下读操作远多于写操作如果写操作比例明显偏高就要重点溯源了。4.2 从流量还原攻击行为讲一个我在实际项目中处置过的典型场景。某生产车间的上位机报出多台仪表数据跳变运维人员怀疑是PLC遭受干扰。拿到工控交换机镜像口的pcap后我先做了一次整体功能码统计发现一个从未见过的IP 192.168.1.101频繁访问多个从站设备的502端口并且使用了大量功能码06去写单个寄存器。对比正常上位机192.168.1.10的行为规律完全不同正常上位机是每隔500毫秒轮询一次功能码只有03和04异常IP则是随机间隔发起连接而且每次连接都执行写操作。接下来用Wireshark的Follow - TCP Stream功能追踪其中一条完整的写操作流可以看到异常IP把仪表内部地址0x0001的寄存器从0x0064改成了0x0000。结合设备手册查0x0001地址对应的是量程上限参数基本可以断定这是一次蓄意的参数篡改。处理这种样本时我固定会做以下动作记录关键包的时间戳精确到毫秒。导出异常IP的所有数据包为单独pcap保留原始证据。用capinfos计算pcap的统计信息记录包数、起止时间、文件哈希值作为证据链完整性的一部分。截图保存Wireshark中的过滤结果和字段展开情况方便写报告。4.3 一个完整的分析样本假设你拿到一个pcap里面有一段写操作。以功能码16写多个寄存器为例一个典型的构造如下请求包事务ID 0x1234协议ID 0长度 15单元ID 1功能码 16起始地址 0x0000寄存器数量 0x0002字节计数 04数据 AABB CCDD。响应包事务ID 0x1234协议ID 0长度 6单元ID 1功能码 16起始地址 0x0000寄存器数量 0x0002。取证分析时我会把请求包和响应包放在一起看确认一次成功的写操作。关键信息提取出来如下源IP、目标IP。源端口、目标端口通常是502。事务ID用于匹配请求/响应对。起始地址和寄存器数量精确到被篡改的数据地址范围。写入的原始数据从字节中还原出十进制或浮点值。时间戳事件发生时间。有了这些要素加上从站设备那边的日志或历史数据库我就能基于时间线把一个写操作讲出完整的上下文。比如凌晨2点15分23秒456毫秒IP 192.168.1.101向PLC发送功能码16写请求起始地址100的2个寄存器被改为0x0000随后历史数据库中温度值开始异常间隔约3秒这个改动生效导致设备跳停。5. 内存取证与主机痕迹排查5.1 Volatility netscan内存取证在事件处置中内存镜像的价值非常高。很多恶意行为在主机运行期间只存在于内存中关机后就会消失。工控主机特别典型工程师站的组态软件、临时打开的Modbus Poll工具、可能残留的远程连接都可以从内存镜像中找到痕迹。推荐的内存采集工具是FTK Imager或DumpIt前者可以图形界面采集并同时计算哈希值后者适合现场快速制作内存镜像。在工控现场执行内存采集时要注意尽量通过只读方式接入移动硬盘避免在目标主机上安装额外驱动造成污染。拿到内存镜像后用Volatility2分析。首先确认系统profilevolatility -f mem.dmp imageinfo确认profile为Win7SP1x64或Win10x64_19041等之后运行netscan插件volatility -f mem.dmp --profileWin7SP1x64 netscan输出中有几个关键字段Proto表示TCP/UDPLocal Address和Foreign Address是连接的五元组State是ESTABLISHED、LISTEN、CLOSE_WAIT等状态PID和Owner指明了连接归属进程。我在分析时会把输出结果导入Excel或直接复制到文本文件然后筛选出Foreign Address为内网工控网段的连接特别是502端口的连接。一个常见的发现是某个工程师站进程残留着一个ESTABLISHED状态的连接而远端IP在流量里已经找不到了这说明攻击者可能远程连接过后台并且痕迹已经断开。进程信息方面可以配合pstree插件查看进程父子关系看Modbus Poll是不是被其他进程启动的。另外如果你在流量取证时发现通信对端的IP在内存里查不到进程不要急着下结论。TCP连接最终是绑定到进程的netscan输出的Owner字段对应的就是创建该连接对象的进程。结合pslist得到进程的可执行路径能进一步确认是哪个软件建立的连接。5.2 Windows主机痕迹排查流程Windows主机的痕迹排查是事件处置的常规动作。我通常按照以下顺序操作确保覆盖主要痕迹点第一步采集系统基本信息。命令如下systeminfo net user tasklist /v netstat -anowmic process get ProcessId,ParentProcessId,ExecutablePath,CommandLine第二步检查网络连接和可疑进程。结合netstat -ano中的PID可以在任务管理器或wmic中定位是哪个进程在监听502端口。如果现场不允许GUI操作可以用PowerShellGet-Process -Id PID | Format-List *第三步排查自启动和服务reg query HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run reg query HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Run Get-Service | Where-Object {$_.Status -eq Running} Get-ScheduledTask | Where-Object {$_.State -ne Disabled}第四步检查日志。重点看Windows事件日志中的登录类型3网络登录、登录类型10远程交互式以及PowerShell的日志。Get-WinEvent -FilterHashtable {LogNameSecurity;Id4624,4625} | Select-Object TimeCreated,Message Get-WinEvent -FilterHashtable {LogNameMicrosoft-Windows-PowerShell/Operational} | Select-Object TimeCreated,Message第五步查看最近打开的文档、下载记录和USB设备使用记录。Modbus相关工具有时候是运维人员用U盘拷进去的USB记录往往能反映文件来源。5.3 工控主机排查的特殊注意事项工控主机的排查和普通办公网主机有本质区别。办公网的Windows可以随便跑全盘杀毒、深度扫描但工控主机上可能运行着关键组态软件任何额外驱动、网络扫描都可能干扰PLC通信导致生产事故。在这方面我踩过一次坑此后都坚持以下原则先镜像、后分析。能采集内存镜像就采集能在测试环境里分析就不要在目标机上反复执行命令。分析命令尽量使用只读工具避免安装可能有冲突的驱动。如果必须实时查看进程或网络连接优先使用系统自带命令如tasklist、netstat不要额外安装第三方安全软件。工控主机的取证时间窗要尽量短避免业务中断太久。时间线对齐时要考虑现场设备的时钟漂移。PLC、HMI、上位机的时间可能相差几分钟甚至更久我一般会在取证时记录每台设备的本地时间和UTC偏移后续统一换算。6. 常见问题与避坑指南6.1 常见问题速查表我整理了一张问题排查表涵盖我学习Modbus取证实操时遇到最多的几个问题问题描述可能原因解决办法Wireshark抓不到Modbus TCP包接口选错或过滤条件过严确认网卡和抓包点过滤放宽为tcp.port 502Modbus Poll连接不上Slave从站ID不一致、端口错误核对Slave ID、端口号检查Windows防火墙串口RTU通信失败波特率、校验位不一致主从站配置必须完全一致确认USB转串口驱动正常功能码显示UnknownWireshark版本旧或私有功能码升级Wireshark查阅设备手册确认功能码请求能发出但无响应从站地址被占用或轮询间隔太短检查从站列表增加轮询间隔netscan没有任何结果profile选择错误重新用imageinfo确定profile内存镜像分析时插件失败镜像不完整或加密重新采集确认采集工具没问题pcap时间序列混乱各设备时钟不同步记录各设备时钟偏移统一换算为UTC6.2 实操避坑经验第一现场取证时抓流量优先于动主机。我在工控环境里的习惯是先想办法在交换机镜像口或网关旁路抓一份长期流量再上主机做静态分析。流量是客观的CPU再高也不会丢失已经抓下来的数据。主机一旦操作很多东西就被改了比如进程列表的瞬态、网络连接的实时状态你敲下netstat那一下某些不断开连接就消失了。第二Modbus Poll/Slave的工程文件里可能藏着操作记录。很多人不知道Modbus Poll的配置信息会保存在.mbp文件里里面记录了连接的目标IP、端口、从站ID、功能码、起始地址、寄存器数量。这些信息在排查异常连接时很有价值我曾在最紧急的处置中靠一个.mbp文件锁定了攻击者利用过的Modbus映射点。第三取证必须保证证据链完整性。每采集一个镜像、一个pcap第一时间计算SHA256哈希并记录在案。报告里写清楚采集时间、采集人、采集工具版本这能省掉后面很多口径拉扯。第四不要把流量取证和内存取证割裂开。一次完整的取证结论往往是先通过流量看到写操作再到内存里找到执行写操作的进程再到主机日志里找到进程启动的路径或RDP登录记录最后形成一条完整的时间线。单一维度的证据说服力有限。最后再分享一个小体会我学习Modbus取证的初衷其实很朴素工控现场的资料少很多老师傅只懂设备正常运行一出安全事件就手足无措。后来经历了几个真实项目我才发现这套老协议的取证工作量大头不在协议本身而在如何把散落在流量、内存、主机、设备里的线索串成证据链。现在每当我拿到一份新的pcap或内存镜像都会习惯先整理一下时间线再开始分析这个习惯帮我省了很多事。Modbus这个协议恐怕还会在工业现场活跃很多年与其抱怨它不安全不如把它的每一个字节、每一个功能码都研究透。希望这篇笔记能让你少走几个弯路。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价