【网络安全】——协议逆向与频繁序列提取:从流量中解码未知协议

发布于:2025-03-08 ⋅ 阅读:(77) ⋅ 点赞:(0)

目录

引言

一、为什么要结合频繁序列提取?

二、四步融合分析法

步骤1:原始流量采集与预处理

步骤2:多粒度序列模式挖掘

层1:单包内字节级频繁项

层2:跨数据包的行为序列

步骤3:关键字段定位与结构假设

通过频繁模式推导协议结构:

步骤4:动态验证与协议还原

三、实战案例:Pj某工控设备协议

背景

关键发现过程

四、对抗干扰策略

常见干扰类型与破解技巧

五、工具链推荐

六、总结


引言

在工业控制、物联网设备通信等场景中,面对私有协议时,工程师常陷入**“盲人摸象”**的困境——没有文档、没有符号信息,只有一串串难以理解的十六进制数据流。本文将提出一种创新方法:将频繁序列提取技术融入协议逆向工程,通过挖掘数据中的统计规律,快速定位协议头、指令类型、校验位等关键字段,大幅提升逆向效率。


一、为什么要结合频繁序列提取?

传统协议逆向依赖人工比对数据包差异,存在三大痛点:

  1. 效率低下:数百个数据包需逐一对比

  2. 主观性强:依赖经验猜测字段含义

  3. 易漏特征:难以发现长跨度关联

频繁序列提取的价值

  • 自动发现高频出现的固定字节序列(如协议头、状态码)

  • 识别指令与响应的关联模式(如A指令必触发B响应)

  • 定位变长字段的分隔符(如0x00结尾的字符串)


二、四步融合分析法

步骤1:原始流量采集与预处理

使用Wireshark捕获原始流量,按会话切分并转换为字节序列:

# 示例:从pcap提取TCP负载序列
from scapy.all import *

packets = rdpcap("unknown_protocol.pcap")
sessions = packets.sessions()

byte_sequences = []
for session in sessions.values():
    tcp_payloads = [bytes(p[TCP].payload) for p in session if TCP in p]
    if tcp_payloads:  
        byte_sequences.append(tcp_payloads)  # 每个会话的包序列

步骤2:多粒度序列模式挖掘

层1:单包内字节级频繁项
from mlxtend.frequent_patterns import apriori

# 将每个字节位置视为一个项(item)
# 示例数据包: [0xaa, 0x01, 0xff], [0xaa, 0x02, 0xee]
transactions = [
    {'pos0:aa', 'pos1:01', 'pos2:ff'},
    {'pos0:aa', 'pos1:02', 'pos2:ee'}
]

freq_items = apriori(transactions, min_support=0.5, use_colnames=True)
print(freq_items)

输出

   support      itemsets
0     1.0       (pos0:aa)  # 发现协议头固定为0xAA
层2:跨数据包的行为序列

使用PrefixSpan挖掘会话级操作码序列:

# 假设已从数据包中提取操作码(如第二个字节)
opcode_sequences = [
    [0x01, 0x03, 0x04],  # 会话1的操作码流
    [0x01, 0x04],         # 会话2
    [0x01, 0x03, 0x04]    # 会话3
]

from prefixspan import PrefixSpan
ps = PrefixSpan(opcode_sequences)
ps.minlen = 2
freq_seqs = ps.frequent(2)  # 最小支持度2次

# 输出:[(2, [0x01, 0x03]), (2, [0x01, 0x03, 0x04])]

结论:操作码0x01后常跟0x03,可能为登录→查询信息的固定流程。


步骤3:关键字段定位与结构假设

通过频繁模式推导协议结构:
字段位置 候选假设 验证方法
字节0 固定头(Magic Number) 全样本一致性检查
字节1 指令类型(高频出现0x01) 触发不同功能观察响应变化
字节4-5 长度字段(与后续数据长度相关) 计算Pearson相关系数
末2字节 校验和(与前面数据存在数学关系) 尝试CRC16/CRC32计算匹配

步骤4:动态验证与协议还原

编写脚本自动化验证假设:

def validate_checksum(packet):
    assumed_crc = packet[-2:]
    calculated_crc = crc16(packet[:-2])
    return assumed_crc == calculated_crc

valid_count = 0
for p in packets:
    if validate_checksum(p):
        valid_count +=1

print(f"校验通过率: {valid_count/len(packets)*100}%")  
# 若通过率接近100%,则确认校验位假设正确

三、实战案例:Pj某工控设备协议

背景

某PLC设备通信协议未知,需实现以下功能逆向:

  • 读取寄存器值(功能码)

  • 设置设备地址(地址字段)

  • 异常状态码解析

关键发现过程

  1. 频繁头定位

    80%的数据包以0x48 0x53开头 → 确认为协议头
  2. 指令类型推断

    第3字节出现0x01(读)和0x02(写)的频率最高 → 功能码字段
  3. 地址字段验证

# 对比两个写地址请求包:
Packet1: 48 53 02 00 01 02 [00 00 00 01] ... 
Packet2: 48 53 02 00 01 02 [00 00 00 02] ...
# 响应包中地址字段变化 → 确认第7-10字节为设备地址

    4. 错误码提取

         当响应包第4字节为0xFF时,末字节出现0x01/0x02 → 错误子码


四、对抗干扰策略

常见干扰类型与破解技巧

干扰手段 破解方法
随机填充字节 过滤低频率项,关注稳定出现的字段
多协议复用 先聚类(如按端口、包长),再分别分析
字段动态编码 寻找编码前后的统计特征(如字节分布变化)
心跳包干扰 剔除固定时间间隔的无关包

五、工具链推荐

  1. 流量预处理:Wireshark + Scapy(Python)

  2. 序列挖掘:SPMF(支持GSP、PrefixSpan算法)

  3. 自动化验证:Python + pwntools(自定义协议测试脚本)

  4. 可视化分析:NetworkX(绘制协议状态转移图)


六、总结

“数据即协议”——通过融合频繁序列提取与协议逆向技术,开发者能在无先验知识的情况下,快速定位关键字段并推测交互逻辑。该方法尤其适用于具有明显统计特征的私有协议逆向场景。

方法论价值

  • 将人工经验转化为可量化的模式识别

  • 为协议逆向提供自动化切入点

  • 降低对特定领域知识的依赖


扩展阅读标签#协议逆向 #频繁序列 #工控安全 #Python #Wireshark


    网站公告

    今日签到

    点亮在社区的每一天
    去签到