Angler Exploit在最近变得非常火热,主要是最近的几次flash 0day都出现在该Exploit Kit中,该Exploit Kit最大的特点就是混淆的十分厉害,相比
国内比较流行DoSWF,这个的混淆方式简直灭绝人性==!,下面就是该Exploit Kit使用的一个CVE-2014-0569样本:
一个个不知道有多长的点点杠杠会看的人整个精神分裂、四肢无力、头昏目眩、口吐白沫…
最近的Angler Exploit Kit中用到了两种不同的混淆方式。在CVE-2014-0569、CVE-2014-8439、CVE-2015-0311、CVE-2015-0313中都有出现。
第一种混淆
这种混淆方式比较简单,该混淆主要将触发漏洞的swf文件以string或者ByteArray的方式保存在变量中,然后通过Loader类的loadBytes方法来加载恶意的swf文件:
因此只需要在调用LoadBytes函数之前拦截到参数peramennaya4即为触发漏洞的swf文件,怎么拦截这个参数呢?
一个方法是直接修改as文件并重新编译,修改后编译的as文件如下:
这里调用了flash一个用来输出调试信息的函数trace,为了捕获trace输出,需要用debug版本的flash插件,下载地址如下:
http://helpx.adobe.com/flash-player/kb/archived-flash-player-versions.html
有了debug版本的插件,还需要一个用来查看调试的工具Vizzy,前面的文章有用到这个工具,这样就可以拦截到swf文件:
swf文件会保存在vizzy的log文件中,默认路径为:C:\Users\用户名\Application Data\Macromedia\Flash Player\Logs\flashlog.txt
但是这样存在一个编码问题,swf文件中的编码会在读取ByteArray时出现错误,导致swf文件错误,那么我们可以使用base64编码的方式将ByteArry进行编码再写入
到log文件:
这里使用了com.dynamicflash.util.Base64库,使用前需要import。
这样就可以完整的得到base64的编码的swf文件。
用以下的python代码进行解码即可:
>import base64 >f1=open("base64.txt",'rb') >f2=open("decode.swf",'wb') >base64.decode(f1,f2) >f2.close() >f1.close()
第二种混淆
第二种混淆相比第一种要复杂很多,反混淆也非常麻烦,这里主要用到一个叫FFDec的工具,其自带一个反混淆的方法,在对Angler混淆时候比较有用:
尽管经过了反混淆的处理后,代码仍然十分难读,这里主要学习下该混淆(实际应该叫加密了)的方法。
1.内嵌二进制数据
as3通过extends ByteArrayAsset来嵌入二进制数据,具体参考以下方法:
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/core/ByteArrayAsset.html
被嵌入的二进制数据可以根据被嵌入时的名称通过类似类的方式直接引用,如下:
2.关键字符串加密
一些可能会被当作检测特征的字符串,如exec、sandboxType等等都经过了一连串的加密处理,这些加密的字符串保存在一个内嵌二进制加密字符串列表中:
第一个4字节代表加密的字符串个数,接下来的结构为:加密字符串长度+加密字符串内容
在解密字符串时,首先获取字符串在字符串加密表中的索引,获取索引的时候会指定第一个用到的access_key ,该key会通过传入的参数异或来得到
在字符串加密表中的索引值。access_key大小为4个字节,通过嵌入的形式保存在swf文件中:
加密方式为简单的一个异或:
public static funtion get_encrypt_index(param1:int) { return (param1^access_key) }
知道了索引后就知道了加密字符串的位置,接下来就是解密字符串了,解密的方式为RC4,RC4使用的key同样以内嵌二进制数据的形式保存:
第一个字节红色代表key的组数,绿色和蓝色是两组key,每组key的长度为16个字节。
根据被加密字符串的长度来选取不同的RC4 key,选取规则如下:
RC4key_array[加密字符串索引位置%RC4 key组数]
当加密的字符串为8BDFD9B7,其索引位置在加密字符串表中为13,则使用的RC4 key为第二组key,解密后的字符串内容为exec:
最后附上python RC4加解密的代码:
def rc4(data, key): ''' data: data that to be encrypted or decrypted. key: key to encrypt or decrypt. ''' #some parameters check here ... #if the data is a string, convert to hex format. if(type(data) is type("string")): tmpData=data data=[] for tmp in tmpData: data.append(ord(tmp)) #if the key is a string, convert to hex format. if(type(key) is type("string")): tmpKey=key key=[] for tmp in tmpKey: key.append(ord(tmp)) #the Key-Scheduling Algorithm x = 0 box= list(range(256)) for i in range(256): x = (x + box[i] + key[i % len(key)]) % 256 box[i], box[x] = box[x], box[i] #the Pseudo-Random Generation Algorithm x = 0 y = 0 out = [] for c in data: x = (x + 1) % 256 y = (y + box[x]) % 256 box[x], box[y] = box[y], box[x] out.append(c ^ box[(box[x] + box[y]) % 256]) result="" printable=True for tmp in out: if(tmp<0x21 or tmp>0x7e): # there is non-printable character printable=False break result += chr(tmp) if(printable==False): result="" #convert to hex string for tmp in out: result += "{0:02X}".format(tmp) return result out=rc4([0x8B,0xDF,0xD9,0xB7], [0x6D,0x0C,0x6B,0x0D,0x54,0x6F,0x38,0x7F,0x45,0x3A,0x36,0x0A,0x5C,0x41,0x60,0x77]) out=rc4([0x8B,0xDF,0xD9,0xB7], [0x1A,0x4D,0x57,0x75,0x7C,0x29,0x11,0x56,0x30,0x20,0x6A,0x5B,0x63,0x72,0x56,0x77]) print(out)
参考链接:
https://www.fireeye.com/blog/threat-research/2015/01/a_different_exploit.html
http://blog.csdn.net/white_eyes/article/details/6560355