Suricata_Binary_Protocol_Detection_Guide

Suricata 二进制协议检测学习指南

本文档系统讲解如何使用 Suricata 规则检测 TCP 二进制协议(如 HTTP/2、DNS、TLS 等),涵盖关键字段匹配、字节级操作、帧结构解析等核心技术。


目录

  1. 为什么需要二进制协议检测
  2. [Suricata 规则基础结构回顾](#Suricata 规则基础结构回顾)
  3. [content 关键字:二进制匹配的核心](#content 关键字:二进制匹配的核心)
  4. 偏移与深度控制:offset、depth、distance、within
  5. 字节级检测:byte_test、byte_jump、byte_extract
  6. 位掩码检测:bitmask
  7. [实战案例:HTTP/2 协议检测](#实战案例:HTTP/2 协议检测)
  8. [实战案例:TLS 协议检测](#实战案例:TLS 协议检测)
  9. 阈值与频率控制:threshold
  10. 常见问题与调试技巧
  11. 参考资料

1. 为什么需要二进制协议检测

许多网络协议并非基于文本(如 HTTP/1.1),而是采用二进制编码:

协议 编码方式 检测难点
HTTP/2 二进制帧 帧头结构固定,payload 可含 HPACK 压缩数据
TLS 二进制记录层 加密后无法检测应用层内容,需在握手阶段检测
DNS 二进制报文 域名使用长度前缀编码,非零终止字符串
QUIC 二进制 + 加密 大部分内容加密,仅初始包可检测
MQTT 二进制报文 固定头部 + 可变头部 + 载荷

核心挑战:不能简单用字符串匹配,必须理解协议的二进制结构,精确定位字段位置和值。


2. Suricata 规则基础结构回顾

复制代码
alert <protocol> <src_ip> <src_port> -> <dst_ip> <dst_port> (\
    msg:"规则描述"; \
    <规则选项>; \
    sid:XXXXXXX; rev:1; \
)

对于二进制协议检测,关键选项包括:

  • content / content| --- 内容匹配(支持十六进制)
  • offset / depth --- 绝对位置控制
  • distance / within --- 相对位置控制
  • byte_test --- 字节值比较
  • byte_jump --- 字节值跳转
  • byte_extract --- 字节值提取到变量
  • bitmask --- 位掩码
  • threshold --- 阈值控制

3. content 关键字:二进制匹配的核心

3.1 十六进制内容匹配

使用 | 包围的十六进制表示二进制数据:

复制代码
# 匹配单个字节 0x01
content:"|01|";

# 匹配多个字节
content:"|00 04 00 00 00 00|";

# 混合文本和十六进制
content:"GET |2f| HTTP";

3.2 HTTP/2 帧头匹配示例

HTTP/2 帧头为 9 字节固定结构:

复制代码
+-----------------------------------------------+
|                 Length (24)                    |
+---------------+---------------+---------------+
|   Type (8)    |   Flags (8)   |
+-+-------------+---------------+-------------------------------+
|R|                 Stream Identifier (31)                      |
+=+=============================================================+
|                   Frame Payload (0...)                       ...
+---------------------------------------------------------------+

匹配 HEADERS 帧(type=0x01):

复制代码
# 帧头第4字节为帧类型,0x01 = HEADERS
content:"|01|"; offset:3; depth:1;

匹配 WINDOW_UPDATE 帧(type=0x08):

复制代码
content:"|08|"; offset:3; depth:1;

3.3 否定匹配

复制代码
# 不包含指定内容
content:!"|be|";

4. 偏移与深度控制:offset、depth、distance、within

4.1 绝对位置:offset 和 depth

  • offset:从 payload 起始偏移多少字节开始匹配(0-based)

  • depth:从 offset 位置开始,匹配多少字节

    从第3字节开始,匹配1字节(即第4字节)

    content:"|01|"; offset:3; depth:1;

    从第0字节开始,匹配9字节(HTTP/2帧头)

    content:"|00 00 00 01 01 00 00 00 00|"; offset:0; depth:9;

图示

复制代码
Payload:  [0x00][0x00][0x00][0x01][0x01][0x00][0x00][0x00][0x00][...]
偏移:      0     1     2     3     4     5     6     7     8
                        ^-- offset:3, depth:1 匹配 0x01 (帧类型HEADERS)

4.2 相对位置:distance 和 within

  • distance:相对于上一个 content 匹配结束位置的偏移

  • within:从 distance 位置开始,匹配多少字节

    先匹配帧类型0x01(HEADERS),然后跳过4字节(stream_id),检查flags

    content:"|01|"; offset:3; depth:1; # 匹配帧类型
    content:"|05|"; distance:4; within:1; # 匹配flags(END_STREAM + END_HEADERS)

图示

复制代码
HTTP/2帧: [Len(3)][Type(1)][Flags(1)][StreamID(4)][Payload...]
           0  1  2   3        4        5  6  7  8
                        ^-- 第1个content匹配
                                    ^-- distance:4, within:1 匹配flags

4.3 位置控制对比

关键字 参考点 含义
offset payload 起始 从起始偏移 N 字节
depth offset 位置 最多匹配 N 字节
distance 上一个 content 末尾 跳过 N 字节
within distance 位置 最多匹配 N 字节

5. 字节级检测:byte_test、byte_jump、byte_extract

5.1 byte_test --- 字节值比较

语法

复制代码
byte_test:<bytes>,<operator>,<value>,<offset>[,relative][,bitmask <mask>][,endian <endian>][,dce>];

参数说明

参数 说明
bytes 读取的字节数(1, 2, 4)
operator 比较操作符:=, !=, <, >, <=, >=, &(位与), ^(位异或)
value 比较值
offset 偏移量(相对于 payload 起始或上一个 content 末尾)
relative 可选,偏移相对于上一个 content
bitmask 可选,先对读取值应用掩码再比较
endian 可选,big(默认)或 little

示例

复制代码
# 读取3字节,判断是否 >= 16384(0x4000)
# HTTP/2 HEADERS帧的payload长度 >= 16384 表示异常大的header block
byte_test:3,>=,16384,0;

# 读取1字节,判断是否等于0x04(END_HEADERS标志)
byte_test:1,=,4,0,relative;

# 读取4字节,判断INITIAL_WINDOW_SIZE是否为0
# SETTINGS帧payload中,settings_id=0x04后跟4字节value
byte_test:4,=,0,0,relative;

5.2 byte_jump --- 字节值跳转

语法

复制代码
byte_jump:<bytes>,<offset>[,relative][,multiplier <mult>][,post_offset <offset>][,bitmask <mask>][,endian <endian>][,dce>];

用途:读取 N 字节的值,将匹配位置跳转到该值指定的偏移。常用于跳过长度可变的字段。

示例

复制代码
# 读取HTTP/2帧头的3字节长度字段,跳过对应长度的payload
# 帧头: [Length(3)][Type(1)][Flags(1)][R+StreamID(4)]
byte_jump:3,0;          # 读取前3字节作为长度,跳过
# 现在位置在帧类型字段
content:"|01|";          # 匹配HEADERS帧类型

5.3 byte_extract --- 字节值提取到变量

语法

复制代码
byte_extract:<bytes>,<offset>,<var_name>[,relative][,bitmask <mask>][,endian <endian>][,dce>];

用途 :将读取的字节值存储到命名变量中,后续可在 offsetdepthdistancewithinbyte_test 等中引用。

示例

复制代码
# 提取HTTP/2帧长度到变量frame_len
byte_extract:3,0,frame_len;
# 使用变量跳过帧头
content:"|01|"; offset:6; depth:1;  # 匹配帧类型

6. 位掩码检测:bitmask

6.1 原理

bitmask 对读取的字节值先执行按位与(AND)操作,再进行比较。常用于检测标志位。

复制代码
读取值: 0x05 (二进制: 00000101)
bitmask: 0x04 (二进制: 00000100)
AND结果: 0x04 (二进制: 00000100) → 检测第3位是否置位

6.2 HTTP/2 标志位检测示例

HTTP/2 帧头的 Flags 字段(第5字节,offset=4):

标志位 含义
END_STREAM 0x01 流结束
END_HEADERS 0x04 头部块结束
PADDED 0x08 存在填充
PRIORITY 0x20 存在优先级信息
复制代码
# 检测END_HEADERS标志位是否置位
# 先匹配帧类型0x01(HEADERS),然后检查flags字段的bit 2
content:"|01|"; offset:3; depth:1;
byte_test:1,=,0,0,relative,bitmask 0x04;

# 等价于: flags & 0x04 == 0x04

6.3 bitmask 与 byte_test 组合

复制代码
# 检测HTTP/2帧头中R位是否置位(Stream Identifier的最高位)
# Stream Identifier占4字节,最高位为Reserved位,必须为0
# 如果为1则可能是恶意构造的帧
byte_test:4,>,,0x7FFFFFFF,5,bitmask 0x80000000;

7. 实战案例:HTTP/2 协议检测

7.1 HTTP/2 帧结构回顾

复制代码
+-----------------------------------------------+
|                 Length (24)                    |  字节 0-2
+---------------+---------------+---------------+
|   Type (8)    |   Flags (8)   |               |  字节 3-4
+-+-------------+---------------+-------------------------------+
|R|                 Stream Identifier (31)      |  字节 5-8
+=+=============================================================+
|                   Frame Payload (0...)        |  字节 9+
+---------------------------------------------------------------+

7.2 检测 HTTP/2 HPACK Bomb(CVE-2026-49975)

攻击特征

  • 发送 SETTINGS 帧,设置 INITIAL_WINDOW_SIZE=0
  • 发送大量 HEADERS 帧,包含极大的 HPACK 压缩头部块
  • 周期性发送 increment=1 的 WINDOW_UPDATE 帧

规则1:检测 INITIAL_WINDOW_SIZE=0

复制代码
# HTTP/2 SETTINGS帧: type=0x04
# SETTINGS_INITIAL_WINDOW_SIZE: id=0x04, value=0x00000000
# 帧头9字节 + payload中: [id(2字节)=0x0004][value(4字节)=0x00000000]

alert tcp any any -> any any (\
    msg:"CVE-2026-49975 HTTP/2 HPACK Bomb - INITIAL_WINDOW_SIZE=0"; \
    flow:established,to_server; \
    content:"|04|"; offset:3; depth:1; \
    content:"|00 04 00 00 00 00|"; offset:9; depth:6; \
    sid:9000001; rev:1; \
)

规则2:检测异常大的 HEADERS 帧

复制代码
# HEADERS帧 type=0x01
# 帧头前3字节为长度,如果 >= 16384 (0x4000) 则异常
# 使用 byte_test 检测3字节长度字段

alert tcp any any -> any any (\
    msg:"CVE-2026-49975 HTTP/2 HPACK Bomb - Oversized HEADERS Frame"; \
    flow:established,to_server; \
    content:"|01|"; offset:3; depth:1; \
    byte_test:3,>=,16384,0; \
    threshold:type both, track by_src, count 5, seconds 3; \
    sid:9000002; rev:1; \
)

规则3:检测 END_STREAM + END_HEADERS 标志的异常组合

复制代码
# HPACK bomb中HEADERS帧通常同时设置END_STREAM和END_HEADERS
# flags = 0x05 (END_STREAM=0x01 | END_HEADERS=0x04)
# 使用byte_test + bitmask检测

alert tcp any any -> any any (\
    msg:"CVE-2026-49975 HTTP/2 HPACK Bomb - HEADERS with END_STREAM flag"; \
    flow:established,to_server; \
    content:"|01|"; offset:3; depth:1; \
    byte_test:1,=,0,0,relative,bitmask 0x04; \
    threshold:type both, track by_src, count 5, seconds 3; \
    sid:9000003; rev:1; \
)

规则4:检测微小 WINDOW_UPDATE(Window Stall)

复制代码
# WINDOW_UPDATE帧: type=0x08
# payload为4字节window increment
# increment=1 (0x00000001) 是异常的微小值

alert tcp any any -> any any (\
    msg:"CVE-2026-49975 HTTP/2 Window Stall - Minimal WINDOW_UPDATE"; \
    flow:established,to_server; \
    content:"|08|"; offset:3; depth:1; \
    content:"|00 00 00 01|"; offset:9; depth:4; \
    threshold:type both, track by_src, count 10, seconds 60; \
    sid:9000004; rev:1; \
)

7.3 实际可检出的规则(已验证)

以下规则已在实际流量中验证可检出:

复制代码
# 规则A: 检测HEADERS帧 + END_HEADERS标志
alert tcp any any -> any any (\
    msg:"LDYVUL-2026-00093922_HTTP/2 拒绝服务漏洞"; \
    content:"|01|"; offset:3; depth:4; \
    byte_test:1,=,0,0,relative,bitmask 0x04; \
    threshold:type both, track by_src, count 5, seconds 3; \
    classtype:attempted-dos; \
    sid:70005642; rev:1; \
)

# 规则B: 检测HEADERS帧 + 超大payload长度
alert tcp any any -> any any (\
    msg:"LDYVUL-2026-00093922_HTTP/2 拒绝服务漏洞"; \
    content:"|01|"; offset:3; depth:4; \
    byte_test:3,>=,16384,0; \
    threshold:type both, track by_src, count 5, seconds 3; \
    classtype:attempted-dos; \
    reference:cve,2024-27316; \
    sid:70005642; rev:1; \
)

规则解析

部分 含义
`content:" 01
byte_test:1,=,0,0,relative,bitmask 0x04 相对于content匹配位置,读取1字节,与0x04做AND后判断是否=0(检测END_HEADERS标志位)
byte_test:3,>=,16384,0 从payload起始读取3字节,判断是否>=16384(检测超大帧长度)
threshold:type both, track by_src, count 5, seconds 3 同一源IP在3秒内触发5次才告警(减少误报)

8. 实战案例:TLS 协议检测

8.1 TLS 记录层结构

复制代码
+-----------------------------------------------+
|  ContentType (1)  |  Version (2)   |  Length (2)  |
+-----------------------------------------------+
|                   Fragment                      |
+--------------------------------------------------+

8.2 检测 TLS ClientHello 中的 ALPN h2 协商

复制代码
# TLS Handshake: ContentType=0x16, HandshakeType=0x01(ClientHello)
# ALPN扩展中包含"h2"

alert tls any any -> any any (\
    msg:"TLS ALPN h2 Negotiation"; \
    content:"|16|"; offset:0; depth:1; \
    content:"h2"; \
    sid:9000010; rev:1; \
)

8.3 检测异常的 TLS 握手

复制代码
# 检测TLS版本低于1.2的连接
alert tls any any -> any any (\
    msg:"Weak TLS Version Detected"; \
    content:"|16|"; offset:0; depth:1; \
    byte_test:2,<,0x0303,1; \
    sid:9000011; rev:1; \
)

9. 阈值与频率控制:threshold

9.1 threshold 语法

复制代码
threshold:type <threshold|limit|both>, track <by_src|by_dst|by_rule>, count <N>, seconds <T>;
类型 含义
threshold 每 N 次/秒触发一次告警
limit 在 T 秒内最多告警 N 次
both 同时满足 threshold 和 limit

9.2 二进制协议中的阈值应用

二进制协议攻击通常表现为高频异常帧,单次匹配可能误报,需要阈值控制:

复制代码
# 3秒内5次异常HEADERS帧才告警
threshold:type both, track by_src, count 5, seconds 3;

# 60秒内10次微小WINDOW_UPDATE才告警
threshold:type both, track by_src, count 10, seconds 60;

10. 常见问题与调试技巧

10.1 为什么规则匹配不到?

原因 解决方案
TLS 加密 Suricata 无法检测加密后的 payload,需在 TLS 解密后检测或检测握手阶段
offset/depth 计算错误 使用 Wireshark 确认字段偏移,注意 TCP payload 起始位置
字节序错误 HTTP/2 使用大端序(网络字节序),byte_test 默认也是大端序
content 位置不对 使用 distance/within 替代 offset/depth 做相对定位
threshold 过严 调低 count 或调大 seconds
flow 方向错误 to_server 是客户端→服务端,to_client 是服务端→客户端

10.2 调试步骤

  1. 用 Wireshark 确认流量特征:找到攻击帧,记录精确的字节偏移和值
  2. 逐步构建规则:先写最简单的 content 匹配,确认能触发
  3. 添加 byte_test:在 content 匹配成功的基础上添加字节级检测
  4. 添加 threshold:最后添加阈值控制,减少误报
  5. 使用 -l 指定日志目录 :检查 fast.logeve.json 确认告警

10.3 Suricata 命令行测试

bash 复制代码
# 测试单条规则
suricata -S /path/to/test.rules -r /path/to/capture.pcap -l /tmp/suricata-out

# 检查告警
cat /tmp/suricata-out/fast.log
cat /tmp/suricata-out/eve.json | jq '.event_type == "alert"'

10.4 HTTP/2 检测的特殊注意事项

  1. TLS 加密:HTTP/2 几乎总是运行在 TLS 之上,Suricata 默认无法检测加密后的帧内容。需要:

    • 配置 SSL/TLS 解密(如使用 ssldump 或中间人解密)
    • 或检测 TLS 握手阶段的特征(如 ALPN 协商 h2)
  2. TCP 重组 :HTTP/2 帧可能跨越多个 TCP 段,确保 Suricata 的 stream.reassembly 开启

  3. 帧边界 :一个 TCP 段可能包含多个 HTTP/2 帧,offset 是相对于 TCP payload 起始的,不是帧起始

  4. HPACK 压缩:头部值经过 HPACK 压缩,无法直接匹配字符串内容


11. 参考资料

官方文档

协议规范

学习资源


附录:二进制检测关键字速查表

关键字 语法 用途 示例
content `content:" hex ";`
offset offset:N; 从 payload 起始偏移 N 字节 offset:3;
depth depth:N; 匹配 N 字节长度 depth:1;
distance distance:N; 相对上一个 content 偏移 N 字节 distance:4;
within within:N; 相对匹配 N 字节长度 within:1;
byte_test byte_test:B,op,V,O; 读取 B 字节,与 V 比较 byte_test:3,>=,16384,0;
byte_jump byte_jump:B,O; 读取 B 字节,跳转到该偏移 byte_jump:3,0;
byte_extract byte_extract:B,O,var; 读取 B 字节,存入变量 byte_extract:3,0,len;
bitmask bitmask 0xNN; 对值执行 AND 掩码 bitmask 0x04;
threshold threshold:type X,track Y,count N,seconds T; 阈值控制 threshold:type both,track by_src,count 5,seconds 3;
flow flow:established,to_server; 流方向控制 flow:established,to_server;
nocase nocase; 大小写不敏感(仅文本) nocase;
fast_pattern fast_pattern; 指定快速匹配模式 fast_pattern;
相关推荐
小五传输1 小时前
宏病毒查杀效率提升80%:2026年宏病毒查杀自动化方案详解
大数据·运维·安全
阿昭L1 小时前
Windows中__security_check_cookie与绕过
安全·缓冲区溢出
EasyDSS1 小时前
私有化视频会议系统/智能会议管理系统EasyDSS筑牢政务会议安全合规数字化防线
安全·政务
一拳一个娘娘腔2 小时前
CVE-2026-46300 — “Fragnesia“ 深度拆解:当修复补丁亲手唤醒了另一只恶魔
linux·安全
中创云图2 小时前
GPRSEEK 大模型:地下安全的 “AI 医生“
人工智能·安全
清晨0012 小时前
工业互联网实时数据统计一致性保障 — 基于 Redis Lua 的并发安全方案
redis·安全·lua
swordbob2 小时前
prototype 注入到 singleton 里,prototype是否还是线程安全的
安全·spring·单例模式·原型模式
风曦Kisaki2 小时前
#Linux监控与安全Day01:Zabbix部署全流程,基础监控配置与自定义监控项
linux·运维·安全·云计算·zabbix
顾凌陵2 小时前
PHP序列化漏洞实战:反序列化攻击的奥秘
安全·网络安全