diff --git a/src/pentesting-web/postmessage-vulnerabilities/README.md b/src/pentesting-web/postmessage-vulnerabilities/README.md index 82aa639e12e..cb7b07d8b0f 100644 --- a/src/pentesting-web/postmessage-vulnerabilities/README.md +++ b/src/pentesting-web/postmessage-vulnerabilities/README.md @@ -247,6 +247,44 @@ 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. + ### Predicting **`Math.random()`** callback tokens in postMessage bridges When message validation uses a “shared secret” generated with `Math.random()` (e.g., `guid() { return "f" + (Math.random() * (1<<30)).toString(16).replace(".", "") }`) and the same helper also names plugin iframes, you can recover PRNG outputs and forge trusted messages: @@ -277,6 +315,7 @@ iframe.location = fbMsg // sends postMessage from facebook.com with forged callb - [https://dev.to/karanbamal/how-to-spot-and-exploit-postmessage-vulnerablities-36cd](https://dev.to/karanbamal/how-to-spot-and-exploit-postmessage-vulnerablities-36cd) - [Leaking fbevents: OAuth code exfiltration via postMessage trust leading to Instagram ATO](https://ysamm.com/uncategorized/2026/01/16/leaking-fbevents-ato.html) - 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) - [Facebook JavaScript SDK Math.random callback prediction → DOM XSS writeup](https://ysamm.com/uncategorized/2026/01/17/math-random-facebook-sdk.html) - [V8 Math.random() state recovery (Z3 predictor)](https://github.com/PwnFunction/v8-randomness-predictor)