pentest · diff

git:20260423.f0067ce to git:20260425.aafb10c

65 added, 7 removed. Audit B to B.

---
name: pentest
description: Security testing and OSINT toolkit wrapping 183+ tools from Z4nzu/hackingtool (nmap, sherlock, amass, subfinder, nuclei, httpx, holehe, maigret, trufflehog, sqlmap, impacket, netexec, and more). Use whenever the user asks to recon a target, scan a network, enumerate subdomains, investigate a username or email, test a web app, check for leaked secrets, or any other pentest / OSINT task. Runs locally on any OS via native Bash, WSL, or purpose-built Docker images — the skill picks the right backend automatically.
---
# Pentest / OSINT Skill
- Claude Code runs on the user's machine. You have real Bash, real filesystem, real process execution. **Run tools immediately; the runtime wrapper handles environment details for you.**
+ Claude Code runs on the user's machine. You have real Bash, real filesystem, real process execution, and a fleet of pentest tools one wrapper call away. **Lean on the wrappers. Manual `curl` loops are a last resort, not a default.**
+ ## Step 0 — MANDATORY PREFLIGHT (run on every first invocation)
+
+ Before doing anything else — before recon, before tool selection, before even acknowledging the request — run:
+
+ ```bash
+ python ${CLAUDE_PLUGIN_ROOT}/scripts/ht_preflight.py
+ ```
+
+ The output tells you:
+ - `verdict`: `ready` | `partial` | `blocked`
+ - `summary_for_user`: a pre-formatted message you should paraphrase to the user
+ - `recommendations`: ordered list of `[priority] action → why` items the user must complete to unlock full coverage
+
+ ### Acting on the verdict
+
+ - **`ready`** (score ≥75): proceed normally. Mention the backend in one sentence ("Running via Docker — nuclei/subfinder/nmap all available.") and start work. Do not nag about info-priority recommendations.
+ - **`partial`** (40–74): tell the user what's missing in plain English using the `recommendations`. Offer to proceed with reduced coverage, or wait for them to fix the gap. Do not silently degrade to manual probes.
+ - **`blocked`** (<40): stop. Surface the recommendations verbatim and ask the user to take action before continuing. Do **not** fall back to manual `curl` / PowerShell probes as a substitute — that produces shallow results and misleads the user about coverage.
+
+ The preflight is cheap (<1 second). Re-run it if the user says they've installed something or started Docker.
+
+ ## Tool-first mindset (HARDENING)
+
+ When you've decided what to do, the order of preference is **always**:
+
+ 1. **Wrapper-mediated tool** via `ht_run.py` — picks the right Docker image, handles permissions, returns structured JSON.
+ 2. **Direct call to a known binary** if it's already on PATH (e.g. `nmap` natively on Linux).
+ 3. **Manual `curl` / `dig` / `nslookup`** only for spot-checks that have no real tool equivalent (e.g. fetching a single header for a sanity check).
+
+ **Anti-patterns to avoid:**
+
+ - ❌ Writing a `for` loop in bash that hits 50 paths with `curl` instead of running `ffuf` / `gobuster`.
+ - ❌ Hand-crafting JSON payloads to test a dozen endpoints when `nuclei -dast` or a custom nuclei template would cover them.
+ - ❌ Manually parsing TLS handshake output instead of running `nuclei -tags ssl` or `testssl.sh`.
+ - ❌ Asking the user to paste WHOIS output when `whois` / `amass intel` / `theharvester` are one wrapper call away.
+ - ❌ Skipping `subfinder` and inferring subdomains from CT logs by hand when the wrapper does both faster.
+ - ❌ Saying "I'd run nuclei but I don't have it" when the preflight said `verdict=ready` — you do have it via Docker.
+
+ **Decision rules** (apply when scope is "audit" / "scan" / "find vulns"):
+
+ | Ask | Default tool chain |
+ |-----|-------------------|
+ | Subdomain enumeration | `subfinder -all` → `httpx -title -tech-detect` |
+ | Web vuln scan | `nuclei -severity medium,high,critical` (then `info,low` separately) |
+ | Port scan | `nmap -sV -sC` (or `naabu` for fast SYN sweep) |
+ | Directory / API discovery | `ffuf -w wordlist -u https://target/FUZZ` |
+ | Secret hunting in repo / files | `trufflehog filesystem .` or `gitleaks detect` |
+ | Username / email investigation | `holehe email@x` → `sherlock username` → `maigret username` |
+ | TLS audit | `nuclei -tags ssl,tls` |
+ | Domain OSINT | `amass intel -d target` → `theharvester -d target` |
+ | Stealer-log / breach lookup | `trufflehog`, then domain-specific APIs |
+
+ If a wrapper exists for the job, **start with the wrapper**. Manual probing is a refinement step after the tool's output has narrowed the surface, not a replacement for it.
+
## The execution model
Every tool runs through `ht_run.py`, which:
1. Reads `ht_env.py` to pick a backend — **native** on Linux/macOS, **WSL** on Windows with a real distro, **Docker** anywhere with Docker Desktop.
2. Looks up a purpose-built Docker image for the tool if one exists (`instrumentisto/nmap`, `projectdiscovery/nuclei`, `caffix/amass`, 20+ more). Falls back to `kalilinux/kali-rolling` for anything not mapped.
3. Executes the command. If permission-denied on native/WSL, auto-retries with `sudo -n`. If an error is classifiable as recoverable, handles it.
4. Returns structured JSON with `status`, `stdout`, `stderr`, `returncode`, and the command that ran.
Only one pre-block exists: tools flagged `interactive` (they read stdin mid-run). Bypass with `--force` + `--command` if you have non-interactive args.
## Bundled scripts
All scripts live at `${CLAUDE_PLUGIN_ROOT}/scripts/`. Call them with `python ${CLAUDE_PLUGIN_ROOT}/scripts/<script>.py ...`. They emit JSON on stdout.
| Script | Purpose |
|---|---|
+ | `ht_preflight.py` | **Run first.** Capability check + user-facing setup recommendations. Verdict drives whether to proceed. |
| `ht_search.py` | Query the tool index. Filter by `--q`, `--category`, `--tag`, `--capability runnable_by_claude`, `--os linux`. |
- | `ht_env.py` | Report host OS, WSL distros, Docker availability, and `preferred_backend`. |
+ | `ht_env.py` | Low-level: report host OS, WSL distros, Docker availability, and `preferred_backend`. (Preflight wraps this.) |
| `ht_run.py` | Execute a tool. `--command "..."` for a full-command override. `--args "..."` for append-args. `--network-host` for LAN scans via docker. `--privileged` for raw sockets / hardware. `--force` to bypass the interactive pre-block. |
## Golden path
- 1. **Read the ask.** Map to a workflow if possible — see `reference/workflows.md`.
- 2. **Check the environment once.** `python ${CLAUDE_PLUGIN_ROOT}/scripts/ht_env.py` tells you which backend will run. If Windows + no WSL + Docker stopped, ask the user to start Docker before Linux-only work.
- 3. **Find candidate tools.** `ht_search.py --q "<keyword>"` to discover tool ids. Don't assume ids.
+ 1. **Preflight.** `ht_preflight.py` — handle verdict per Step 0 above.
+ 2. **Read the ask.** Map to a workflow if possible — see `reference/workflows.md`. Apply the decision rules table above for the default tool chain.
+ 3. **Find candidate tools.** `ht_search.py --q "<keyword>"` to discover tool ids. Don't assume ids — they're snake-cased and namespaced (e.g. `web_attack.Nuclei`, not `nuclei`).
4. **Execute them.**
- If RUN_COMMANDS is populated → `ht_run.py <tool_id> --args "..."`
- If RUN_COMMANDS is empty (many upstream tools have `runnable=False`) → use `--command "<full command>"`. The wrapper still picks the backend and image for you.
- For LAN / gateway scans via Docker → add `--network-host` so the container sees your LAN.
- For raw sockets / hardware → add `--privileged`.
5. **Parse the JSON result:**
- `status: ok` → summarize the interesting parts of stdout; don't paste the whole output if it's long.
- `status: error` with `returncode != 0` → tool ran but failed. Report stderr and decide whether to retry with different args.
- `status: fallback` → see `reference/runtime-fallbacks.md`. Pick the template matching the `reason` field.
- `status: timeout` → raise `--timeout <N>` or break the scan into smaller chunks.
6. **Compose, don't just call once.** OSINT chains: `subfinder → httpx → nuclei`. `holehe → sherlock → maigret`. Feed outputs into the next step.
## Docker image overrides
`ht_run.py` maps common tools to purpose-built images. These pull faster than Kali and have proper ENTRYPOINTs, so you just pass args:
| Tool | Image |
|---|---|
| NMAP | `instrumentisto/nmap` |
| Nuclei | `projectdiscovery/nuclei` |
| Subfinder / Httpx / Katana | `projectdiscovery/*` |
| Amass | `caffix/amass` |
| TheHarvester | `secsi/theharvester` |
| Holehe / Maigret / SpiderFoot | official images |
| TruffleHog / Gitleaks | official images |
| Sqlmap | `paoloo/sqlmap` |
| Impacket / NetExec | `rflathers/impacket`, `byt3bl33d3r/netexec` |
Override with `--docker-image my/image` for one-off swaps.
- ## Ad-hoc commands (no wrapper)
+ ## Ad-hoc commands (no wrapper) — narrow use only
- For one-off invocations that don't map to a hackingtool tool id — e.g. `curl -I https://target`, `arp -a`, `dig @8.8.8.8 example.com` — just use Bash directly. Use `ht_run.py` when:
+ For one-off invocations that genuinely don't map to a hackingtool tool id — e.g. `curl -I https://target` for a single header sanity check, `arp -a`, `dig @8.8.8.8 example.com` — Bash is fine. Use `ht_run.py` whenever:
- The tool is in the index and you want automatic image/backend selection
- You want permission-error auto-retry
- You're chaining multiple tools and want uniform JSON output
+ - The task is enumeration / scanning / fuzzing at any scale (≥5 requests against a target)
+
+ If you find yourself writing a `for` loop with `curl` to test more than a handful of paths, **stop and reach for `ffuf` / `nuclei` / `gobuster` instead**.
## References
- `${CLAUDE_PLUGIN_ROOT}/skills/pentest/reference/workflows.md` — named playbooks
- `${CLAUDE_PLUGIN_ROOT}/skills/pentest/reference/runtime-fallbacks.md` — templates for each fallback reason