DOM型XSS漏洞挖掘:完全指南
目录
- 什么是基于DOM的跨站脚本(XSS)
- 方法论
- DOM型XSS利用
- 结论
什么是基于DOM的跨站脚本(XSS)
传统跨站脚本(XSS)漏洞在服务器端渲染(使用PHP、JSP和ASP等语言)成为规范时很普遍。然而,随着应用程序变得越来越复杂,开发人员继续将应用程序逻辑转移到客户端,预计会出现更复杂的客户端漏洞。
在本文中,我们将介绍什么是基于DOM的跨站脚本(XSS)漏洞、其潜在影响,以及如何有效识别和利用现代应用程序中的这些漏洞。
让我们开始吧!
基于DOM的跨站脚本(XSS)与传统XSS的区别
在传统跨站脚本(XSS)漏洞中,恶意输入被发送到服务器端,并在HTTP响应中呈现,没有任何额外的输入清理。而对于基于DOM的跨站脚本(XSS),恶意输入来自DOM源,并纯粹通过DOM接收器在浏览器中评估,这意味着输出永远不会在HTTP响应正文中可见。
未清理数据(如有效载荷)从DOM源传递到DOM接收器,使得能够执行任意JavaScript代码。与反射型XSS类似,攻击者可以向受害者发送特制的漏洞页面链接,以执行客户端代码并控制受害者的会话。
在我们进入测试阶段之前,让我们简要了解所有DOM源和接收器。
DOM源
DOM源是包含用户可控数据的JavaScript属性,攻击者可以操纵这些数据(通常通过URL)。以下是基于DOM的XSS攻击所有可能入口点的全面列表:
DOM型XSS:DOM源解释
DOM接收器
DOM接收器是可以执行或呈现用户可控数据的JavaScript函数。当不受信任的数据从源流向接收器时,这些地方实际上会触发基于DOM的XSS漏洞。
在下图中,您可以找到一些DOM接收器的示例:
DOM型XSS:DOM接收器解释
现在我们理解了DOM接收器和源之间的区别,我们可以进入测试阶段,您将学习如何识别这些漏洞类型。
方法论
与传统XSS不同,在传统XSS中您注入关键字并寻找反射和注入点,基于DOM的XSS需要不同的方法,您将有效载荷注入DOM源并拦截运行时DOM事件处理程序,以查找您的输入在何处以及是否被处理。还有另一种用于基于DOM的XSS漏洞的方法,涉及彻底审查JavaScript代码。
让我们更仔细地看看这两种方法。
通过静态代码分析查找DOM型XSS
这种方法需要JavaScript的基础知识。您需要手动审查JS代码,搜索DOM源,并向前工作,直到找到任何对DOM源的引用。
此外,您需要单独审查每个JavaScript文件和代码片段,包括那些被混淆和压缩的文件。
通过DOM运行时拦截查找DOM型XSS
第二种方法涉及主动拦截从事件处理程序在运行时发出的DOM事件,并搜索您的输入可能已被处理的地方。您需要使用浏览器的开发者控制台来搜索DOM接收器,并在您的输入可能被处理的地方设置断点。
这种方法将允许您在数据从源移动到接收器时拦截和分析数据:
通过浏览器开发者控制台拦截基于DOM的事件
使用自动化工具!
这两种方法都很繁琐,并且在规模测试时可能会形成困难。幸运的是,有自动化工具可用,例如Untrusted Types和DOM Invador,可以帮助您轻松发现基于DOM的漏洞,包括基于DOM的跨站脚本(XSS)。
DOM型XSS利用
既然我们已经建立了基于DOM的XSS漏洞的核心基础知识,让我们探索如何在野外利用这些漏洞。
通过innerHTML接收器利用DOM型XSS
正如我们之前在本文章的DOM接收器部分所看到的,innerHTML接收器用于解析和呈现HTML标签,包括恶意有效载荷。
您有时会注意到,在将服务器数据与来自客户端的动态输入(例如URL查询参数的值)连接时,innerHTML是首选。当出现这种情况,并且没有执行进一步的验证时,我们实际上可以注入任何带有事件处理程序的HTML标签,该事件处理程序将执行我们的任意JavaScript代码。
考虑以下代码片段:
通过innerHTML DOM接收器的DOM型XSS
在第10行,我们可以看到易受攻击的应用程序从firstName查询参数读取数据,并将其传递给DOM接收器,特别是innerHTML。由于我们完全控制firstName查询参数,我们基本上可以将以下有效载荷作为其值传递,并呈现任何HTML标签,包括XSS有效载荷:
|
|
上述案例代表了一个基本示例。在现实世界场景中,您会遇到某种形式的验证。这可能是一个过滤掉恶意标签的基本正则表达式模式、用于清理输入的第三方包(如DOMPurify)或对所有数据进行HTML编码的服务器端措施。在任何情况下,可能仍有机会规避任何措施。
提示!
一些开发人员使用base64或其他编码来正确格式化和显示客户端数据。始终检查JavaScript代码,以识别在源和接收器之间是否使用了atob()、btoa()或其他解码函数,以避免错过任何潜在的基于DOM的XSS案例。
通过动态eval函数利用DOM型XSS
虽然这不太常见,但您可能偶尔会遇到基于动态数据执行客户端函数的目标,这些数据主要来自用户可控源(如查询参数)。在这种情况下,我们几乎总是距离执行任意JavaScript代码只有一步之遥。
让我们看一个例子:
通过Function DOM接收器的DOM型XSS
这个传统的登录表单似乎处理locale参数,并将其作为参数包含在Function()接收器中。要执行任意代码,我们必须使用locale参数来跳出上下文并注入我们自己的代码:
|
|
这个有效载荷基本上将允许我们调用alert()函数,证明任意JavaScript代码执行:
通过Function DOM接收器的DOM型XSS
通过客户端重定向利用DOM型XSS
应用内重定向通常用于增强最终用户的应用体验。考虑在会话令牌发出后您被重定向的登录表单。然而,当用户可控数据在没有输入验证的情况下立即传递到DOM接收器时,在某些条件下,可能允许我们执行任意JavaScript代码,这种可能性并不是每个开发人员都意识到的。
考虑以下示例:
通过Location DOM接收器的DOM型XSS
注意在第33行,redirectURL参数的值被传递到location接收器。使用我们之前的备忘单,我们可以确定通过JavaScript协议可能执行代码,至少在没有强制执行内容安全策略(CSP)的情况下:
DOM型XSS:DOM接收器解释
有了这些信息,我们实际上可以访问以下概念验证URL来利用这个基于DOM的跨站脚本(XSS)漏洞:
|
|
通过Location DOM接收器的DOM型XSS
与我们之前的示例类似,您可能需要试验您的有效载荷以规避任何过滤器。根据过滤器的不同,这可能涉及注入空字节、换行符或回车符(CR/LF)等。
服务器端还是客户端重定向?
如果HTTP响应返回3XX状态码和’Location’ HTTP响应头,则可能是服务器端重定向,并且(基于DOM的)XSS将不可能,因为浏览器将遵循Location头并且不会呈现任何HTML或执行任何JavaScript代码。
否则,它是客户端重定向,并且在某些条件下可能发生基于DOM的跨站脚本。
通过导入的第三方包利用DOM型XSS
现代Web应用程序严重依赖第三方JavaScript库和包。这些依赖项在不遵循最佳实践使用时或保持过时时,有时会引入基于DOM的XSS漏洞,创建一个经常被忽视的攻击面。
让我们看几个例子。
通过jQuery的DOM型XSS
jQuery是最广泛使用的JavaScript库之一。虽然它简化了DOM操作,但在处理用户可控输入时,它也引入了几种可能导致基于DOM的XSS的方法。
主要罪魁祸首是jQuery的html()方法,它的行为与innerHTML相同,通过解析和呈现HTML内容,包括可执行脚本标签和事件处理程序。
当开发人员将来自DOM源(请参阅我们之前的备忘单中的示例)的未清理数据传递到诸如html()、append()甚至jQuery选择器本身等方法时,可能可以注入在受害者浏览器中执行的恶意有效载荷。
AngularJS/VueJS中的客户端模板注入
在像AngularJS和VueJS这样的JavaScript框架中,当JavaScript模板引擎在没有适当清理的情况下处理用户可控输入时,可能会发生客户端模板注入(CSTI)。这两个框架都使用表达式语法来动态呈现数据,当用户控制的输入到达这些表达式时,可以执行任意JavaScript代码。
例如,在AngularJS中,我们可以使用constructor全局属性来调用函数:
|
|
这种模板注入漏洞是一种基于DOM的漏洞,会导致基于DOM的XSS。当您测试积极使用AngularJS或VueJS的目标时,请务必注意模板注入漏洞。
结论
基于DOM的漏洞,如DOM XSS,经常被忽视,因为它们难以检测和规模测试。在本文中,我们探索了您可以测试和利用这些基于DOM的漏洞的各种方式。
所以,您刚刚学到了一些关于利用基于DOM的XSS漏洞的新知识…现在是时候测试您的技能了!您可以通过在易受攻击的实验室和CTF上练习开始,或者…浏览我们在Intigriti上的70多个公共漏洞赏金计划,谁知道呢,也许在您下一次提交时获得赏金!