Qwerty-zsw/WatchTower-for-Bug-Bounty-with-UI
GitHub: Qwerty-zsw/WatchTower-for-Bug-Bounty-with-UI
集成了枚举、DNS解析、HTTP探测和漏洞扫描的 Bug Bounty 攻击面持续监控平台,通过单页仪表板和内嵌SQLite实现轻量化、零依赖的资产侦察与告警。
Stars: 0 | Forks: 0
带有 UI 的 Bug Bounty WatchTower
持续的攻击面侦察
映射 · 解析 · 探测 · 监控你的 bug-bounty 范围 —— 尽在一个仪表板。
## 功能
- **Web 仪表板** —— 程序、子域名、存活主机和 HTTP 服务整合于一个 UI 中,支持搜索、过滤和实时统计。零外部资源(无 CDN/字体)—— 这是一个仅约 36 KB 的独立页面,可在隔离的机器上离线运行。
- **实时扫描器** —— 从浏览器启动任何模块,并通过轻量级轮询实时跟踪工具输出(无需为每次扫描保持长时间运行的 SSE 线程)。
- **内嵌 SQLite 存储** —— 单文件,无守护进程,WAL 模式;Flask 进程和每个独立扫描任务并发对其进行读写。
- **感知程序的流水线** —— 范围按程序定义(范围内、范围外、通配符、CIDR、原始 IP);每个阶段都会自动解析所属程序。
- **全程序处理** —— DNS 解析和 HTTP 探测在程序的整个资产集上运行一次,而不是按根域执行,因此不会遗漏任何内容,也不会重复工作。
- **原始 IP 处理** —— 程序的 IP(和 CIDR 范围)会与发现的域名一起被解析(通过 dnsx 进行反向 DNS)和探测(httpx)。
- **幂等存储** —— 重新运行任何阶段都会更新现有记录,而不是创建重复项。
- **自动同步** —— 将程序 JSON 放入 `programs/`,文件系统监视器会立即将其导入。
- **通知** —— 资产新增/变更时通过 Discord webhook 和 Telegram bot 发送警报。
- **应用内设置** —— API 密钥、通知通道和 subfinder provider 配置均可通过浏览器编辑。
## 架构
```
watchTower/
├── app.py Flask app — web UI, REST API, scan-job control
├── config.py Central config (WATCH_DIR, DB_PATH, webhook)
├── database/
│ ├── db.py SQLite engine + MongoEngine-compat shim + helpers
│ ├── scope_utils.py Wildcard → enumerable-root + program resolution
│ └── watchtower.db SQLite database file (created at runtime)
├── programs/ Program scope JSON (auto-synced → SQLite)
├── subdomain_enum/ subfinder · crtsh · abuseipdb · wayback · chaos
├── ns/ dnsx DNS resolution → LiveSubdomains
├── http_probe/ httpx HTTP probing → HTTP
├── nuclei/ Nuclei scanning → notifications
├── templates/index.html Single-page dashboard
├── ecosystem.config.js pm2 process definition
└── start.sh One-shot installer / deployer
```
### 数据流
```
program scope ─► enumeration ─► DNS resolution ─► HTTP probing ─► vuln scan
(scopes, (subfinder, (dnsx) (httpx) (nuclei)
wildcards, crtsh, ...) │ │ │
CIDRs, IPs) │ ▼ ▼ ▼
▼ LiveSubdomains HTTP Discord /
Subdomains Telegram
```
## SQLite 表
所有数据都存储在一个文件中(`database/watchtower.db`,WAL 模式)。列表值
列(providers、ips、tech、status codes、headers)以 JSON 文本形式
存储并进行延迟解码,因此为单个字段遍历数十万行记录时,绝不会实体化其余数据。
| 表名 | 内容 |
|------------------|--------------------------------------------------------------------|
| `programs` | 带有 `ooscopes`、`wildcards`、`cidrs`、`ips`、`domains` 的程序 |
| `subdomains` | 原始发现的子域名(DNS 之前),标记有发现来源 |
| `livesubdomains` | 带有 IP 和 CDN 信息的 DNS 解析主机 |
| `http` | 存活的 HTTP 服务 —— 标题、状态、技术、标头、favicon |
唯一性由 `UNIQUE(program_name, subdomain)`(按表)强制执行,因此
重新运行任何阶段都会执行 upsert,而不是重复创建。Provider 列表作为
集合累积。不涉及外部数据库进程。
范围模型:程序的可枚举根是其 `scopes` 加上每个 `wildcards` 条目的
固定根(`*.example.com` → `example.com`),减去 `ooscopes`。
`_program_for_domain` 解析器将任何根 —— 字面范围、通配符根或
原始 IP —— 映射回其所属程序,因此无论范围是如何
定义的,每个阶段都能正确绑定结果。
## 模块
### 枚举 (`subdomain_enum/`)
| 模块 | 来源 | 需要密钥 |
|-------------|--------------------------------------------------|----------------------------|
| `subfinder` | ProjectDiscovery subfinder (`-all -recursive`) | provider 密钥 (可选) |
| `crtsh` | crt.sh Certificate Transparency (PostgreSQL) | — |
| `abuseipdb` | AbuseIPDB `/check` 反向 DNS 主机名 | **AbuseIPDB 密钥** |
| `wayback` | Wayback Machine | — |
| `chaos` | ProjectDiscovery Chaos | **PDCP 密钥** |
| `enum_all` | 对所有程序运行每个枚举来源 | — |
### DNS 解析 (`ns/`)
- `ns` —— 通过 **dnsx** 解析程序的所有子域名及其原始 IP(反向 DNS),写入存活主机。
- `ns_all` —— 跨越每个程序执行相同操作。
### HTTP 探测 (`http_probe/`)
- `http` —— 通过 **httpx** 探测程序的所有存活主机和原始 IP。探测使用发起请求的浏览器的 `User-Agent`。
- `http_all` —— 跨越每个程序执行相同操作。
### 漏洞扫描 (`nuclei/`)
- `nuclei_fresh` —— 扫描最近发现的 HTTP 服务。
- `nuclei_all` —— 扫描每个已存储的 HTTP 服务。
## 设置
### 1. 依赖
```
# Python
pip install -r requirements.txt
# Go tools (ProjectDiscovery)
go install -v github.com/projectdiscovery/subfinder/v2/cmd/subfinder@latest
go install -v github.com/projectdiscovery/dnsx/cmd/dnsx@latest
go install -v github.com/projectdiscovery/httpx/cmd/httpx@latest
go install -v github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest
```
Python 依赖要求:`flask`、`waitress`、`tldextract`、`requests`、
`watchdog`、`pyyaml`、`psycopg2-binary`。**无需 MongoDB,无需数据库服务器** ——
存储使用的是标准库中的 `sqlite3` 模块。
### 2. 数据库
无需安装或运行任何内容。SQLite 文件会在首次
启动时自动创建于 `database/watchtower.db`(可通过 `WATCHTOWER_DB` 环境变量覆盖)。
### 3. 配置
- `config.py` —— `WATCH_DIR`、`DB_PATH`、`WEBHOOK_URL`。
- `.env` —— `WATCHTOWER_PORT`、`WATCHTOWER_DIR`。
- **可选环境变量。** 侦察工具 (httpx/dnsx/subfinder/nuclei) 以
其自身的原生并发运行 —— 没有包装器强加的限制。仅有的调节项:
| 变量 | 默认值 | 控制 |
|-----|---------|----------|
| `WATCHTOWER_THREADS` | `4` | waitress WSGI 线程 |
| `WT_JOB_WORKERS` | `4` | 每次扫描任务的并行目标数 |
| `WATCHTOWER_DB` | `database/watchtower.db` | SQLite 文件路径 |
### 4. 运行
```
# 开发 (Werkzeug reloader) — 设置 WATCHTOWER_DEBUG=1
WATCHTOWER_DEBUG=1 python app.py
# 生产 — waitress (未处于 debug 时自动选择)
python app.py
# 生产 (pm2) — 参见 ecosystem.config.js
pm2 start ecosystem.config.js
pm2 save
```
`start.sh` 自动安装/部署到 `/opt/watchtower`,设置 pm2,并添加
shell 别名。
在 `http://localhost:8854`(或你的 `WATCHTOWER_PORT`)打开仪表板。
## 定义程序
在 `programs/` 中添加一个 JSON 文件(保存时自动导入),或者使用 UI 中的 **程序**
页面:
```
{
"program_name": "example",
"scopes": ["example.com", "example.io"],
"ooscopes": ["cdn.example.com"],
"wildcards": ["*.example.com", "vpn.*.example.com"],
"cidrs": ["1.2.3.0/24"],
"ips": ["8.8.8.8"]
}
```
## 用法
### Web UI(推荐)
进入 **Scanner**,选择一个目标程序(或单个域名),选择一个模块,
然后点击 **Run**。输出将实时流式传输。建议顺序:
```
enumeration (subfinder / crtsh / …) → ns → http → nuclei
```
### REST API
| Endpoint | 描述 |
|-----------------------------------------|--------------------------------------|
| `GET /api/stats` | 仪表板计数器 |
| `GET /api/programs/all` | 所有程序 |
| `POST /api/programs/add` | 添加程序 |
| `DELETE /api/programs/
` | 删除程序及其资产 |
| `GET /api/subdomains/program/` | 程序的原始子域名 |
| `GET /api/lives/program/
` | 程序的 DNS 解析主机 |
| `GET /api/http/program/
` | 程序的 HTTP 服务 |
| `POST /api/scan/start` | 启动独立扫描任务 |
| `GET /api/scan/jobs` | 列出最近的扫描任务 |
| `GET /api/scan/job/` | 单个任务的状态 |
| `GET /api/scan/log?job=&offset=` | 增量日志跟踪 (poll) |
| `POST /api/scan/stop?job=` | 停止运行中的任务 |
| `GET\|POST /api/settings` | 读取 / 更新设置 |
| `GET\|POST /api/subfinder-config` | 读取 / 更新 subfinder provider |
通过 API 运行模块:
```
# 启动 job
curl -s -X POST http://localhost:8854/api/scan/start \
-H 'Content-Type: application/json' \
-d '{"tool":"subfinder","program":"example"}'
# tail 其 log (使用返回的 offset 重复执行)
curl -s "http://localhost:8854/api/scan/log?job=&offset=0"
```
扫描作为**独立进程**运行,并写入日志文件,因此在浏览器关闭后
扫描仍会继续运行,甚至在 Flask 重启后也能幸存 —— UI
通过轮询日志重新附加。
## 设置
可从 **Settings** 页面配置(持久化到 `settings.json`):
- **通知** —— Discord webhook、Telegram bot token + chat ID。
- **系统** —— 监视目录、程序自动同步开关。
- **API 密钥** —— ProjectDiscovery (Chaos/PDCP)、AbuseIPDB。
- **Subfinder provider** —— 在模态 YAML 编辑器中直接编辑 `provider-config.yaml`(保存时验证)。
## 注意事项
- crt.sh 的公共 PostgreSQL endpoint 不稳定;`crtsh` 模块会自动重新连接并重试。
- `abuseipdb` 模块使用真实的 AbuseIPDB API 并需要密钥 —— 它将域名解析为其 IP,并存储在范围内发现的反向 DNS 主机名。
- `ns` 和 `http` 是有状态的消费者:它们对枚举已经发现的内容进行操作,因此请先运行枚举。
## 免责声明
仅用于对你已获得授权测试的目标(例如,在其声明范围内的 bug-bounty 程序)进行操作。你对如何使用此工具负责。
标签:Bug Bounty, Flask, GitHub, SQLite, Web面板, 可自定义解析器, 实时处理, 密码管理, 攻击面测绘, 数据可视化, 网络测绘, 自动化侦察, 运行时操纵, 逆向工具