原型污染是一个有趣的漏洞,无论是服务器端还是客户端。基于应用逻辑,原型污染会导致其他漏洞。例如,posix 引入了一种有趣的技术来在模板引擎中实现 RCE,Michał Bentkowski 展示了绕过客户端 HTML 清理程序,而 William Bowling 使用原型污染在 HackerOne 上发现了一个反射型 XSS。从 RCE 到 SQL,任何漏洞都可能与 javascript 应用程序中的原型污染有关。
介绍
在这项研究中,我们的目标很简单,即扫描所有漏洞披露程序的原型污染,并找到实现 XSS 的脚本小工具。这篇技术文章将涉及我们创建的工具、面临的挑战以及整个过程中的案例研究。
我们对 Web 应用程序感兴趣的两种情况是检查它是否容易受到原型污染。
情况1
在第一种情况下,我们要检查应用程序是否正在解析查询/哈希参数,并检查它是否在过程中污染原型。我们发现 80% 的嵌套参数解析器容易受到原型污染的影响。
让我们假设 Web 应用程序使用 canjs-deparam 库来解析查询参数。正如你在下面的代码中看到的,它创建了一个空对象并添加了键值对。显然,如果我们请求的 URL 是 https://victim.com/#a=b&__proto__[admin]=1,这会导致原型污染。
如你所想,通过在 location.hash 和 location.search 中迭代不同的原型污染有效负载,很容易识别应用程序是否具有易受攻击的原型污染解析器。
以下是查询字符串的不同变体,这些变体在解析时可能会导致污染。
Selenium Bot
为了实现自动化,我们编写了一个seleniumBot,它运行在一个巨大的子域数据库上,并检查应用程序是否存在漏洞。
浏览器扩展
Bot的一个漏洞是我们无法扫描应用程序的目录和授权终端,因为数据库变得非常大,扫描需要几天时间,且大多数程序禁止扫描。为了解决这个漏洞,我们编写了一个 chrome 扩展,其运行逻辑与Bot相同,但它会在用户访问 chrome 中的特定终端时进行扫描。使用扩展程序,我们可以随便使用chrome,并在后台扫描原型污染,你可以在这里找到插件。
情况2
在这种情况下,我们要检查是否有任何功能在客户端的用户输入或某些数据/响应处理导致原型污染,大多数情况下这会导致self-XSS,因为攻击者无法控制输入如情况 1 中的来自该位置输入。但它值得扫描,大多数时候self-XSS可以转换为reflection-XSS。
幸运的是,在这种情况下,自动化有点困难,CodeQL 使事情变得更容易。我们只选择了收入最高的顶级程序,并转储了所有的 javascript 文件,创建了一个 CodeQL 数据库,并扫描了导致原型污染的模式。
这样,我们就能够找到一个用户控制的JSON,他可以与另一个导致原型污染的应用程序合并。
识别易受攻击的库
一旦Bot识别出易受攻击的应用程序,我们的下一个任务是识别易受攻击的库和原型被污染的确切行,并将结果存储在数据库中。为了识别,我们使用了几种不同的技术。
如果应用程序并不复杂,在 Chrome 开发者工具中搜索诸如 location.hash/decodeURIComponent/location.search 之类的关键字将导致找到易受攻击的实现的确切功能。
在 Firefox 中阻止 JS 资源请求
在 Firefox 开发者工具网络活动中有一个很好的选项叫做 Block URL,所以为了找到负责原型污染的 js 资源,我们阻止 URL 并检查污染的属性是否未定义。
setter 上的调试器断点
这种技术比其他技术更简单,当属性设置为object .prototype时,我们可以设置一个断点。
查找脚本小工具
什么是脚本小工具?
在某个属性被污染后,是否有应用程序逻辑或函数会导致Javascript执行?
让我们看一个在SwiftType Search库中找到的脚本小工具的简单示例。实现XSS的有效负载是https://example.com/#__proto__[xxx]=alert(1)。
下面是一段代码(脚本小工具)负责弹出警报,$.each 迭代 this._userServerConfiguration.install.hooks 对象以及原型上的属性,这导致我们被污染的属性 xxx 被评估。
基于这个应用程序,我们使用了不同的技术来查找脚本小工具。
关键字搜索和源代码审查
如果应用比较简单,我们可以搜索srcdoc/innerHTML/iframe/createElement 等关键字,查看源代码,检查是否导致javascript 执行。有时,提到的技术可能根本找不到小工具。在这种情况下,纯源代码审查会显示一些不错的小工具,如下例所示。
BlackFan 通过源代码审查在 jQuery 中发现了这个很酷的小工具。
小工具
这是一段小工具的代码:
SecurityMB 的 pollute.js
我们已经围绕 SecurityMB 的 pollute.js 编写了一个 burp 扩展,它将所有 JS 资源替换为由 pollute.js 生成的修改版本。此外,我们修改了 pollute.js,使其仅在某个属性受到污染时才记录信息。
pollute.js 的基本思想是它通过在所有属性访问周围添加调试函数来检测代码,该函数会记录访问 Object.prototype 属性时的确切访问行。
检查下面的插件。
注意:插件并不完美,tmp.js 可能会被覆盖,最好使用一个随机名称。
Filedescriptor 的不受信任类型扩展
不受信任类型通过滥用可信类型来记录 DOM sink,我们检查这些 DOM sinks是否有任何可能被污染的属性,进而导致 XSS。
如果你在安装了插件的情况下访问 https://msrkp.github.io/,你会注意到 jQuery 中的一个 innerHTML sink。其中,wrapMap[tag] 是未定义的,这意味着我们可以用数组污染 wrapMap 的“li”属性,并且第一个或第二个元素将被注入到页面中。
通过污染“li”属性导致XSS
类似于文件描述符的扩展securitymb的pollution .js记录类似的堆栈跟踪,我们必须检查源代码,并检查它是否导致手动XSS。
一旦找到这个小工具,我们就向相应的程序报告这个漏洞。
将易受攻击的库和小工具存储在数据库中
我们计划将所有易受攻击的小工具和库存储在数据库中。
在构建了易受攻击的库和脚本、小工具的数据库后,可以使用它来促进 Prototype Pollution 的搜索和利用。
例如,在某些情况下,JavaScript 代码中存在易受攻击的库,但会在特定条件下执行。为了覆盖这些变体,可以使用正则表达式检测库。由于代码可以通过缩小修改并组装成一个大的 JS 文件,所以搜索正则表达式不应太严格,应该使用在缩小过程中不改变的片段。例如,你可以搜索在查询字符串处理中使用的正则表达式。
为此,构建了一个规则库,可以通过使用 Burp 的“漏洞消息检查”或“软件版本报告器”扩展分析 HTTP 响应来检测被动模式下的易受攻击的库。
chrome 扩展中添加了相同的功能,它使用数据库中提到的导致污染的模式搜索 js 资源。
Web 应用程序中的被动搜索记录 jQuery 查询对象易受攻击的库。链接到 burp 插件:https://github.com/BlackFan/cspp-tools/tree/main/match_rules。
示例研究
案例研究 1:CodeQL
这是我最喜欢的一个漏洞,有一次我试图使用插件和 selenium bot 找到污染。但他们都没有显示出任何有趣的结果。所以,我想到了使用CodeQL来扫描这个漏洞,因为程序的范围非常大,而且有很多JS密集型的应用程序。
于是我只能扫描所有有趣的应用程序并将 JS 文件下载到一个文件夹中。然后,我创建了一个 CodeQL 数据库,并在 https://github.com/github/codeql 上提供的查询的帮助下编写了一个查询,但我面临的漏洞是我必须为每个库的基本 deparam 查询编写一个易受攻击的代码模式,这是不可行的。来自 GHSecurity 实验室的 @asgerf 提出了一个通用查询,其中 RemoteFlowSource 或 location.{hash,search} 作为源,不安全的属性分配作为 Sink。此查询的缺点是应该调用解析器函数https://www.google.com/url?q=https%3A%2F%2Fgithub.com%2Fgithub%2Fsecuritylab%2Fdiscussions%2F209%23discussioncomment-145109&sa=D&sntz=1&usg=AFQjCNFDSqqg5OWJTbhafhqaa4OR2chcjg。无论如何,我在我创建的 JS 数据库上运行这些查询,并希望找到易受攻击的合并调用或位置解析器。
令我惊讶的是,它显示了下载的 javascript 文件中存在易受攻击的合并的结果。然后一位研究人员和我开始努力利用它。由于位置解析中不存在污染,我们必须找出哪些函数污染了原型。
1、污染原型
经过两天的努力,我们能够通过将 JSON 有效负载发送到保存有效负载的某个终端来污染原型,当客户端收到相同的有效负载时,原型就会受到污染。
2、寻找小工具
我们花了两天多的时间才找到合适的小工具,在一个Web Worker中发现了一个javascript代码的执行。
由于 Web Worker 不能直接操作 DOM,所以这个 XSS 的影响非常低。经过大量的源代码审查,我们能够找到合适的小工具。
3、帐户接管权限
你可能已经注意到这是一个self XSS,我们必须展示其影响。又过了一天,我们通过在 iframes/windows 中打开敏感页面来升级 self XSS 以接管帐户,并使用 SAML 登录我们的帐户并读取敏感页面中的数据以接管帐户。
案例研究 2:Jira Service Management 4.16.0 上的原型污染
我们使用 selenium bot 扫描了 HackerOne、Bugcrowd 和 Intigriti 中的所有私有和公共程序。有许多具有位置解析功能的应用程序会导致污染,而且大多数情况下漏洞在于第三方分析服务或使用易受攻击的库。我们注意到一个易受攻击的网站,其域为 jira.random.com/servicedesk/customer/user/requests?__proto__.x=11111。出于好奇,我们寻找了各个公司的 Jira 服务管理。
污染的根本原因:Jira服务管理使用的骨干查询参数容易受到原型污染的影响。
XSS脚本小工具:Posix想出了下面这个小工具,它可以在所有Jira网站上使用。
Gadget:__proto__.isFresh=xxx&__proto__.onmousemove=alert(1)//&__proto__.onmousemove=1
脚本:
下面是使用文件描述符的不受信任类型找到的其他一些小工具。
jira.mozilla.com 上的 XSS
其中一个使用Jira的Mozilla域也有同样的漏洞,我们把这个漏洞提交给了Mozilla,得到了2000美元的奖励。
URL:
我们最初认为这是用户安装的模块漏洞,但后来意识到该漏洞存在于所有自托管的 4.16.0 版以下的Jira网站中。
Jira 通过将__proto__, constructor和prototype项列入黑名单来修复该漏洞,但是如果你清楚地注意到 _setParamValue 函数,字符 [] 将从项中删除,这意味着我们可以使用像 __pro[]to__ 这样的项绕过修复。
绕过:https://local:8080/servicedesk/customer/user/signup?__pro[]to__.div=1&__pro[]to__.div=%3Cimg%20src%20onerror=alert(document.domain)%3E&__pro[]to__.div=1
案例研究 3:使用 Rahul 和 Harsh 的 chrome 扩展程序发现 apple.com 上的 XSS
1、发现漏洞
Rahul 和 Harsh最终确定了创建可用于这些终端的 chrome 扩展。他们编写了一个基本的 chrome 扩展,基本上用原型污染有效载荷更改 location.search/location.hash 并检查原型是否被污染。
当时,他们已经在研究苹果的计划。所以,他们做的第一件事就是开始浏览apple.com的网页来测试这个插件。该扩展程序在 https://www.apple.com/shop/buy-watch/apple-watch 弹出了存在原型污染的通知。有那么一瞬间,我们都认为这是一个误报,但原型确实被污染了。
2、寻找小工具
在 BlackFan 的 帮助下,我们很快找到了一个小工具。最终的 URL 是,https://www.apple.com/shop/buy-watch/apple-watch?__proto__[src]=image&__proto__[onerror]=alert(1)
污染位于苹果用来解析位置的 canJS-deparam 库中。
最初,苹果通过检查 __proto__ 是否在属性中来修复该漏洞,因为你可能已经知道这可以使用 [constructor][prototype] 绕过,因此最终绕过 URL 将是 https://www.apple.com/shop /buy-watch/apple-watch?a[constructor][prototype]=image&a[constructor][prototype][onerror]=alert(1)。
我们提交了绕过修复,苹果通过完全删除位置解析修复了这个漏洞。
案例研究 4:HubSpot 分析
HubSpot 容易受到原型污染的影响,它在解析查询字符串(location.search)的 js 文件中使用了 deparam。HubSpot 被超过 121000 家公司使用。我们发现,由于HubSpot使用的第三方分析,许多应用程序容易受到XSS的攻击。
1、第一种绕过方法
Hubspot通过将__proto__ key列入黑名单来修复这个漏洞,因此它可以被构造函数[prototype][taint]= contamination绕过,我们报告了这个绕过,他们通过创建一个空Object来修复这个绕过。
2、第二种绕过方法:通过 Nikita Stupin 绕过
Nikita Stupin 使用以下有效载荷找到了一个很酷的绕过方法:
?__proto__=&0[taint]=polluted
如果 __proto_, constructor, prototype 存在于项中,他们通过将小写更改为大写来修复绕过。
案例研究 5:Masato Kinugawa 的细分分析污染
Segment Analytics 使用容易受到原型污染的组件查询字符串。这是一个有趣的原型污染,只有当属性为 Number 时才会发生污染。
这是造成污染的代码。
找到一个只有数字污染的小工具是非常困难的。我们发现许多使用组件查询字符串或分段分析的漏洞赏金网站仍然容易受到污染,但没有小工具,就没有任何影响。我们无法在任何易受此漏洞影响的应用程序中实现 XSS。
Trello 就是这个漏洞的一个例子,你可以注意到 Object.prototype[123] 被污染了:https://trello.com/?__proto__[123]=xx
在knockout.js中,securityymb找到了一个使用数字的小工具,如果易受攻击的网站使用knockout.js,那你就太幸运了。
缓解措施
1.在合并两个对象或解析位置并将其转换为对象时,请确保使用包含以下 __proto__、prototype、constructor 的属性的拒绝列表,确保在将属性添加到对象之前进行拒绝列表检查,并且不要像 Jira 那样犯错误。
2.如果应用程序是 Node.js,你可以使用命令行选项 --disable-proto 禁用 Object.prototype.__proto__ 属性。