PostMessage Vulnerabilities
Last updated
Last updated
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
PostMessage utilizza la seguente funzione per inviare un messaggio:
Nota che targetOrigin può essere un '*' o un URL come https://company.com. Nel secondo scenario, il messaggio può essere inviato solo a quel dominio (anche se l'origine dell'oggetto finestra è diversa). Se viene utilizzato il carattere jolly, i messaggi possono essere inviati a qualsiasi dominio, e saranno inviati all'origine dell'oggetto Window.
Come spiegato in questo report, se trovi una pagina che può essere iframed (senza protezione X-Frame-Header
) e che sta inviando messaggi sensibili tramite postMessage utilizzando un carattere jolly (*), puoi modificare l'origine dell'iframe e leak il messaggio sensibile a un dominio controllato da te.
Nota che se la pagina può essere iframed ma il targetOrigin è impostato su un URL e non su un carattere jolly, questo trucco non funzionerà.
addEventListener
è la funzione utilizzata da JS per dichiarare la funzione che si aspetta postMessages
.
Un codice simile a quello seguente sarà utilizzato:
Nota in questo caso come la prima cosa che il codice sta facendo è controllare l'origine. Questo è terribilmente importante principalmente se la pagina deve fare qualcosa di sensibile con le informazioni ricevute (come cambiare una password). Se non controlla l'origine, gli attaccanti possono far inviare dati arbitrari a questi endpoint e cambiare le password delle vittime (in questo esempio).
Per trovare i listener di eventi nella pagina corrente puoi:
Cercare il codice JS per window.addEventListener
e $(window).on
(versione JQuery)
Eseguire nella console degli strumenti per sviluppatori: getEventListeners(window)
Andare a Elements --> Event Listeners negli strumenti per sviluppatori del browser
Utilizzare un estensione del browser come https://github.com/benso-io/posta o https://github.com/fransr/postMessage-tracker. Queste estensioni del browser intercetteranno tutti i messaggi e te li mostreranno.
L'attributo event.isTrusted
è considerato sicuro in quanto restituisce True
solo per eventi generati da azioni genuine dell'utente. Anche se è difficile da bypassare se implementato correttamente, la sua importanza nei controlli di sicurezza è notevole.
L'uso di indexOf()
per la validazione dell'origine negli eventi PostMessage può essere suscettibile a bypass. Un esempio che illustra questa vulnerabilità è:
Il metodo search()
di String.prototype.search()
è destinato alle espressioni regolari, non alle stringhe. Passare qualsiasi cosa diversa da una regexp porta a una conversione implicita in regex, rendendo il metodo potenzialmente insicuro. Questo perché nelle regex, un punto (.) agisce come un carattere jolly, consentendo di bypassare la validazione con domini appositamente creati. Ad esempio:
La funzione match()
, simile a search()
, elabora regex. Se la regex è strutturata in modo improprio, potrebbe essere soggetta a bypass.
La funzione escapeHtml
è destinata a sanificare gli input sfuggendo ai caratteri. Tuttavia, non crea un nuovo oggetto sfuggito ma sovrascrive le proprietà dell'oggetto esistente. Questo comportamento può essere sfruttato. In particolare, se un oggetto può essere manipolato in modo tale che la sua proprietà controllata non riconosca hasOwnProperty
, la escapeHtml
non funzionerà come previsto. Questo è dimostrato negli esempi seguenti:
Fallimento previsto:
Bypassando l'escape:
Nel contesto di questa vulnerabilità, l'oggetto File
è notevolmente sfruttabile a causa della sua proprietà name
di sola lettura. Questa proprietà, quando utilizzata nei modelli, non è sanificata dalla funzione escapeHtml
, portando a potenziali rischi per la sicurezza.
La proprietà document.domain
in JavaScript può essere impostata da uno script per accorciare il dominio, consentendo un'applicazione più rilassata della politica di stessa origine all'interno dello stesso dominio padre.
Quando si incorpora una pagina web all'interno di un iframe sandboxed utilizzando %%%%%%, è cruciale comprendere che l'origine dell'iframe sarà impostata su null. Questo è particolarmente importante quando si trattano attributi sandbox e le loro implicazioni sulla sicurezza e sulla funzionalità.
Specificando allow-popups
nell'attributo sandbox, qualsiasi finestra popup aperta dall'interno dell'iframe eredita le restrizioni sandbox del suo genitore. Ciò significa che a meno che l'attributo allow-popups-to-escape-sandbox
non sia incluso, l'origine della finestra popup è anch'essa impostata su null
, allineandosi con l'origine dell'iframe.
Di conseguenza, quando una popup viene aperta in queste condizioni e un messaggio viene inviato dall'iframe alla popup utilizzando postMessage
, sia l'invio che la ricezione hanno le loro origini impostate su null
. Questa situazione porta a uno scenario in cui e.origin == window.origin
risulta vero (null == null
), poiché sia l'iframe che la popup condividono lo stesso valore di origine di null
.
Per ulteriori informazioni leggi:
Bypassing SOP with Iframes - 1È possibile controllare se il messaggio proviene dalla stessa finestra in cui lo script sta ascoltando (particolarmente interessante per Content Scripts delle estensioni del browser per controllare se il messaggio è stato inviato dalla stessa pagina):
Puoi forzare e.source
di un messaggio a essere nullo creando un iframe che invia il postMessage e viene immediatamente eliminato.
Per ulteriori informazioni leggi:
Bypassing SOP with Iframes - 2Per eseguire questi attacchi, idealmente dovresti essere in grado di mettere la pagina web della vittima all'interno di un iframe
. Ma alcuni header come X-Frame-Header
possono prevenire quel comportamento.
In quei scenari puoi comunque utilizzare un attacco meno furtivo. Puoi aprire una nuova scheda per l'applicazione web vulnerabile e comunicare con essa:
Nella seguente pagina puoi vedere come potresti rubare dei dati postmessage sensibili inviati a un child iframe bloccando la pagina principale prima di inviare i dati e abusando di un XSS nel child per leakare i dati prima che vengano ricevuti:
Blocking main page to steal postmessageSe puoi iframe una pagina web senza X-Frame-Header che contiene un altro iframe, puoi cambiare la posizione di quel child iframe, quindi se sta ricevendo un postmessage inviato utilizzando un wildcard, un attaccante potrebbe cambiare quell'iframe origin a una pagina controllata da lui e rubare il messaggio:
Steal postmessage modifying iframe locationIn scenari in cui i dati inviati tramite postMessage
vengono eseguiti da JS, puoi iframe la pagina e sfruttare la prototype pollution/XSS inviando l'exploit tramite postMessage
.
Un paio di XSS molto ben spiegati tramite postMessage
possono essere trovati in https://jlajara.gitlab.io/web/2020/07/17/Dom_XSS_PostMessage_2.html
Esempio di un exploit per abusare di Prototype Pollution e poi XSS tramite un postMessage
a un iframe
:
Per maggiori informazioni:
Link alla pagina su prototype pollution
Link alla pagina su XSS
Link alla pagina su client side prototype pollution to XSS
Per esercitarsi: https://github.com/yavolo/eventlistener-xss-recon
Impara e pratica il hacking AWS:HackTricks Training AWS Red Team Expert (ARTE) Impara e pratica il hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)