基于 Zeek 检测 DNS 数据外渗:dns.log 字段解析、熵分析与多工具联动实战
【免费下载链接】Anthropic-Cybersecurity-Skills817 structured cybersecurity skills for AI agents · Mapped to 6 frameworks: MITRE ATT&CK, NIST CSF 2.0, MITRE ATLAS, D3FEND, NIST AI RMF & MITRE F3 (Fight Fraud) · agentskills.io standard · Works with Claude Code, GitHub Copilot, Codex CLI, Cursor, Gemini CLI & 20+ platforms · 29 security domains · Apache 2.0项目地址: https://gitcode.com/GitHub_Trending/an/Anthropic-Cybersecurity-Skills
本文基于 Anthropic-Cybersecurity-Skills 仓库中的detecting-exfiltration-over-dns-with-zeek技能,系统讲解如何利用 Zeek 的dns.log(TSV 格式)检测 DNS 隧道与数据外渗。全文围绕该技能提供的 API 参考文档 展开,覆盖 dns.log 字段语义、zeek-cut字段提取、Shannon 熵分析、RITA 信标检测、Suricata 检测规则与 Splunk 检索查询,并结合仓库内 agent.py 的源码实现,给出可直接落地的检测脚本与判定阈值。读完本文,你将掌握一套覆盖"抓取日志 → 解析字段 → 熵与行为分析 → 交叉验证 → 生成报告"的完整 DNS 外渗检测工作流。
一、为什么 DNS 是数据外渗的隐蔽通道
DNS 协议几乎在所有网络中都默认放行,防火墙与 DLP 系统很少拦截 DNS 查询,这让攻击者得以将敏感数据编码进 DNS 查询的子域(subdomain)中完成隐蔽传输。合法的 DNS 查询在熵值、标签长度和查询模式上具有可预测性,而外渗工具(如 dnscat2、iodine、dns2tcp 以及自定义实现)生成的查询往往呈现三个显著特征:子域标签具有高 Shannon 熵、标签长度异常长、同一父域下出现大量不重复子域。这正是本技能 SKILL.md 定义的核心检测模型。
对应 MITRE ATT&CK 框架,该场景主要映射到以下技术(见 mappings/mitre-attack/coverage-summary.md):
| 技术 | ID | 说明 |
|---|---|---|
| Exfiltration Over Alternative Protocol | T1048 | 利用 DNS 等替代协议外传数据 |
| Application Layer Protocol | T1071 | 通过应用层协议(含 DNS)进行 C2 通信 |
技能前端元数据(frontmatter)同时声明了 NIST CSF 2.0 映射:PR.IR-01(威胁与漏洞响应)、DE.CM-01(持续监控)、ID.AM-03(资产管理)、PR.DS-02(数据安全保护),覆盖检测与响应两大环节。
二、Zeek dns.log 字段参考(TSV 格式)
Zeek(原 Bro)在解析 DNS 流量后会把每一条查询/响应写入dns.log,默认采用 TSV 分隔的表格格式,文件头包含#separator与#fields两行元信息,用于声明列分隔符和字段名。理解每个字段的语义是后续一切分析与规则编写的基础。API 参考文档中给出的完整字段清单如下:
| 字段 | 类型 | 描述 |
|---|---|---|
ts | time | DNS 请求的时间戳 |
uid | string | 唯一连接标识符 |
id.orig_h | addr | 源 IP 地址 |
id.orig_p | port | 源端口 |
id.resp_h | addr | 目的 IP(DNS 服务器) |
id.resp_p | port | 目的端口(通常为 53) |
proto | enum | 传输协议(udp/tcp) |
trans_id | count | DNS 事务 ID |
rtt | interval | 往返时间 |
query | string | 被查询的域名 |
qclass | count | 查询类别数值 |
qclass_name | string | 查询类别名称(如 C_INTERNET) |
qtype | count | 查询类型数值 |
qtype_name | string | 查询类型名称(A、AAAA、TXT、MX、CNAME、NULL 等) |
rcode | count | 响应码数值 |
rcode_name | string | 响应码名称(NOERROR、NXDOMAIN、SERVFAIL) |
AA | bool | 权威应答(Authoritative Answer)标志 |
TC | bool | 截断(Truncation)标志 |
RD | bool | 递归期望(Recursion Desired)标志 |
RA | bool | 递归可用(Recursion Available)标志 |
Z | count | 保留字段 |
answers | vector | 资源记录应答内容 |
TTLs | vector | 各应答 RR 的 TTL 值 |
rejected | bool | 查询是否被拒绝 |
其中,与 DNS 外渗检测最相关的是:query(待解析的载荷载体)、qtype_name(TXT/NULL 类型常被隧道工具用作数据通道)、answers(可能回传指令数据)、id.orig_h(定位受害源 IP)、rcode_name(异常响应码组合)。
三、用 zeek-cut 快速提取与筛选关键字段
Zeek 自带的zeek-cut工具可以从 TSV 日志中按字段名抽取列,是日常排查的第一步。API 参考中给出的三组高频用法如下:
# 提取 dns.log 中的关键字段 cat dns.log | zeek-cut ts id.orig_h query qtype_name answers # 筛选 TXT 查询(DNS 隧道中的常见数据通道) cat dns.log | zeek-cut query qtype_name | grep TXT # 统计每个二级域名下的查询次数 cat dns.log | zeek-cut query | rev | cut -d. -f1-2 | rev | sort | uniq -c | sort -rn第一条命令用于快速浏览单条查询的时间、来源、域名、类型与应答;第二条直接聚焦 TXT 记录——dnscat2 等工具倾向将数据载荷封装在 TXT 应答中;第三条把域名反转后截取末尾两层(即父域),再排序统计,可一眼看出哪些父域承接了异常大的查询量。这三条命令组合使用,能在秒级完成初筛,为后续深度分析圈定目标域名。
需要补充的进阶用法:zeek-cut同样支持在统计前先去重,例如结合sort -u统计不重复子域数量,这正是判断"同一父域下海量子域"这一外渗特征的最快手段。
四、核心检测算法:Shannon 熵与多指标打分
初筛命中后,需要更精确的量化分析。仓库内的 scripts/agent.py 给出了完整的参考实现,其核心是逐子域计算 Shannon 熵并对父域聚合打分。
4.1 熵值计算原理
shannon_entropy 函数 基于字符频率计算信息熵:
def shannon_entropy(data: str) -> float: if not data: return 0.0 freq = defaultdict(int) for ch in data: freq[ch] += 1 length = len(data) entropy = 0.0 for count in freq.values(): prob = count / length entropy -= prob * math.log2(prob) return round(entropy, 4)合法的子域(如www、api、mail)字符分布集中,熵值通常低于 3.5;而经 Base32/Base64 或加密处理后的载荷字符分布均匀,熵值普遍高于 4.0。因此技能将3.5 作为默认熵阈值。
4.2 五项检测指标
analyze_dns_log 函数 对每个父域聚合统计,命中以下任一条件即记录对应指标:
- high_entropy(高熵):平均熵 ≥ 熵阈值,且不重复子域数 ≥ 5;
- long_labels(长标签):最长的标签长度 ≥ 标签长度阈值(默认 52,逼近 DNS 63 字符的标签上限);
- high_subdomain_count(海量子域):不重复子域数 ≥ 子域数阈值(默认 50);
- high_txt_ratio(TXT 占比异常):TXT 查询占比超过 50% 且查询总量超过 20 条;
- null_queries(NULL 记录异常):NULL 类型查询占比超过 30%。
此外,脚本内置了SAFE_DOMAINS白名单(agent.py),包含google.com、microsoft.com、apple.com、akamai.net、cloudflare.com、amazonaws.com、azure.com、local、in-addr.arpa等常见域与反向解析区,直接从分析中剔除,降低误报。
4.3 复合风险评分
命中指标后,脚本按权重叠加风险分并封顶 10 分(agent.py):
| 指标 | 计分规则 | 上限 |
|---|---|---|
| high_entropy | min(avg_entropy, 5.0) | 5.0 |
| long_labels | min(max_label / 15.0, 3.0) | 3.0 |
| high_subdomain_count | min(unique_count / 100.0, 3.0) | 3.0 |
| high_txt_ratio | 固定 1.5 | 1.5 |
| null_queries | 固定 1.0 | 1.0 |
最终按风险分降序输出可疑域名,SOC 可据此直接确定处置优先级。
4.4 运行与参数
脚本通过标准库(math、collections)实现,仅需 Python 3.9+,无需第三方依赖:
# 基础运行 python3 scripts/agent.py --log-file /opt/zeek/logs/current/dns.log # 自定义阈值并输出到文件 python3 scripts/agent.py --log-file dns.log \ --entropy-threshold 4.0 \ --subdomain-threshold 100 \ --label-length-threshold 52 \ --output report.jsonCLI 参数(见 main 函数)及其默认值:
| 参数 | 默认值 | 含义 |
|---|---|---|
--log-file | 必填 | Zeek dns.log 路径 |
--entropy-threshold | 3.5 | 熵判定阈值 |
--subdomain-threshold | 50 | 不重复子域数阈值 |
--label-length-threshold | 52 | 标签长度阈值 |
--output | 无 | 输出 JSON 报告路径 |
值得说明的是,parse_zeek_dns_log 会先读取#separator与#fields两行头信息动态确定列分隔符与字段位置,因此不依赖固定的列顺序,可兼容 Zeek 不同版本输出的dns.log——前提是日志由 Zeek 5.0 或更高版本处理网络流量生成,且包含标准字段头。
4.5 输出报告示例
分析完成后生成 JSON 报告,顶层包含analysis_summary与flagged_domains两个部分。SKILL.md 中给出的示意输出如下:
{ "analysis_summary": { "total_queries_analyzed": 145832, "unique_domains": 3421, "flagged_domains": 3, "entropy_threshold": 3.5 }, "flagged_domains": [ { "domain": "data.evil-c2.com", "unique_subdomains": 892, "avg_entropy": 4.72, "max_label_length": 61, "source_ips": ["10.0.1.45"], "risk_score": 9.4, "indicators": ["high_entropy", "long_labels", "high_subdomain_count"] } ] }实际脚本还会附加query_count、qtypes分布与sample_queries样本查询,便于分析师直接回溯原始报文。
五、用 RITA 交叉验证信标行为
RITA(Real Intelligence Threat Analytics)是面向 Zeek 日志的开源分析框架,擅长从流量中挖掘信标(beaconing)与 DNS 隧道统计特征,可作为熵分析的有力交叉验证。API 参考中的完整命令序列如下:
# 将 Zeek 日志导入 RITA 数据集 rita import /opt/zeek/logs/current rita-dataset # 分析信标行为 rita show-beacons rita-dataset # 展示 DNS 隧道指标 rita show-dns rita-dataset # 生成 HTML 报告 rita html-report rita-dataset /var/www/html/rita-report工作流建议:先用rita import导入当前日志目录,随后用show-dns查看可疑 DNS 活动、用show-beacons确认是否存在周期性回连(外渗或 C2 的典型行为),最后通过html-report生成可供团队共享的可视化报告。RITA 关注的是查询的时序规律性,与熵分析关注的载荷特征互补,二者命中重叠时可显著提高置信度。
六、Suricata 规则:在流量侧实时拦截
如果需要在流量侧做实时检测(而非事后分析 Zeek 日志),可使用 Suricata 的 DNS 规则。API 参考提供了两条基础规则:
# 检测超长 DNS 查询(潜在隧道) alert dns any any -> any any (msg:"Possible DNS tunneling - long query"; \ dns.query; content:"|00|"; byte_test:1,>,50,0,relative; \ sid:1000001; rev:1;) # 检测指向异常域名的 TXT 记录查询 alert dns any any -> any any (msg:"Suspicious DNS TXT query"; \ dns_query; pcre:"/^[a-z0-9]{30,}\./i"; sid:1000002; rev:1;)两条规则分别对应两种外渗特征:
- 规则一:对 DNS 查询内容执行字节级检查(
byte_test),判断标签长度是否超过 50 字节,逼近 63 字节的协议上限。content:"|00|"用于定位标签边界(点分隔符在 DNS 报文中的编码),relative使偏移检查相对该内容匹配位置进行。 - 规则二:用 PCRE 正则
^[a-z0-9]{30,}\.匹配以 30 个以上随机小写字母/数字开头、随后紧跟点号的查询——这是高熵随机标签的典型形态。
部署时可保留sid:1000001、sid:1000002作为自定义规则段的起始编号,按需继续追加,并通过rev:1管理规则修订版本。需要提醒的是,规则阈值需结合自身网络基线调优,否则可能在高流量环境产生较多误报。
七、Splunk SPL:在 SIEM 中落地检测
对于已将 Zeek 日志接入 SIEM 的环境,API 参考给出了对应的 Splunk 检索语句:
index=zeek sourcetype=zeek_dns | eval subdomain_len=len(mvindex(split(query, "."), 0)) | where subdomain_len > 50 | stats count dc(query) as unique_queries by "id.orig_h" query | where unique_queries > 100 | sort -unique_queries逐段解读这条查询:
index=zeek sourcetype=zeek_dns:锁定 Zeek DNS 日志索引;eval subdomain_len=...:按点号切分query字段,取第一个元素(最左侧子域)并计算长度;where subdomain_len > 50:筛选出超过 50 字符的标签(对应 63 字符上限的逼近阈值);stats count dc(query) ...:按源 IP 和查询聚合,统计每个父域下的不重复查询数;where unique_queries > 100:保留不重复查询超过 100 的域名(海量子域特征);sort -unique_queries:按数量降序排列,便于从顶部开始排查。
这条 SPL 与本技能的熵分析互为补充:SPL 适合在 SIEM 中做持续、全量的基线告警;agent.py 则适合对告警目标做深度的熵与行为画像。
八、完整检测工作流串联
综合上述工具,可形成一条闭环的检测流水线:
- 采集:Zeek 5.0+ 处理网络流量,产出 TSV 格式
dns.log; - 初筛:
zeek-cut提取字段,观察 TXT/NULL 类型占比与查询量排名(第三节); - 深度分析:运行 agent.py,输出熵、标签长度、子域数与复合风险分(第四节);
- 交叉验证:
rita import+rita show-dns/show-beacons确认信标与隧道特征(第五节); - 实时防护:将 Suricata 规则(第六节)下发至流量侧,阻断后续外渗;
- 持续监控:将 Splunk SPL(第七节)建立为 SIEM 告警,纳入日常监控基线。
九、使用前提与注意事项
- 日志格式前提:本文全部命令与分析均假设日志为 Zeek 生成的 TSV 格式
dns.log且包含标准#fields头,版本要求 Zeek 5.0 及以上(依据 SKILL.md 的 Prerequisites 部分); - 运行环境前提:agent.py 仅依赖 Python 3.9+ 标准库,无需额外安装第三方包;
- 阈值需要调优:3.5 的熵阈值、50 的子域阈值、52 的标签阈值均为默认值,应结合企业 DNS 基线流量分布进行调整,避免在大量 CDN/动态 DNS 场景下误报;
- 合规边界:本技能属安全检测能力,应仅用于自有或已获授权网络的防御分析,遵循仓库 SECURITY.md 与 CODE_OF_CONDUCT.md 规定的合法使用范围;
- 协议限制:DNS 单个标签最长 63 字符,单个查询总长不超过 255 字符,这意味着单次查询可携带的载荷很小——外渗工具必须以极高频率或大量不重复子域来搬运数据,这正是"查询量、子域数、熵值"三重指标可行的根本原因。
通过将 Zeek 日志字段语义、熵与行为分析算法、流量侧规则与 SIEM 查询四层能力叠加,本技能提供了一套完整且可落地的 DNS 外渗检测方案。完整字段参考可随时查阅仓库内的 api-reference.md,方法论与输出格式定义见 SKILL.md,参考实现位于 scripts/agent.py。
【免费下载链接】Anthropic-Cybersecurity-Skills817 structured cybersecurity skills for AI agents · Mapped to 6 frameworks: MITRE ATT&CK, NIST CSF 2.0, MITRE ATLAS, D3FEND, NIST AI RMF & MITRE F3 (Fight Fraud) · agentskills.io standard · Works with Claude Code, GitHub Copilot, Codex CLI, Cursor, Gemini CLI & 20+ platforms · 29 security domains · Apache 2.0项目地址: https://gitcode.com/GitHub_Trending/an/Anthropic-Cybersecurity-Skills
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考