Web安全学院
Web安全学院
  • 首页
  • 译序
  • 学习路线
  • 前篇
    • Web应用程序安全测试
    • 动态应用程序安全测试(DAST)
    • 带外应用程序安全测试(OAST)
  • 服务器端主题
    • SQL注入
      • SQL注入
      • SQL注入UNION攻击
      • 在SQL注入攻击中检索数据库
      • SQL盲注
      • SQL注入速查表
    • 认证
      • 认证漏洞
      • 基于密码登录中的漏洞
      • 多因素认证中的漏洞
      • 其他认证机制中的漏洞
      • 如何保护你的认证机制
    • 目录遍历
      • 目录遍历
    • 命令注入
      • OS命令注入
    • 业务逻辑漏洞
      • 业务逻辑漏洞
      • 业务逻辑漏洞示例
    • 信息泄露
      • 信息泄露漏洞
      • 如何发现并利用信息泄露漏洞
    • 访问控制
      • 访问控制漏洞与权限提升
      • 不安全的直接对象引用(IDOR)
      • 访问控制安全模型
    • 文件上传漏洞
      • 文件上传漏洞
    • 条件竞争
      • 条件竞争
    • 服务器端请求伪造(SSRF)
      • 服务器端请求伪造(SSRF)
      • 盲SSRF漏洞
    • XXE注入
      • XML外部实体(XXE)注入
      • XML实体
      • 发现并利用盲XXE漏洞
  • 客户端主题
    • 跨站脚本(XSS)
      • 跨站脚本
      • 反射型XSS
      • 存储型XSS
      • 基于DOM的XSS
      • XSS上下文
        • 跨站脚本上下文
        • 客户端模版注入
      • 利用跨站脚本漏洞
      • 内容安全策略
      • 悬空标记注入
      • 如何防范XSS漏洞
      • 跨站脚本(XSS)速查表
    • 跨站请求伪造(CSRF)
      • 跨站请求伪造(CSRF)
      • XSS与CSRF
      • 绕过CSRF令牌验证
      • 绕过SameSite Cookie限制
      • 绕过基于Referer的CSRF防御
      • 如何防范CSRF漏洞
    • 跨域资源共享(CORS)
      • 跨域资源共享(CORS)
      • 同源策略(SOP)
      • CORS和Access-Control-Allow-Origin响应标头
    • 点击劫持
      • 点击劫持(UI伪装)
    • 基于DOM的漏洞
      • 基于DOM的漏洞
      • 控制Web消息源
      • 基于DOM的开放重定向
      • 基于DOM的Cookie操纵
      • 基于DOM的JavaScript注入
      • 基于DOM的document-domain操纵
      • 基于DOM的WebSocket URL投毒
      • 基于DOM的链接操纵
      • Web消息操纵
      • 基于DOM的Ajax请求标头操纵
      • 基于DOM的本地文件路径操纵
      • 基于DOM的客户端SQL注入
      • 基于DOM的HTML5 Storage操纵
      • 基于DOM的客户端XPath注入
      • 基于DOM的客户端JSON注入
      • DOM-data操纵
      • 基于DOM的拒绝服务
      • DOM破坏
    • WebSocket
      • 测试WebSocket安全漏洞
      • 什么是WebSocket?
      • 跨站WebSocket劫持
  • 进阶主题
    • 不安全的反序列化
      • 不安全的反序列化
      • 利用不安全的反序列化漏洞
    • 测试GraphQL API
      • 测试GraphQL API
      • 什么是GraphQL?
    • 服务器端模板注入
      • 服务器端模板注入
      • 利用服务器端模板注入漏洞
    • Web缓存投毒
      • Web缓存投毒
      • 缓存设计缺陷的利用
      • 缓存实现缺陷的利用
    • HTTP Host标头攻击
      • HTTP Host标头攻击
      • 如何识别和利用HTTP Host头的漏洞
      • 密码重置投毒
    • HTTP请求走私
      • HTTP请求走私
      • 查找HTTP请求走私漏洞
      • 利用HTTP请求走私漏洞
      • 高级请求走私
        • 高级请求走私
        • HTTP/2降级
        • 响应队列投毒
        • HTTP/2专属载体
        • HTTP请求隧道
      • 浏览器驱动的请求伪造
        • 浏览器驱动的请求伪造
        • CL.0请求走私
        • 客户端异步攻击
        • 基于暂停的异步攻击
    • OAuth认证
      • OAuth 2.0认证漏洞
      • OAuth授权类型
      • OpenID Connect
      • 如何防范OAuth认证漏洞
    • JWT攻击
      • JWT攻击
      • 在Burp Suite中使用JWT
      • 算法混淆攻击
    • 原型污染
      • 什么是原型污染?
      • JavaScript原型和继承
      • 客户端
        • 客户端原型污染漏洞
        • 通过浏览器API进行原型污染
      • 服务器端
        • 服务器端原型污染
      • 预防原型污染漏洞
    • 基本技能
      • 基本技能
      • 使用编码混淆攻击
      • 在手动测试中使用Burp Scanner
Powered by GitBook
On this page
  • 什么是基于DOM的跨站脚本?
  • 如何测试基于DOM的跨站脚本
  • 测试HTML接收器
  • 测试JavaScript执行接收器
  • 使用DOM Invader测试DOM型XSS
  • 利用不同源和接收器进行DOM型XSS利用
  • 第三方依赖中的源和接收器
  • DOM型XSS结合反射和存储数据
  • 哪些接收器可能导致DOM型XSS漏洞?
  • 如何防范DOM型XSS漏洞
  1. 客户端主题
  2. 跨站脚本(XSS)

基于DOM的XSS

Previous存储型XSSNextXSS上下文

Last updated 1 year ago

在本节中,我们将描述基于DOM的跨站脚本(DOM型XSS),讲解如何发现DOM型XSS漏洞,并讨论如何利用不同的源和接收器来利用DOM型XSS。

什么是基于DOM的跨站脚本?

基于DOM的XSS漏洞通常发生在JavaScript从攻击者可控制的源(如URL)获取数据,并将其传递到支持动态代码执行的接收器(如eval()或innerHTML)时。这样,攻击者就可以执行恶意JavaScript,通常能够劫持其他用户的账户。

要实施基于DOM的XSS攻击,你需要将数据放入源中,使其传播到接收器并导致任意JavaScript的执行。

对于DOM型XSS,最常见的源是URL,通常通过window.location对象访问。攻击者可以通过在URL的查询字符串和片段部分中嵌入有效载荷来构造一个链接,将受害者引导到一个存在漏洞的页面。在某些情况下,比如在针对404页面或运行PHP的网站时,有效载荷也可以放置在路径中。

有关源与接收器之间污染流的详细解释,请参阅。

如何测试基于DOM的跨站脚本

大多数DOM型XSS漏洞可以通过Burp Suite的Web漏洞扫描器快速可靠地找到。手动测试基于DOM的跨站脚本,通常需要使用带有开发者工具的浏览器,如Chrome。你需要逐个检查每个可用的源,并逐个进行测试。

测试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(Chromium之前的版本)不会对这些源进行URL编码。如果你的数据在处理之前就被URL编码,那么XSS攻击不太可能奏效。

测试JavaScript执行接收器

针对基于DOM的XSS进行JavaScript执行接收器测试要稍微困难一些。对于这些接收器,你的输入不一定会出现在DOM中,因此无法对其进行搜索。相反,你需要使用JavaScript调试器来确定输入是否以及如何被发送到接收器。

对于每个潜在的源,如location,首先需要在页面的JavaScript代码中找到源被引用的地方。在Chrome的开发者工具中,你可以使用Control+Shift+F(或MacOS上的Command+Alt+F)搜索页面上的所有JavaScript代码以找到源。

一旦找到源被读取的地方,就可以使用JavaScript调试器添加一个断点,并跟踪源的值如何被使用。可能你会发现源被分配给了其他变量。如果是这种情况,就需要再次使用搜索功能来跟踪这些变量,看看它们是否被传递给了接收器。当找到一个接收来自源的数据的接收器时,你可以使用调试器检查变量的值,方法是将鼠标悬停在变量上,显示其被发送到接收器之前的值。然后,与HTML接收器一样,改进你的输入,看看是否可以成功实施XSS攻击。

使用DOM Invader测试DOM型XSS

在实际环境中识别和利用DOM型XSS可能是一个繁琐的过程,通常需要手动遍历复杂的、经过精简的JavaScript。不过,如果使用Burp的浏览器,就可以利用其内置的DOM Invader扩展,它能为你完成大部分繁重的工作。

阅读更多

利用不同源和接收器进行DOM型XSS利用

document.write接收器可与script元素配合使用,因此你可以使用一个简单的有效载荷,如下所示:

document.write('... <script>alert(document.domain)</script> ...');

LAB

但请注意,在某些情况下,写入document.write的内容可能会包含一些周围的上下文,在利用时需要考虑到这些上下文。例如,在使用JavaScript有效载荷之前,可能需要关闭一些现有元素。

LAB

innerHTML接收器在任何现代浏览器上都不接受script元素,也不会触发svg onload事件。意味着你需要使用img或iframe等替代元素。onload和onerror等事件处理器可以与这些元素结合使用。例如:

element.innerHTML='... <img src=1 onerror=alert(document.domain)> ...'

LAB

第三方依赖中的源和接收器

现代Web应用程序通常使用大量的第三方库和框架构建,这些库和框架通常为开发人员提供额外的功能和能力。重要的是要记住,其中一些也可能是DOM型XSS的潜在源和接收器。

jQuery中的DOM型XSS

如果使用的是jQuery之类的JavaScript库,则要留意是否有可以更改页面上DOM元素的接收器。比如,jQuery的attr()函数可以更改DOM元素的属性。如果数据是从用户控制的源(如URL)读取的,然后传递给attr()函数,那么就有可能操纵发送的值,从而导致XSS。例如,下面的JavaScript,它使用URL中的数据更改了锚元素的href属性:

$(function() {
	$('#backLink').attr("href",(new URLSearchParams(window.location.search)).get('returnUrl'));
});

你可以通过修改URL,使location.search源包含恶意JavaScript URL来利用这个漏洞。当页面的JavaScript将此恶意URL应用到返回链接的href后,点击返回链接将执行该URL:

?returnUrl=javascript:alert(document.domain)

LAB

另一个需要留意的潜在接收器是jQuery的$()选择器函数,它可以用于向DOM注入恶意对象。

jQuery曾经非常流行,一个典型的DOM型XSS漏洞就是由于网站将该选择器与location.hash源结合使用,以实现动画或自动滚动到页面上特定的元素而造成的。这种行为通常是使用一个易受攻击的hashchange事件处理器实现的,类似于以下:

$(window).on('hashchange', function() {
	var element = $(location.hash);
	element[0].scrollIntoView();
});

由于hash是用户可控的,攻击者可以利用它将XSS载体注入到$()选择器接收器中。较新版本的jQuery已修补了这一特定漏洞,当输入以哈希字符(#)开头时,将无法向选择器中注入HTML。不过,你仍然可以在实际环境中发现易受攻击的代码。

要真正利用这一经典漏洞,你需要找到一种方法,在不需要用户交互的情况下触发hashchange事件。其中一个最简单的方法就是通过iframe传递你的利用:

<iframe src="https://vulnerable-website.com#" onload="this.src+='<img src=1 onerror=alert(1)>'">

在这个例子中,src属性指向一个带有空哈希值的易受攻击的页面。当iframe加载时,XSS载体会被添加到哈希值中,从而导致hashchange事件触发。

注意

即使是较新版本的 jQuery,只要你对来自源的输入具有完全的控制,并且该源无需#前缀,那么它仍然可能通过$()选择器接收器而易受到攻击。

LAB

AngularJS中的DOM型XSS

如果使用像AngularJS这样的框架,则有可能在没有角括号或事件的情况下执行JavaScript。当一个网站在HTML元素上使用ng-app属性时,AngularJS将对其进行处理。在这种情况下,AngularJS将在双花括号内执行JavaScript,双花括号可以直接出现在HTML中,也可以出现在属性内。

LAB

DOM型XSS结合反射和存储数据

一些纯粹基于DOM的漏洞在单个页面内自包含。如果脚本从URL读取一些数据并将其写入到一个危险的接收器,那么漏洞就完全是客户端的。

不过,源并不仅限于浏览器直接暴露的数据,它们也可以来自网站。例如,网站通常会在服务器的HTML响应中反射URL参数。这通常与普通XSS有关,但也可能导致反射型DOM XSS漏洞。

在反射型DOM XSS漏洞中,服务器会处理来自请求的数据,并将数据回显到响应中。反射的数据可能被放置在JavaScript字符串字面值中,或者在DOM的数据项中,如表单字段。然后页面上的某个脚本会以不安全的方式处理反射的数据,最终将其写入到一个危险的接收器。

eval('var data = "reflected string"');

LAB

网站可能也会将数据存储在服务器上,并在其他地方反射它。在一个存储型DOM XSS漏洞中,服务器从一个请求接收数据,存储它,然后在后续的响应中包含这些数据。后续响应中的某个脚本包含一个接收器,然后该接收器以不安全的方式处理数据。

element.innerHTML = comment.author

LAB

哪些接收器可能导致DOM型XSS漏洞?

以下是一些可能导致DOM型XSS漏洞的主要接收器:

document.write()
document.writeln()
document.domain
element.innerHTML
element.outerHTML
element.insertAdjacentHTML
element.onevent

以下jQuery函数也是可能导致DOM型XSS漏洞的接收器:

add()
after()
append()
animate()
insertAfter()
insertBefore()
before()
html()
prepend()
replaceAll()
replaceWith()
wrap()
wrapInner()
wrapAll()
has()
constructor()
init()
index()
jQuery.parseHTML()
$.parseHTML()

如何防范DOM型XSS漏洞

原则上,如果存在一条可执行路径,数据可以从源传播到接收器,那么网站就容易受到基于DOM的跨站脚本攻击。在实践中,不同的源和接收器具有不同的属性和行为,这可能会影响可利用性,并决定需要采取什么技术。此外,网站的脚本可能会对数据进行验证或其他处理,在尝试利用漏洞时必须考虑这些处理。有多种与基于DOM的漏洞相关的接收器。详情请参阅这个。

除了在中描述的通用措施外,还应避免允许来自任何不受信任的源的数据动态写入到HTML文档。

基于DOM的漏洞
DOM Invader文档
列表
在使用location.search源的document.write接收器中的DOM型XSS
在select元素内使用location.search源的document.write接收器中的DOM型XSS
在使用location.search源的innerHTML接收器中的DOM型XSS
在使用location.search源的jQuery锚href属性接收器中的DOM型XSS
在使用hashchange事件的jQuery选择器接收器中的DOM型XSS
带有角括号和双引号HTML编码的AngularJS表达式中的DOM型XSS
反射型DOM XSS
存储型DOM XSS
基于DOM的漏洞