当 DOM XSS 隐藏在数千行代码中时,查找 DOM XSS 可能会很棘手。我们最近开发了 DOM Invader 来帮助解决这个问题,使用组合的动态+手动方法来发现漏洞,并迅速发现了一个影响 PayPal 的有趣的 Polyglot DOM XSS。在这篇文章中,我们将展示如何使用意外脚本gadget绕过基于允许列表的 CSP。大多数现代网站都使用多个JavaScript库,并且有很多行复杂的压缩代码,这使得对DOM XSS的测试变得非常令人头痛,PortSwigger安全研究部门专门开发了DOM Invader,使对DOM XSS的测试更加容易。DOM Invader将为你提供一个方便的树状视图,以此来显示目标的源和汇(不理解别着急,这是BurpSuite的一个定义),这极大地简化了发现DOM XSS的过程。
首先,我们使用 Burp 的嵌入式浏览器来导航站点并注入canary以查看每个页面上使用了哪些源和接收器。当我们遇到一些有趣的接收器时,我们会使用canary一起发送诸如 <>'" 之类的字符探测器,并检查接收器以查看它们是否被允许。我们没花多少时间就找到了一个页面,它以一种不安全的方式反映了我们的探测器。通常这很困难,因为反射是不可见的,但使用DOM Invader就很容易了。
正如你在上面的截图中看到的,我们的canary被反映在一个 id 属性中。如果我们发送一个双引号,则可以看到值如何到达接收器。但是当发送双引号时,屏幕变为空白。但是,如果我们转义双引号,则站点不会中断,我们可以看到它到达接收器:
在 HTML 中,反斜杠对双引号没有影响——所以我们似乎有一个 XSS 漏洞。我们需要通过注入其他字符来确认这一点,这将导致 JavaScript 执行。在对这个漏洞进行多次探测后,我们注意到注入的值必须是一个有效的 CSS 选择器。所以我们想出了以下向量:
由于CSP的原因,这一功能最初并没有发挥作用,但当我们在Burp中禁用这一功能时,我们收到了警报。然后,我们在HackerOne上向PayPal报告了这一情况,以及禁用CSP的说明。让我们惊讶的是,我们得到了 HackerOne 人员的回应:经过审查,您所描述的行为似乎没有任何安全风险或安全影响。
显然我们不同意这个评估,于是开始寻找绕过 PayPal 政策的方法。
绕过PayPal上的CSP
首先,我们研究了CSP,并注意到一些薄弱的部分。在script-src指令中,他们允许某些域,例如 *.paypalobjects.com 和 *.paypal.com。它们还包括“unsafe-eval”指令,该指令将允许使用 eval、Function 构造函数和其他 JavaScript 执行接收器:
查看策略,允许列表和“unsafe-eval”可能是绕过CSP的最佳目标。因此,我们在Burp Suite范围中添加了这些域。你可以在作用域中使用正则表达式,这非常方便。我们的范围是这样的:
Burp允许你在范围中选择特定的协议,由于策略具有“block-all-mixed-content”指令,我们只选择了 HTTPS 协议。
在学习了CSP之后,我们打开了Burp中的嵌入式浏览器,开始手动浏览网站,这是为了挑选那些拥有大量JavaScript资源的目标。当我们收集了大量的代理历史记录后,就可以使用 Burp 出色的搜索功能来查找较旧的 JavaScript 库。Burp允许你只搜索范围项,所以我们选中了那个框,这允许我们找到绕过CSP的资产。
我们从搜索AngularJS开始,因为用它很容易创建CSP绕过。有对 Angular 的引用,但没有对 AngularJS 的引用但我们尝试的JavaScript文件似乎并没有加载Angular,也没有引发异常。所以我们转向Bootstrap,在请求头和响应体中进行搜索。出现了几个 Bootstrap 实例,我们发现了一个旧版本 (3.4.1)。
接下来,我们研究了 Bootstrap gadget。 GitHub 上存在一些 XSS 问题,但这些影响了 3.4.0 版本。我们查看了Bootstrap代码一段时间,寻找jQuery的使用情况,但没有找到合适的gadget。
我们没有在数据库中找gadget,而是想到了 PayPal gadget。如果 PayPal 有一些我们可以利用的不安全 JavaScript ,那岂不是更好。这一次,我们没有搜索特定的库,而是搜索托管库的路径的一部分(例如“/c979c6f780cc5b37d2dc068f15894/js/lib/”)。在搜索结果中,我们注意到一个名为 youtube.js 的文件,并立即在其中发现了一个明显的 DOM XSS 漏洞:
这个文件使用的是jQuery,所以我们所需要做的就是包含jQuery和youtube.js,利用这个漏洞,然后我们绕过了CSP。看看YouTube .js文件,我们看到它使用了一个CSS选择器来找到YouTube播放器元素:
因此,我们需要注入一个带有“youtube-player”类的元素和一个包含jQuery XSS向量的data-id属性。一旦我们有了通用PayPal CSP绕过的基础,要做的就是把它与原始注入结合起来。首先,我们注入了一个带有 srcdoc 属性的 iframe。这是因为我们想注入一个外部脚本,但因为这是一个基于 DOM 的漏洞,脚本将无法执行。但是有了srcdoc,会发生以下情况:
请注意,我们需要通过转义双引号并为选择器的值部分分配单引号来确保它是一个有效的选择器。然后再注入指向 jQuery 和 YouTube gadget的脚本:
请注意,我们必须对向量进行 HTML 编码,因为我们不希望它以>字符关闭srcdoc属性。出于同样的原因,我们避免使用空格。然后我们使用 YouTube gadget注入脚本,jQuery 会转换并执行该脚本。我们再次需要对向量进行 HTML 编码,给它正确的类名,并使用 data-id 属性来注入我们的向量。注意,我们使用了一个编码的单引号来避免属性中断。我们必须对双引号进行HTML编码,因为srcdoc将解码HTML,而data-id属性将在iframe中呈现时进行解码,因此双编码可确保引号在注入 YouTube gadget时存在。最后,我们使用单行注释进行清理,以确保脚本在注入后忽略任何内容,即用双引号和单引号完成 CSS 选择器。
可以在此处找到最终的概念证明。
概念证明
这是 PoC 的截图:
可以看到对所有 PayPal 的完整 CSP 绕过,但它是必要的吗?正如我们所见,jQuery是CSP的克星。它使用“unsafe-eval”指令转换脚本,并且很乐意使用策略执行它们。看看原始的XSS漏洞,它似乎是一个jQuery选择器。因此,我们可以注入一个脚本,它将被jQuery转换。所以不需要单独的 CSP 绕过。因此,我们可以将注入简化为以下内容:
完整的概念证明请点此。
总结
允许列表策略绝对是不安全的,尤其是当你有大量可能被滥用的脚本/库时。即使用户输入通常不需要,也要修复XSS,这有助于防止意外的脚本gadget。
你永远不应该仅仅依靠 CSP 来保护XSS。 虽然这是你防御的一部分,但它不是唯一可用的障碍。
本文翻译自:https://portswigger.net/research/finding-dom-polyglot-xss-in-paypal-the-easy-way如若转载,请注明原文地址