|
1 | | -# Engagement engine (v0) |
| 1 | +# Engagement engine |
2 | 2 |
|
3 | | -The eval harness proved the gap to "automate 80% of the grind" isn't the *skills* |
4 | | -(the base model already exploits standard classes) — it's an **autonomous engagement |
5 | | -system**: scope-safe, stateful, multi-step, false-positive-disciplined. This is that |
6 | | -system's v0 skeleton. |
| 3 | +A **decision-support engine**, not an autonomous robot. It maps a target's attack surface |
| 4 | +deterministically, **categorizes it against the skill arsenal** (which `hunt-*` skill applies |
| 5 | +where), and **shows you each stage live** — so you spend your expert 20% where the 80% |
| 6 | +automation points. It does **not** try to test everything itself; active hunting is opt-in. |
7 | 7 |
|
8 | | -## Design principle |
9 | | -**Control flow is deterministic code; only hunting/verifying is the LLM.** Scope, |
10 | | -state, dispatch, ranking, dedup, and reporting are Python — so a long unattended run |
11 | | -is *safe* (can't go out of scope), *auditable* (everything on disk), and *resumable*. |
| 8 | +## Design principles |
| 9 | +1. **Deterministic-first.** Breadth (recon, parameter discovery, secret scanning, service |
| 10 | + fingerprint, categorization) is plain Python + passive tooling — **`$0`, no agents, no |
| 11 | + rate-limit burn**. The LLM is reserved for the few judgment calls in the opt-in hunt. |
| 12 | +2. **Map-first, hunting opt-in.** A default run stops at the **arsenal map** and hands off to |
| 13 | + you. Spend agents only when you choose (`--hunt`). |
| 14 | +3. **Show every stage.** Each phase logs what it found, live, so you always know where to focus. |
| 15 | +4. **Curl-first.** Active testing uses `curl`; Burp MCP is optional (OOB/blind/fuzzing only). |
| 16 | +5. **Safe by construction.** Scope is a deterministic allowlist; agents run **read-only by |
| 17 | + default** with hard rules-of-engagement; a deterministic scope-audit flags any out-of-scope PoC. |
12 | 18 |
|
13 | 19 | ``` |
14 | | -scope ─▶ recon ─▶ rank ─▶ hunt ─▶ validate ─▶ report |
15 | | - │ │ │ │ |
16 | | - │ └ discoveries filtered to in-scope hosts |
17 | | - └ deterministic allowlist; no agent is ever dispatched at an out-of-scope target |
18 | | - │ └ adversarial verifier rejects false positives |
19 | | - └ one focused hunt agent per ranked (url, param, class) |
| 20 | + DEFAULT (deterministic, $0, no agents) │ OPT-IN (--hunt) |
| 21 | + recon ───▶ rank ───▶ map ──────────────────────────────▶│ hunt ─▶ validate ─▶ report |
| 22 | + │ │ └ surface → skill arsenal + │ │ └ adversarial verifier (read-only) |
| 23 | + │ │ curl-first probes (arsenal.md) │ └ curl-first agent per ranked (url,param,class), skills-off |
| 24 | + │ └ class-weight priority (secrets boosted) │ |
| 25 | + └ service/tech + JS endpoints + JS secrets + ALL params (gau + katana), categorized |
20 | 26 | ``` |
| 27 | +> **OSINT (subdomain/asset enum) is a *separate* concern** — handled by Claude-OSINT, not the |
| 28 | +> engine. The engine takes the in-scope seed target(s) and goes straight to deterministic recon. |
21 | 29 |
|
22 | 30 | | Piece | What it is | |
23 | 31 | |---|---| |
24 | 32 | | `scope.py` | deterministic allowlist (apex/wildcard/CIDR/regex; deny-wins; default-deny). Enforced at recon **and** hunt. | |
25 | | -| `state.py` | persistent, resumable engagement store (`state.json` + `evidence/` + `engine.log` + `report.md`). | |
26 | | -| `agent.py` | headless `claude -p` dispatch (skills + Burp MCP) + JSON extraction. | |
27 | | -| `engine.py` | the orchestrator: phases, scope enforcement, ranking, candidate→confirm flow, report. | |
| 33 | +| `recon.py` | **deterministic recon** — per target: service/tech (JS markers), JS-bundle endpoint mining, **JS secret scanning** (AWS/GCP/Anthropic/OpenAI/Slack/GitHub/Stripe/EmailJS… keys, redacted), and **all input parameters** from two independent sources — `gau` (passive historical) + `katana` (active live crawl). Noise-filtered, scope-filtered, multi-class categorized. No LLM in the find-step. | |
| 34 | +| `skill_map.py` | **arsenal categorization** — maps each `(endpoint\|param, class)` → the specific `hunt-*` skill(s) **actually installed** in `~/.claude/skills`, plus a curl-first starter probe. Tech-stack skills (`hunt-nextjs`, `hunt-nodejs`…) mapped from the fingerprint. | |
| 35 | +| `osint.py` | **separate/optional** — per-target service/tech probe (PD `httpx-toolkit`) reused by recon. Its subdomain-enum path is *not* in the engine flow (that's Claude-OSINT). | |
| 36 | +| `state.py` | persistent, resumable engagement store (`state.json` + `evidence/` + `engine.log` + `arsenal.md` + `report.md`). | |
| 37 | +| `agent.py` | headless `claude -p` dispatch + JSON extraction. **Skills OFF by default** (eval: ~0 capability gain, saves ~12–15k tokens/agent). Used only for the opt-in hunt/validate. | |
| 38 | +| `engine.py` | the orchestrator: phases, scope enforcement, ranking, the map, parallel hunt/validate, candidate→confirm, report. | |
| 39 | + |
| 40 | +## The map (the default deliverable) |
| 41 | +`map` writes `arsenal.md` and logs every target live — for each endpoint/parameter: the attack |
| 42 | +classes, the exact `hunt-*` skill(s) to open, and a ready-to-run curl. Example line: |
| 43 | +``` |
| 44 | +map: redirect_to https://t/wp-login.php?redirect_to=FUZZ ssrf→hunt-ssrf lfi→hunt-lfi open-redirect→hunt-open-redirect |
| 45 | +``` |
28 | 46 |
|
29 | 47 | ## Run |
30 | 48 | ```bash |
31 | | -cp engine/burp-mcp.json.example engine/burp-mcp.json # set your mcp-proxy jar path |
| 49 | +# DEFAULT — deterministic map only ($0, no agents). Stops for you with arsenal.md: |
| 50 | +python3 engine/engine.py --scope my-engagement.json |
| 51 | +# scope file = {name, in_scope, out_of_scope, seeds}; output in ~/.bughunter-engagements/<name>/ |
32 | 52 |
|
33 | | -# dry-run the whole flow with canned agent output (no agents, no budget) — proves the wiring: |
34 | | -python3 engine/engine.py --scope engine/engagement.example.json --base /tmp/eng --mock |
| 53 | +# OPT-IN — auto-test the mapped surface with agents (read-only, curl-first, parallel): |
| 54 | +cp engine/burp-mcp.json.example engine/burp-mcp.json # only if you want Burp for OOB/blind |
| 55 | +python3 engine/engine.py --scope my-engagement.json --hunt --parallel 3 --max-hunts 12 |
| 56 | +python3 engine/engine.py --scope my-engagement.json --hunt --allow-intrusive # permit state-changing PoCs (off by default) |
35 | 57 |
|
36 | | -# live (needs Burp running + claude budget); scope file = {name, in_scope, out_of_scope, seeds}: |
37 | | -python3 engine/engine.py --scope my-engagement.json --max-hunts 8 |
38 | | -python3 engine/engine.py --scope my-engagement.json --phases hunt,validate,report # resume later phases |
| 58 | +# dry-run the whole wiring with canned output (no agents, no budget): |
| 59 | +python3 engine/engine.py --scope engine/engagement.example.json --base /tmp/eng --mock --hunt |
| 60 | + |
| 61 | +# standalone recon (deterministic, no engine state): |
| 62 | +python3 engine/recon.py https://target/ target.com |
39 | 63 | ``` |
40 | | -Engagement state + report land in `~/.bughunter-engagements/<name>/` (outside the repo). |
41 | | - |
42 | | -## Honest status (v0) |
43 | | -- **Deterministic backbone: built, unit-tested, and mock-validated end-to-end** (scope-drop of |
44 | | - out-of-scope hosts, rank, candidate→confirm, FP-rejection at validate, report, resume). |
45 | | -- **Live agent phases: wired but not yet run** — blocked on Burp + claude budget (rate-limited at |
46 | | - build time). The same `claude -p` + Burp MCP path is already proven by the eval harness. |
47 | | -- **v0 limitations (the road ahead):** recon is single-seed and agent-driven (no subdomain enum / |
48 | | - multi-host sweep yet); no chaining/escalation between findings; ranking is a static class-weight |
49 | | - heuristic; reporting is a deterministic template (not yet the report skills). These are the next |
50 | | - increments toward a system that does a real multi-host engagement unattended. |
| 64 | +Key flags: `--hunt` (opt into agents) · `--allow-intrusive` (default OFF = read-only) · |
| 65 | +`--parallel N` (concurrent agents, default 3) · `--phases a,b,c` (explicit override). |
| 66 | + |
| 67 | +## Safety |
| 68 | +- **Read-only by default** — hunt/validate agents are told: in-scope hosts only (never |
| 69 | + third-party, even to prove a finding), and no state-changing actions (no emails/writes/ |
| 70 | + deletes/cache-purge, don't exercise exposed creds). `--allow-intrusive` lifts this. |
| 71 | +- **Deterministic scope-audit** — every confirmed finding is checked for out-of-scope hosts in |
| 72 | + its PoC; any hit is flagged (⚠) in the report for review. |
| 73 | +- **Calibrated severity** — the adversarial validator's severity (not the hunt's raw guess) is |
| 74 | + what's stored. |
51 | 75 |
|
52 | 76 | ## Why this and not more skills |
53 | | -The measured result (`eval/`): skills add ~0 capability on benchmarkable tasks because the model |
54 | | -already has them. The leverage is here — turning that raw capability into a *safe, stateful, |
55 | | -self-verifying* engagement loop. This is the part that doesn't exist for free in the base model. |
| 77 | +The measured result (`eval/`): skills add ~0 capability on benchmarkable tasks — the base model |
| 78 | +already exploits standard classes, and skills cost ~12–15k tokens/agent to load. The leverage is |
| 79 | +here: turning that raw capability into a **safe, deterministic, skill-routing, operator-in-the- |
| 80 | +loop** engine. Breadth is free and visible; you bring the judgment. |
0 commit comments