1chunghu/dns-tunnel-detect

GitHub: 1chunghu/dns-tunnel-detect

一个无依赖的单文件 Python 脚本,通过熵、唯一比率、子域长度和流量等信号从 DNS 日志中标记可能的 DNS 隧道与数据外泄行为。

Stars: 0 | Forks: 0

# dns-tunnel-detect 从 DNS 查询日志中标记可能的 **DNS 隧道 / DNS 数据外泄** —— 这是一个用于解决蓝队问题的单文件、无依赖 Python 脚本。 DNS 隧道将数据隐藏在查询名称本身中。攻击者控制某个域名的权威服务器,受控主机将数据编码到子域中并将其查询出去: ``` x000.INHU4RSJIRCU4VCJIFGCA4DSN5SCARCCEBRXEZLE.t.attacker.example x001.OMFGQ33TOQ6TCMBOGEYC4MJQFY2TACTVONSXEPLB.t.attacker.example ... ``` 对于仅允许 `udp/53` 的防火墙来说,这是“正常的 DNS”。但在记录了每个查询的 **解析器** 上,这非常惹眼——惹眼就意味着可被检测。该工具正是用来衡量这种惹眼程度的。 背景 / 其诞生的实验室: [你允许的 DNS 就是一个数据外泄通道](https://1chung.net/en/blog/dns-tunnel-egress/) ([繁中](https://1chung.net/blog/dns-tunnel-egress/))。 ## 它的检测维度 它会按父域名聚合查询,并根据区分隧道与正常流量的信号对每个域名进行评分: | 信号 | 正常流量 | DNS 隧道 | |---|---|---| | **标签熵** (比特/字符) | ~1–3,可读的名称 | ~4.3–5.0,编码后的乱码 | | **唯一比率** | 低 —— 相同的少数几个名称不断重复 | ~1.0 —— 几乎每个子域都是唯一的 | | **子域长度** | 短 | 长,标签几乎塞满 63 字符的限制 | | **流量** | 分散在多个域名中 | 集中在单一父域名上的突发流量 | 当父域名超过流量阈值,*并且* 同时满足熵、唯一比率和子域长度的所有阈值时,它就会被**标记**。每个父域也会获得一个 0–100 的评分用于排名。 ## 用法 ``` # resolver 日志(自动检测 dnsmasq 风格的行) ./dns-tunnel-detect.py /var/log/dnsmasq.log # 纯 query 名称,每行一个(例如文章中的小型 authoritative server) grep -oE '\S+\.t\.attacker\.example' capture.log | ./dns-tunnel-detect.py # 通过 tshark 从 pcap 中提取,无需代码 tshark -r dns.pcap -Y 'dns.flags.response==0' -T fields -e dns.qry.name \ | ./dns-tunnel-detect.py # 机器可读,用于 pipe 到 alert ./dns-tunnel-detect.py --json /var/log/dnsmasq.log # 证明其适用于合成 normal + tunnel 流量 ./dns-tunnel-detect.py --selftest --all ``` 当有项目被标记时退出状态为 `1`,否则为 `0` —— 因此可以直接放入 cron 或 CI 检查中运行: ``` ./dns-tunnel-detect.py /var/log/dnsmasq.log || notify "possible DNS tunnel" ``` ### 输入格式 - `--format auto`(默认):优先尝试解析 dnsmasq 的 `query[T] name from client` 行,否则提取该行中最后一个看起来像主机名的 token(如果有两个或以上的 token,则将第一个 token 作为客户端)。也支持纯 qname 列表。 - `--format dnsmasq` / `--format qname`:强制使用指定的解析器。 ### 调优 ``` --labels N labels that form the parent domain (default 2) --min-queries N ignore parents below this volume (default 20) --entropy X bits/char threshold (default 3.8) --uniq-ratio X unique-subdomain ratio threshold (default 0.8) --sub-len X mean subdomain length threshold (default 20) ``` ## 环境要求 Python 3.9+。仅使用标准库 —— 无需 `pip install`,直接将其放在解析器上运行即可。 ## 诚实的局限性 这能捕获**高频大流量**的数据外泄场景,这也是最常见的情况。它不是万能药,配套文章明确解释了为什么检测(而不是防火墙规则)才是此处的真正解法: - **低速且隐蔽能绕过阈值。** 每小时只缓慢发送几个低熵、短查询的攻击者可以躲避所有阈值。流量和熵是必要信号,但非充分信号 —— 请将其与随时间推移建立的每个客户端的速率基线结合使用。 - **父域名是基于 2 个标签的近似值。** 在没有 Public Suffix List 的情况下,`--labels 2` 会将 `foo.co.uk` 的父域视为 `co.uk`。由于隧道几乎总是使用裸域名(如 `attacker.example`),因此这对检测没有影响;如果你关心精确的 eTLD+1,可以针对使用多标签后缀的域名调高 `--labels`。 - **目前没有响应码信号。** 每个客户端较高的 `NXDOMAIN` 比率是另一个强烈的隧道特征;此版本仅根据查询名称进行评分。 - **DoH/DoT 对它是不可见的。** 一旦 DNS 搭载在 `https://` 上,它就不会到达解析器日志 —— 那是 443 端口的问题,而不是本工具的问题。请首先强制终端使用系统解析器。 ## 许可证 MIT —— 见 [LICENSE](LICENSE)。
标签:DNS隧道检测, Python, 动态分析, 无后门, 网络安全, 逆向工具, 隐私保护