Flash Mob Episode II: Attack of the Clones

by Bing Liu
November 20, 2009 at 2:42 pm

Flash exploits targeting the old integer overflow vulnerability (CVE-2007-071) in Flash Player are still relatively active and multiplying on the base of the early versions exploit code, with more or less slight differences. One such variation was rendered tremendously more stealth and reliable, thanks to the use of a Flash run-time packer spawning a multiplexer component. It is caught as SWF/Dloader!exploit by Fortinet, yet, detection of this peculiar variant across the spectrum of antivirus products is still extremely scarce. Let’s lift the lid on that variant by examining a sample here, named F1.swf.

As usual, all the dirty tricks here are done through ActionScript. ActionScript is compiled and stored in the flash file as bytecode. For analysis, it is therefore convenient to decompile the bytecode using casual tools, such as swfscan. Unfortunately, the latter having failed to decompile F1.swf for me, I had to summon swfdump, which can disassemble the bytecode into “something” easier to read. The analysis below is based on that dis-assembly.

1).F1.swf

Following below is the staticconstructor of class BinaryData, which contains an encoded payload:

sealed protectedNS([protected]BinaryData) class <q>[public]::BinaryData extends <q>[public]::Object{

staticconstructor * =()(0 params, 0 optional)

[stack:10349 locals:1 scope:3-4 flags:]

{

00000) + 0:0 getlocal_0
00001) + 1:0 pushscope
00002) + 0:1 debug [register 00=xorkey]
00003) + 0:1 findproperty <q>[public]::xorkey
00004) + 1:1 pushstring “PrivateKey01232dfdFSdf”————-Property “xorkey”: decryption key
00005) + 2:1 setproperty <q>[public]::xorkey
00006) + 0:1 debug [register 01=data]
00007) + 0:1 findproperty <q>[public]::data
00008) + 1:1 pushbyte 19
00009) + 2:1 pushbyte 37
00010) + 3:1 pushbyte 58
[...]
10352) + 10345:1 pushshort 245
10353) + 10346:1 pushbyte 123
10354) + 10347:1 pushbyte 2
10355) + 10348:1 pushshort 170
10356) + 10349:1 newarray 10348 params
10357) + 2:1 setproperty <q>[public]::data—————Property “data”: encoded payload
10358) + 0:1 returnvoid
}

As can be seen above, the decoding key “PrivateKey01232dfdFSdf” is hard-coded in the flash file, as well as the encoded payload. The class member (or “property”) holding the key being called “xorkey”, it is with a moderate surprise that we find out the nature of the decryption algorithm, consisting in a simple XORing of the payload with the key. This happens in the constructor of class Main:

constructor * <q>[public]::Main=Main/Main()(0 params, 0 optional)
[stack:7 locals:3 scope:10-15 flags: need_activation]
slot 4: var <q>[packageinternal]::loader:<q>[public]flash.display::Loader
slot 3: var <q>[packageinternal]::i:<q>[public]::Number
slot 2: var <q>[packageinternal]::j:<q>[public]::Number
slot 1: var <q>[packageinternal]::bytes:<q>[public]flash.utils::ByteArray
{
[...]
00029) + 1:2 pushbyte 0
00030) + 2:2 convert_d
00031) + 2:2 setslot 3—————————counter i=0
00032) + 0:2 jump ->77
00033) + 0:2 label ——————————-decryption loop start
[...]
00039) + 2:2 getlex <q>[public]::BinaryData
00040) + 3:2 getproperty <q>[public]::data————encoded flash
[...]
00044) + 3:2 getlex <q>[public]::BinaryData
00045) + 4:2 getproperty <q>[public]::xorkey————-decoding key
[...]
00055) + 5:2 callproperty <q>[namespace]http://adobe.com/AS3/2006/builtin::charCodeAt, 1 params
00056) + 4:2 bitxor———————–decoding algorithm: XOR

00057) + 3:2 setproperty <l,multi>{[private]Main,[packageinternal]“”,…[Truncated]}———-store decoded byte in slot 1
[...]
00077) + 0:2 getscopeobject 1
00078) + 1:2 getslot 3
00079) + 1:2 getlex <q>[public]::BinaryData
00080) + 2:2 getproperty <q>[public]::data
00081) + 2:2 getproperty <q>[public]::length
00082) + 2:2 iflt ->33————————loop if counter i is lower than length
00083) + 0:2 debugline 23
00084) + 0:2 getscopeobject 1
00085) + 1:2 findpropstrict <q>[public]flash.display::Loader
00086) + 2:2 constructprop <q>[public]flash.display::Loader, 0 params
00087) + 2:2 coerce <q>[public]flash.display::Loader
00088) + 2:2 setslot 4——————–Initialize a flash.display::Loader instance to load the decoded flash F2.swf
[...]
00105) + 1:2 getslot 4
00106) + 1:2 getscopeobject 1
00107) + 2:2 getslot 1
00108) + 2:2 callpropvoid <q>[public]::loadBytes, 1 params——--load F2.swf
[...]
00130) + 0:2 returnvoid
}

The decoded payload is flash itself and loaded again. Let’s name it F2.swf for clarity and proceed with our analysis:

2).F2.swf

In the constructor of class “Zasder” appears a piece of multiplexing code, which aims at adapting the exploit string to the player type and version:

{
[...]
00009) + 0:1 pushstring “4657530825060000…[Truncated]”
00010) + 1:1 coerce <q>[public]::String
00011) + 1:1 setlocal_1 ———————-exploit version: 1.swf
[...]
00024) + 0:1 pushstring “4657530825060000…[Truncated]”
00025) + 1:1 coerce <q>[public]::String
00026) + 1:1 setlocal r6——————–exploit version: 6.swf
[...]
00042) + 0:1 pushstring “4657530825060000…[Truncated]”
00043) + 1:1 coerce <q>[public]::String
00044) + 1:1 setlocal r12————————exploit version: 12.swf
00045) + 0:1 getlex <q>[public]flash.system::Capabilities
00046) + 1:1 getproperty <q>[public]::playerType——————–query player type
00047) + 1:1 coerce <q>[public]::String
00048) + 1:1 setlocal r14
00049) + 0:1 getlex <q>[public]flash.system::Capabilities
00050) + 1:1 getproperty <q>[public]::version————-query player version
00051) + 1:1 coerce <q>[public]::String
00052) + 1:1 setlocal r15
00053) + 0:1 getlocal r14
00054) + 1:1 pushstring “PlugIn”————–“Top” case “PlugIn”
00055) + 2:1 ifne ->92—————jump to next top case if not equal to player type (stored in local variable r14)
00056) + 0:1 getlocal r15
00057) + 1:1 pushstring “WIN 9,0,115,0″——–sub case “WIN 9,0,115,0″
00058) + 2:1 ifne ->62—————–jump to next sub case if not equal to player version (stored in local variable r15)
00059) + 0:1 getlocal r6
00060) + 1:1 coerce <q>[public]::String
00061) + 1:1 setlocal r13———————-set exploit string (stored in r13) to 6.swf
[...]
00081) + 1:1 pushstring “WIN 9,0,47,0″———sub case “WIN 9,0,47,0″
00082) + 2:1 ifne ->86
00083) + 0:1 getlocal_1
00084) + 1:1 coerce <q>[public]::String
00085) + 1:1 setlocal r13—————————-set exploit string to 1.swf
[...]
00092) + 0:1 getlocal r14
00093) + 1:1 pushstring “ActiveX”—————–“Top” case “ActiveX”
00094) + 2:1 ifne ->131
00095) + 0:1 getlocal r15
00096) + 1:1 pushstring “WIN 9,0,115,0″——–sub case “WIN 9,0,115,0″
00097) + 2:1 ifne ->101
00098) + 0:1 getlocal r11
00099) + 1:1 coerce <q>[public]::String
00100) + 1:1 setlocal r13———————–set exploit string to 11.swf
[...]
00198) + 0:1 findpropstrict <q>[public]::ldr
00199) + 1:1 findpropstrict <q>[public]flash.display::Loader
00200) + 2:1 constructprop <q>[public]flash.display::Loader, 0 params
00201) + 2:1 initproperty <q>[public]::ldr
[...]
00210) + 0:1 findpropstrict <q>[public]::ldr
00211) + 1:1 getproperty <q>[public]::ldr
00212) + 1:1 getlocal r16
00213) + 2:1 callpropvoid <q>[public]::loadBytes, 1 params——–load selected exploit version
00214) + 0:1 returnvoid
}

This is a simple two-level switch-case on the flash player type and version. In total, 12 combinations – corresponding to 12 exploit versions (1.swf to 12.swf) – are available. For example, 6.swf is used when the flash player is embedded in the browser and the player version is 9.0.115.

Looking closer at flash 6.swf reveals that it contains a large (therefore negative, as the value is signed: 0x840381de > 0x7fffffff) SceneCount value in DefineSceneAndFrameData. In other words, it is trying to exploit CVE-2007-0071.

attackofclones

All these 12 actual exploits are similar, the only differences being adjustments (for example the SceneCount value, bogus DoABC ByteStream) meant to ensure correct jumping to the shellcode depending on the player type/version. Details of these 12 exploits can be find at Application-Specific Attacks:Leveraging the ActionScript Virtual Machine.

As a conclusion, F1.swf works as a run-time packer/decryptor and F2.swf works as an exploit multiplexer. It is easy to make this kind of attacks more stealth and wide-ranged, based on that packer/multiplexer framework: Lots of binary customer packer techniques may be used, and more flash vulnerabilities (not only one) may be integrated in the multiplexer, in the fashion of “exploit-packs” webapps. The threat landscape is such that most AV companies master, to a certain extent, the art of x86 binary unpacking. Will they have to integrate Flash-bytecode unpacking in their products soon?

Guillaume Lovet contributed to this post

Author bio: Bing Liu works as a senior researcher/IPS manager for Fortinet. 10+ years work experience in the field of Information Security/CISSP.

2 Responses to “Flash Mob Episode II: Attack of the Clones”

  1. [...] uses a similar run-time packer as the one discussed in Flash Mob Episode II: Attack of the Clones, thus I will only address the differences here. Again, I had to summon swfdump because swfscan [...]

  2. [...] actionscript are constantly targeted to exploit systems, with innovations being leveraged such as Flash run-time packers. New developments on the Threatscape this period include an out-of-band patch for Adobe Shockwave [...]

Leave a Reply