In mid-September 2019, Emotet resumed its activity and we evaluated changes to its operation in a previous blog post by Alex Holland.
- 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.
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.
Figure 3 – Obfuscated Document_Open subroutine, which contains junk lines.
Figure 5 – VirusTotal detection summary for 0.7055475.jse.
- Path: %USERPROFILE%\0.7055475.jse
- SHA256: D1292f0e74af41db6139b453effb022d8c506efa3108a22f87d580fab9c5e864
Heavy use of Bracket Notation
Use of Anonymous Functions
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.
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.
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.
The synchronous mode on the HTTP request is set by changing bAsync parameter of the Open method to false.
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 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.
Process Interaction Graph
Indicators of Compromise
|SHA256 (Documento_2019_69318.docm) Document-Word.Trojan.Sdrop||82bb3612b299cba0350e1dc4c299af9d50354cc1448b1dd931017f4381d0606a|
|SHA256 (in4684.exe) Win32.Trojan.Emotet||d2f7affdd9a9c6fd06911934ae409a2922e02619233305b074224f6f08229f39|
|SHA256 (ADA3154D.png) Win32.Trojan.Doc||6255a9df4bd42e8e89d7000e49b77038c887888715252a895b6f835a827a1063|