DOM型XSS
翻译
原文:https://portswigger.net/web-security/cross-site-scripting/dom-based
- name: 翻译
desc: 原文:https://portswigger.net/web-security/cross-site-scripting/dom-based
bgColor: '#F0DFB1'
textColor: 'green'
2
3
4
# 基于DOM的XSS
在本节中,我们将描述基于 DOM 的跨站点脚本(DOM型XSS),说明如何发现 DOM型XSS 漏洞,并讨论如何使用不同的源和接收器来利用 DOM型XSS。
# 1什么是DOM型XSS?
当 JavaScript 从攻击者可控制的来源(如 URL)中获取数据,并将其传递给支持动态代码执行的接收器(如eval()
或innerHTML
)时,通常会出现 DOM型XSS 漏洞。这使得攻击者能够执行恶意 JavaScript,并允许他们劫持其他用户的帐户。
要想造成 DOM型XSS 攻击,你需要将数据放入源中,以便将其传播到接收器,并导致执行任意 JavaScript。
DOM型XSS 最常见的来源是 URL,通常使用window.location
对象访问它。攻击者可以构造一个链接,将受害者转到易受攻击的页面,该页面的查询字符串和 URL 的片段部分中具有攻击载荷。在某些情况下,例如针对 404 页面或运行 PHP 的网站时,也可以将有效负载放置在路径中。
有关源和接收器之间污染流的详细说明,请参阅基于DOM的漏洞 (opens new window)。
# 2如何测试 DOM型XSS
绝大多数 DOM 型跨站脚本漏洞,都可以使用 Burp Suite 的Web漏洞扫描程序 (opens new window)快速而可靠地找到。
想要手动测试 DOM 型跨站脚本,你通常需要使用带有开发者工具的浏览器(例如 Chrome)。你需要依次处理每个可用的源,并单独测试每个源。
# 2.1测试 HTML 接收器
若要在 HTML 接收器中测试 DOM型XSS,请将随机的字母数字字符串放入源(例如location.search
)当中,然后使用开发者工具检查 HTML 并查找字符串的回显位置。请注意,浏览器的 “查看源代码” 选项不适用于 DOM型XSS 测试,因为它不会考虑到 JavaScript 在 HTML 中执行的更改。在 Chrome 的开发者工具中,你可以使用Control+F
(或MacOS上的Command+F
)在 DOM 中搜索字符串。
对于字符串在 DOM 中出现的每个位置,都需要确定其上下文。基于此上下文,你需要细化输入,以查看其处理方式。例如,如果你的字符串出现在双引号属性中,请尝试在字符串中插入双引号,并查看是否可以突破该属性。
请注意,不同浏览器在 URL 编码方面的不同行为,Chrome、Firefox 和 Safari 将对location.search
和location.hash
进行 URL 编码,而 IE11 和 Microsoft Edge(pre-Chromium)不会对这些源进行 URL 编码。如果你的数据在处理之前已经被 URL 编码,那么 XSS 攻击就不太可能奏效。
# 2.2测试 JavaScript 执行接收器
在 JavaScript 执行接收器中测试 DOM型XSS 有点困难。使用这些接收器时,你的输入不一定会在 DOM 中显示,因此你无法搜索它。相反,你需要使用 JavaScript 调试器来确定 如何将输入发送到接收器、接收器是否已经接收到数据。
对于每个潜在的来源(例如location
),你首先需要在页面的 JavaScript 代码中找到引用源的案例。在 Chrome 的开发者工具中,你可以使用Control+Shift+F
(或MacOS上的Command+Alt+F
)来搜索页面中的所有 JavaScript 源代码。
找到引用源的位置后,可以使用 JavaScript 调试器添加断点,并跟踪源值的处理过程。你可能会发现源的值被分配给其他变量。如果遇到这种情况,则需要再次使用搜索功能来跟踪这些变量,并查看它们是否被传递到接收器。
当你发现一个源的数据被传递到接收器中时,可以使用调试器检查该值(在变量传递到接收器之前,将鼠标悬停在变量上以显示其值)。然后,与 HTML 接收器一样,你需要细化输入,并查看是否可以成功地造成 XSS 攻击。
# 2.3使用 DOM Invader 测试 DOM型XSS
在野识别和利用 DOM型XSS 可能是一个乏味的过程,这通常需要你手动浏览复杂的、细小的 JavaScript。但是,如果你使用 Burp 的浏览器,则可以利用其内置的 DOM Invader 扩展,该扩展为你完成了大量繁琐的工作。
# 3利用不同的源和接收器触发 DOM型XSS
原则上,如果存在一条执行路径,可以将数据从源传播到接收器,则网站容易受到基于 DOM 的跨站脚本攻击。实际上,不同的源和接收器具有不同的属性和行为,需要根据不同的项来确定所使用的技术,这可能会影响漏洞可利用性。此外,在尝试利用漏洞时,网站的脚本可能会对 必须容纳的数据 执行验证或其他处理。有多种接收器与 DOM 型漏洞相关。有关详细信息,请参阅列表 (opens new window)。
假设document.write
接收器与script
元素一起工作,则你可以使用一个简单的有效负载,如下所示:
document.write('... <script>alert(document.domain)</script> ...');
- name: 实验室-学徒
desc: DOM型XSS-document.write接收器-location.search源 >>
avatar: https://fastly.statically.io/gh/clincat/blog-imgs@main/vuepress/static/imgs/docs/burpsuite-learn/public/lab-logo.png
link: https://portswigger.net/web-security/cross-site-scripting/dom-based/lab-document-write-sink
bgColor: '#001350'
textColor: '#39d50c'
2
3
4
5
6
但请注意,在某些情况下,写入document.write
的内容包括一些周围的上下文,你需要在利用漏洞时考虑这些上下文。例如,你可能需要在使用 JavaScript 有效负载之前闭合一些现有元素。
- name: 实验室-从业者
desc: DOM型XSS-document.write接收器-location.search源-位于select元素内 >>
avatar: https://fastly.statically.io/gh/clincat/blog-imgs@main/vuepress/static/imgs/docs/burpsuite-learn/public/lab-logo.png
link: https://portswigger.net/web-security/cross-site-scripting/dom-based/lab-document-write-sink-inside-select-element
bgColor: '#001350'
textColor: '#4cc1ff'
2
3
4
5
6
innerHTML
接收器不接受任何现代浏览器上的script
元素,也不会触发svg onload
事件。这意味着你需要使用其他替代元素,如img
或iframe
。onload
和onerror
等事件处理程序可以与这些元素结合使用。例如:
element.innerHTML='... <img src=1 onerror=alert(document.domain)> ...'
- name: 实验室-学徒
desc: DOM型XSS-innerHTML接收器-location.search源 >>
avatar: https://fastly.statically.io/gh/clincat/blog-imgs@main/vuepress/static/imgs/docs/burpsuite-learn/public/lab-logo.png
link: https://portswigger.net/web-security/cross-site-scripting/dom-based/lab-innerhtml-sink
bgColor: '#001350'
textColor: '#39d50c'
2
3
4
5
6
# 3.1第三方依赖项中的源和接收器
现代 Web 应用程序通常使用许多第三方库和框架构建,这些库和框架为开发人员提供了额外的功能和开发能力。值得注意的是,其中包含一些 DOM型XSS 的潜在来源和接收器。
# 3.1.1jQuery中的DOM XSS
如果使用了 JavaScript 库(例如 jQuery),请留意可以更改页面上 DOM 元素的接收器。例如,jQuery 的attr()
函数可以更改 DOM 元素的属性。如果数据是从用户控制的源(如 URL)中读取的,然后传递给attr()
函数,那么用户将可以操纵发送的值并导致 XSS。例如,这里有一些 JavaScript,它使用 URL 中的数据来更改锚元素的href
属性:
$(function() {
$('#backLink').attr("href",(new URLSearchParams(window.location.search)).get('returnUrl'));
});
2
3
你可以通过修改 URL 来利用此漏洞,以便在location.search
源中包含恶意 JavaScript URL。在页面的 JavaScript 将此恶意 URL 应用到 backLink 的href
属性中后,单击 backLink 将执行:
?returnUrl=javascript:alert(document.domain)
- name: 实验室-学徒
desc: DOM型XSS-jQuery锚点href属性接收器-location.search源 >>
avatar: https://fastly.statically.io/gh/clincat/blog-imgs@main/vuepress/static/imgs/docs/burpsuite-learn/public/lab-logo.png
link: https://portswigger.net/web-security/cross-site-scripting/dom-based/lab-jquery-href-attribute-sink
bgColor: '#001350'
textColor: '#39d50c'
2
3
4
5
6
另一个需要注意的潜在接收器是 jQuery 的$()
选择器函数,它可用于将恶意对象注入 DOM 中。
jQuery 曾经非常流行,一个经典的 DOM型XSS 漏洞——在制作前端动画或自动滚动功能时,由于网站将此选择器与location.hash
源结合使用而引起的。此行为通常使用易受攻击的hashchange
事件处理程序来实现,类似于以下内容:
$(window).on('hashchange', function() {
var element = $(location.hash);
element[0].scrollIntoView();
});
2
3
4
(((译者加:在经典情况下,符号#
被称为 “锚点”,但在前端路由系统中,它被称为 “hash”。详情可参阅这两篇文章:文章1 (opens new window)、文章2 (opens new window))))
由于hash
是用户可控制的,攻击者可以利用它将 XSS 向量注入$()
选择接收器当中。jQuery 的最新版本已经修补了这个特殊的漏洞,当你的输入以 hash 字符(#
)开头时,它会阻止你将 HTML 注入选择器中。但是,你仍然可能会在野外发现易受攻击的代码。
要实际利用此经典漏洞,你需要找到一种无需用户交互即可触发hashchange
事件的方法。最简单的方法之一是通过iframe
来实现漏洞利用:
<iframe src="https://vulnerable-website.com#" onload="this.src+='<img src=1 onerror=alert(1)>'">
在此示例中,src
属性指向一个具有空 hash 值的易受攻击页面。加载iframe
时,XSS 向量被附加到 hash 中,从而触发hashchange
事件。
笔记
即使是新版本的 jQuery,其$()
选择接收器也仍然容易受到攻击,前提是存在一个不需要#
前缀的源,并且你可以完全控制来自该源的输入。
- name: 实验室-学徒
desc: DOM型XSS-jQuery选择接收器-hashchange事件 >>
avatar: https://fastly.statically.io/gh/clincat/blog-imgs@main/vuepress/static/imgs/docs/burpsuite-learn/public/lab-logo.png
link: https://portswigger.net/web-security/cross-site-scripting/dom-based/lab-jquery-selector-hash-change-event
bgColor: '#001350'
textColor: '#39d50c'
2
3
4
5
6
# 3.1.2AngularJS中的DOM XSS
(译者注:“花括号{}” 也叫 “大括号{}”)
如果使用了类似AngularJS (opens new window)的框架,则可以在没有尖括号或事件的情况下执行 JavaScript。当一个网站在 HTML 元素上使用ng-app
属性时,它将由 AngularJS 进行处理。在这种情况下,AngularJS 将在双花括号内执行 JavaScript,这些花括号可以直接出现在 HTML 或属性当中。
- name: 实验室-从业者
desc: DOM型XSS-AngularJS表达式-尖括号与双引号HTML编码 >>
avatar: https://fastly.statically.io/gh/clincat/blog-imgs@main/vuepress/static/imgs/docs/burpsuite-learn/public/lab-logo.png
link: https://portswigger.net/web-security/cross-site-scripting/dom-based/lab-angularjs-expression
bgColor: '#001350'
textColor: '#4cc1ff'
2
3
4
5
6
# 4结合反射与数据存储的DOM型XSS
一些纯基于 DOM 的漏洞在单个页面中是自包含的。如果脚本从 URL 读取一些数据并将其写入危险的接收器,则漏洞是完全处于客户端中的。
然而,数据源并不局限于浏览器直接公开的数据,它们也可以来自网站自身。例如,网站经常在来自服务器的 HTML 响应中反映 URL 参数。这通常与普通的反射型 XSS 相关联,但它也可能导致反射型的 DOM XSS 漏洞。
在反射型 DOM XSS 漏洞中,服务器处理来自请求的数据,并将数据回显到响应中。反射的数据可能被放入 JavaScript 字符串文本或 DOM 中的数据项当中,例如表单字段。然后,页面上的脚本以不安全的方式处理反射的数据,最终将其写入危险的接收器。
eval('var data = "reflected string"');
- name: 实验室-从业者
desc: 反射型DOM XSS >>
avatar: https://fastly.statically.io/gh/clincat/blog-imgs@main/vuepress/static/imgs/docs/burpsuite-learn/public/lab-logo.png
link: https://portswigger.net/web-security/cross-site-scripting/dom-based/lab-dom-xss-reflected
bgColor: '#001350'
textColor: '#4cc1ff'
2
3
4
5
6
网站还可以在服务器上存储数据,并将其反映在其他地方。在存储型的 DOM XSS 漏洞中,服务器从一个请求中接收数据并存储它,在稍后的响应中包含该数据。在稍后的响应中,网页脚本包含一个接收器,接收器将以不安全的方式处理数据。
element.innerHTML = comment.author
- name: 实验室-从业者
desc: 存储型DOM XSS >>
avatar: https://fastly.statically.io/gh/clincat/blog-imgs@main/vuepress/static/imgs/docs/burpsuite-learn/public/lab-logo.png
link: https://portswigger.net/web-security/cross-site-scripting/dom-based/lab-dom-xss-stored
bgColor: '#001350'
textColor: '#4cc1ff'
2
3
4
5
6
# 5哪些接收器会导致DOM-XSS漏洞?
以下是可能导致 DOM-XSS 漏洞的一些主要接收器:
document.write()
document.writeln()
document.domain
element.innerHTML
element.outerHTML
element.insertAdjacentHTML
element.onevent
2
3
4
5
6
7
以下 jQuery 函数也是可能导致 DOM-XSS 漏洞的接收器:
add()
after()
append()
animate()
insertAfter()
insertBefore()
before()
html()
prepend()
replaceAll()
replaceWith()
wrap()
wrapInner()
wrapAll()
has()
constructor()
init()
index()
jQuery.parseHTML()
$.parseHTML()
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 6如何防范DOM-XSS漏洞
除了基于DOM的漏洞 (opens new window)中描述的一般措施外,你还应该避免——将来自任何不受信任源的数据动态写入 HTML 文档。