【漏洞分析】对Youtube中高级Flash漏洞的分析

http://p3.qhimg.com/t0111e46ff162242f00.jpg

译者:興趣使然的小胃

预估稿费:180RMB

投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿

一、前言

Flash至今仍是一个活跃的威胁来源。在2017年,我分别向Facebook、Youtube、WordPress、Yahoo、Paypal以及Stripe提交了Flash漏洞。在过去的3年中,我向漏洞奖励项目提交了超过50个Flash漏洞,获得了超过80k美元的奖励。由于精力有限,还有很多漏洞我来不及提交,也有些漏洞在我提交后还没有被修复。

与此同时,Flash已经被新推出的javascript/html5所取代。这些功能引入了新的更为复杂的漏洞,比如错误的CORS实现方法、通过postMessageXHR请求触发DOM XSS、主动混淆的数据内容等等。我们可以从Flash漏洞中汲取教训,以实现更加安全的javascript应用程序。新推出的Youtube html5 Api看上去更像是Youtube Flash Api移植到javascript上的实现版本,因此是一个非常理想的研究对象。实际上,利用我在Flash Api中积累的经验,我的确在Youtube html5 Api中找到了多个XSS漏洞。

在本文中,我会介绍我在Youtube Flash Api中找到的一些高级Flash漏洞,同时我也会顺便提到html/javascript安全性方面的内容。这些内容的技术细节比较多,所以如果有什么意见或者建议可以随时通过Twitter联系我(@opnsec)。你也可以访问此链接以了解Flash安全模型的详细信息。


二、逆向分析Youtube Flash Api

开发者可以利用Youtube Flash Api在外部网站中插入Youtube视频。

Api的工作流程如下图所示:

作为入口点,Youtube Wrapper其实是一个Flash文件,文件的具体路径为youtube.com/v/[VIDEO_ID],该文件其实是HTML页面以及Main App(主应用)之间的一个封装器。

主应用(Main Application)是一个大型Flash文件,大约有100k行代码,地址位于s.ytimg.com这个沙箱域名中。

Modules(模块)用来处理可选功能,比如字幕或者广告功能。这些模块不是独立的Flash文件,只能由Main App来加载。

此外,还有一个Flash转Javascript的Api,html页面可以通过这个Api向Youtube Api发送命令,这些命令包括play()、pause()等等。Flash文件也会执行ajax风格(ajax style)的跨站请求,以加载配置文件以及视频数据。


三、用户信息泄露漏洞

首先,我们先来分析一个简单的漏洞。如下这段Flash ActionScript3(AS3)代码是一段简化版的Youtube Wrapper实现代码:

http://p2.qhimg.com/t010e072177ae4b972b.png

这段代码会实时生成Youtube Wrapper,其中“username”属性包含Google用户的用户名(如果用户已连接到Google),“userpicture”包含用户个人资料图片的具体链接。在这个漏洞中,攻击者可以窃取这些属性的值。

开发者可以从自己的Flash文件(我们可以称之为Evil Wrapper)中加载Youtube Wrapper。在这种情况下,这两种Wrapper都会在另一个Flash安全沙箱中执行。

备注:

在Flash中加载外部Flash文件有点类似于在html中加载一个<iframe>。如果iframe的来源与其父节点不同,由于同源策略(Same-Origin Policy,SOP),这两者无法访问彼此的属性。

Youtube Wrapper中包含Security.allowDomain("*")这样的代码,以便宿主网页中的javascript能够向Flash应用发送诸如play()、pause()等命令。这也意味着Evil Wrapper可以访问Youtube Wrapper的任何公开属性,因为这两者处于同一个安全沙箱中。然而,Evil Wrapper无法访问私有属性。

由于user_name属性为私有属性,因此Evil Wrapper无法访问它。

此外,Flash还提供了一个Api以便Loader(加载者)与被加载文件之间能够通过loaderInfo.sharedEvents相互通信。Youtube Wrapper使用这个api来与Main App进行通信。当Main App将一个事件(event)发送给sharedEvents Api时,Youtube Wrapper会收到这个事件,然后利用event.data这个属性来返回用户信息。不仅Loader以及被加载文件能够访问loaderInfo.sharedEvents,只要引用了这个loaderInfo对象,其他任何Flash文件都可以访问loaderInfo.sharedEvents

备注:

这种情况类似于javascript的postMessage Api,这个Api同样可以允许跨域iframe之间的通信交流。不仅iframe及其父窗口可以访问postMessage Api,只要使用window.open以及window.frames,任何域名都可以访问这些引用,这种情况不受SOP限制。

如果Evil Loader可以访问这个loaderInfo对象,那么它就可以向Youtube Wrapper发送事件,窃取用户信息。

由于loaderInfo是appLoader的一个属性,而appLoader是Youtube Wrapper的一个私有属性,因此Evil Wrapper无法访问这个属性。

然而,当使用Loader时,如果我们想要显示已加载的文件,就必须将其添加为Display Container的子节点。通常情况下,我们会使用this.addChild(this.loader)来完成这个任务,这也正是Youtube Wrapper采用的方法。

问题在于,Youtube Wrapper还有一个内置的公共方法,名为getChildAt(),这个方法可以返回Youtube Wrapper的子节点。这意味着Evil Wrapper可以调用YoutubeWrapper.getChildAt(0),这样就可以返回Loader对象,绕过Loader属性的隐私限制策略。

备注:

将属性设为“私有(private)”是一种封装方法。然而,这种情况下,只有引用本身是私有的,引用所指向的那个对象并不是私有对象。

这样一来,Evil Wrapper就可以访问YoutubeWrapper.getChildAt(0).loaderInfo.sharedEvents,而这正是Youtube Wrapper以及Main App之间的接口。Evil Wrapper可以往Youtube Wrapper发送事件,Youtube Wrapper会在event.data属性中提供用户信息,因此Evil Wrapper就可以从event.data中读取用户信息。

3.1 PoC代码

Evil Wrapper代码如下所示:

http://p0.qhimg.com/t0161e74977ff099245.png

3.2 PoC工作流程

PoC代码的工作流程如下图所示:

3.3 攻击场景

攻击的前提是,受害者的Google处于已登录状态,并且受害者已安装Flash player

攻击场景如下:

(1)受害者访问攻击者的网站(evil.com/evil.html),这个网站包含一个恶意的Flash对象(evil.com/evil.swf)。

(2)evil.swf加载Youtube wrapper(https://www.youtube.com/v/[VIDEO_ID]),获取用户的Google用户名(4-5-6),然后evil.com就可以得知访问该站点的用户名。此外,由于个人资料的图片链接具有唯一特征,因此攻击者有可能识别出用户的Google账户。

3.4 影响范围

如果网站用户已登录Google,那么任何网站都可以使用这种方法来提取网站访问用户的身份。想象一下,如果我们随机访问一个网站,然后这个网站竟然会显示我们的姓名和照片,惊不惊喜?意不意外?

3.5 缓解措施

为了解决这个问题,Youtube Wrapper已经停止往event.data属性中写入用户信息,现在会将用户信息直接发往Main App。这样处理后,即使Evil Wrapper往Youtube Wrapper发送消息,它也不会收到用户信息,因为相关信息会直接发送到Main App。

3.6 时间线

08/27/2015 – 向Google VRP提交漏洞

09/09/2015 – 漏洞被修复,获得奖励(1星,满分4星)。


四、总结

这是一个简单的漏洞,希望你能通过这个漏洞理解基本的原理。你可以进一步阅读第二篇文章,在那篇文章中,我们利用另一个漏洞实现了在youtube.com上执行任意Flash代码。

(完)