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

张开发
2026/4/15 23:54:17 15 分钟阅读

分享文章

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_filtermodbus) 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_filtermodbus.func_code16) 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数据块{i1}: {chunk.hex()})遇到加密数据时可以尝试这些方法Hex解码直接转ASCII看看位移操作可能是简单的加减或异或常见编码Base64、URL编码等频率分析对二进制数据进行统计特征分析4. Flag提取实战从数据到flag的完整过程去年一场比赛的真实案例让我印象深刻。题目给的Modbus流量包有2000个报文但只有3个16号功能码报文。用Wireshark过滤modbus.func_code16后发现数据域特别长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事务ID00 00协议ID00 09长度01单元标识符10功能码16进制表示16号功能码00 01起始地址00 02寄存器数量04字节数41 42 43 44实际数据ASCII是ABCD58 59 5a可疑的额外数据XYZ最终flag就藏在那些多出来的字节里。完整提取脚本如下import pyshark from binascii import unhexlify def extract_hidden_data(pcap_path): cap pyshark.FileCapture(pcap_path, display_filtermodbus.func_code16) 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)常见坑点提醒字节序问题Modbus默认大端序但题目可能用小端序数据截断Wireshark默认只显示部分数据要检查包长度干扰数据正常工控数据可能和flag混在一起编码陷阱看起来像hex的数据可能是其他编码5. 防御视角从攻击手法看工控安全站在蓝队角度分析这类题目特别有意思。正常工控系统里16号功能码应该严格限制使用因为它可以直接修改设备参数没有默认认证机制可能引发物理设备异常有次企业渗透测试中我们发现攻击者就是利用Modbus协议扫描识别502端口Modbus默认端口发送16号功能码报文修改PLC参数导致生产线温度控制器异常防护建议网络分段隔离工控网络协议过滤限制非常用功能码深度检测监控寄存器值突变协议加固使用Modbus Secure版本# 简易Modbus流量监控脚本示例 def monitor_modbus_anomalies(pcap_path): cap pyshark.LiveCapture(interfaceeth0, display_filtertcp.port502) 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这些工具也很实用ModbusPalJava开发的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)进阶分析技巧时间序列分析统计报文间隔时间异常通信可能有规律会话重组跟踪同一TCP会话的多个请求响应协议仿真重放报文观察设备响应模糊测试修改正常报文进行异常检测7. 从比赛到实战的经验之谈打了这么多CTF我发现工控协议题目的套路往往集中在异常功能码使用非常用功能码藏数据协议字段滥用长度字段、保留字段藏信息时序特征特定时间间隔的报文可能触发flag混合编码HexBase64反转等多种编码嵌套有次真实项目里我们分析生产线异常发现就是有人误用了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_filtermodbus) 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, indent2) export_to_json(modbus_ctf.pcap, modbus_analysis.json)

更多文章