Appunti WAPT: DOM Clobbering
DOM Clobbering è una tecnica molto interessante che unisce tecniche di bypass di sanitizzazioni dell'input utente e metodi di esecuzione di JavaScript agendo sulla renderizzazione degli HTML elements da parte del browser.
Trovo molto interessanti i nuovi lab di PortSwigger DOM-based vulnerabilities, ho avuto l'opportunità di imparare molto e penso che mi concentrerò molto su ognuno dei lab di questa nuova categoria per i prossimi video/post. DOM Clobbering è una tecnica molto interessante che unisce tecniche di bypass di sanitizzazioni dell'input utente e metodi di esecuzione di JavaScript agendo sulla renderizzazione degli HTML elements da parte del browser.
Ormai siamo abituati alla fantasia di Gareth Heyes nella scelta dei nomi delle tecniche per sfruttare vulnerabilità delle web application (vedi DOM-based dangling markup) fantasia che, nel 2013, si esprime nell'etichettare questa tecnica come clobbering (picchiare):
The term clobbering comes from the fact that you are "clobbering" a global variable or property of an object and overwriting it with a DOM node or HTML collection instead
Tralasciando la creatività di Gareth per concentrarci sull'articolo che, qualche giorno fa, ha pubblicato sul blog di PortSwigger "DOM Clobbering strikes back". La tecnica sfrutta la possibilità di sovrascrivere una variable o un oggetto JavaScript con una HTMLCollection per modificare il comportamento dello script JavaScript per arrivare a un Cross-Site Scripting. Tutto ciò è molto utile se, come nel caso del Lab che risolveremo in questo post, l'injection HTML è sanitizzato per impedire l'exploit di vulnerabilità XSS. Facciamo un passo indietro.
HTMLCollection
Piccola nota: in più parti del sito, PortSwigger si riferisce a HTMLCollection con "DOM Collection" e la cosa potrebbe confondere.
In JavaScript l'interfaccia HTMLCollection è una "generic collection" di elementi (simile all'oggetto argument) che potremmo definire array-like. Offre metodi e propietà per selezionare i singoli elementi di cui è composta, che includono: la selezione degli elementi tramite index number, e la selezione tramite nome dell'elemento. Facciamo un esempio pratico. I seguenti elementi possono essere inclusi in una HTMLCollection:
tramite l'oggetto window.pippo
. Questo è ancor più evidente utilizzando la debug console del browser:
Come si evince dallo screenshot, possiamo selezionare uno qualsiasi degli elementi tramite l'index number (0, 1 o 2) oppure tramite il nome ricavato dall'attributo "name" dei tag "a":
La vulnerabilità
Perchè abbiamo parlato di sostituzione di una variable o oggetto? Uno dei casi più comuni in cui si verifica questa condizione è l'assegnazione di valori di default a una variabile. Per esempio:
Nello screenshot, la variabile pippo viene definita con una condizione: se window.pippo
non è false
allora pippo = window.pippo
, altrimenti pippo = "foo"
. Questo fa sì che, nel caso in cui avessimo la possibilità di iniettare tag HTML all'interno della pagina, e che l'input venisse sanitizzato escludendo la possibilità di inserire direttamente script JavaScript, potremmo creare elementi HTML con id "pippo" e intervenire sulle operazioni che lo script farà con la variabile pippo.
PoC
Scopiazzando il Lab di PortSwigger, ammettiamo di avere uno script come questo all'interno di una pagina in cui possiamo iniettare codice HTML che viene sanitizzato (esempio: commento di un blog post):
in poche parole, questo script inserisce un'immagine nell'elemento con id "output" per ogni tag "a", prendendo il valore dell'attributo src
dal parametro avatar
dell'oggetto defaultAvatar
.
Iniettando HTML tag come nel seguente screenshot, trasformiamo la variabile defaultAvatar in una HTMLCollection e, impostando l'attributo "name" con valore "avatar" possiamo sovrascrivere la variabile defaultAvatar.avatar
con il contenuto del parametro "href" del tag iniettato:
nell'attributo "href" tentiamo di inserire l'handler "onerror" per eseguire lo script alert(1)
. Il risultato è che il browser della vittima renderizzerà l'elemento in questo modo:
Nella riga selezionata nello screenshot qui sopra vediamo come il browser ha creato l'elemento "img" inserendo nell'attributo src URL%22onerror...
. Questo perchè il browser effettua URL encoding del valore recuperato dall'attributo "href". La buona notizia è che possiamo "bypassare" ciò, o meglio impedire che il browser faccia encoding utilizzando lo schema cid
(Content-ID) come da RFC 2392.
Content-ID
Anche in questo caso, PortSwigger (in varie parti del sito) si riferisce al URL schema cid:
chiamandolo "protocollo cid"... e nuovamente potrebbe confondere un po'.
The Uniform Resource Locator (URL) schemes, "cid:" and "mid:" allow references to messages and the body parts of messages. For example, within a single multipart message, one HTML body part might include embedded references to other parts of the same message.
È solitamente utilizzato, ad esempio, in un multipart message (come può essere un'email HTML encoded) per inserire un tag "img" che fa riferimento a un'immagine allegata tramite il suo id, ad esempio: <img src="cid:image-id">
. La peculiarità è che il browser non farà l'encoding del contenuto inserendo nell'attributo "src" la stringa "cidr:" e creando un nuovo attributo "onerror" con il nostro JavaScript alert(1)
. Possiamo quindi usare questo schema per triggerare la vulnerabilità ed eseguire codice JavaScript in questo modo:
Attenzione: nel lab PortSwigger il payload consigliato è cid:"
ma non è necessario utilizzare l'entità html del carattere "
. Il risultato, renderizzato dal browser sarà:
come si vede dallo screenshot sopra, l'attributo "onerror" questa volta è stato renderizzato correttamente e il browser, non riuscendo a recuperare la risorsa, eseguirà lo script alert(1)
:
Il laboratorio lo risolvo nel video :)
Video
References
- https://portswigger.net/research/dom-clobbering-strikes-back
- https://portswigger.net/web-security/dom-based/dom-clobbering
- https://developer.mozilla.org/en-US/docs/Web/API/HTMLCollection
- https://tools.ietf.org/html/rfc2392