专栏首页信安之路我是如何找到 Google Colaboratory 中的一个 xss 漏洞的

我是如何找到 Google Colaboratory 中的一个 xss 漏洞的

本文作者:Michał Bentkowski 原文地址:https://blog.bentkowski.info/2018/06/xss-in-google-colaboratory-csp-bypass.html?view=classic 翻译作者:晚风(信安之路作者团队成员)

在本文中,我来讲讲我碰到的一个有趣的 XSS。2018 年 2 月,我在 google 的一个网络应用中发现了这个 XSS。这篇文章我不希望只是直接写出这个 XSS 存在在哪里,我会写出我找到这个 XSS 漏洞的思路,以及我在这个过程中需要克服哪些困难。另外,我还会讲一个用 javascript 小技巧绕过 CSP(内容安全策略)的例子。

什么是 Google Colaboratory

Google Colaboratory 是基于 Jupyter Notebook 的一个应用,主要作为大数据分析记录数据的笔记本。在 Colaboratory 中你可以创建包含文本和代码的文档,文本格式类似 markdown,支持 python2 或 3。代码可以在 Google Cloud 中执行,执行结果可以直接放在文档中。这种处理方式在科学研究中很方便。你可以准备一组数据和以什么方式处理这组数据的代码或者是维恩图。在 Colaboratory 的首页就有这种例子的展示。

像往常一样,我专注于寻找 XSS 漏洞和其他的一些漏洞。

我在之前就提到过了,Colaboratory 的文本使用 markdown 标记语法,markdown 是一种非常适合写笔记的语法,举个例子,你可以输入 **test** 来打印出粗体字,输入*test*打印出斜体字。

有趣的是,许多 markdown 语法解析器允许你直接使用 HTML 标记。Colaratory 也是同样的。例如,当你输入以下代码:

This is <strong>bold</strong>

然后你会在网页的 DOM 树中看到同样的代码

并且“bold”这个单词就变成了粗体。

接下来尝试着加一点简单的 XSS 代码:

Test<imgsrc=1onerror=alert(1)>

然而 DOM 树中显示的是

Test<imgsrc=1>

这意味着 Colaboratory 使用了 html 过滤器过滤掉了一些危险代码,像onerror事件,我在下面会说他到底用了什么 html 过滤库。

所以我们尝试一些别的方法。一个非常常见的在 markdown 解析器中注入 js 代码的方法是使用 javascript 伪协议的超链接,像这段代码:

[CLICK](javascript:alert(1))

被解析后就会被变成

<ahref="javascript:alert(1)">CLICK</a>

然而在 Colaboratory 中,并没有什么效果。当我使用 http/https 以外的协议时,这段 HTML 代码不会包含一个链接。另外我注意到,即使这个URL不包含一个正确的域名,这个链接也还是会被生成。就像我输入:

[CLICK](http://aaa$$$**bbbb)

上面的代码会被解析成

<ahref="https://aaa$$$**bbbb">CLICK</a>

我们便可以猜测URL的验证是通过简单的正则表达式完成的。因为 markdown 在 Colaboratory 中被解析成 javascript 代码,于是我准备从这个应用中的 js 文件入手,查找到那段用于验证 URL 的正则表达式。很快我就找到了下面的这段代码:

[...]
       returnqd(b?a: "about:invalid#zClosurez")
  }
    , sd=/^(?:(?:https?|mailto|ftp):|[^:/?#]*(?:[/?#]|$))/i
    , td=function(a) {
[...]

高亮的那一行是验证链接中的 URL 的正则表达式。我仔细看了一下,但找不到任何办法去绕过。虽然我花费一些时间去寻找这个表达式而且绕过不了,但时间并没有被浪费。我在想既然我发现一个地方会去验证链接的正确性,那或许附近的一些地方为会有一些代码去过滤 HTML?

换句话说,我应该能够找到那段在之前移除 onerror 事件的函数。我的直觉并没有让我失望,在附近的几行代码中,我找到了以下的一段代码:

varFm=xK("goog.html.sanitizer.SafeDomTreProcessor")

我快速地谷歌了一下,goog.hml.sanitizer.SafeDomTreeProcessor是 Google Closure library 的一部分。它包含了一份标签黑白名单。我花了些时间尝试去绕过 Closure 的过滤器但无济于事。在 HTML 过滤方面 Closure 毕竟是一个很受欢迎的依赖库。因此我不太可能在短时间内找到它的一些安全缺陷。

在这方面,我可以从不同的角度看待 Colaboratory。我在应用文档中注意到之前没有注意到的一件事: Colaboratory 还支持 LaTeX 语法。这可能是突破点。

我回到 Colaboratory 中,写出了以下的代码:

\frac12

这在 DOM 树中产生了以下的内容:

<spanclass="MathJax"id="MathJax-Element-5-Frame"tabindex="0"data-mathml="<math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;><mfrac><mn>1</mn><mn>2</mn></mfrac></math>"role="presentation"style="position: relative;">
<nobraria-hidden="true">[...] </nobr>
<spanclass="MJX_Assistive_MathML"role="presentation">
 <mathxmlns="http://www.w3.org/1998/Math/MathML">
  <mfrac>
   <mn>1</mn>
   <mn>2</mn>
  </mfrac>
 </math>
</span>
</span>

<nobr>标记中还有一大块代码,但这里为了简洁把他们删除了。

这些代码看起来非常有意思。我之前提到过 Colaboratory 使用 Closure 依赖库去清除 HTML 代码的危险元素。Closure 有一个标签的白名单,白名单中不包含这些标签:<math><mfrac><mn>。然而,由于渲染了 LaTeX,这些标签出现在了 HTML 中。此外,在第一行中,在data-mathml属性中,你可以看到完全相同的 HTML,这些 HTML 将在 DOM 树中渲染多行。

现在我感觉我离正确的答案越来越近了。为什么?因为,这个应用的这种行为显示了 Closure 库从不清除由 MathJax(LaTeX 依赖库)生成的 HTML 代码。此时,在 Colaboratory 中寻找 XSS 的问题就演变成了在 MathJax 中寻找 XSS。对于我来说,MathJax 似乎没有因为安全问题而经过仔细审核。

所以我查找 MathJax 的文档去寻找它支持哪些 LaTeX 命令。一开始,我注意到了下面的命令:

\href{url}{math}

根据文档的说明,你可以用这条命令在 LaTeX 里创建一个超链接,感觉可以在这里构造 XSS

\href{javascript:alert(1)}{1}

不幸的是,事实证明,MathJax 具有安全模式,可以防止这种攻击。

继续看文档,我发现 \unicode 命令可以使所有的 unicode 字符通过代码值的形式表示在 LaTeX 代码中。可以使用十进制和十六进制形式的数字。于是我在 Colaboratory 中尝试了一下,用下面两种方法输入大写字母 A

\unicode{x41}\unicode{65}

然后在 DOM 树中出现了以下的内容:

<spanclass="MathJax"id="MathJax-Element-6-Frame"tabindex="0"data-mathml="<math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;><mtext>&#x41;</mtext><mtext>&#65;</mtext></math>"role="presentation"style="position: relative;">
<spanclass="MJX_Assistive_MathML"role="presentation">
 <mathxmlns="http://www.w3.org/1998/Math/MathML">
  <mtext>A</mtext>
  <mtext>A</mtext>
 </math>
</span>
</span>

其中,data-mathml 属性中包含了<mtext>标签,HTML 实体与我输入的格式完全相同,就像&#x41;&#65;。因此,MathJax 可能根本不验证 \unicode 命令的参数,只是将其直接放入 HTML 中。我们再试一下:

\unicode{<imgsrc=1onerror=alert(1)>}

于是 DOM 树中出现了:

<spanclass="MathJax"id="MathJax-Element-7-Frame"tabindex="0"data-mathml="<math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;><mtext>&amp;#<img src=1 onerror=alert(1)>;</mtext></math>"role="presentation"style="position: relative;">
<spanclass="MJX_Assistive_MathML"role="presentation">
 <mathxmlns="http://www.w3.org/1998/Math/MathML">
  <mtext>&amp;#
   <imgsrc="1"onerror="alert(1)">
  ;</mtext>
 </math>
</span>
</span>

很棒!img 标签没有被过滤,出现在了 DOM 树中,现在我们的问题在于...页面中并没有出现 alert 这个框。

我想了一会没想出来为什么页面没有 alert 出来,但是当我看到控制台的时候,一切都明白了。

因为 Colaboratory 被 CSP 保护了。CSP 生效从而防御住了 XSS。但不管怎么样我决定向 Google 提交这个 bug,因为 CSP 没有改变 XSS(MathJax bug)存在的这个事实。

我发送了一个报告给 Google 并决定睡觉去了。明天早上起来再想办法绕过 CSP。

CSP绕过

其实昨晚我并没有睡好。虽然我昨天提交了一个 XSS bug,但它不能正常弹出 alert 的框,我有点不甘心。今天继续努力。

Colaboratory 中使用的 CSP 策略包含了两个最重要的指令:'nonce-...' 和 'strict-dynamic'。通常,'nonce-...' 会使 script 标签只有在这个 script 标签包含一个 nonce 属性的值和 'nonce-...' 指令的值相同的时候,这个 script 脚本才会被执行。'strict-dynamic' 允许将信任关系传递给动态生成的脚本,也就是说,“strict-dynamic”允许 js 动态添加的脚本执行,而忽略 script-src 的白名单。并且,其他的 script-src 白名单会被忽略,浏览器不会执行静态或解析器插入的脚本,除非它伴随有效的 nonce 值。 当你有一个可信的脚本(假设他有正确的 nonce 值),并且它在 DOM 树中添加了一个新的<script>脚本,那么这个新的脚本是可信的。因为它是被一个已存在的可信脚本添加的。

去年,Sebastian Lekies, Krzysztof Kotowicz 和 Eduardo Vela Nava 在各种安全会议上发表了题为“Breaking XSS mitigations via Script Gadgets"

https://www.blackhat.com/docs/us-17/thursday/us-17-Lekies-Dont-Trust-The-DOM-Bypassing-XSS-Mitigations-Via-Script-Gadgets.pdf

的精彩演讲。演讲中提到了在各种受欢迎的 JS 框架中绕过针对 XSS 的各种缓解措施,这其中就包括了 CSP。在演讲中你还可以找到一张幻灯片,其中显示了你可以绕过以下框架的哪种安全措施。事实表明,Polymer(Colaboratory 使用的框架)可以绕过任何类型的 CSP。

Polymer 是什么?这是一个 JS 库,可以用它来自定义你自己的 HTML 元素,并在代码中直接使用。打个比方,你可以按“SHARE”按钮,然后新的元素<colab-dialog-impl>将会出现在 DOM 树中。我的想法是尝试替换该元素的默认模板,所以我写了下面的代码:

$ \unicode{</math><dom-moduleid=colab-dialog-impl>
<template>
SOME RANDOM TEXT
</template>
</dom-module>} $

结果你可以看下面的演示动画。

这很棒!在点击了“SHARE”后,你可以清楚地看到我写的“SOME RANDOM TEXT”文字出现,取代了之前的窗口。

现在让我们来换上注入的脚本:

$ \unicode{</math><dom-moduleid=colab-dialog-impl>
<template>
 <script>alert(1)</script>
</template>
</dom-module>
<colab-dialog-impl>} $

我们再次停下来理解一下为什么它能生效。<script>标签事实上位于<template>元素中。接下来,每当“SHARE”按钮被按下时,脚本将会被 Polymer 插入进 DOM 树中。因为 Polymer 是可信的脚本,所以新生成的脚本也是可信的。这就利用了 CSP 的‘strict-dynamic’指令绕过了限制。

经过了这漫长的探索,这个 XSS 终于能正常弹框了。

总结

最后总结一下,首先我展示了我是如何在 Colaboratory 中识别 XSS,然后通过在 MathJax 依赖库中寻找到了安全问题从而在 DOM 树中注入了我们的恶意代码。最后,我使用了一个被称为 JS 小技巧来绕过 CSP(内容安全策略)。

目前,MathJax 中的安全问题已经得到了修复。

本文分享自微信公众号 - 信安之路(xazlsec)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-08-04

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 轻松理解 X-XSS-Protection

    首先我们来理解一下什么是“X-XSS-Protection”,从字面意思上看,就是浏览器内置的一种 XSS 防范措施。

    信安之路
  • XSS学习笔记【一】

    非持久型XSS也称反射型XSS。具体原理就是当用户提交一段代码的时候,服务端会马上返回页面的执行结果。那么当攻击者让被攻击者提交一个伪装好的带有恶意代码的链接时...

    信安之路
  • nmap使用指南(终极版)

    2.指定范围 192.168.1.1-255 192.168.1-255.1(任意位置) 3.IPv6地址只能用规范的IPv6地址或主机名指定。 CIDR 和...

    信安之路
  • Spring Boot 2.0(七):SpringApplication 深入探索

    对于第一个注解 @SpringBootApplication,我已经在博客 Spring Boot 2.0系列文章(六):Spring Boot 2.0中Spr...

    zhisheng
  • 跨站的艺术:XSS Fuzzing 的技巧

    Fuzzing(模糊测试)是挖掘漏洞最常用的手段之一,对于每一种漏洞,都有其 Fuzzing 的技巧,XSS 也是如此,在这篇文章里我将根据自己的经验与一起大家...

    云鼎实验室
  • 代码审计day7

    跨站脚本攻击( Cross Site Scripting )是指攻击者利用网站程序对用户输入过滤不足,输入可以显示在页面上对其他用户造成影响的HTML代码,从而...

  • 这些Java 代码必须要说一说优化细节!

    代码 优化 ,一个很重要的课题。可能有些人觉得没用,一些细小的地方有什么好修改的,改与不改对于代码的运行效率有什么影响呢?这个问题我是这么考虑的,就像大海里面的...

    用户5224393
  • 安全|常见的Web攻击手段之XSS攻击

    黄小怪
  • 学习资源 | 来自NOAA的AI与环境科学学习资源(七)

    AI,机器学习/深度学习技术(包括深层神经网络,DNN)在许多领域和应用中取得了很大的进展,包括医药、自动驾驶、社交媒体、金融工业等。在私有领域,人工智能的准确...

    郭好奇同学
  • Hyperf + uni-app 使用 EasyWechat 实现微信小程序登录和支付

    修改 SWOOLE_HOOK_FLAGS 编辑 bin/hyperf.php 文件

    hedeqiang

扫码关注云+社区

领取腾讯云代金券