ParshwaBhavsar/dnswatch
GitHub: ParshwaBhavsar/dnswatch
dnswatch 是一款被动 DNS 日志分析器,通过五种统计与行为检测器从已有 DNS 日志中发现 C2 beaconing、DNS 数据外泄、DGA 域名及 NXDOMAIN 风暴等威胁。
Stars: 0 | Forks: 0
# dnswatch




**专为检测工程师设计的被动 DNS 日志分析器。** 只需将来自路由器、Pi-hole、Zeek 或 pfSense 的导出 DNS 日志输入其中,它便会对每一次查询运行五种行为检测器——从而发现 C2 beaconing、DNS 数据外泄隧道、DGA 域名、NXDOMAIN 风暴以及已知恶意域名,并在每次告警中提供 MITRE ATT&CK 映射。
没有流量拦截,也没有主动的 DNS 组件——`dnswatch` 仅读取您已有的日志文件。
## 目录
- [为什么开发此项目](#why-this-exists)
- [检测器](#detectors)
- [安装说明](#install)
- [快速开始](#quick-start)
- [用法](#usage)
- [输出示例](#example-output)
- [工作原理](#how-it-works)
- [支持的日志格式](#supported-log-formats)
- [测试](#testing)
- [项目结构](#project-structure)
- [展示的概念](#concepts-demonstrated)
- [客观存在的局限性](#honest-limitations)
- [路线图](#roadmap)
- [道德与范围](#ethics--scope)
## 为什么开发此项目
DNS 是互联网的电话簿——而攻击者无时无刻不在滥用它。C2 框架通过 DNS 查询与控制端进行通信。恶意软件使用算法生成的域名,以至于没有任何静态拦截列表能够将它们全部捕获。数据外泄工具将窃取的字节编码到子域名标签中,并将其发送到攻击者控制的域名服务器。这些攻击中的每一次都会在您的 DNS 查询日志中留下蛛丝马迹。
`dnswatch` 读取这些日志,并应用 SOC 分析师通常手动应用的相同统计和行为分析技术——beaconing 规律性、子域名熵值、域名中的辅音分布——并将它们转化为结构化、可解释的告警。
该项目涵盖了检测工程领域的**网络层**:继 `bintriage`(文件层)和 `authdetect`(应用/日志层)之后,DNS 层的分析补全了全栈防御的蓝图。
## 检测器
| 检测器 | 特征 | MITRE | 严重程度 |
|----------|--------|-------|----------|
| **黑名单 (Blocklist)** | 域名匹配已知的恶意威胁情报列表 | T1071.004 | CRITICAL–LOW |
| **DNS 数据外泄** | 子域名标签长度 > 45 个字符且熵 > 3.5 bits/char;或者同一基础域名拥有 > 15 个唯一子域名 | T1048.003 | HIGH / MEDIUM |
| **Beaconing** | 以固定间隔查询同一域名 (CV < 0.4) —— 自动化的 C2 签到 | T1071.004 | HIGH / MEDIUM |
| **DGA 检测** | 高辅音比例 (> 62%),高熵,标签长度 14-22 —— 算法生成的域名 | T1568.002 | HIGH / MEDIUM |
| **NXDOMAIN 风暴** | 60 秒内一个客户端收到 > 10 个 NXDOMAIN 响应 —— DGA 恶意软件正在循环尝试候选域名 | T1568, T1568.002 | HIGH |
每次告警包含:
- 源 IP、域名、时间戳
- 关于*为什么*会触发告警的人类可读描述
- 量化证据(熵值分数、CV、查询次数等)
- MITRE ATT&CK 战术和技术 ID
- 误报指导
## 安装说明
```
git clone https://github.com//dnswatch.git
cd dnswatch
pip install -r requirements.txt
pip install -e .
```
要求 Python 3.10+。运行时依赖项:`rich`。
## 快速开始
```
# 1. 生成模拟日志(所有数据均为虚构——不包含真实域名或 IP)
python -m dnswatch generate-logs --output sample.ndjson
# 2. 运行全部五个检测器
python -m dnswatch analyze --logfile sample.ndjson
```
## 用法
```
# 分析日志文件 — 丰富的终端表格
python -m dnswatch analyze --logfile /var/log/pihole.log
# 用于管道传输到 SIEM 或 jq 的 JSON 输出
python -m dnswatch analyze --logfile dns.ndjson --output-format json
# 添加自定义 blocklist(每行一个域名)
python -m dnswatch analyze --logfile dns.ndjson --blocklist my_iocs.txt
# 过滤为 HIGH 及以上级别
python -m dnswatch analyze --logfile dns.ndjson --min-severity high
# 显式指定日志格式
python -m dnswatch analyze --logfile dns.log --format pihole
# 生成模拟测试日志
python -m dnswatch generate-logs --output test.ndjson
```
## 输出示例
```
Blocklist: 3 domains
Parsed 247 events from sample.ndjson
dnswatch — 4 alert(s)
┏━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Sev ┃ Detector ┃ Src IP ┃ Finding ┃
┡━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ 🟠 HIGH │ dns_exfiltration │ 192.168.1.55 │ Possible DNS Data Exfil │
│ │ │ │ Label 48 chars, entropy │
│ │ │ │ 4.71 bits/char │
│ │ │ │ [MITRE] T1048.003 │
│ 🟠 HIGH │ dga_detection │ 192.168.1.99 │ Possible DGA Domain │
│ │ │ │ cgkhyqwdmvlqzh.net │
│ │ │ │ entropy 3.82, 91% conson. │
│ │ │ │ [MITRE] T1568.002 │
│ 🟠 HIGH │ nxdomain_storm │ 192.168.1.99 │ NXDOMAIN Storm │
│ │ │ │ 10 NXDOMAIN in 60s │
│ │ │ │ [MITRE] T1568, T1568.002 │
└──────────┴──────────────────┴───────────────┴───────────────────────────┘
╭────────── Summary ───────────╮
│ Events analysed: 247 │
│ Total alerts: 4 │
│ 🟠 HIGH: 4 │
│ dga_detection 2 │
│ dns_exfiltration 1 │
│ nxdomain_storm 1 │
╰──────────────────────────────╯
```
## 工作原理
```
log file (Pi-hole / Zeek / CSV / NDJSON)
│
▼
parsers.py auto-detect format → normalise to DNSQueryEvent
│ timestamp · src_ip · domain · qtype · response
▼
detectors/
├── blocklist.py exact + parent-domain match against threat intel
├── exfil.py label length + entropy + subdomain diversity
├── beaconing.py inter-query interval CV (σ/μ)
├── dga.py consonant ratio + entropy + label length scoring
└── dga.py NXDOMAIN sliding-window count
│
▼
model.py Alert with evidence dict + MITRE ATT&CK
│
▼
report.py rich terminal table / NDJSON stream
```
### 检测逻辑详解
**DNS 数据外泄** —— DNS 隧道工具 (iodine, dnscat2) 将数据进行 base64/hex 编码并放入子域名标签中。包含两个信号:(1) 长度 > 45 个字符且 Shannon 熵 > 3.5 bits/char 的标签指示了编码后的 payload;(2) 在一个会话中对同一基础域名有 > 15 个唯一子域名指示了分块数据传输。
**Beaconing** —— C2 框架会按计划回连。取证信号在于其*规律性*。`dnswatch` 会计算每个 (src_ip, domain) 对的查询间隔变异系数 (σ/μ)。CV < 0.40 被标记为 MEDIUM;CV < 0.20 被标记为 HIGH。合法的浏览器流量通常是突发性的(高 CV);而恶意软件的计时器则像节拍器一样极其规律(低 CV)。
**DGA** —— 域名生成算法通过将种子(通常是当天的日期)输入 PRNG 来生成域名。生成的名称在统计学上与人类选择的域名有所区别:高辅音密度、无可识别词汇、Shannon 熵升高。`dnswatch` 会在三个维度上对每个标签进行评分,当综合得分超过 0.70 时触发告警。
**NXDOMAIN 风暴** —— 当 DGA 恶意软件启动时,它会快速遍历候选域名,直到有一个解析成功。每次失败的尝试都会产生一个 NXDOMAIN 响应。在 60 秒内来自同一客户端的 > 10 次 NXDOMAIN 响应是一个强烈的 DGA 指标,特别是当这些解析失败的域名共享结构属性时。
**黑名单** —— 与调用方提供的威胁情报集进行精确匹配和父域名匹配,并支持父域名传播(拦截 `evil.com` 也会拦截 `sub.evil.com`)。严重程度派生自类别标签(c2 → CRITICAL,malware → HIGH,tracker → LOW)。
## 支持的日志格式
| 格式 | 解析器 | 自动检测条件 |
|--------|--------|-----------------|
| JSON / NDJSON | `JSONParser` | 以 `{` 开头的行 |
| Pi-hole / dnsmasq | `PiholeParser` | 包含 `query[` 或 `dnsmasq` |
| Zeek dns.log | `ZeekParser` | 以 `#fields` 或 `#separator` 开头 |
| CSV | `CSVParser` | 包含逗号,表头可选 |
**JSON 字段别名** —— JSON 解析器会自动解析常见的字段名变体(`query` → `domain`,`client` → `src_ip`,`rcode_name` → `response` 等),因此来自不同来源的日志无需预处理即可直接使用。
## 测试
```
pip install pytest
pytest -q
```
```
42 passed in 0.12s
```
测试范围涵盖了每个解析器、全部五个检测器、合成日志生成器,以及对样本日志能够触发多个检测器的端到端验证。
## 项目结构
```
dnswatch/
├── dnswatch/
│ ├── model.py # DNSQueryEvent, Alert dataclasses
│ ├── parsers.py # Pi-hole / Zeek / CSV / JSON parsers
│ ├── report.py # rich terminal + NDJSON + log generator
│ ├── cli.py # analyze / generate-logs subcommands
│ └── detectors/
│ ├── base.py # BaseDetector ABC
│ ├── blocklist.py # threat intel lookup
│ ├── exfil.py # DNS exfiltration patterns
│ ├── beaconing.py # C2 beacon regularity
│ └── dga.py # DGA scoring + NXDOMAIN storm
├── tests/
│ └── test_dnswatch.py # 42 tests
├── requirements.txt
├── pyproject.toml
└── README.md
```
## 展示的概念
- **DNS 协议** —— 查询和响应是如何工作的,NXDOMAIN / NOERROR / SERVFAIL 代表什么,子域名标签是如何结构的
- **Shannon 熵**作为一种分析基础 —— 与 `bintriage` 的加壳检测器中的概念相同,此处应用于检测 DNS 标签中的编码 payload
- **统计行为分析** —— 用于 beaconing 的变异系数;用于 DGA 的辅音比例 + 熵值评分;用于 NXDOMAIN 风暴的滑动窗口计数
- **MITRE ATT&CK** —— T1048(通过替代协议外泄)、T1071.004(DNS)、T1568.002(DGA);与 `authdetect` 使用相同的框架
- **日志标准化** —— 将四种不同的 DNS 日志格式映射到单一的 `DNSQueryEvent` 模型中,从而使所有检测器都与格式无关
- **模块化检测器架构** —— 每个检测器都是一个独立的类;添加新检测器只需编写一个文件,并将其追加到 `cli.py` 的列表中即可
## 客观存在的局限性
- **无实时捕获** —— `dnswatch` 读取的是导出的日志,而不是实时流量。如需实时分析,请使用日志转发器(Filebeat, Vector)或 tail 模式为其提供数据。
- **DGA 误报** —— 某些合法服务会使用看起来像随机生成的子域名(CDN 资产哈希、ACME 验证 token)。阈值经过了保守调整;请根据您的环境调整 `detectors/dga.py` 中的 `_MIN_LABEL_LEN`、`_MIN_ENTROPY` 和 `_MIN_CONSONANT`。
- **Beaconing 需要历史记录** —— 您需要每个 (IP, 域名) 对有足够的事件才能计算出有意义的统计数据。较短的日志时间窗口会遗漏掉频率较慢的 beaconing。
- **不支持加密 DNS** —— DoH / DoT 流量在 DNS 层是不透明的;此工具只能看到以未加密形式通过网络传输的查询。
## 路线图
- [ ] Zeek + Suricata 告警关联(DNS 异常 + IDS 特征 = 更高的置信度)
- [ ] Pi-hole 实时日志 tail 模式(流式分析)
- [ ] 被动 DNS 信誉查询(VirusTotal / PassiveDNS API)
- [ ] 基于 YAML 的自定义检测器规则(与 `authdetect` 格式相同)
- [ ] 包含各检测器操作演练和可视化的 Jupyter notebook
## 道德与范围
专为防御用途构建:威胁狩猎、检测工程、事件响应和安全教育。`dnswatch` 仅读取日志文件;它不会建立任何网络连接,不执行任何 DNS 查找,也不与任何实时流量进行交互。请仅分析您被授权访问的日志。
## 许可证
MIT
标签:C2检测, DNS日志分析, IP 地址批量处理, PB级数据处理, Python, 威胁情报, 安全规则引擎, 安全运维, 开发者工具, 无后门, 逆向工具