Google在线编程竞赛网Code-in因JSON数据逃逸出现的XSS漏洞
Google Code-in是一个由Google主办的针对学生的在线编程竞赛,每年举办一次。
当我第二次注册时,我将payload放入所有文本框中。我觉得应该不会发生什么异常,但是当我单击提交按钮时,所有的payload都被执行。并且在我访问的每个页面上payload都会执行。以上一点意味着它不仅仅是一个Self-XSS,很可能其他页面也存在JSON数据逃逸的问题。我把这个漏洞提交给Google的技术支持和Google VRP,以防它被黑客所利用。
在Google Code-in中,您可以提交任务以供查看,还可以向它们添加评论。在上次发现后,像往常一样,我将payload插入中评论中。令人惊讶的是,当我添加完成后,payload再次生效。甚至在重新加载页面后,它依然生效。我给Google发了一个报告,第二天他们就修好了。
现在让我们来看看payload如何生效的。
Google使用在后端生成的类型为application/json的sc ript元素将用户数据传递到客户端。
<sc ript type="application/json">
{"someData": true, "text": "hello world", "user": 123}
</sc ript>
在针对评论和其他字段中,我使用了一个简单的payload,如下所示:
"'><sc ript src=x></sc ript>{{1-1}}
在发送一个新评论时,它会被添加到JSON对象中,这个JSON对象会保存任务的评论以及其他相关数据。因此,当添加评论时,JSON对象就会变成下面这样:
<sc ript type="application/json">
{
"someData": true,
"comments": [{
"id": 123,
"text": "\"'><sc ript src=x></sc ript>{{1-1}}"
}]
}
</sc ript>
正如你看到的,双引号使得payload成功逃逸,形成了一个新的有效JSON。看起来,Google的开发人员忘记了关于逃逸的一件重要的事。
在HTML4文档中关于结束标签的解释:
字符串“</”第一次出现的位置(结束标签的打开分隔符)作为元素内容的结束端。在有效的文档中,这就是元素的结束标签。
这意味着一旦HTML解析器读取这个字符串,就认定元素内容到这结束。
我们可以在HTML4文档的附录中得到更多的信息:
当sc ript或者style数据是元素(sc ript和styel)的内容之一时,从元素的第一个开始标签和第一个结束标签之间(“</”)为元素内容,结束标签后可跟字符集([A-Za-z]);注意,结束标签后面跟的字符串可能不是正确的元素名字。作者因此可以利用“</”进行逃逸。
如何防止这种漏洞,可以利用CSP(内容安全策略):
使用CSP是最简单,最安全的防御XSS的方法。它可以使你避免使用生硬的字符串限制,例如“<!--”,“<\!--”,“<sc ript”,“<\sc ript”, “</sc ript”,“<\/sc ript”等。还避免了你编写代码,用于限制表达式。最后,使用CSP还避免了在编写安全限制代码时很容易触发的陷阱:即由于历史的原因,HTML脚本的解析有时会很奇怪,和你想的不一样。
以上还不足以在现代浏览器上得到一个可以生效的XSS,因为它们已经建立了CSP,我在另一篇文章(https://blog.thomasorlita.cz/vulns/google-csp-evaluator/)写了如何绕过它。简而言之,CSP可以利用白名单过滤sc ript,style,和其他资源,以阻止XSS攻击。这意味着<sc ript>
元素内容因CSP阻挡而不会被执行。
幸运的是,谷歌在其前端代码使用了Angular,这意味着CSP将不会生效。 像{{1-1}}这样的表达式更容易生效。由于Angular 1.6,谷歌移除了表达式沙盒,这意味着我们可以无障碍的访问的文档,就像这样:
{{constructor.constructor('alert("xss")')()}}
现在我们已植入一个有效payload,每次有人(导师或管理员)打开评论页就会执行。
时间线:
2018-10-30:漏洞报告
2018-10-31: 已修复 (by the dev team)
2018-11-01: 问题关闭
2018-11-21: 问题重新打开并接受,优先级更改为P2
2018-11-12: 奖励已发放
2018-12-12: 被标记为为已修复
原文链接:https://blog.thomasorlita.cz/vulns/google-code-in-xss/
最新评论