gengen008/threat-hunting
GitHub: gengen008/threat-hunting
一个零依赖的 Python 威胁狩猎工具包,通过网络流量和 DNS 日志的多维度启发式分析,帮助安全分析师发现 C2 通信等高级威胁模式。
Stars: 0 | Forks: 0
# 威胁狩猎:命令与控制 (C2) 流量模式
一个无依赖的 Python 工具包,用于在网络流量和 DNS 日志中狩猎命令与控制 (C2) 流量模式——包括规律间隔的 Beaconing、DNS 隧道 / DGA 式数据外发、罕见且持久的通信目标、低速慢速会话,以及重用单一 TLS 指纹的轮换基础设施。
它内置了一个带有标签的合成流量生成器(因此无需外部 pcap 数据即可完整运行和测试整个 pipeline)、一系列测试(用于衡量针对已知真实情况的实际检测召回率/误报率),以及一份独立的交互式 HTML 狩猎报告。
**实时演示报告:** https://gengen008.github.io/threat-hunting/
*(每次向 `main` 分支推送代码时由 CI 自动基于 `data/` 中的示例数据集重新生成)*
## 为什么是“狩猎”,而不是“检测”
IDS/IPS 会基于特征码做出非黑即白的拦截/放行决策。威胁狩猎则不同:它是**假设驱动、有人参与的排查**。这个工具包不会断言“主机 X 已被感染”——它会呈现*值得分析师审查的异常*,并根据有多少个独立的弱信号指向同一台主机来对其进行排名。这种理念影响了这里的每一个设计决策:检测器是基于启发式且可解释的(每个评分都附带了产生该评分的证据),并且输出的是供人类查看的排名报告,而不是自动化的修复触发器。
## 检测内容
| 技术 | 狩猎假设 | MITRE ATT&CK |
|---|---|---|
| **Beaconing** | `(src, dst)` 对以可疑的*规律*间隔(到达时间间隔的变异系数较低)进行通信——这是脚本化 `sleep(N) + jitter` C2 植入物的特征,有别于突发性的人类驱动流量。 | [T1071](https://attack.mitre.org/techniques/T1071/) 应用层协议,[T1573](https://attack.mitre.org/techniques/T1573/) 加密通道 |
| **DNS 隧道 / DGA** | 一台主机以较高的频率发出大量具有高熵、极少重复的子域名 DNS 查询——这符合将数据编码到 DNS 标签中的行为,而不是正常的、有利于缓存的查找。 | [T1071.004](https://attack.mitre.org/techniques/T1071/004/) 应用层协议:DNS,[T1568.002](https://attack.mitre.org/techniques/T1568/002/) 动态解析:DGA |
| **罕见 + 持久的目标** | 网络上几乎没有其他主机与之通信的目标,却被某一台主机*反复*联系——一次性的罕见流量属于正常的长尾浏览噪音,而反复出现的罕见流量看起来就像是私有通道。 | [T1071](https://attack.mitre.org/techniques/T1071/),[T1090](https://attack.mitre.org/techniques/T1090/) 代理 |
| **低速慢速会话** | 一个保持打开状态长达数小时,但每秒只渗出少量数据的连接——这不是正常的下载/流媒体行为,而是符合空闲的 C2 保活机制或缓慢的数据外发。 | [T1029](https://attack.mitre.org/techniques/T1029/) 定时传输,[T1071](https://attack.mitre.org/techniques/T1071/) |
| **TLS 指纹重用** | 一个单一的罕见 JA3 客户端 TLS 指纹被同一台主机用于*许多不同的目标*——恶意软件通常自带一套 TLS 协议栈,因此即使运营者轮换前端域名/IP(fast-flux、重定向器轮换),其指纹也会保持不变。 | [T1568](https://attack.mitre.org/techniques/T1568/) 动态解析,[T1573.002](https://attack.mitre.org/techniques/T1573/002/) 加密通道:非对称加密 |
所有五个检测器的发现结果会按主机汇总为 0-100 的综合**风险评分**,该评分会对技术*多样性*给予奖励——一台触发了三个不相关检测器的主机,其信号强度远高于一台仅在阈值附近触发一次检测的主机(参见 `threat_hunting/scoring.py`)。
## 架构
```
flowchart LR
subgraph Input
A[Zeek conn.log / DNS log CSV]
G[Synthetic generator\nwith ground truth]
end
A --> IO[io_utils.py]
G --> IO
IO --> D1[beaconing.py]
IO --> D2[dns_tunneling.py]
IO --> D3[rare_destination.py]
IO --> D4[long_session.py]
IO --> D5[fingerprint_reuse.py]
D1 & D2 & D3 & D4 & D5 --> S[scoring.py\ncomposite risk score]
S --> R[report.py\nHTML hunt report]
S --> I[ioc.py\nIOC CSV export]
```
每个检测器都是一个纯函数 `list[ConnRecord|DnsRecord] -> list[Finding]`,没有共享状态,因此可以独立地进行测试、调优或替换——参见 `threat_hunting/detectors/`。
## 项目结构
```
threat_hunting/
models.py ConnRecord, DnsRecord, Finding, HostRiskProfile
stats.py entropy, coefficient of variation, percentile helpers
generator.py labeled synthetic C2 traffic generator
io_utils.py CSV loaders/writers (real Zeek/SIEM export or synthetic)
detectors/
beaconing.py
dns_tunneling.py
rare_destination.py
long_session.py
fingerprint_reuse.py
scoring.py per-host composite risk scoring
ioc.py de-duplicated IOC roll-up + CSV export
report.py self-contained interactive HTML report
cli.py `generate` / `hunt` / `demo` commands
data/ committed sample dataset (25 hosts, 12h, 4 malicious)
tests/ pytest suite, incl. recall/false-positive validation
.github/workflows/ CI: run tests, build report, deploy to GitHub Pages
```
## 快速开始
需要 Python 3.10+。运行时具有**零外部依赖**——只需要 `pytest`,且仅用于运行测试套件。
```
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt # pytest, for tests only
# 一步完成生成 + hunt + report,并与 ground truth 进行核对:
python -m threat_hunting.cli demo --report report.html --iocs iocs.csv
# 或者分步进行,针对已提交的 sample dataset:
python -m threat_hunting.cli hunt --conn data/conn.csv --dns data/dns.csv \
--report report.html --iocs iocs.csv
# 或者将其指向你自己的 Zeek conn.log / dns.log CSV export:
python -m threat_hunting.cli hunt --conn my_conn.csv --dns my_dns.csv --report report.html
```
在浏览器中打开 `report.html`——它是完全独立的(Chart.js 从 CDN 加载;其他所有内容都是内联的)。
### CLI 参考
```
threat_hunting.cli generate --hosts 40 --hours 48 --malicious 4 --seed 1337 --outdir data/
threat_hunting.cli hunt --conn CONN.csv [--dns DNS.csv] [--report report.html] [--iocs iocs.csv]
threat_hunting.cli demo --hosts 40 --hours 48 --malicious 4 --seed 1337 --report report.html
```
`demo` 还会额外打印哪些真实的恶意主机被捕获或遗漏,下面的准确率数据就是这样产生的。
### 自带数据格式
`--conn` CSV 列:`ts,src_ip,dst_ip,dst_port,proto,duration,orig_bytes,resp_bytes,ja3`(`ja3` 可选)。`--dns` CSV 列:`ts,src_ip,query,qtype`(`qtype` 可选)。这些与 Zeek 的 `conn.log`/`dns.log` 字段集相匹配,因此从 Zeek 导出到 CSV 通常是直接映射。
## 测试
```
pytest -v
```
30 个测试涵盖了:统计辅助工具、针对手动构建的正例/负例案例的每个检测器(包括每个阈值旨在拒绝的擦边案例——例如,时间长但吞吐量高的会话、流行但持久的目标、常见的浏览器 TLS 指纹)、综合评分行为、生成器的确定性,以及针对合成数据集运行完整 pipeline 并断言**实际召回率和已知真实情况的误报率**的端到端检查——而不仅仅是“它在运行中没有崩溃”:
```
test_default_dataset_full_recall_zero_false_positives 4/4 malicious hosts caught, 0/36 benign hosts flagged
test_recall_is_robust_across_seeds recall >= 75%, FP rate <= 15% across 4 additional seeds
```
## 部署
CI (`.github/workflows/ci-deploy.yml`) 在每次推送时运行测试套件,然后——只有在测试通过后——对提交的示例数据集运行 `hunt`,以重建 `docs/index.html` 并通过 `actions/deploy-pages` 将其部署到 GitHub Pages。没有任何生成的内容被提交到仓库;实时报告是上一次成功测试运行的构建产物。
## 局限性与诚实的注意事项
这是一个狩猎/排查辅助工具,而不是生产级的检测技术栈:
- **仅限合成数据。** 未捆绑真实的恶意软件 pcap(出于许可/安全原因);生成器的良性流量模型是简化的,因此实际环境中的误报率会有所不同。在信任评分之前,请根据您自己网络的基线验证阈值。
- **已注册域名提取功能很原始**(最后两个 DNS 标签),这对于像 `co.uk` 这样的多部分公共后缀是错误的。在生产使用时请替换为 `tldextract`/`publicsuffix2`。
- **阈值是启发式常量**,不是从数据中学习的(参见 `detectors/` 中每个文件顶部的模块级常量)——在部署之前,请针对您自身环境的正常流量对它们进行调优。
- **JA3 需要 TLS 可见性**(解密代理或 TLS 指纹传感器);仅从流元数据中无法推导出来。
## 许可证
MIT — 参见 [LICENSE](LICENSE)。
标签:IP 地址批量处理, Python, 安全规则引擎, 异常检测, 无后门, 网络流量分析, 逆向工具