diff --git a/capabilities/web-security/skills/dom-vulnerability-detection/SKILL.md b/capabilities/web-security/skills/dom-vulnerability-detection/SKILL.md index 6f2a5d9..ef057b2 100644 --- a/capabilities/web-security/skills/dom-vulnerability-detection/SKILL.md +++ b/capabilities/web-security/skills/dom-vulnerability-detection/SKILL.md @@ -49,6 +49,8 @@ window.addEventListener('message', (e) => { }); ``` +**targetOrigin bypass via IP normalization:** When `postMessage(data, targetOrigin)` uses regex validation like `/https?:\/\/[^.]+[.]target[.]com/`, the `[^.]+` class matches `/` -- so `http://2130706433/.target.com` passes the regex. The browser's URL parser then normalizes the integer IP to `127.0.0.1` and sends the message to `http://127.0.0.1` (attacker-controlled). Same technique works with hex (`0x7f000001`) and octal IP forms. Check: does the sender validate `targetOrigin` with regex rather than strict string equality? If yes, test integer IP + path injection. + **Checkpoint:** For each handler, verify: (1) strict `e.origin` equality check exists, (2) no `window.origin` comparison, (3) no `startsWith`/`endsWith` on origin, (4) data is not passed to dynamic execution (`window[data.func]`). ### 5. Test CSTI (Client-Side Template Injection) diff --git a/capabilities/web-security/skills/git-integration-exploitation/SKILL.md b/capabilities/web-security/skills/git-integration-exploitation/SKILL.md new file mode 100644 index 0000000..86cf066 --- /dev/null +++ b/capabilities/web-security/skills/git-integration-exploitation/SKILL.md @@ -0,0 +1,99 @@ +--- +name: git-integration-exploitation +description: Exploit git integrations in SaaS and cloud services -- argument injection per git subcommand, JGit vs native git attack path selection, .git/config append-only takeover, error-based file read via --pathspec-from-file, and symlink-based filesystem escape. Use when target has git-backed features like web IDEs, CI/CD pipelines, deployment from repo, LookML/Dataform-style config, or any feature that clones/pulls/commits on the server side. +--- + +# Git Integration Exploitation + +Systematic audit methodology for SaaS services that integrate git server-side. The attack surface is not git itself -- it is the service's assumptions about what git operations are safe. + +## When to Use + +- Target has a web IDE, notebook, or config editor backed by git +- CI/CD pipeline clones user-controlled repos +- Deployment feature pulls from git (Heroku-style, Cloud Build, Dataform) +- Service accepts git URLs as input (import, migration, dependency resolution) +- `.git/` directory or git CLI invocation visible in errors, headers, or source + +## Recon: Identify the Git Implementation + +The first decision point. Different implementations have different exploitable surfaces. + +| Implementation | Hooks | fsmonitor | symlinks | Argument injection | +|---|---|---|---|---| +| **Native git CLI** | Yes | Yes | Yes (Linux/macOS default) | Yes | +| **JGit (Java)** | No | No | Only if `core.symlinks=true` in config | No (API-based) | +| **libgit2 / go-git** | No | No | Varies | No (API-based) | + +**How to fingerprint:** +- Error messages: Java stack traces (JGit), C/Go traces (libgit2/go-git), shell errors (native) +- Timing: native git shells out (slower cold start), JGit is in-process +- Behavior: create a repo with a `post-checkout` hook -- if it fires, native git + +**Rule:** If JGit, skip hooks/fsmonitor -- pivot to symlinks or config-based file read/write. If native git, hooks and fsmonitor are the fastest path to RCE. + +## Attack Primitives + +### 1. Argument Injection (native git only) + +The service constructs a git CLI command with user-controlled input (branch name, file path, remote URL). If the input starts with `-`, git interprets it as an option. + +**The surface is per-command** -- enumerate which git subcommand the service calls, then check that command's dangerous flags: + +| Git command | Dangerous flag | Effect | +|---|---|---| +| `git clone` / `git fetch` | `--upload-pack=` | Arbitrary command execution | +| `git rm` | `--pathspec-from-file=` | Read arbitrary file (contents leak via error) | +| `git diff` | `--output=` | Write diff output to arbitrary path | +| `git log` | `--output=` | Write log output to arbitrary path | +| `git apply` | `--directory=` | Control patch application target directory | +| `git push` | `--receive-pack=` | Arbitrary command execution on remote | + +**Error-based file read via `--pathspec-from-file`:** Create a file or folder named `--pathspec-from-file=/etc/passwd`. When the service runs `git rm` on it, git reads the target file, tries to parse each line as a pathspec, and dumps non-matching lines in error output. Works best on text files with non-path characters. Binary files or files with path-like content may not leak meaningfully. Test with `/etc/hostname` (short, predictable) before targeting larger files. + +### 2. Config Append-Only Takeover + +Git's `.git/config` uses INI format where duplicate `[core]` sections are merged -- last value wins (see `config-file-parsing-bugs` skill for the general INI parser pattern). Append-only write access to `.git/config` lets you override any config key, including `core.fsmonitor` (RCE on next `git status`) and `core.symlinks` (enable symlink following on JGit). + +**Where to look:** Any API that writes to the repo working directory without path sanitization (`WriteFile`, file upload, template generation). Test: write to `.git/config` directly -- many services forget to block the `.git/` prefix. + +### 3. Symlink Filesystem Escape + +When `core.symlinks = true` (default on Linux/macOS for native git), git creates real filesystem symlinks during checkout. A repo containing a symlink to `/` exposes the entire filesystem through the service's file browser. For symlink attacks via archive upload (non-git), see `archive-path-traversal` skill. + +**JGit twist:** JGit defaults `core.symlinks = false`. But if you can write to `.git/config` (primitive #2), add `symlinks = true` under `[core]`. Next checkout (triggered by pull, merge, or reset) creates real symlinks. + +**Cross-tenant escalation:** In multi-tenant cloud services, filesystem escape via symlink often reaches other tenants' repo directories on shared infrastructure. + +### 4. Embedded Bare Repository + +Push a repo containing a subdirectory structured as a bare git repo (has `HEAD`, `config`, `objects/`, `refs/`). If the service runs any git command from within that subdirectory, git discovers the embedded config. + +Weaponize: set `bare = false` + `core.worktree = .` + `core.fsmonitor = ` in the embedded config. Any `git status` from that directory triggers execution. + +### 5. TOCTOU on Config Regeneration + +Services that regenerate `.git/config` before each git operation (as a safety measure) create a race window. Concurrent requests -- one writing the malicious config, one triggering the git operation -- can win the race. + +**Test:** Use an intruder/fuzzer with two request groups running in parallel. Usually wins within 5-20 attempts. + +## Audit Checklist + +``` +1. [ ] Does the service expose git-backed features? (IDE, deploy, import, CI) +2. [ ] Which git implementation? (native / JGit / libgit2 / go-git) +3. [ ] Can you write to .git/config? (file API, upload, template injection) +4. [ ] Which git subcommands does the service call? (trigger commit/push/pull/diff, + grep responses for subcommand names, review client JS for action/command params) +5. [ ] Is user input used in git CLI arguments? (branch, path, remote URL, ref name) +6. [ ] Does the file browser follow symlinks? (create symlink in repo, check UI) +7. [ ] Does the service regenerate config before operations? (race condition window) +8. [ ] Multi-tenant? (filesystem escape = cross-tenant = critical) +``` + +## References + +- [CVE-2024-32002](https://nvd.nist.gov/vuln/detail/CVE-2024-32002) -- Git recursive clone RCE via embedded bare repo + symlink +- [CVE-2022-39253](https://nvd.nist.gov/vuln/detail/CVE-2022-39253) -- Git local clone file disclosure via symlink +- [GCP-2025-045](https://cloud.google.com/dataform/docs/security-bulletins) -- Google Dataform cross-tenant via symlink (CVSS 10.0) +- [Tenable: LookOut](https://www.tenable.com/blog/google-looker-vulnerabilities-rce-internal-access-lookout) -- Google Looker RCE via hook override + race condition diff --git a/capabilities/web-security/skills/http-query-method/SKILL.md b/capabilities/web-security/skills/http-query-method/SKILL.md new file mode 100644 index 0000000..90811e7 --- /dev/null +++ b/capabilities/web-security/skills/http-query-method/SKILL.md @@ -0,0 +1,152 @@ +--- +name: http-query-method +description: Exploit HTTP QUERY method (RFC 10008, June 2026) parser differentials -- WAF body inspection bypass, cache poisoning via body-ignorant caching, and request smuggling from body handling disagreements. Use when target has a CDN/cache/WAF layer and accepts or forwards unknown HTTP methods, or when testing for method-based parser differentials. +--- + +# HTTP QUERY Method Exploitation + +RFC 10008 (June 2026) defines QUERY -- the first new HTTP method standardized in 20+ years. It is semantically GET-with-a-body: safe, idempotent, cacheable, but the response cache key MUST include the request body and Content-Type. + +Most infrastructure does not implement this correctly yet. The adoption gap between spec and deployment is the attack surface. + +## When to Use + +- Target sits behind a CDN, cache, or WAF (most do) +- WAF blocks injection payloads in POST bodies but you haven't tested QUERY +- Cache layer detected (Varnish, Squid, CloudFront, Fastly, Cloudflare, Akamai) +- Target accepts or forwards unrecognized HTTP methods (test with `curl -X QUERY`) +- You've exhausted standard `parser-differential-bypass` and `h2-waf-bypass` techniques + +## QUERY vs GET vs POST + +| Property | GET | POST | QUERY | +|---|---|---|---| +| Safe / idempotent | Yes / Yes | No / No | Yes / Yes | +| Body | Ignored by most infra | Required | Required | +| Cacheable | Yes (URL-keyed) | No | Yes (URL + body + Content-Type keyed) | +| CORS safelisted | Yes | Yes (simple) | No (triggers preflight) | + +The critical difference: QUERY responses are cacheable but the cache key must include the body. Caches that don't understand QUERY will key on URL only -- identical to GET -- creating poisoning conditions. + +## Attack Scenarios + +### 1. WAF Body Inspection Bypass + +WAFs apply method-specific inspection. Most inspect POST bodies for injection. If the WAF doesn't recognize QUERY, it may skip body inspection entirely or apply GET-tier rules (URL only). + +```bash +# Baseline: POST blocked by WAF +curl -X POST https://target.com/api/search \ + -d "q=' OR 1=1--" + +# Test: same payload via QUERY +curl -X QUERY https://target.com/api/search \ + -H "Content-Type: application/x-www-form-urlencoded" \ + -d "q=' OR 1=1--" +``` + +If POST returns WAF block (403/406) but QUERY reaches the backend, you have an inspection gap. The QUERY method is the bypass -- the finding is whatever the payload achieves (SQLi, XSS, etc.). + +### 2. Cache Poisoning via Body-Ignorant Caching + +If the cache treats QUERY like GET (keys on URL only, ignores body): + +**Primary case (QUERY-to-QUERY, body ignored in cache key):** + +1. Attacker sends `QUERY /search` with body `{"q":""}` +2. Backend processes the query, returns results containing the reflected payload +3. Cache stores response keyed on method + URL only (body ignored) +4. Victim sends `QUERY /search` with a different body -- receives the attacker's cached response + +**Escalated case (method also ignored in cache key):** + +If the cache ignores both body and method, the poisoned QUERY response is also served to `GET /search` requests -- affecting all users, not just QUERY senders. + +```bash +# Step 1: poison the cache +curl -X QUERY https://target.com/search \ + -H "Content-Type: application/json" \ + -d '{"q":""}' + +# Step 2: verify cache serves poisoned response to clean request +curl https://target.com/search +``` + +Check `Age`, `X-Cache`, `CF-Cache-Status` headers to confirm caching behavior. + +### 3. Request Smuggling via Body Handling Disagreement + +Front-end (CDN/LB) treats QUERY as bodyless (like GET), ignores Content-Length. Back-end reads the body. The "ignored" body becomes a new request from the back-end's perspective. + +```bash +# Through CDN -- compare behavior +curl -X QUERY https://target.com/ \ + -H "Content-Type: text/plain" \ + -H "Content-Length: 50" \ + -d "GET /admin HTTP/1.1\r\nHost: target.com\r\n\r\n" + +# Direct to origin -- compare Content-Length handling +curl -X QUERY https://origin-ip/ \ + -H "Host: target.com" \ + -H "Content-Type: text/plain" \ + -H "Content-Length: 50" \ + -d "GET /admin HTTP/1.1\r\nHost: target.com\r\n\r\n" +``` + +Divergence in body handling between CDN and origin = smuggling potential. See `te0-request-smuggling` and `h2-waf-bypass` skills for full smuggling methodology. + +### 4. Method Routing Confusion + +Frameworks that don't recognize QUERY may route it to a catch-all handler with weaker authorization, or fall through to GET/POST handlers with different access controls. + +```bash +# Does QUERY reach a different handler than GET? +curl -X QUERY https://target.com/admin/users \ + -H "Content-Type: application/json" \ + -d '{"page":1}' + +# Compare with GET +curl https://target.com/admin/users +``` + +A 405 response leaks the `Allow` header (supported methods) -- useful recon but not a finding by itself. + +## Adoption Gaps (as of July 2026) + +| Layer | QUERY Support | Implication | +|---|---|---| +| Node.js / Express | Accepts (custom methods routed via app.all/router.all) | Backend processes QUERY bodies | +| Go net/http | Accepts (any method string handled) | Backend processes QUERY bodies | +| Spring / Rails | Pending / Under discussion | May reject or misroute | +| Cloudflare / Akamai | Co-authored RFC -- QUERY-specific caching behavior untested | CDN may pass through but cache keying unverified | +| Varnish / Squid / HAProxy | Unknown | Highest-signal cache differential targets | +| ModSecurity / AWS WAF / Azure WAF | No documented rules | Likely skip body inspection | +| Imperva / F5 BIG-IP | No public updates | Method whitelists may block or pass without inspection | +| Nginx | Passes through, config-dependent | `limit_except` directives may not include QUERY | + +**Test priority:** targets behind Varnish, Squid, HAProxy, or any WAF without documented QUERY support. + +## Testing Checklist + +``` +1. [ ] Does target accept QUERY? (send QUERY, check for non-405 response) +2. [ ] WAF bypass: send blocked POST payload via QUERY -- does it pass? +3. [ ] Cache behavior: send QUERY with body, check cache headers (Age, X-Cache) +4. [ ] Cache key: send two QUERY requests with different bodies to same URL -- same cached response? +5. [ ] Body stripping: send QUERY with body through CDN, verify origin receives body intact +6. [ ] Smuggling: compare QUERY body handling CDN vs direct-to-origin +7. [ ] Routing: does QUERY reach a different handler or authz context than GET/POST? +``` + +## Related Skills + +- **parser-differential-bypass** -- general parser differential methodology +- **h2-waf-bypass** -- WAF bypass via HTTP/2 framing (complementary vector) +- **web-cache-deception-path** -- cache deception via path confusion (different primitive, same cache layer) +- **te0-request-smuggling** -- smuggling methodology applicable to QUERY body disagreements + +## References + +- [RFC 10008](https://www.rfc-editor.org/rfc/rfc10008.html) -- HTTP QUERY Method specification +- [Hive Security: HTTP QUERY Attack Surface](https://hivesecurity.gitlab.io/blog/http-query-method-rfc-10008-attack-surface/) -- WAF bypass, cache poisoning, smuggling analysis +- [WAFFLED: Parsing Discrepancies in WAFs](https://arxiv.org/html/2503.10846v4) -- general WAF parsing differential research