用 nocase、depth、offset 收紧匹配边界

约 30 分钟

能用 nocase、depth、offset 修饰符缩小匹配范围并减少误报。

上一课你通过测试模式、PCAP 回放和 fast.log,亲手验证了 content 对 ASCII 字面量和 |xx| 十六进制字节都能精确命中。验证之后,两个隐患浮出水面:content 默认大小写敏感,还会在整段载荷里任意位置搜索。结果有两个问题:攻击者换个大小写,规则就漏报;同一个串出现在无关位置,规则就误报。

接下来你用三个修饰符解决:nocase、depth、offset。它们都跟在 content 后面,作用是把搜索范围收窄。范围越窄,误报越少,引擎要比较的字节也越少。

核心概念

nocase:让匹配忽略大小写

类比:门卫拿着名单找人,只认“Li Ming”这一种写法,写成“li ming”就被放走了。nocase 相当于告诉门卫:写法不分大小写,字母相同就算找到。

定义:nocase 是紧跟 content 的修饰符,令该 content 的匹配不区分字母大小写,即执行不区分大小写的搜索。例如 content:"GET"; nocase; 能同时命中 GET、get、Get。

把 nocase 加进规则:

text
alert tcp any any -> any any (msg:"HTTP GET 请求"; content:"GET"; nocase; sid:2100011; rev:1;)

现在 get、Get、gEt 都能命中,大小写变体不再漏报。注意:nocase 只作用于它前面那一个 content;规则里若有多个 content,需要各自声明修饰符。

核心概念

depth 与 offset:把搜索框进窗口

类比:在一面长墙上找一行字。整面墙逐字看,慢,还容易认错,墙尾相似的涂鸦也会干扰你。你先从墙头量到字的大致位置(offset),再限定只看墙头起多长一段(depth),范围就清楚了。

定义:offset:N 指定 content 从载荷第 N 个字节起才开始搜索(从 0 计数);depth:N 限制搜索最远到载荷起点算起的第 N 个字节。组合使用后,搜索被限制在 offset 到 depth 之间的窗口内,单位都是字节。

窗口匹配示例:

text
alert tcp any any -> any any (msg:"窗口内的 admin"; content:"admin"; offset:10; depth:20; sid:2100012; rev:1;)

载荷第 10 字节到第 20 字节之间出现 admin 才告警。窗口之外出现的 admin 不再触发,位置相近但无关的流量被过滤掉。窗口收得越紧,误报越少;但要保证目标串完整落在窗口内,否则连真实告警一起漏掉。

什么时候值得用窗口匹配?目标串在载荷里的位置相对固定时,offset 与 depth 最能发挥作用。位置越确定,窗口收得越小,误报越少。位置不确定时,先用宽松窗口,观察误报来源后再逐步收紧。

收紧边界并对比命中变化

  1. 1

    确认 suricata.yaml 中已启用 fast.log 输出;未启用先补上(沿用上一节配置)。

  2. 2

    用上一节的测试模式命令校验基线规则,确认语法无误。

  3. 3

    用 suricata -r path-to-pcap 回放基线规则,统计 fast.log 中目标 sid 的告警行数,记为基线。

    bash
    suricata -r path-to-pcap
  4. 4

    改写规则:目标 content 加 nocase,再按目标串实际位置补 offset 与 depth,把匹配框进窗口。

  5. 5

    再次用测试模式校验改写后的规则,通过后回放同一份 PCAP。

  6. 6

    对比两次 fast.log 中该 sid 的告警行数,并确认目标告警仍然出现。

你应该看到

二次回放后,目标 sid 在 fast.log 中的行数明显少于基线,且目标告警仍出现。命中减少、目标仍在,边界收紧有效;若目标告警消失,说明窗口圈错,参考 troubleshoot 排查。

遇到问题:加上 offset/depth 后回放,目标告警在 fast.log 中消失。

可能原因

  • 目标串实际位置落在 offset 与 depth 圈出的窗口之外。
  • offset 与 depth 的含义用反,搜索窗口与预期不符。
  • 窗口内目标串的大小写与规则不一致,且规则未加 nocase。
  • 规则语法或修饰符顺序有误,规则未被引擎正常加载。

排查步骤

  1. 先过测试模式,确认规则被正常加载、无语法错误。
  2. 用 Wireshark 查看载荷中目标串的实际字节位置,重新计算 offset 与 depth。
  3. 大小写不稳定就先加 nocase,再单独调整窗口,一次只改一个变量。
  4. 每次改动后回放同一 PCAP,对照 fast.log 行数变化定位问题。
自检:目标串 Login 在载荷中出现三次:第 4 字节是 login,第 12 字节是 Login,第 30 字节是 Login。规则为 content:"Login"; nocase; offset:6; depth:20;。哪一处会告警?为什么?

只有第 12 字节那处告警。nocase 让大小写不敏感,第 4 字节的 login 也算候选命中;但 offset:6 从第 6 字节才开始搜索,第 4 字节在窗口之前。depth:20 限定最远到第 20 字节,第 30 字节在窗口之外。窗口内只剩第 12 字节。