能编写 DNS 恶意域与 TLS 可疑 SNI 规则,并通过 PCAP 回放与 eve.json 验证告警。
上一节我们已经在离线回放中,通过 fast.log 与 eve.json 的核对验证了检测条件的设计。现在把这些验证过的知识固化成可运行的规则,走完「分析 → 写规则 → 回放 → 核对」的完整闭环。
先看一个类比。安检员不会凭空判断谁可疑:先看录像,再对照通缉名单,最后重放录像确认抓到了谁。你也一样。先用 Wireshark 观察 PCAP,从 Statistics → Protocol Hierarchy 看协议分布,判断该优先分析哪些协议;再把恶意域名名单转成规则;接着用 suricata -r path-to-pcap 离线回放;最后核对 fast.log 的告警,并用 jq 读取 eve.json 的字段。
回放走离线模式,不依赖真实网卡。告警落在两个输出里:fast.log 是纯文本告警行,适合快速确认是否命中;eve.json 是结构化 JSON,能读到域名等字段细节。jq 是官方推荐用来查看 EVE JSON 输出的工具。
整个实验只使用本地 PCAP 与授权流量,延续上一节全程遵守的被动观察与授权边界。
把恶意域名名单写成 dns.query 规则
- 1
在 Wireshark 的 Statistics → Protocol Hierarchy 确认 PCAP 里存在 DNS 与 TLS 流量,记下要检测的恶意域名。先看协议分布,再决定优先写哪类规则。
- 2
新建本地规则文件。规则默认安装在 /var/lib/suricata/rules,默认规则集文件是 suricata.rules。创建 /var/lib/suricata/rules/local-dns-tls.rules,并把该文件加入 suricata.yaml 的规则文件列表;路径写错时运行会直接报错。
bashsudo touch /var/lib/suricata/rules/local-dns-tls.rules - 3
名单里的每个域名转成一条 alert。沿用上一节的 dns.query 写法,content 精确匹配查询域名,nocase 忽略大小写:
suricataalert dns any any -> any any (msg:"MALWARE DNS query for evil.example.com"; dns.query; content:"evil.example.com"; nocase; classtype:bad-unknown; sid:1000001; rev:1;) - 4
名单有多少个域名就写多少条规则。sid 依次递增且全局唯一,msg 里的域名与 content 保持一致。
- 5
用第一课学过的测试模式检查语法,确认无 error 后再进入回放。
bashsudo suricata -T -c /etc/suricata/suricata.yaml
你应该看到
测试模式无 error,规则语法通过;若启动日志提示找不到文件,说明 suricata.yaml 中的路径写错,修正后重新测试。
编写 TLS 可疑 SNI 规则
- 1
在 Wireshark 中定位可疑的 TLS 握手流量。ClientHello 的 SNI 字段携带客户端要连接的域名,跟随 TCP 流查看完整交互,确认目标域名。写规则前先在 Wireshark 里检查流量,是常规做法。
- 2
用 tls.sni 匹配 SNI,规则骨架与 DNS 规则相同,协议字段改为 tls。沿用上一节的 tls.sni 写法:
suricataalert tls any any -> any any (msg:"SUSPICIOUS TLS SNI evil.example.com"; tls.sni; content:"evil.example.com"; nocase; classtype:bad-unknown; sid:1000002; rev:1;) - 3
方向沿用第一课学过的写法即可,SNI 由客户端发往服务器,无需新增关键字。
- 4
把 TLS 规则追加到同一个 local-dns-tls.rules,sid 继续递增且不与已有规则重复。
- 5
再次运行测试模式,确认两条规则都通过语法检查。
bashsudo suricata -T -c /etc/suricata/suricata.yaml
你应该看到
DNS 与 TLS 规则全部通过语法检查,sid 无冲突,测试模式无 error。
回放 PCAP 并核对 fast.log 与 eve.json
- 1
用离线模式回放 PCAP,命令格式就是
suricata -r path-to-pcap,path-to-pcap 换成你的实验抓包路径。bashsudo suricata -r /path/to/lab-dns-tls.pcap - 2
查看 fast.log 的新增告警行,确认 msg 与 sid 对应你写的规则。fast.log 为空时,先确认 suricata.yaml 里启用了 fast 输出——这一点官方特别提醒过。
bashsudo tail -n 20 /var/log/suricata/fast.log - 3
用 jq 从 eve.json 过滤 DNS 事件,核对告警中的域名。
bashjq 'select(.event_type == "dns") | .dns' /var/log/suricata/eve.json - 4
同样过滤 TLS 事件,核对 tls.sni 字段与规则中的域名一致。
bashjq 'select(.event_type == "tls") | .tls' /var/log/suricata/eve.json - 5
某个域名没告警时,回到 Wireshark 核对查询中的域名大小写与拼写,再检查规则 content 是否完全一致。
你应该看到
fast.log 出现对应的 DNS 与 TLS 告警行;eve.json 中 event_type 为 dns / tls 的事件分别包含 dns.query / tls.sni 字段,且值与规则中的恶意域名一致。
规则有效性只能靠回放本地 PCAP 验证,例如课程提供或可下载的练习抓包;不要对真实生产目标发起未授权扫描或探测。TLS 检测只读取 ClientHello 明文中的 SNI 字段,不涉及解密流量,也不要做任何规避检测的尝试。
遇到问题:回放结束后 fast.log 没有任何新增告警,但规则已通过测试模式。
可能原因
- suricata.yaml 中没有启用 fast 输出;官方提醒过不要忘记在 suricata.yaml 设置中启用 fast.log 输出。
- suricata.yaml 中引用的规则文件路径不正确,运行日志会提示找不到文件。
- PCAP 里实际没有你要检测的域名或协议,先回 Wireshark 用协议层级与 DNS/TLS 过滤器确认。
- 域名大小写或拼写与 PCAP 中的查询不一致,content 匹配不到。
排查步骤
- 查看运行输出与 /var/log/suricata/suricata.log,确认规则文件被加载、fast 输出已启用。
- 用 jq 按 event_type 过滤 eve.json:判断是事件没产生,还是产生了但没触发告警。
- 在 Wireshark 用 Statistics → Protocol Hierarchy 与 DNS/TLS 过滤条件核对流量内容。
- 修正规则中的域名写法或启用 nocase 后重新回放。
自检:你写了一条 dns 规则和一条 tls 规则,回放后 fast.log 有告警。为了确认告警分别来自 DNS 查询与 TLS 握手,你该查看 eve.json 中的哪些字段来区分?
按事件类型过滤。event_type 为 dns 的事件看 dns.query 字段,该字段应等于 dns 规则中的恶意域名;event_type 为 tls 的事件看 tls.sni 字段,该字段应等于 tls 规则中的可疑域名。用这两个字段把两类告警分开核对即可。