Deobfuscating VBA & PowerShell Scripts of an Emotet Trojan Downloader

by Lubomir Stroetmann, Senior Consultant

Contents

  1. Introduction
  2. Deobfuscating the VBA Macro
  3. Deobfuscating the PowerShell script
  4. Running the Emotet Trojan

1. Introduction

We analyzed a recent wave of phishing mails trying to spread the Emotet banking trojan via malicious Word documents. This post provides details of the obfuscation methods used in the VBA macro and the PowerShell script contained within the Word documents.

In order to be infected, four user interactions are required: Open the email, click the link contained within, open the word document that is downloaded and then enable the execution of macros:
From phishing mail to infection
The macro then proceeds to execute a PowerShell script which in turn downloads and executes the Emotet trojan.

The phishing mails do not use a fake sender, instead they spoof the display name. The display name is set to a (valid) email address: "MatthiasPeters@firma.de" <juan.reynolds@resory.pl>

The email text purports to contain an important invoice, provided as a link. Clicking the link downloads a .doc Microsoft Word file. The linked domains seem to be websites with hacked CMS software. The word document uses a standard phishing trick: It claims it is “protected” and requests the user to activate macros to be able to see the document contents:

2. Deobfuscating the VBA Macro
We extracted the VBA code of the macro using oledump.py:

Of the 152 lines of code, only a few have an actual purpose – the rest is just there for misdirection. Most of the code’s functions actually never get called.

A good start is to look for the autoopen() function which gets executed when the document is opened:

Sub autoopen()
VKbZcLUg
End Sub

This points us to the VKbZcLUg() function. It contains loads of useless code such as

YbaUHkeFD = uHbuDLuPaXz + dTEEdye = zSHBfXvvPhg

These are pointless comparison operations. A variable x gets set to true or false depending on whether a + b is equal to c or not:

x = a + b = c

All those lines are irrelevant and can be skipped.

Lines with function calls in brackets need a closer look:

ZneZkvTk = yKvCXNf("PpRDVaYk") + yKvCXNf("SnVfbyV") + yKvCXNf("NBhWRnnr") + yKvCXNf("nGmERhbgD") + yKvCXNf("MHmBmVtxxeD") + KeyeUgtkrd + HuPuESkLhy + zemaEVc + SuGvNTkzE + YPCrwmVkT + HptZKepNwvX + vmuvTSP + KxxGMpUX + RkbrfNxRNWd + tNGdshzMD + yKvCXNf("GZnvfVd")

The yKvCXNf() function keeps getting called with different arguments. This function contains more comparison operations as a distraction and one line of actually useful code:

Public Function yKvCXNf(vRKbufsX)
[...]
KADXEmH = ActiveDocument.CustomDocumentProperties(vRKbufsX)

This line looks up and returns custom document properties set for the word document, based on the parameter given to it. We take a look at the custom document properties and see they contain string parts for the strings "powershell" and "wscript.shell":

Getting back to the main VKbZcLUg() function, there are two lines of code doing the actual work. They can be recognized by the strings ActiveDocument.BuiltInDocumentProperties("Comments") and CreateObject(DEBAKSwY).Run:

mNaCbmDx = ZneZkvTk + "" + ActiveDocument.BuiltInDocumentProperties("Comments") + KeyeUgtkrd + HuPuESkLhy + zemaEVc + SuGvNTkzE + YPCrwmVkT + HptZKepNwvX + vmuvTSP + KxxGMpUX + RkbrfNxRNWd + tNGdshzMD + fPsFbYX
CreateObject(DEBAKSwY).Run$ mNaCbmDx + KeyeUgtkrd + HuPuESkLhy + zemaEVc + SuGvNTkzE + YPCrwmVkT + HptZKepNwvX + vmuvTSP + KxxGMpUX + RkbrfNxRNWd + tNGdshzMD + atMRBBmV, 0

Plenty of string concatenation is taking place, with undefined variables that can all be ignored. The actual string comes from the document’s comments field. Taking a look we find a long Base64-encoded string:

Time to put all our findings together! We have a CreateObject call which creates an object of the type “wscript.shell”. It then runs the shell command "powershell -e JAB7AFcAYABzAEMAUgBgAEk[...]CgA=" with the complete Base64-encoded PowerShell script. This uses the handy PowerShell command line option -EncodedCommand or -e which accepts Base64-encoded commands.

Here’s the fully deobfuscated macro:

3. Deobfuscating the PowerShell script
Decoding the Base64-string we got from the document’s comment field, we find some slightly obfuscated PowerShell code:

The code does some minor string trickery using PowerShell’s -f Format operator. It rearranges fragments of a string ('new-ob','t','jec') into the order provided by numbered placeholders ({0}{2}{1}). The rest is just fancy variable naming such as ${W`sCR`IpT}.

Re-arranging the strings and cleaning up the variable names we get:

As we can see, the code downloads the trojan from five different URLs, saves it in the temp directory using a randomly generated numerical name, and then executes it.

4. Running the Emotet Trojan

We run the trojan in a custom VM without a network adapter and a fake network provided by Fakenet-NG. Sniffing the network traffic of the trojan we can see periodic HTTP POSTS with encrypted data to a rotating list of C&C servers:

We let the trojan run for a while to get the following full list of servers:

IP Port Network Location
173.212.227.54 443 AS51167 Contabo GmbH Germany
104.236.252.178 8080 AS62567 DigitalOcean, LLC Clifton, NJ, USA
162.243.159.58 443 AS14061 DigitalOcean, LLC San Francisco, CA, USA
45.33.55.157 8080 AS63949 Linode, LLC Fremont, CA, USA
77.244.245.37 7080 AS47692 Nessus GmbH Vienna, Austria
192.81.212.79 443 AS62567 DigitalOcean, LLC North Bergen, NJ, USA
173.212.192.45 443 AS51167 Contabo GmbH Germany
103.16.131.20 8080 AS133159 Mammoth Media Pty Ltd Australia

Check out other interesting topics in our blog.