A (security) bug’s life

Follow up ad una precedente discussione. In questo thread provero’ a condividere informazioni tecniche su vulnerabilita’ che trovo nel mio lavoro part-time come bug bounty hunter. Non conosco il livello tecnico medio dei members, dunque se avete domande o qualcosa non e’ chiaro, chiedete pure.

Questa sera ho trovato una bella vulnerabilita’ in un private program su cui ho iniziato a lavorare oggi. E’ una vulnerabilita’ di tipo XSS (Cross Site Scripting) che sfrutta una feature dei browser chiamata postMessage.

In breve, postMessage consente di bypassare la SOP o Same Origin Policy forzata dai browser. SOP, in breve, previene by default che un sito ad una certa origine (dove origine = schema/protocollo + dominio/hostname + porta) di manipulare un sito ad una origine differente. Prima che SOP fu introdotta, era possibile per un sito controllato da un attacker di controllare altri siti, che era una vulnerabilita’ critica. Esempio: era possibile caricare il sito di e.g. una banca in un iframe di un sito controllato dall’attacker, e manipolare il DOM (Document Object Model) della pagina nel sito della banca, o eseguire code, per cambiarne in comportamento, che come potete immaginare e’ critico. Been there, done that :asd:

Normalmente, a causa di SOP dunque cross-domain communication non e’ consentita direttamente. Cioe’ sito A non puo’ per esempio modificare il DOM di sito B oppure eseguire custom JavaScript code in sito B. Pero’, come potete immaginare, ci possono essere casi in cui e’ necessario per un sito poter collaborare con un altro sito per esempio con iframe, e un meccanismo per fare questo bypassando la SOP di proposito e’ postMessage.

Leggete la pagina del link sopra per dettagli, ma in breve postMessage consente ad un sito di inviare un messaggio ad un sito in altra origine, e l’altro sito puo’ usare il contenuto del messaggio come vuole.

Ovviamente, perche’ si bypassa la SOP, con postMessage e’ possibile introdurre vulnerabilita’ se a) il sito target usa il contenuto del messaggio in modo poco sicuro, b) il sito target non verifica correttamente la origine del messaggio con una allowlist di qualche tipo.

Con questa premessa, la vulnerabilita’ che ho trovato oggi sfrutta il fatto che il sito target controlla l’origine del messaggio, ma lo fa in maniera poco sicura. Per verificare l’origine usa una regex o Regular Expression abbastanza complicata. Purtroppo per i devs, ma per fortuna mia, hanno dimenticato di aggiungere un $ alla fine della regex, e questo e’ una delle 3 condizioni che mi hanno consentito di fare exploit. Il carattere $ (o un alternativa e’ \Z) delimita la fine del valore ricercato con la regex; quindi se per esempio la regex e’ ^/www\.something\.com/$, la regex permette soltanto www.something.com come origine dei messaggi ricevuti con postMessage. Dal momento che i devs hanno dimenticato la $ finale (la regex e’ un po’ complessa), questo significa che la regex accetta anche un valore come www.something.com.attacker-site.com, quindi mi permette di appendere un dominio che controllo.

La seconda condizione in questo caso di oggi, e’ che il sito target si aspetta, tra i messaggi possibili, un messaggio con un oggetto JSON che include una proprieta’ paymentUrl che normalmente contiene uno URL, come il nome suggerisce.

La terza condizione e’ che il sito target usa il valore di quella proprieta’ per impostare lo URL di un link nella pagina, che invia la vittima alla pagina con i dettagli del pagamento sul sito del payment gateway. Qui i devs hanno dimenticato di sanitizzare lo URL (sanitization e’ un processo che filtra un testo per prevenire l’esecuzione di codice o l’injection di custom HTML).

Queste tre condizioni insieme costituiscono una vulnerabilita’ XSS, che - in breve - mi consente di eseguire codice JavaScript a mio piacimento nel sito target, e nel contesto della vittima.

Steps:

  • far visitare alla vittima, in qualche modo, un link ad un sito controllato da me con hostname www.target.com.something.com; l’hostname deve essere tale che la vittima, grazie al prefisso www.target.com pensa che e’ il sito target stesso
  • questo sito controllato da me carica il sito target in un iframe a piena pagina, cosi’ sembra visualmente che la vittima sta visitando il sito target
  • quando la pagina nel mio sito (di attacker) viene caricata, invia un messaggio al sito target nell’iframe con postMessage, e come valore dello URL di cui parlavo prima usa java-scr-ipt:al-ert() (l’alert e’ solo per demo, perche’ posso fare quello che mi pare con JS code a mio piacimento)
  • quando il sito target riceve il messaggio, accetta l’origine www.target.com.something.com a causa del bug nella regex, e imposta l’href attribute di un link per il pagamento a java-scr-ipt:al-ert()
  • quando la vittima clicca su quel link, il mio codice JavaScript viene eseguito.

L’impatto e’ critico perche’ tra le varie cose con questo attacco posso, per esempio:

  • inviare il session cookie ad un sito che controllo, e in questo modo impersonare la vittima e accedere al suo account (account takeover)
  • eseguire azioni come se e’ la vittima ad eseguirle
  • modificare il contenuto della pagina nel sito target, per esempio per phishing
  • fare keylogging, ovvero inviare tutti i tasti premuti dalla vittima ad un server che controllo
  • fare hijacking per controllare il browser della vittima (per esempio posso far comparire un login fake di Facebook or Google etc per catturare le credenziali per questi siti)
  • accedere a webcamera e microfono se questi sono attivati per il sito target
  • etc etc

Tutto qui. E’ stato divertente trovarla :)

6 Likes

Dimenticavo, ho dovuto obfuscare un pochino alcune parole perche’ questo sito usa Cloudflare WAF e le filtra perche’ pensa che sto provando un attacco :asd:

4 Likes

Mai capito perché nel 2020 e passa ancora non si è droppato il supporto agli iframe.

Cioè, si, lo capisco, ma è veramente idiota dover mantenerlo e averci attorno tutto quel complicato sistema di controllo che oltretutto rende tutto a rischio, quando se c’è una collaborazione basterebbe creare un sistema di api e uno scambio di token tra backends per risolvere in maniera pulita.

Visto che sei anche architect, che ne pensi tu? Hai mai trovato casi in cui usare iframe aveva senso e non era solo “deadline” o “budget”?

iframe di per se non è un problema, è come è stato implementato.

La soluzione è sistemare infatti quegli elementi non “togliere i frame”

Ci sono casi dove iframe ha perfettamente senso, se vuoi includere un widget di cui non hai controllo usi un iframe no?

Non capita magari spesso nel web moderno dov’è tanta gente espone API o componenti da includere nella build ma ci sono ancora casi dove questo non avviene

Gli embed del forum su cui scrivi sono in gran parte iframe

Lo so, ma un conto e’ un forum di quattro coglioni per cui ho attivato gli iframe solo perche’ rompete il cazzo che “non vedo l’anteprima dei video boomer di facebook”, un conto e’ un iframe di corporate A dentro al sito di corporate B dove magari le due corporate trattano di soldi.

Tra l’altro, per dire, qui su discourse ci sarebbe OneBox che e’ un modulo che, quando un sito lo permette, fa un probing del link e genera una anteprima in-page.

Esempio su un sito che lo permette (guarda se ora non funziona :asd:):

Chiaro che se un sito come “share button” ti mette solo il poter incollare un iframe, tocca o mandarli a fanculo o adeguarsi.

Mah, non so poi tanto. Io su YT sono loggato, la login è la stessa di Google e su Google ho il wallet.

Per dire, se YT usa male PostMessage Crius mi frega la sessione di Google e mi svuota il portafoglio :asd:

Stai parlando di SSO, voglio sperare che il “widget” dell’utenza non sia un iframe :look:

1 Like

La preview no, ma se clicchi per farlo partire embedda l’frame di YT

<iframe src="https://www.youtube.com/embed/dQw4w9WgXcQ?autoplay=1&amp;rel=0" title=" - YouTube" allowfullscreen="" scrolling="no" frameborder="0" seamless="seamless" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"></iframe>

Te lo trovi anche in cronologia

Si ma torniamo la’. E’ youtube merda che non offre uno stream a player esterni (in cui potrebbe streammare anche la pubblicita’ volendo eh).

I motivi per cui iframe continuano a esistere, nella mia esperienza, son sempre perche’ dietro c’e’ una ragione economica perche’ a livello tecnico e di sicurezza sono una rottura di cazzo infinita.

1 Like

Discontinuare il supporto per iframe risolverebbe alcuni problemi ma non sarebbe facile e non accadra’ velocemente, se mai accadra’.

Come gia’ detto da altri, gli iframes rendono semplice l’embedding di contenuti esterni senza spendere particolare tempo nell’implementazione di API etc etc. Pensa ai molti casi di embedding (non solo YT ma anche ads, maps e social media widgets) che sono facilissimi per persone che non sono devs grazie agli iframe.

Poi c’e’ il bisogno di legacy support. Troppi siti e apps dipendono da iframes, quindi non sara’ veloce eliminarli.

Per quanto riguarda la sicurezza, se sostituisci iframes con una integrazione dei due siti via API, cmq non fai altro che sostituire alcuni problemi con altri. Se si paga un po’ di attenzione con gli iframe, la isolation provvista dalla SOP e’ migliore di altre cose che di dovrebbero tenere conto con altri metodi. Inoltre gli iframe supportano anche sandboxing, che puo’ mitigare alcuni problemi quando implementato correttamente.

2 Likes

Ho visto (e lavorato su) molti casi dove gli iframes convenivano perche’ con un iframe puoi rendere l’altro sito cosi’ come e’, con tutto lo styling e dinamismo che ha. Se fai una integrazione con API invece, devi praticamente replicare un bel po’ di cose per rendere i contenuti come atteso.

Ho trovato molte vulnerabilita’ SSRF (Server Side Request Forgery - poi do qualche esempio piu’ tardi) grazie alla funzionalita’ di anteprima di molte applicazioni :asd:

1 Like

this, ci sono scenari dove iframe e’ esattamente la tecnologia giusta, basta fare le cose bene, se usato sostanzialmente come “fai render di un widget” e’ totalmente innocuo.

Beh il problema non sono gli iframes dai, ci sono metodi sia lato server (cors) che lato client (un pizzico di js) per “proteggersi” lato sito web se non si vuole farli funzionare, se l’implementazione nei browser è bacata, sono i browser che sono da aggiornare dai

1 Like

cors non c’entrano nulla con iframes, proprio zero, puoi embeddare qualsiasi iframe di qualsisi orgine vuoi, servono esattamente per quello :asd:

non so cosa tu voglia fare lato JS ma non e’ la soluzione, se vuoi bloccare iframes la cosa giusta non e’ reinventare la ruota con qualcosa JS ma utilizzare gli standard a disposizione, in questo caso CSP

non c’e’ nessuna implementazione bacata nei browser che viceversa sono un ottimo modello di sandbox

Cors non serve? Ma se è fatto apposta per evitare i cross-origin request?
Lato client js puoi evitare che la tua pagina sia caricata in un contesto dove top!=self, non è una soluzione finale ma aiuta.
I CSP funzionano “dall’altro lato”, ma sono header che se uno ha un browser modificato può ignorare, però anche quelli servono.

Diciamo che è un insieme di tecniche che possono essere usate, basta esserne consapevoli, il problema di molte situazioni è che non ne sono consapevoli, sai quanti frontend dev quando gli dico “cors” rispondono con “cosa?” :asd:

1 Like

si ma quando si parla di xhr/fetch requests, non di embed di iframe.

Corretto su CSP, per la frame-ancestors directive :+1:

CORS ha un ruolo appunto quando l’iframe ha bisogno di interagire con risorse nella pagina parent se questa e’ da una origine diversa. Quindi dire che “CORS” non c’entra nulla con iframes non e’ corretto :slight_smile:
Ma se si fa solo embedding di un sito in un iframe, senza alcuna interazione tra parent and iframe, allora non c’e’ bisogno di configurare CORS.

si quello che volevo dire era relativo solo alla parte di embed, li cors non c’entrano nulla, entrano in gioco quando vuoi fare richieste.

per me un iframe che non fa nessuna richiesta non rappresenta una minaccia di sicurezza, e’ il caso piu’ semplice e pulito per cui possa essere utilizzato.

quando si comincia a voler fare richieste via postMessage secondo me si entra nella zona dove prestare attenzione e border line dove vale la pena chiedersi: e’ la cosa giusta da fare?

1 Like