diff --git a/src/pentesting-web/postmessage-vulnerabilities/README.md b/src/pentesting-web/postmessage-vulnerabilities/README.md index de19a76d9f9..4509975ac9b 100644 --- a/src/pentesting-web/postmessage-vulnerabilities/README.md +++ b/src/pentesting-web/postmessage-vulnerabilities/README.md @@ -232,11 +232,50 @@ For **more information**: - Link to page about [**XSS**](../xss-cross-site-scripting/index.html) - Link to page about [**client side prototype pollution to XSS**](../deserialization/nodejs-proto-prototype-pollution/index.html#client-side-prototype-pollution-to-xss) +### Origin-derived script loading & supply-chain pivot (CAPIG case study) + +`capig-events.js` only registered a `message` handler when `window.opener` existed. On `IWL_BOOTSTRAP` it checked `pixel_id` but stored `event.origin` and later used it to build `${host}/sdk/${pixel_id}/iwl.js`. + +
+Handler writing attacker-controlled origin + +```javascript +if (window.opener) { + window.addEventListener("message", (event) => { + if ( + !localStorage.getItem("AHP_IWL_CONFIG_STORAGE_KEY") && + !localStorage.getItem("FACEBOOK_IWL_CONFIG_STORAGE_KEY") && + event.data.msg_type === "IWL_BOOTSTRAP" && + checkInList(g.pixels, event.data.pixel_id) !== -1 + ) { + localStorage.setItem("AHP_IWL_CONFIG_STORAGE_KEY", { + pixelID: event.data.pixel_id, + host: event.origin, + sessionStartTime: event.data.session_start_time, + }) + startIWL() // loads `${host}/sdk/${pixel_id}/iwl.js` + } + }) +} +``` + +
+ +**Exploit (origin → script-src pivot):** +1. Get an opener: e.g., in Facebook Android WebView reuse `window.name` with `window.open(target, name)` so the window becomes its own opener, then post a message from a malicious iframe. +2. Send `IWL_BOOTSTRAP` from any origin to persist `host = event.origin` in `localStorage`. +3. Host `/sdk//iwl.js` on any CSP-allowed origin (takeover/XSS/upload on a whitelisted analytics domain). `startIWL()` then loads attacker JS in the embedding site (e.g., `www.meta.com`), enabling credentialed cross-origin calls and account takeover. + +If direct opener control was impossible, compromising a third-party iframe on the page still allowed sending the crafted `postMessage` to the parent to poison the stored host and force the script load. + +**Backend-generated shared script → stored XSS:** the plugin `AHPixelIWLParametersPlugin` concatenated user rule parameters into JS appended to `capig-events.js` (e.g., `cbq.config.set(...)`). Injecting breakouts like `"]}` injected arbitrary JS, creating stored XSS in the shared script served to all sites loading it. + ## References - [https://jlajara.gitlab.io/web/2020/07/17/Dom_XSS_PostMessage_2.html](https://jlajara.gitlab.io/web/2020/07/17/Dom_XSS_PostMessage_2.html) - [https://dev.to/karanbamal/how-to-spot-and-exploit-postmessage-vulnerablities-36cd](https://dev.to/karanbamal/how-to-spot-and-exploit-postmessage-vulnerablities-36cd) - To practice: [https://github.com/yavolo/eventlistener-xss-recon](https://github.com/yavolo/eventlistener-xss-recon) +- [CAPIG postMessage origin trust → script loading + stored JS injection](https://ysamm.com/uncategorized/2025/01/13/capig-xss.html) {{#include ../../banners/hacktricks-training.md}}