当前位置: 首页 > news >正文

CTFHub Modbus协议流量分析实战:从功能码到Flag提取

1. Modbus协议基础:工控系统的"快递员"

Modbus协议就像工业控制系统里的快递员,负责在不同设备之间传递数据。这个诞生于1979年的老牌协议,至今仍在工厂自动化、楼宇控制等领域广泛使用。我第一次接触Modbus是在某次工厂设备调试现场,看着PLC和传感器用这个协议默契配合,才明白它为什么能活这么久。

Modbus协议主要分为三种传输模式:

  • RTU模式:二进制格式,效率高但可读性差
  • ASCII模式:文本格式,效率低但可读性好
  • TCP模式:基于以太网传输,现代工控系统最常用

在CTF比赛中,我们最常见的是Modbus/TCP协议。它就像给传统Modbus套了个网络外套,协议结构特别简单:

  • 事务标识符(2字节)
  • 协议标识符(2字节,固定0x0000)
  • 长度字段(2字节)
  • 单元标识符(1字节)
  • 功能码(1字节)
  • 数据字段(变长)

其中功能码就像快递单上的操作类型,告诉设备该干什么。常见的有:

  • 01:读线圈状态(相当于读取开关量)
  • 03:读保持寄存器(读取模拟量)
  • 16:写多个寄存器(批量修改数据)

2. CTF中的Modbus流量分析:从抓包开始

拿到一个Modbus流量包(pcap文件),我习惯先用Wireshark快速浏览整体情况。打开文件后输入modbus过滤,所有Modbus协议报文就会乖乖排好队。这里有个小技巧:在Wireshark的"分析->专家信息"里,可以快速查看异常报文。

第一次分析时我犯过错误——直接扎进海量报文里找flag。后来发现应该先看统计信息:"统计->协议分级"能显示各功能码的使用频率。就像那次比赛,发现16号功能码(写多个寄存器)出现次数异常少,立刻锁定它为突破口。

用Python分析流量包时,pyshark库是我的首选工具。安装很简单:

pip install pyshark

基础分析脚本长这样:

import pyshark def analyze_modbus(pcap_path): cap = pyshark.FileCapture(pcap_path, display_filter='modbus') func_code_stats = {} for pkt in cap: if hasattr(pkt, 'modbus'): func_code = int(pkt.modbus.func_code) func_code_stats[func_code] = func_code_stats.get(func_code, 0) + 1 print("功能码统计:") for code, count in sorted(func_code_stats.items()): print(f"功能码 {code}: {count}次") analyze_modbus('modbus_ctf.pcap')

这个脚本会输出各功能码出现次数,帮你快速定位异常点。记得处理完要关闭文件捕获(cap.close()),不然文件会被占用。

3. 深度解析16号功能码:隐藏的flag通道

16号功能码(写多个寄存器)在正常工控系统中使用频率很低,但在CTF里往往藏着关键信息。它的协议结构很有特点:

  • 起始地址(2字节)
  • 寄存器数量(2字节)
  • 字节计数(1字节)
  • 寄存器值(N字节)

有次比赛我遇到个坑:题目把flag分段藏在多个16号功能码报文的寄存器值里,但每段数据都做了位移处理。当时差点错过,后来发现数据域的字节数异常多才反应过来。

提取16号功能码数据的进阶脚本:

def extract_16func_data(pcap_path): cap = pyshark.FileCapture(pcap_path, display_filter='modbus.func_code==16') suspicious_packets = [] for pkt in cap: if hasattr(pkt.modbus, 'data'): raw_data = pkt.modbus.data.raw_value # 寄存器值通常从第7字节开始 register_data = bytes.fromhex(raw_data.replace(':', ''))[6:] suspicious_packets.append(register_data) return suspicious_packets data_chunks = extract_16func_data('modbus_ctf.pcap') for i, chunk in enumerate(data_chunks): print(f"数据块{i+1}: {chunk.hex()}")

遇到加密数据时,可以尝试这些方法:

  1. Hex解码:直接转ASCII看看
  2. 位移操作:可能是简单的加减或异或
  3. 常见编码:Base64、URL编码等
  4. 频率分析:对二进制数据进行统计特征分析

4. Flag提取实战:从数据到flag的完整过程

去年一场比赛的真实案例让我印象深刻。题目给的Modbus流量包有2000+个报文,但只有3个16号功能码报文。用Wireshark过滤modbus.func_code==16后,发现数据域特别长:

0000: 00 01 00 00 00 09 01 10 00 01 00 02 04 41 42 43 0010: 44 58 59 5a

按照Modbus协议解析:

  • 00 01:事务ID
  • 00 00:协议ID
  • 00 09:长度
  • 01:单元标识符
  • 10:功能码(16进制表示16号功能码)
  • 00 01:起始地址
  • 00 02:寄存器数量
  • 04:字节数
  • 41 42 43 44:实际数据(ASCII是"ABCD")
  • 58 59 5a:可疑的额外数据("XYZ")

最终flag就藏在那些"多出来"的字节里。完整提取脚本如下:

import pyshark from binascii import unhexlify def extract_hidden_data(pcap_path): cap = pyshark.FileCapture(pcap_path, display_filter='modbus.func_code==16') hidden_parts = [] for pkt in cap: if hasattr(pkt.modbus, 'data'): raw_data = pkt.modbus.data.raw_value.replace(':', '') # 正常Modbus数据部分(前13字节是头部) modbus_data = raw_data[:26] # 13字节的16进制表示 # 可能隐藏的数据(从第14字节开始) extra_data = raw_data[26:] if extra_data: hidden_parts.append(extra_data) return ''.join(hidden_parts) hidden_hex = extract_hidden_data('modbus_ctf.pcap') flag = unhexlify(hidden_hex).decode('ascii') print("提取到的flag:", flag)

常见坑点提醒:

  1. 字节序问题:Modbus默认大端序,但题目可能用小端序
  2. 数据截断:Wireshark默认只显示部分数据,要检查包长度
  3. 干扰数据:正常工控数据可能和flag混在一起
  4. 编码陷阱:看起来像hex的数据可能是其他编码

5. 防御视角:从攻击手法看工控安全

站在蓝队角度分析这类题目特别有意思。正常工控系统里,16号功能码应该严格限制使用,因为:

  1. 它可以直接修改设备参数
  2. 没有默认认证机制
  3. 可能引发物理设备异常

有次企业渗透测试中,我们发现攻击者就是利用Modbus协议:

  1. 扫描识别502端口(Modbus默认端口)
  2. 发送16号功能码报文修改PLC参数
  3. 导致生产线温度控制器异常

防护建议:

  • 网络分段:隔离工控网络
  • 协议过滤:限制非常用功能码
  • 深度检测:监控寄存器值突变
  • 协议加固:使用Modbus Secure版本
# 简易Modbus流量监控脚本示例 def monitor_modbus_anomalies(pcap_path): cap = pyshark.LiveCapture(interface='eth0', display_filter='tcp.port==502') normal_func_codes = {1, 2, 3, 4} # 允许的功能码 for pkt in cap: if hasattr(pkt, 'modbus'): func_code = int(pkt.modbus.func_code) if func_code == 16: print(f"警告!检测到16号功能码报文: {pkt.frame_info.number}") elif func_code not in normal_func_codes: print(f"异常功能码 {func_code} 出现在报文 {pkt.frame_info.number}")

6. 工具链与进阶技巧

除了Wireshark和pyshark,这些工具也很实用:

  • ModbusPal:Java开发的Modbus模拟器
  • mbpoll:命令行Modbus客户端
  • Scapy:更底层的网络包操作

有次遇到加密的Modbus流量,我用Scapy写了自动化分析脚本:

from scapy.all import * from scapy.layers.modbus import * def decrypt_modbus(pcap): pkts = rdpcap(pcap) for pkt in pkts: if pkt.haslayer(ModbusADURequest): raw = bytes(pkt[ModbusADURequest]) # 简单的异或解密示例 key = 0xAA decrypted = bytes([b ^ key for b in raw]) print(f"原始: {raw.hex()} 解密后: {decrypted.hex()}") decrypt_modbus('encrypted_modbus.pcap')

进阶分析技巧:

  1. 时间序列分析:统计报文间隔时间,异常通信可能有规律
  2. 会话重组:跟踪同一TCP会话的多个请求响应
  3. 协议仿真:重放报文观察设备响应
  4. 模糊测试:修改正常报文进行异常检测

7. 从比赛到实战的经验之谈

打了这么多CTF,我发现工控协议题目的套路往往集中在:

  1. 异常功能码使用:非常用功能码藏数据
  2. 协议字段滥用:长度字段、保留字段藏信息
  3. 时序特征:特定时间间隔的报文可能触发flag
  4. 混合编码:Hex+Base64+反转等多种编码嵌套

有次真实项目里,我们分析生产线异常,发现就是有人误用了16号功能码批量修改参数。用Wireshark的"Follow TCP Stream"功能,直接还原了整个操作过程。这让我意识到,CTF里的技能真的能用在实战中。

最后分享个实用技巧:遇到复杂Modbus流量时,先导出JSON再处理会更灵活:

import json import pyshark def export_to_json(pcap_path, output_json): cap = pyshark.FileCapture(pcap_path, display_filter='modbus') result = [] for pkt in cap: pkt_data = { 'frame_num': pkt.frame_info.number, 'timestamp': pkt.sniff_time.isoformat(), 'func_code': int(pkt.modbus.func_code), 'data': pkt.modbus.data.raw_value if hasattr(pkt.modbus, 'data') else None } result.append(pkt_data) with open(output_json, 'w') as f: json.dump(result, f, indent=2) export_to_json('modbus_ctf.pcap', 'modbus_analysis.json')
http://www.jsqmd.com/news/647302/

相关文章:

  • 线性插值与Sinc插值的数学原理及实战
  • RuoYi-Plus(前后端分离)视频上传实战:从Vue3组件到SpringBoot后端的完整实现
  • STM32F4串口烧录实战:FlyMCU高效配置指南
  • 从一道CTF题看Python原型链污染:手把手教你用Flask靶场复现DSACTF EzFlask漏洞
  • LeetCode刷题 day10
  • ONNX模型转换实战:从PyTorch到TensorRT的完整优化指南
  • Ubuntu 20.04离线环境下的NFS服务部署与配置指南
  • OpenHarmony-L2开发全流程实战指南:从源码到应用部署
  • Git冷命令拯救崩溃现场:从灾难到重生的终极指南
  • 【生成式AI架构设计黄金法则】:20年架构师亲授5大避坑指南与3套可落地的高可用方案
  • ESP8266+Tasmota智能电表DIY:从硬件选型到Home Assistant接入全流程(附避坑指南)
  • 用Matlab搞定偏微分方程数值解:从Poisson方程五点差分到Gauss-Seidel迭代的保姆级实战
  • OpenCV形态学处理实战:用C++手搓腐蚀膨胀算法,对比库函数效果
  • 智能问数大模型调用的4种部署方式
  • 国民技术 N32WB031KEQ6-2 QFN-32 蓝牙模块
  • 招生数据看不明白?大数据分析让智慧招生平台帮你理清思路
  • 网吧 / 营业厅实名核验更严了,帮你合规
  • 3分钟搞定PDF找茬:diff-pdf视觉对比神器完全指南
  • 基于COMSOL的BIC本征态计算通用算法:直观出图,适用于多种场景,附论文研究链接
  • XXL-JOB调度中心集群部署实战:从编译到反向代理全流程解析
  • 如何快速掌握ESP-CSI技术:无线感知的完整入门指南
  • 【生死心法】别用 assert() 谋杀物理世界!撕碎软件异常的“停机幻觉”,论“失效安全”与硬件级绝对熔断
  • Cursor+Apifox MCP Server:智能接口自动化测试的实践与突破
  • ThreeJS实战:如何优雅地给3D模型添加点击弹窗(附完整代码)
  • Win10 LTSC 1809(Hyper-V)环境下Docker与CVAT的兼容性部署指南
  • Node.js 日志选型指南:Winston vs Log4js 全方位对比与实战
  • 揭秘Stable Diffusion 3.5企业级部署瓶颈:3类GPU资源浪费模式及实时优化方案
  • 人工智能技术生成对抗网络图像合成与风格迁移应用
  • 给Pixel4注入新灵魂:手把手教你定制Android 12内核,开启隐藏功能与性能调优
  • JavaScript对象、原型与继承知识体系综合实战案例