PWNSTXR69/Sentinel
GitHub: PWNSTXR69/Sentinel
一个基于 FastAPI 的 OSINT 聚合仪表板,将域名或 IP 的公开情报(端口、证书、子域名、WHOIS、邮件)整合到单一界面并提供历史趋势追踪。
Stars: 1 | Forks: 0
# Sentinel — OSINT 聚合仪表板
Sentinel 将有关域名或 IP 的公开可用信息整合到一个仪表板中:暴露的端口/服务、证书透明度数据和子域名、域名注册数据 (WHOIS),以及发布在目标自身公共网页上的电子邮件地址。结果存储在 SQLite 中,因此您可以利用目标页面上的 Chart.js 趋势线来跟踪目标的暴露状态随时间的变化。
基于 FastAPI(异步,因此四个查询并发运行,而不是依次执行)+ SQLAlchemy + SQLite + 服务器渲染的 Jinja2 模板构建。
## 检查内容
| 来源 | 收集的信息 | 是否需要 API key? |
|---|---|---|
| Shodan | 已解析 IP 上的开放端口、服务、banners | 可选 — 无需 key 时使用免费的 [InternetDB](https://internetdb.shodan.io)(仅限端口);添加 `SHODAN_API_KEY` 即可通过 Host API 获取完整的 banners/products/versions |
| crt.sh | 为域名颁发的证书,以及从其 SAN 中提取的子域名 | 否 |
| WHOIS | Registrar、org、creation/expiry dates、name servers | 否 |
| 公共页面 | 在域名自身的主页/联系/关于/隐私页面的 `mailto:` 链接或可见文本中找到的电子邮件 | 否 |
电子邮件收集器被特意设计为被动模式 — 它仅获取目标已经公开提供的页面(不猜测子域名,不使用第三方数据代理,不进行主动扫描)。
## 设置
Sentinel 目标版本为 **Python 3.14**。如果您在 Windows 上全新安装了 3.14,有几点值得注意:
- 始终在虚拟环境中安装,并始终以相同的方式调用 `pip`/`python`(`python -m pip ...`,然后是 `python run.py`)— 将纯粹的 `pip install` 与 PATH 中解析方式不同的 `python`/`uvicorn` 混合使用,是在看似成功的安装之后出现 `ModuleNotFoundError: No module named 'uvicorn'` 的最常见原因。
- `requirements.txt` 故意不对 `pydantic`/`pydantic-settings` 进行**版本锁定**(`>=2.10` / `>=2.7`),而不是锁定到确切的版本。Python 3.14 足够新,以至于较早的固定版本的 `pydantic-core`(其基于 Rust 的验证引擎)没有为它提供预构建的 Windows wheels,这迫使 pip 从源码编译 — 除非您安装了 MSVC C++ build tools(`link.exe not found`),否则编译会失败。让 pip 解析到最新的 `pydantic-core` 可以完全避免编译步骤,因为当前版本提供了预构建的 `cp314` wheels。在没有先检查 [Python 3.14 wheel 覆盖范围](https://pypi.org/project/pydantic-core/#files) 的情况下,不要将它们重新锁定到旧的确切版本。
- 如果您确实在其他依赖项上遇到 wheel 构建错误,解决方法几乎总是 (a) 以相同的方式提升该软件包的版本,或者 (b) 回退到 Python 3.12,它在所有地方都有完整的 wheel 覆盖。
```
cd sentinel
pip install -r requirements.txt
```
## 运行
```
python run.py
```
然后打开 **http://127.0.0.1:8000**。
- 添加目标(如 `example.com` 的域名,或原始 IP)。
- 在目标页面上点击 **Run New Scan**。它会并发查询所有四个来源,保存结果并显示在仪表板上。
- 稍后再次对同一目标运行扫描以建立趋势历史记录 — 目标页面上的图表会绘制每次扫描随时间发现的端口/子域名/证书/电子邮件。
- **Delete Target**(在目标列表或目标详情页面上)会要求您输入目标名称进行确认,然后才会删除目标及其完整的扫描历史记录 — 此操作无法撤销,因此特意设置得比普通的“您确定吗?”弹窗更难被意外触发。
交互式 API 文档(由 FastAPI 自动生成)位于 `/docs`。
## 项目布局
```
sentinel/
app/
main.py FastAPI app + startup (creates SQLite tables)
config.py Settings loaded from .env
database.py SQLAlchemy engine/session
models.py Target, Scan, PortResult, SubdomainResult,
CertificateResult, EmailResult, WhoisResult
schemas.py Pydantic response models
services/
shodan_service.py InternetDB / Shodan Host API
crtsh_service.py Certificate transparency lookups
whois_service.py WHOIS (blocking, run in a thread pool)
email_service.py Passive email harvesting from the target's own site
aggregator.py Runs all four concurrently, persists to DB
routers/
targets.py CRUD for targets
scans.py Trigger scans, fetch scan history, trend data
dashboard.py Server-rendered HTML pages
templates/ Jinja2 templates (dark navy/gold theme)
static/ CSS + (Chart.js loaded from CDN)
run.py Dev server entrypoint (uvicorn, --reload)
```
## 关于数据源的说明
- **crt.sh** 是一项免费的、社区运营的服务,也是四个来源中最不稳定的一个 — 它可能会超时或在负载下返回意外的错误代码(404、502、504),特别是对于具有庞大证书历史记录的域名(例如大型知名网站)。Sentinel 会以更长的超时时间重试一次,并将 404 视为“无匹配”而不是严重错误;持续性的失败仍然会记录在扫描的“Notes”部分中,而不会导致整个扫描失败。
- **WHOIS** 是一个阻塞式 socket 调用(不是 HTTP),因此它是通过 `asyncio.to_thread` 与其他异步查询一起调度的,而不是阻塞事件循环。许多 gTLD 现在默认对注册人电子邮件/姓名进行脱敏(GDPR 风格的隐私保护),因此 `raw_emails` 通常为空 — 这是预期行为,而不是 bug。
- **Shodan without a key** 使用免费的 InternetDB endpoint,它仅返回端口号/CPE,而不返回 banners。在 `.env` 中添加 key 以获取完整的服务 banners、products 和 versions。
- 部分失败(一个源宕机、达到速率限制等)不会导致整个扫描失败 — 每个源的 error 都会被收集并显示在目标页面的“Notes”部分,并且无论返回了什么数据,这些数据仍会被保存。
标签:AV绕过, ESC4, FastAPI, OSINT, Python, 动态插桩, 安全仪表盘, 实时处理, 情报收集, 无后门, 漏洞研究, 进程管理, 逆向工具