cray44/detection-validator
GitHub: cray44/detection-validator
一个用于对 Sigma 检测规则进行离线单元测试的验证工具,通过配对的 JSON 样本确保检测逻辑的准确无误并减少误报。
Stars: 0 | Forks: 0
# detection-validator
针对配对的 JSON 测试样本验证 Sigma 检测规则 —— 无需 Splunk。
给定一个 Sigma 规则和两个 JSON 文件(恶意事件,良性事件),它会断言:
- **至少一个恶意事件匹配** 检测逻辑
- **零个良性事件匹配** 检测逻辑
每次规则检查时也会通过 [sigma-to-spl](https://github.com/cray44/sigma-to-spl) 进行转换:如果规则转换失败或产生 `MANUAL:` 警告,这些信息会显示在输出中。
## 安装
```
pip install -e .
# 转换检查也必须安装 sigma-to-spl
pip install -e ../sigma-to-spl
```
## 用法
```
# 测试所有规则,自动发现 validator.yml 和 test-data 路径
detection-validator test rules/
# 测试单个规则
detection-validator test rules/network/dns-tunneling-high-entropy-subdomains.yml
# 显式 sigma-to-spl 配置 (Corelight/Zeek 字段映射)
detection-validator test rules/ --config config/corelight.yml
# 显式 test-data 目录(仅限单个规则)
detection-validator test rules/network/dns-tunneling.yml --test-data ../detection-notes/detections/network/dns/test-data/
# 显式 validator.yml(覆盖自动发现)
detection-validator test rules/ --mappings config/validator.yml
```
## 输出
```
PASS network/dns-tunneling-high-entropy-subdomains
conversion: clean
malicious: 3/4 matched benign: 0/5 matched
WARN network/statistical-beaconing-zeek-conn-log
conversion: clean
manual: MANUAL: rule has SPL-only additions not expressible in Sigma — see detection writeup
malicious: 10/10 matched benign: 6/12 matched
benign FPs: 6/12 — SPL additions handle these
SKIP identity/oauth-device-code-phishing-sigmahq
no test-data directory
FAIL windows/some-rule
malicious: 0/3 matched <- detection gap
10/11 passed 1 skipped 0 failed
```
退出码:`0` = 全部通过/警告/跳过,`1` = 任何失败或错误,`2` = 配置错误。
## 状态码
| 状态 | 含义 |
|--------|---------|
| `PASS` | 转换无误,恶意事件匹配,无良性事件匹配 |
| `WARN` | 断言通过,但规则带有 `MANUAL:` 警告(SPL 添加了超出 Sigma 表达范围的过滤) —— 预期会产生良性误报 |
| `SKIP` | 未配置测试数据,或需要时间窗口的聚合条件 |
| `FAIL` | 检测遗漏(未匹配到恶意事件),纯净规则上出现误报,或转换错误 |
| `ERROR` | YAML 解析失败或样本加载失败 |
`WARN` 不是 CI 失败。检测遗漏总会导致失败,与 `MANUAL:` 状态无关。
## 工作原理
### Sigma 原生评估
评估器直接作用于 Sigma 的检测 YAML —— 而不是 SPL 输出。这使其无需依赖特定基础设施,并且测试的是数据源真实面貌,而非派生产物。
检测块被解析为条件 AST(抽象语法树)(递归下降解析器处理 `and`、`or`、`not`、`1 of`、`all of`)。每个命名选择块使用规则中的字段修饰符对事件进行评估:
| 修饰符 | 行为 |
|----------|----------|
| *(无)* | 不区分大小写的相等匹配;`*` 作为值时 = 字段存在且具有任意值 |
| `|contains` | 子字符串匹配 |
| `|startswith` | 前缀匹配 |
| `|endswith` | 后缀匹配 |
| `|contains|all` | 所有值必须出现在字段中 (AND) |
| `|cidr` | 通过 Python `ipaddress` 进行 IP/子网成员关系匹配 |
| `|fieldref` | 将字段值与同一事件中另一个字段的值进行比较 |
| `|re` | 正则表达式匹配 |
**字段解析** 首先使用字面键查找(如 `id.orig_h` 这类的 Zeek 扁平字段),然后回退到嵌套字典遍历(如 `DeviceDetail.isCompliant` 这类的 Azure 结构化字段)。这能正确处理这两种日志格式,而无需特殊用例处理。
### 转换检查
在评估之前,每条规则都会通过 sigma-to-spl 的 `Converter` 运行。有两种结果会标记一条规则:
- **转换错误** → 状态为 `FAIL` 并附带异常消息
- **输出中包含 `MANUAL:`** → 规则被标记为宽松评估(误报将变为 `WARN` 而不是 `FAIL`)
`MANUAL:` 警告由 sigma-to-spl 的 `PostProcessor` 在以下两种情况下发出:
1. 规则的 logsource category 为 `dns`(需要熵评分)
2. 原始规则 YAML 包含 `# NOTE:` 注释(内联记录了仅限 SPL 的逻辑)
使用 `# NOTE:` 记录仅限 SPL 新增内容的规则在 Sigma 层级上被视为有意放宽 —— 它们的误报是预期之中的,并由 SPL 进行处理。
### 无法测试的内容
- **聚合条件** —— 使用 `count by`、`stats`、`streamstats` 的规则需要时间窗口,会被自动跳过
- **仅限 SPL 的过滤** —— 风险评分、基于查找的抑制、`eval`/`rex` 转换;这些由 `MANUAL:` / `WARN` 路径覆盖
- **字段提取** —— 由 PostProcessor 应用的转换(索引路由、宏替换)不会反映在 Sigma 条件中
## 测试数据格式
每项检测需要在文章旁边有两个 JSON 文件:
```
test-data/
malicious-sample.json # events the rule MUST match (≥1 required)
benign-sample.json # events the rule MUST NOT match (0 allowed, unless MANUAL:)
```
文件可以包含单个 JSON 对象或 JSON 数组。请随意使用 `_comment` 键 —— 评估器会忽略未知字段。Sigma 规则合法触发但被 SPL 抑制的事件(已知误报)仅当规则带有 `# NOTE:` / `MANUAL:` 标记时才属于 `benign-sample.json`。
## 规则 → 测试数据映射
该工具从规则目录向上遍历以自动发现 `config/validator.yml`。该配置将规则标识符映射到测试数据路径:
```
rules:
network/dns-tunneling-high-entropy-subdomains:
test_data: ../../detection-notes/detections/network/dns/test-data
# Intentionally excluded (upstream mirror — no local test data)
identity/oauth-device-code-phishing-sigmahq:
test_data:
```
路径相对于 `validator.yml` 进行解析。具有 `test_data: null` 的规则被视为明确排除(不会被覆盖率检查标记为缺失)。
## CI 集成
在 `sigma-to-spl` 的 GitHub Actions 工作流中,`validate` 作业将检出所有三个代码库作为同级目录,以便 `validator.yml` 中的相对路径解析与本地开发保持一致:
```
$GITHUB_WORKSPACE/
sigma-to-spl/ ← main checkout (rules, config)
detection-notes/ ← test-data source
detection-validator/← tool
```
`validate` 作业在 `convert` 作业之后运行,并作为 PR 的门禁。检测断言失败将阻止合并。
## 设计决策
**为什么选择 Sigma 原生评估而不是 SPL 评估?**
pySigma 是一个编译器,而不是运行时 —— 它没有内置的“此事件是否匹配此规则?”函数。编写一个 SPL 子集评估器将测试派生产物(转换输出),而不是数据源真实面貌。Sigma 条件是工程师编写的逻辑;这才是应该被测试的内容。
**为什么对 MANUAL: 规则使用 WARN 而不是跳过?**
跳过会掩盖检测遗漏。带有 SPL 新增内容的规则仍然需要在 Sigma 层级触发恶意事件 —— SPL 只是 *增加* 了对误报的过滤。WARN 确认了基础检测在运行,同时承认由 SPL 处理精度问题。
**为什么使用 `# NOTE:` 约定?**
pySigma 在解析期间会剥离 YAML 注释,因此没有其他方法可以从规则元数据中传达“此规则有意不完整”。检测块中的 `# NOTE:` 是一种可见且轻量级的信号,为检测作者和工具都提供了上下文。
标签:AMSI绕过, Homebrew安装, JSON测试, Maven, Python, Rootkit, Sigma-to-SPL, Sigma规则, URL发现, Zeek, 威胁检测, 安全检测, 无后门, 漏洞验证, 目标导入, 网络安全, 自动化payload嵌入, 规则验证, 误报测试, 逆向工具, 隐私保护