DreadpiratePickles/sentry-sundae
GitHub: DreadpiratePickles/sentry-sundae
一款将 Suricata/Snort 原始告警日志转化为可读的终端与 Web 仪表板的防御性 IDS 告警分拣与规则校验工具。
Stars: 0 | Forks: 0
# 🍨 Sentry Sundae
### 带有上下文樱桃的 IDS 警报。
    
*Suricata 会交给你 40,000 条警报,却不会提供任何关于它们的见解。*
`sentry-sundae` 将原始的 Suricata/Snort 警报日志转化为人类可以实际分拣的内容。它提供了一小包本地检测规则,对它们进行 **lint**,将 Suricata EVE JSON 和 Snort "fast" 警报 **标准化** 到 SQLite 存储中,并将结果呈现为 **漂亮的终端仪表板** 或 **本地 Flask Web 控制台** —— 同时为整个过程的脚本化提供了清晰的 `--json` 路径。
它是一个用于 **你拥有或被授权监控** 的网络和主机的 **防御性** 工具。它只 *读取* 警报日志并 *写入* 检测规则;它从不接触目标、发送流量或阻止任何东西。
## 为什么会有这个工具
IDS 引擎非常擅长检测,但作为审查界面却很糟糕 —— 没人愿意永远 `tail -f eve.json`。Suricata 继续进行数据包检查;`sentry-sundae` 位于其上,回答操作员的问题:*有多少警报,严重程度如何,谁是对话最多的 IP,哪些签名被触发了,以及我的规则包是否有效?*
## 工作原理(数据流)
```
rules/local.rules ──lint──▶ findings (sid/msg/parens…)
│ write-rules
▼
Suricata ──▶ eve.json ─┐
├─▶ parse ──▶ normalize (IDSAlert) ──▶ SQLite (dedup) ──┐
Snort ────▶ fast log ──┘ │
▼
summary (rich terminal) │
serve (Flask + JSON) ◀┘
```
1. **解析。** 每个日志都在大小限制下逐行(从不整体读取)流式读取。每一行都被视为恶意的:格式错误/截断的行会被 *计数并跳过*,而不是致命错误。Suricata `alert` 事件和 Snort fast 行被映射为一个统一的 `IDSAlert` 结构(时间戳、引擎、签名、类别、严重性、五元组)。
2. **存储。** 警报落入 SQLite。每一行都带有一个内容指纹,并使用 `INSERT OR IGNORE` 插入,因此 **重新解析同一个日志是幂等的** —— 不会重复计数。严重性是统一的:对于两个引擎,**1 = 最紧急**。
3. **可视化。** `summary` 汇总总数、严重性直方图、源 IP Top 排行、签名 Top 排行和最近的警报。`serve` 将相同的数据作为 Web 仪表板和 JSON API 公开。
**数据库结构:** `alerts(id, timestamp, engine, signature, category, severity, src_ip, src_port, dest_ip, dest_port, protocol, fingerprint)`。
## 设置
```
cd sentry-sundae
python -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txt
# (可选)pip install -e . 以将 `sentry-sundae` entrypoint 添加到 PATH
```
开发无需可编辑安装 —— 使用 `PYTHONPATH=src` 运行所有内容:
```
PYTHONPATH=src python -m sentry_sundae.cli --help
```
要实时生成警报,你还需要在传感器主机上安装 Suricata 和/或 Snort(在 Kali/Parrot 上使用 `sudo apt install suricata snort`)。解析现有日志、lint 规则或运行仪表板**不需要**它们。
## CLI 用法
全局:`--db PATH`(环境变量 `SENTRY_SUNDAE_DB`)选择 SQLite 存储。
每个数据命令还接受 `--json`(纯 JSON 输出到 stdout)、`--plain`(禁用颜色/动画),并遵循 `NO_COLOR` 环境变量和非 TTY 管道。
### `parse-eve` / `parse-snort` — 摄取警报
```
# 使用 Suricata 生成 alerts,然后 ingest 它们
suricata -c configs/suricata.local.yaml -S rules/local.rules -r sample.pcap -l logs
PYTHONPATH=src python -m sentry_sundae.cli parse-eve --file logs/eve.json
PYTHONPATH=src python -m sentry_sundae.cli parse-snort --file /var/log/snort/alert
```
标志:`--file`(必需)、`--max-bytes`(内存保护,默认 512 MiB)。
```
┌───────────────────────────── Ingested eve.json ─────────────────────────────┐
│ matched 3 │
│ new rows 3 │
│ non-alerts 1 ← valid EVE events that weren't alerts (e.g. stats) │
│ malformed 1 ← truncated/garbage lines, safely skipped │
│ db sentry_sundae.sqlite3 │
└──────────────────────────────────────────────────────────────────────────────┘
```
`--json`:
```
{ "matched": 3, "inserted": 3, "duplicates": 0, "skipped": 1, "malformed": 1,
"total_lines": 5, "path": "logs/eve.json" }
```
### `summary` — 终端仪表板
```
PYTHONPATH=src python -m sentry_sundae.cli summary
PYTHONPATH=src python -m sentry_sundae.cli summary --min-severity 2 --engine snort
PYTHONPATH=src python -m sentry_sundae.cli summary --json > snapshot.json
```
标志:`--limit`(最近行数,1–1000)、`--min-severity N`(保留处于/高于该级别的警报,1=critical)、`--engine suricata|snort`。
```
┌── alerts ──┐ ┌── critical ──┐ ┌── engines ──┐
│ 5 │ │ 1 │ │ 2 │
└────────────┘ └──────────────┘ └─────────────┘
──────────────── severity mix ────────────────
sev 1 (critical) █████ 1
sev 2 (high) ██████████████ 3
sev 3 (medium) █████ 1
Top source IPs Top signatures
203.0.113.9 3 LOCAL XSS script tag in URI 1
198.51.100.7 2 LOCAL SQL injection keywords ... 1
Recent alerts
1 critical suricata 203.0.113.9:51344 → 192.0.2.10:80 LOCAL SQL injection …
```
### `lint-rules` — 验证规则包
Suricata/Snort 规则的结构化 linter:捕获缺失/重复的 `sid`、缺失的 `msg`、缺失的 `rev`/`classtype`(警告)以及不匹配的括号(典型的隐形规则杀手)。如果发现任何 *错误*,则 **退出代码为 2** —— 在 CI/pre-commit 中非常实用。
```
PYTHONPATH=src python -m sentry_sundae.cli lint-rules --file rules/local.rules
```
```
Rule lint
┌───────┬──────┬─────┬───────────────────────────┐
│ level │ line │ sid │ message │
├───────┼──────┼─────┼───────────────────────────┤
│ error │ 2 │ - │ unbalanced parentheses │
│ error │ 1 │ 1 │ missing msg │
└───────┴──────┴─────┴───────────────────────────┘
```
### `write-rules` — 生成本地规则包
```
PYTHONPATH=src python -m sentry_sundae.cli write-rules --out /etc/suricata/rules/local.rules --force
```
标志:`--out`(必需)、`--force`(如果没有此标志,将拒绝覆盖现有文件)。写入捆绑的规则包(URI 中的 SQLi/XSS、SSH SYN burst、路径遍历、已知的 Web 扫描器 user-agents),对写入的内容进行 lint,并打印规则树。
### `serve` — Flask Web 仪表板
```
PYTHONPATH=src python -m sentry_sundae.cli serve --host 127.0.0.1 --port 5069
```
- `GET /` — HTML 仪表板(严重性分布 + 对话最多者 + 最近警报)。
- `GET /api/alerts` — 相同数据的 JSON 格式;接受 `?limit=`、`?min_severity=`、`?engine=`(全部经过验证;垃圾数据将被忽略,绝不会导致崩溃)。
- `GET /healthz` — 存活探针。
## 安全与授权
- **默认回环地址。** `serve` 绑定 `127.0.0.1`。除非你传递 `--i-understand-exposure`(明确承认你拥有/被授权在该接口上公开仪表板),否则将 **拒绝** 绑定非回环地址。
- **无远程调试器暴露。** 在任何非回环绑定上都会拒绝 `--debug`,因为 Werkzeug 调试器允许远程代码执行。
- **假定输入是恶意的。** 日志和规则文件有大小限制、流式传输,并经过防御性解析;错误的行会被跳过,而不是致命的。不受信任的警报字符串被渲染为无危险的文本(无终端/标记注入),并在 Web 视图中通过 Jinja 自动转义,该视图还会发送保守的 CSP/frame 标头。
- **输出中无秘密。** 该工具仅读取本地文件及其自己的 SQLite 存储。它从不发出凭据或 token。
- 仅针对 **你拥有或被明确授权监控** 的网络和主机运行此程序。
## 运行测试
```
cd sentry-sundae
PYTHONPATH=src python -m pytest -q
```
快速、离线、无需网络且无休眠。涵盖了解析(包括格式错误和过大的输入)、幂等存储、严重性过滤、规则 linter 和 CLI 退出代码(包括 serve 绑定守卫)。还有一个无依赖的规则 linter 自检:
```
PYTHONPATH=src python -m sentry_sundae.rules # prints "rules self-check ok"
```
## 🏷️ 为什么叫 "Sentry Sundae"?
IDS 警报,顶部配上一颗上下文的樱桃。原始的警报日志就像对着一个还有其他工作要做的人开火。这个工具将其转变为在终端中可读的内容,并且 —— 这一点能在无形中帮你省去糟糕的一周 —— 在你将规则包发布到传感器 *之前* 对其进行 lint,此时一个损坏的规则还只是一个拼写错误,而不是一个盲区。
## 🔬 这个工具是如何构建的
**目的。** 一个平静的 IDS 审查控制台。它让 Suricata/Snort 继续进行检测,并将其原始的、本质上带有敌意的警报日志转化为令人愉悦的终端仪表板和安全的本地 Web 视图 —— 同时对你发送到传感器的规则包进行 lint。对日志只读,默认回环地址。
**工作原理。** 它在大小限制下逐行流式传输 `eve.json` / Snort 日志,防御性地强制转换垃圾字段,对每个警报进行指纹识别,并使用 `INSERT OR IGNORE` 插入,因此重新解析相同的日志是幂等的。`summary` 渲染汇总数据;`lint-rules` 对规则包进行评分;`write-rules` 生成并 lint 规则。
**出色的 CLI。** 统计磁贴仪表板(alerts/critical/engines)、颜色编码的严重性直方图、并排的源 IP Top 排行和签名 Top 排行表、可折叠的最近警报表,以及当存在错误时 `lint-rules` 返回退出代码 2(对 CI/pre-commit 友好);`write-rules` 打印其生成内容的丰富树状视图。
**关键改进。** *功能性:* 格式错误/截断的行会被计数并跳过,而不是导致摄取崩溃;文件在 512 MiB 的默认限制(`--max-bytes`)下流式传输;幂等的指纹摄取终结了重复计数;Snort 解析器现在可以恢复 `[Classification: ...]` 和 `gid:sid:rev`;原位 SQLite 迁移将指纹列添加到旧数据库中;wrappers、keys、subcommands 和退出代码的完全向后兼容性。*安全性:* 没有 `--i-understand-exposure`,`serve` 会拒绝非回环地址,并拒绝在回环地址外使用调试器;不受信任的警报/规则字符串被渲染为无危险的 `rich.Text`(禁用标记),以阻止控制台标记注入;经过验证/限制的 Web 查询参数;完全参数化的 SQL。
**示例。**
```
PYTHONPATH=src python -m sentry_sundae.cli summary
```
## ⚖️ 授权使用与安全章程
**这些是用于你拥有或被明确授权评估的系统、文件、网络和人员的防御性工具。** 在运行任何内容之前,请阅读本文:
- **授权不是可选项。** 钓鱼模拟、网络扫描、IP 信誉查询和 Web 应用程序探测都会触及他人的系统或数据。请首先获得书面授权。有几个工具 *拒绝行动*,直到你声明这一点(`--yes`、`--authorized-training`、`--i-have-authorization`、`--i-am-authorized` 及其相关参数)。
- **默认安全。** 每个 Web UI 都绑定到 `127.0.0.1`(回环地址)。出站流量、实时发送和主动扫描都受显式标志控制 —— 试运行、被动模式或拒绝并警告始终是默认行为。
- **没有意外的“自爆”隐患。** Flask `--debug`(Werkzeug 交互式调试器在任何 traceback 上都可以执行远程代码执行)会受到强烈的警告,并且在离开回环地址后会被完全拒绝。不受信任的输入有大小限制、经过验证,并以无危险的方式渲染,因此恶意文件或日志行无法崩溃 —— 或接管 —— 你的终端。
- **输出中无秘密。** API key 保留在请求头中,password 来自环境变量,任何敏感信息都不会被记录或打印。
这些不是攻击性工具。它们不包含任何 exploit、凭据收集器或 payload。如果某个工具 *可能* 被滥用,它的构造方式就是为了抵抗这种滥用。
## 🧪 开发
```
python -m venv .venv && source .venv/bin/activate
pip install -e .
pytest -q # 18 tests, no network, no sleeps
sentry-sundae --help
```
## 📄 许可证
在 **MIT License** 下发布。见 [LICENSE](LICENSE)。
防御性工具。无 exploit,无 payload,无凭据收集器。
标签:IDS/IPS, PB级数据处理, Python, SQLite, 安全运维, 无后门, 终端UI, 逆向工具