discovery_X
**用于授权渗透测试的自主发现/侦察 Agent**,完全通过
Web 控制面板控制。收集目标的攻击面,然后利用 AI
推断隐藏的 endpoint —— 具备严格的 scope 防护栏。
**核心能力:**
- 🔎 **发现隐藏的 endpoint** — 爬取 HTML + 分析 JavaScript(文件和内联)以
挖掘未链接的 path/endpoint;**有或无** AI 均可运行。
- 🧬 **指纹识别技术栈及版本**(WordPress、Next.js、Laravel、nginx 等),然后
对每种技术的特有 path 进行**定向 dirbust**。
- ✅ **验证 liveness**(检测 *soft-404*)并通过 headless browser **渲染 SPA**。
- 🤖 **多 Provider 的 AI 大脑** — 兼容任何 OpenAI 兼容的 endpoint,或使用 **LiteLLM**
代理以支持 OpenAI / Anthropic / Gemini / Ollama 等。
- 🕸️ **交互式 attack graph** — 映射资产关系;突出显示 AI 推断出的 endpoint。
- 🖥️ **Web 控制面板(OWASP 加固)** — 每项发现都会显示 **技术栈及版本**、
**HTTP 状态码**、服务器、标题以及存活/死亡状态。保存扫描历史记录。
- 🐳 **一条命令部署**(基于 Docker,内置 Chromium 和 Graphviz)。
设计与架构背景:见 [`discovery.md`](./discovery.md)。
## 使用 Docker 快速开始(推荐)
无需在宿主机上安装 Rust/Node/Chromium —— 它们全都包含在镜像中。
```
# 1. 生成 admin 密码 hash(若无此项,server 将拒绝启动)。
docker compose run --rm discovery_x hash-password
# → 输入密码,复制 hash 行 "$argon2id$..."
# 2. 将凭据保存在 docker-compose.yml 旁的 .env 文件中。
# 重要:请用单引号包裹 hash —— 如果不加引号,'$' 将被
# Compose 插值,导致 hash 损坏。
cat > .env <<'EOF'
DISCOVERY_ADMIN_USER=admin
DISCOVERY_ADMIN_PASSWORD_HASH='$argon2id$v=19$m=19456,t=2,p=1$...' # hasil langkah 1
AGENT_AI_API_KEY=sk-... # opsional → AI brain
EOF
# 3. 构建并运行。
docker compose up -d --build
# 4. 打开 http://127.0.0.1:7373 → 登录。
```
端口仅映射到 `127.0.0.1`(不暴露至局域网)。发现结果与历史记录数据库
存储在 `./data`(volume)中。镜像内已内置 Chromium(用于渲染 SPA)和 Graphviz(用于 attack graph)。如需远程访问,请放置于 **reverse-proxy TLS** 之后。
## 手动构建(不使用 Docker)
需要:Rust(≥1.81)、Node 20+,以及可选的 `chromium`(用于渲染 SPA)和 `graphviz`(用于 attack graph)。
前端(React/Vite)会被嵌入到二进制文件中,因此**必须先构建前端**:
```
cd frontend && npm install && npm run build && cd .. # menghasilkan frontend/dist
cargo build --release # binary: target/release/discovery_x
cargo test # unit test (scope, kontrak AI, parser)
```
配置并运行:
```
cp config.example.toml config.toml # lalu sunting bila perlu
./target/release/discovery_x hash-password # cetak hash Argon2id admin
# → 将其放入 config.toml [server].admin_password_hash,或者:
# export DISCOVERY_ADMIN_PASSWORD_HASH='$argon2id$...'
./target/release/discovery_x --config config.toml
# → 打开 http://127.0.0.1:7373 → 登录
```
## 使用控制面板
- **Config** — 配置侦察(深度、feeds、dirbust、渲染、verify-live 等)+ **AI API key**
(存储在 SQLite 中,显示时进行掩码处理;无 key 则进入“仅侦察模式”)。
- **Dashboard** — 填写 *seed* 和 *scope*(白名单,每行一个 host/IP)并勾选
授权选项 → **开始**。实时监控统计/发现/日志(通过 SSE)。
- **发现详情** — 每个资产都会获得以下徽章标识:
- 检测到的**技术栈**及其**版本**(例如 `WordPress 6.2`、`nginx 1.18`);
- 根据类别显示颜色的 **HTTP 状态码**(2xx 绿色,3xx 蓝色,4xx 黄色,5xx 红色);
- **server** header、页面**标题**、**SPA** 标记,以及 **liveness**(`● 存活`/`○ 死亡?`)。
- 列表上方有**检测到的技术栈**和 **HTTP 状态分布**的摘要。
- **交互式 attack graph (D3)** — 点击 **“查看 attack graph →”** 按钮可打开
力导向图:节点按资产类型着色,hub 节点更大,`calls` 边(AI 推断的 endpoint)
会被高亮显示;支持拖拽/缩放,点击节点打开 URL。支持导出 **SVG** (Graphviz)
和下载 **DOT**。
发现结果保存在 SQLite (`discovery.db`) 中:包含 `assets`(单次扫描)、`scans`(历史记录)、
`settings`(配置)等数据表。手动查询:
```
sqlite3 discovery.db 'SELECT kind, url, origin, notes FROM assets WHERE scan_id=1'
```
### 控制面板的安全性 (OWASP)
使用 **Argon2id** 密码;基于 CSPRNG 的会话 token(cookie 为 `HttpOnly; SameSite=Strict`);每次变更操作均包含 **CSRF**
token;基于 IP 的登录 **rate-limit/lockout**;安全 headers(CSP `self`、
`X-Frame-Options: DENY`、`nosniff`、`no-referrer`);API key **绝不会回传**
(仅显示状态和最后 4 个字符)。默认 **绑定 localhost** —— 如需远程访问,请使用
reverse-proxy TLS。
## AI 大脑与多 Provider (LiteLLM)
AI 大脑使用 **兼容 OpenAI 的 chat-completions endpoint**,因此任何
采用该格式的 provider 都可以直接接入 —— 只需设置 **Base URL + Model + API key**
(通过控制面板的 **Config**、`config.toml` 文件,或环境变量 `AGENT_AI_BASE_URL` / `AGENT_AI_MODEL`
/ `AGENT_AI_API_KEY`)。默认值为:GLM-5.2。
为了**同时访问多个 provider**(OpenAI、Anthropic/Claude、Gemini、Ollama 等)
而无需修改代码,请使用已集成在 `docker-compose.yml` 中的 **LiteLLM** 代理
(`litellm` profile):
```
# 1. 准备 model/provider 列表。
cp litellm.config.example.yaml litellm.config.yaml # sunting model_list sesuai kebutuhan
# 2. 填写 .env(provider 密钥不放入 config 文件 —— 从 env 中读取):
cat >> .env <<'EOF'
LITELLM_MASTER_KEY=sk-rahasia-proxy-anda
OPENAI_API_KEY=sk-...
ANTHROPIC_API_KEY=sk-ant-...
GEMINI_API_KEY=...
# 将 discovery_X 指向 proxy 并从 litellm_config.yaml 中选择 model alias:
AGENT_AI_BASE_URL=http://litellm:4000/v1/chat/completions
AGENT_AI_MODEL=claude
AGENT_AI_API_KEY=sk-rahasia-proxy-anda
EOF
# 3. 同时运行 discovery_X 和 LiteLLM。
docker compose --profile litellm up -d --build
```
LiteLLM 会根据 `litellm.config.yaml` 中的 `model_name`(别名),将单一 endpoint 的请求路由到多个 provider。只需将 `AGENT_AI_MODEL` 更改为其他别名即可切换模型。
代理仅在 Docker 内部网络中暴露(不对宿主机暴露)。
## 架构
```
main.rs → web server (axum, bind 127.0.0.1:7373)
├─ /api/login,/logout,/csrf auth (Argon2id, sesi cookie, CSRF, rate-limit login)
├─ /api/config recon + API key (disimpan di SQLite, key dimask)
├─ /api/scan, /api/scans start/stop + riwayat (satu scan aktif)
├─ /api/events (SSE) progres live → React dashboard
└─ static (rust-embed) frontend React/Vite (di-embed ke binary)
│ ScanManager.start
▼
engine::run_scan → Orchestrator (tokio, mpsc + select!)
├─ http worker (reqwest) → crawl + jsparse (swc) + fingerprint/dirbust + feeds + render SPA
├─ dns worker (hickory) → enumerasi subdomain
└─ AI brain (GLM-5.2) → AIActionPlan (divalidasi serde, retry-on-error)
State: SQLite (sqlx) — `assets` (per-scan) + `scans` (riwayat) + `settings` (config)
Graph: petgraph attack graph → ekspor DOT (Graphviz) / JSON (D3)
```
**Attack graph** (`petgraph`):每个资产作为节点,关系作为边
(`links`、`references`、`contains`、`calls`、`resolves`、`hosts`、`guessed`)。`calls` 边
代表 AI 根据 JS 文件推断出的 endpoint —— 这也是最引人注目的“隐藏资产”。
并发受全局 **及** 域名级别的 `Semaphore` 限制(防止对目标发起洪水请求);
每个请求在发送前都会针对 scope 白名单进行校验。
提升发现覆盖范围:
- **解析内联 `