从Wireshark抓包到Modbus协议分析:实战解析工控流量中的隐藏数据
1. 项目概述一次从实战出发的工控协议分析之旅最近在复盘一些网络安全竞赛的题目其中一道来自CISCN2023的题目让我觉得特别有教学意义。它没有复杂的漏洞利用也没有高深的逆向工程而是聚焦在一个非常基础但又极其重要的领域工控协议流量分析。题目以Modbus协议为载体要求选手从Wireshark抓包文件中通过过滤和协议解码最终找到一个隐藏的Flag。这恰恰是很多刚接触工控安全或网络分析的新手最需要掌握的“硬功夫”。很多人一听到Modbus、Wireshark就觉得头大觉得这是资深工程师的领域。其实不然只要掌握了正确的分析思路和工具技巧新手完全可以从零开始一步步解开谜题。这道题就是一个完美的切入点它串联起了Wireshark过滤语法、Modbus协议结构解析和Base32编码识别与解码这几个关键技能点。通过复现这道题的解题过程我希望不仅能带你找到那个Flag更能让你建立起一套处理类似网络协议分析问题的通用方法论。无论你是网络安全爱好者、工控领域的新人还是对数据包分析感兴趣的学生这篇内容都将为你提供一条清晰、可操作的路径。2. 核心需求与工具准备我们到底要解决什么问题在深入抓包文件之前我们必须先明确目标。这道题的核心需求非常明确从一个可能包含大量冗余流量的抓包文件.pcapng格式中定位到与Modbus协议相关的特定数据包并从中提取出经过编码的关键信息最终解码获得Flag。这个过程可以分解为三个子任务第一从海量数据中快速筛选出目标协议Modbus的流量第二理解Modbus协议的数据单元结构找到承载有效数据的部分第三识别数据的编码方式本题为Base32并进行正确解码。工欲善其事必先利其器。我们需要的工具很简单Wireshark网络协议分析的事实标准。请务必从官网下载最新稳定版安装过程一路下一步即可。对于新手我建议在安装时勾选所有组件特别是NpcapWindows下的抓包驱动这是Wireshark能抓到网卡流量的基础。文本编辑器或IDE用于查看和整理解码前后的文本信息如VS Code、Notepad等。Python环境或在线解码工具用于执行Base32解码。Python内置了base64模块使用起来非常方便。如果不想写代码也有很多可靠的在线Base32解码网站可供临时使用。注意在真实工控环境或竞赛中拿到的抓包文件可能来自任何网络环境。第一步永远是在隔离的虚拟机或专用分析环境中打开文件切勿在生产机或存有敏感信息的个人电脑上直接分析未知流量这是最基本的安全操作规范。3. 初探流量使用Wireshark加载与初步观察拿到抓包文件假设名为ciscn2023_modbus.pcapng后用Wireshark打开。主界面通常分为三大部分顶部的数据包列表、中部的协议分层详情、底部的原始数据字节流。首先我们不做任何过滤直接浏览数据包列表。你可能会看到成千上万个数据包协议类型五花八门比如TCP、HTTP、TLS、ARP等等。我们的目标是Modbus它是一种应用层协议通常运行在TCP/502端口或作为串行链路协议RTU/ASCII。在工控网络尤其是模拟赛题环境中Modbus over TCPModbus/TCP更为常见。此时一个高效的技巧是查看Wireshark的“协议”列。如果该列没有显示可以在列表栏右键点击选择“列”然后添加“Protocol”列。快速滚动寻找显示为“MODBUS”的数据包。如果找到了记下它的特征比如目的端口是不是502。如果数据包太多看不清我们就需要祭出Wireshark的核心功能之一显示过滤器。4. Wireshark过滤语法精讲精准定位目标数据显示过滤器Display Filter是Wireshark的“搜索引擎”它允许我们根据几乎任何条件筛选数据包而不会修改原始文件。对于新手掌握几个最常用的过滤语法足矣应对大部分场景。4.1 基于协议的过滤这是最直接的过滤方式。在过滤器栏输入modbusWireshark会只显示协议栈中包含Modbus协议的数据包。如果过滤后没有任何显示可能的原因有1确实没有Modbus流量2Modbus运行在非标准端口上。对于第二种情况我们可以尝试基于端口过滤。4.2 基于端口的过滤Modbus/TCP的官方指定端口是502。我们可以过滤TCP端口号tcp.port 502或者更精确地过滤目标端口为502的流量通常是客户端发给Modbus服务器的请求tcp.dstport 502也可以过滤源端口为502的流量服务器响应tcp.srcport 502有时题目可能会将Modbus服务部署在其他端口以增加隐蔽性。如果你用modbus和tcp.port 502都过滤不出东西一个办法是观察哪些TCP会话在频繁地进行“请求-响应”式通信数据包长度规律然后尝试过滤该端口。4.3 基于数据包内容的过滤进阶Modbus协议数据包中从TCP载荷开始其结构是事务标识符2字节 协议标识符2字节Modbus为0x0000 长度字段2字节 单元标识符1字节 功能码1字节 数据。 如果我们想筛选执行了特定操作的数据包比如“写单个寄存器”功能码06或“读保持寄存器”功能码03可以使用modbus.func_code过滤器。modbus.func_code 0x03在本题的上下文中Flag信息很可能被写入或读出寄存器因此关注读写寄存器的功能码03, 06, 10, 16等是关键。4.4 组合过滤过滤器支持逻辑运算符如and与、or或、not非。例如我们想查看所有发往Modbus服务器端口502的“写寄存器”请求tcp.dstport 502 and modbus.func_code 0x06掌握这些过滤语法你就能像使用搜索引擎一样在数据包的海洋中快速定位到感兴趣的“岛屿”。在本题中我们首先尝试modbus或tcp.port 502应该能立刻将数据包数量从数万减少到几十或几百个大大降低了分析难度。5. Modbus协议关键字段解析数据藏在哪里过滤出Modbus数据包后我们需要读懂它。点击一个Modbus数据包在中部详情窗格中展开“Modbus”协议层。你会看到类似下面的结构Transaction Identifier: 事务ID用于匹配请求和响应。Protocol Identifier: 协议IDModbus为0。Length: 后续字节的长度。Unit Identifier: 从站地址Slave ID。Function Code: 功能码这是核心定义了操作类型如 03: 读保持寄存器 06: 写单个寄存器 10: 写多个寄存器。Data: 具体的数据内容其格式由功能码决定。对于这道题Flag很可能隐藏在Data字段中。但Flag通常是一串可读的字符串而Modbus寄存器存储的是16位2字节无符号整数。那么字符串如何存储呢常见的方式有两种ASCII码直接存储每个寄存器存两个ASCII字符高字节和低字节。例如字符串“AB”的ASCII码是0x41和0x42可能存储在一个寄存器值为0x4142。编码后存储先将Flag用Base32、Base64等编码成纯ASCII或十六进制字符串再将编码后的每个字符或字节存入寄存器。如何判断我们需要查看Data部分的原始字节。在Wireshark底部“数据包字节”窗格选中Modbus数据部分对应的十六进制字节观察其内容。如果看到像66 6c 61 67 7b对应ASCII “flag{”这样的规律字节可能是直接存储。如果看到一串由A-Z、2-7、组成的字符Base32特征或者A-Z、a-z、0-9、、/组成的字符Base64特征那就是编码后存储了。在本题中根据题目提示和常见出题思路我们需要关注写寄存器Function Code 06 或 16的请求包因为出题人可能模拟了向寄存器写入Flag编码数据的过程。或者关注读寄存器Function Code 03的响应包因为可能模拟了从寄存器读取Flag的过程。我们需要在过滤后的数据包中逐个检查这些数据包的Data字段。6. 实战演练从过滤到发现编码数据假设我们使用modbus过滤器后得到了50个数据包。通过观察功能码我们发现其中有一系列连续的“写多个寄存器”Function Code 16 十进制22请求。这非常可疑因为写入大量数据正是隐藏信息的常用手段。我们选中其中一个功能码为16的请求包在详情面板中找到Data字段。在“数据包字节”窗格对应数据部分的十六进制显示可能如下示例00 01 00 10 4e 47 4a 58 65 4f 4e 42 47 6c 59 57 35 30 49 47 46 75 5a 47 55 67 55 32 39 75 64 57 31 6c 49 47 35 68 62 57 55 67 55 33 52 76 64 47 46 73 5a 41 3d 3d这看起来不像直接的ASCII文本。我们将其转换为ASCII字符看看可以在Wireshark中右键点击十六进制部分选择“复制”-“...作为Hex Stream”然后借助外部工具转换或用Python脚本。转换后发现它是一串像NGJXeONBGlYW50IGFuZGUgU29tZSBWYXJpYWJsZVN0cmluZz的字符串。仔细观察这串字符字符集范围主要是大写字母A-Z和数字2-7末尾有等号。这是Base32编码的典型特征Base32编码表使用A-Z和2-7共32个字符编码后的数据长度通常是8的倍数不足部分用填充。至此我们完成了关键一步通过Wireshark过滤定位到可疑的Modbus写数据包并从其数据载荷中识别出一段Base32编码的字符串。7. Base32解码原理与实操还原隐藏信息Base32是一种用32个可打印字符A-Z, 2-7表示二进制数据的编码方式。每5个字节40位的二进制数据被分成8组5位每组5位值范围0-31映射到一个编码表字符。解码是其逆过程。我们不需要手动计算使用工具即可。最推荐使用Python因为它精准且可离线操作。7.1 使用Python解码打开Python解释器或创建一个.py文件。import base64 # 这是我们从Wireshark中提取的Base32编码字符串示例 encoded_str NGJXeONBGlYW50IGFuZGUgU29tZSBWYXJpYWJsZVN0cmluZz # Base32解码 try: # base64.b32decode 会自动处理末尾的等号填充 decoded_bytes base64.b32decode(encoded_str) # 将解码后的字节转换为字符串假设是UTF-8文本 decoded_str decoded_bytes.decode(utf-8) print(解码后的字符串:, decoded_str) except Exception as e: print(解码出错:, e)执行这段代码输出很可能就是我们要找的Flag格式可能为flag{...}或FLAG{...}。7.2 解码过程中的注意事项字符集问题Base32标准编码表是大写A-Z和数字2-7。但有些变种如Crockford‘s Base32会使用不同的映射或允许小写。Wireshark中提取的字符串通常是大写标准格式。如果解码失败首先检查字符串是否混入小写字母、数字0/1/8/9或特殊字符。必要时先进行upper()转换并剔除非法字符。填充等号是填充字符用于确保编码字符串长度为8的倍数。Python的base64.b32decode函数能自动处理填充。但如果手动去除填充解码时需要确保数据长度正确。提取完整性一个Flag可能被分割到多个Modbus数据包中。我们需要按照数据包的顺序参考Wireshark的No.序号或Modbus事务ID、寄存器地址将所有相关数据部分的Base32字符串拼接起来再进行整体解码。在本题中我们之前发现了一系列连续的“写多个寄存器”请求很可能每个请求的数据部分都包含一段Base32字符串需要按顺序拼接。8. 完整解题流程复盘与技巧总结让我们从头到尾梳理一遍这道题的理想解题路径打开文件宏观观察用Wireshark打开pcapng文件查看协议统计Statistics-Protocol Hierarchy快速了解协议分布确认Modbus协议存在。应用过滤缩小范围在显示过滤器栏输入modbus或tcp.port 502聚焦目标流量。分析协议定位数据在过滤后的数据包列表中根据Function Code排序或浏览重点关注功能码为06写单个寄存器、16写多个寄存器或03读保持寄存器的数据包。查看这些包的Data字段详情。识别编码提取字符串在数据包字节流中找到Modbus数据部分对应的十六进制将其转换为ASCII字符串。观察字符串是否具有Base32特征A-Z, 2-7, 。将可疑的字符串完整复制出来。如果数据分散在多个包按顺序拼接。执行解码获取Flag使用Python脚本或可靠的在线工具对提取出的Base32字符串进行解码。输出结果即为Flag。8.1 避坑技巧与心得技巧一善用Wireshark的“追踪流”功能。在某个Modbus TCP数据包上右键选择“追踪流” - “TCP流”Wireshark会重组这个TCP会话的所有数据并以ASCII和十六进制对照的形式展示。这能让你更清晰地看到完整的请求-响应对话更容易发现跨多个数据包的完整编码字符串。技巧二使用“导出分组字节流”。当你确定了一段包含编码数据的TCP载荷范围在字节流视图中选中可以右键选择“导出分组字节流”将其保存为二进制文件。然后用文本编辑器打开或者用Python以二进制模式读取后再进行解码操作避免复制粘贴过程中引入错误。技巧三注意字节序Endianness。Modbus协议本身使用大端序Big-Endian即高位在前。但有些设备或出题人可能会在小端序系统上生成数据。如果你发现解码后的字符串是乱码但看起来像是字节顺序错了比如“flag”变成了“galf”可以尝试将原始字节对调后再进行解码。在Python中可以用bytes(reversed(decoded_bytes))进行简单的字节反转尝试。心得工控协议分析耐心和细心往往比掌握高深技巧更重要。一道题目的突破口常常就藏在某个数据包某个字段的细微异常里。养成记录和假设的习惯比如“这个寄存器地址为什么跳变了”、“这个数据长度为什么不符合常规”并动手去验证是快速提升分析能力的不二法门。9. 举一反三Beyond the CTF – 真实场景中的Modbus分析CTF题目简化了场景但技能是相通的。在真实的工业控制系统安全评估或故障诊断中Modbus流量分析同样至关重要。9.1 安全审计中的应用异常指令检测过滤并检查所有非标准的Modbus功能码。标准功能码范围是1-127其中公共代码是1-64。如果出现超出范围或生僻的功能码可能意味着自定义功能或恶意指令。寄存器范围审计监控对关键控制寄存器例如控制电机启停的线圈、设置温度阈值的保持寄存器的写操作功能码05, 06, 15, 16。在正常工况下这些操作应有固定的模式或仅来自特定的主站Master。异常的写操作可能是攻击迹象。扫描与爆破识别攻击者可能对从站地址Unit ID或功能码进行扫描。在Wireshark中可以构造过滤器如modbus !(tcp.srcport 502)来查找所有非Modbus服务器端发出的Modbus请求即攻击者发起的扫描流量并观察其目标Unit ID和功能码的分布。9.2 故障排查中的应用通信超时与重传通过tcp.analysis.retransmission或tcp.analysis.ack_rtt过滤器可以查看是否存在TCP重传或高延迟的ACK这可能是网络拥堵或设备响应慢的表现。协议解析错误Wireshark的Modbus解析器非常成熟。如果某个数据包被标记为“Malformed Packet”畸形包或者协议树无法正确展开很可能数据包本身不符合Modbus协议规范可能是底层传输错误、设备固件bug或恶意篡改的结果。数据一致性检查对于读响应检查返回的字节数是否与请求中要求的寄存器数量匹配。例如请求读10个保持寄存器20字节响应数据长度字段应为232事务ID2协议ID2长度1单元ID1功能码1字节计数20数据如果不对则通信异常。掌握从CTF中练就的这套“过滤-定位-解析-解码”组合拳你就能在面对真实的、噪音更大的工控网络流量时保持清晰的思路快速定位到问题的核心。这不仅仅是解一道题更是培养一种解决实际问题的思维能力。