Meterpreter stage AV/IDS evasion with powershell

This article proposes a basic technique (I mean very basic, but still efficient) for the meterpreter stage antivirus and IDS/IPS evasion, in an up-to-standards secure corporate environment, which poses many challenges, using some Powershell Fu.

Reminder on the Meterpreter

The Meterpreter: a stager, and and stage.

The Meterpreter payload is definitely one of the best and probably most used Metasploit framework payload. It comes in the form of a staged payload, which means a small size stager payload is first executed on the victim’s system (through the use of an exploit or through a rogue file sent via e-mail or drive-by download), this stager then establishes a communication channel between the attacker and the victim, in various possible ways, and then downloads a stage payload (basically a DLL) which is loaded into memory and executed via a reflective DLL injection technique invented by Stephen Fewer.

The problem

A lot of articles can be found here and there about evading antivirus detection for the stager payload, through the use of encoding techniques, encryption techniques, or by compiling one’s own version of an executable containing the Meterpreter shellcode, or by using various scripting languages to load and run the shellcode (I’ve seen examples with python, VBA macros, and well known examples with Powershell, etc.).

But I found much less articles focusing on the fact that the stage payload is also very well known by antiviruses, or can be detected/blocked by properly configured web proxies (we’ll see how) and by IDS/IPS.

From the victim’s system standpoint, everything happens in memory: the stage DLL doesn’t touch the disk, so the victim’s antivirus cannot detect it. But in a secure up-to-standards corporate environment there are many other challenges to take into account including, but not limited to, an antivirus on the web proxy. As a result, some evasion techniques have to be used for this stage payload to make its way down to the victim’s system.

At the time of writing, there’s only one meterpreter payload family (namely the meterpreter rc4 payloads) that can perform end-to-end encryption of the stage DLL hence providing some kind of evasion capability, but it doesn’t pass the bar in regards of the other challenges I’ll explain further down.

Corporate environment challenges

Let me introduce here a typical corporate environment an attacker would be facing, and the challenges that come along. In terms of architecture, it would be something like this:

What we have here is:

  1. An internet access web proxy configured this way:
    1. Transparent (for the user, ie: SSO) proxy authentication requiring proper ActiveDirectory credentials, using NTLM method
    2. SSL interception is ON, so forget about hiding stuff within an SSL/TLS channel
    3. Antivirus enabled at the proxy level analyzing part or all of the incoming traffic (SSL or not, remember there’s SSL interception ON)
    4. Capable of analyzing HTTP response body, and blocking a well-known IoC of the Meterpreter stage DLL
  2. A frontal IDS/IPS with some known signature on the Meterperter stage


  1. The stager has to be able to detect and use the victim’s system default proxy
  2. The stager has to be able to play the victim’s credentials to authenticate on the proxy
  3. The stage has to be somehow obfuscated in order to evade both the proxy AV, the IDS, and the proxy detection itself

So far, in terms of Meterpreter payloads available:

  • the meterpreter/reverse_winhttp payload matches point 1 and 2, but does not match point 3 (EDIT 2016-04-25: this statement is not true as the stage_encoder option is available and provides a way of somehow obfuscating the stage. See comments below for details and why the technique presented here might still be of interest),
  • the meterpreter/reverse_tcp_rc4 payload matches point 3 (by rc4 encrypting the stage with a user defined password derived key) but does not match point 1 and 2.

A word on proxy detection

Some proxies have the capability of analyzing the content of the HTTP response body itself. Considering SSL interception is ON, using HTTPS makes no difference on that matter and still leaves the proxy with the ability to perform some inspection on almost any part of the HTTP traffic, be it the request or the response. As an example of such proxies, I can name my favorite, and well known buddy (see my other articles): the BlueCoat ProxySG appliance.

A Meterpreter stage DLL IoC:

The Meterpreter stage is a DLL (actually 2 DLL’s, for both x86 and x64 architectures) which PE DOS header is being modified on the fly before being sent on the wire back to the victim’s system. A specific ASM stub is added, required by the reflective DLL injection technique. Looking at the /usr/share/metasploit-framework/lib/msf/core/payload/windows/meterpreter_loader.rb file, we can see how the PE DOS header is modified, matching the description given by Stephen Fewer for his reflective DLL injection technique :

def asm_invoke_metsrv(opts={})
    asm = %Q^
        ; prologue
          dec ebp               ; 'M'
          pop edx               ; 'Z'
          call $+5              ; call next instruction
          pop ebx               ; get the current location (+7 bytes)
          push edx              ; restore edx
          inc ebp               ; restore ebp
          push ebp              ; save ebp for later
          mov ebp, esp          ; set up a new stack frame
        ; Invoke ReflectiveLoader()
          ; add the offset to ReflectiveLoader() (0x????????)
          add ebx, #{"0x%.8x" % (opts[:rdi_offset] - 7)}
          call ebx              ; invoke ReflectiveLoader()
        ; Invoke DllMain(hInstance, DLL_METASPLOIT_ATTACH, config_ptr)
          ; offset from ReflectiveLoader() to the end of the DLL
          add ebx, #{"0x%.8x" % (opts[:length] - opts[:rdi_offset])}

    unless opts[:stageless]
      asm << %Q^
          mov [ebx], edi        ; write the current socket to the config

    asm << %Q^
          push ebx              ; push the pointer to the configuration start
          push 4                ; indicate that we have attached
          push eax              ; push some arbitrary value for hInstance
          call eax              ; call DllMain(hInstance, DLL_METASPLOIT_ATTACH, config_ptr)
    # patch the bootstrap code into the dll's DOS header...
    dll[ 0, bootstrap.length ] = bootstrap

The ASM code is slightly different for the x64 DLL version, but still the same important point remains: we do have a known static stub of code at a fixed position at the beginning of the stage transmitted over the wire. This is a perfect IoC and a perfect signature for use at the proxy inspection level.

The above stub of code translate into the following sequence of hex values:

In a BlueCoat proxySG configuration, this can be translated into the following condition definition:

define condition Meterpreter_ReflectiveDLL
; x86 payload"^\x4d\x5a\xe8\x00\x00\x00\x00\x5b\x52\x45\x55"

This condition can then be used in a proxy access rule to block the corresponding traffic. It works like a charm: tested and approved.

The evasion technique

I guess the most sophisticated and smartest idea would be to write a new metasploit payload that would combine both the reverse_winhttp and reverse_tcp_rc4 payloads capabilities into one new payload that would fit all our needs (ie: full transparent proxy support and stage encryption or obfuscation of some sort) but this is way beyond my skills. So I decided to follow another path.

First, the evasion technique is so dumb that I’m almost ashamed to present it here: all I’m doing is adding an arbitrary number of random bytes at the beginning of the stage being sent back to the stager. I opted for a 64KB (precisely 65536 bytes) stub, as I think that would be enough to fool antivirus analysis.

This is done by slightly modifying the meterpreter_loader.rb file (or its x64 counterpart). At the begining of the file, add the ‘securerandom’ native Ruby library:

require 'msf/core'
require 'msf/core/reflective_dll_loader'
require 'securerandom'

Then, at the end of the file, replace one line by two new lines:

# patch the bootstrap code into the dll's DOS header...
dll[ 0, bootstrap.length ] = bootstrap

# Comment the above line

# Replace by:
randomData = SecureRandom.random_bytes(65536)
randomData + dll

On the victim’s side, I opted for a Powershell wrapper around a standard reverse_winhttp payload. Why Powershell ? Well, I don’t want to restate here all the pros and cons of Powershell in the post-exploitation arsenal, there’s plenty of great articles about it (especially around the Empire framework). One other reason is I wanted to learn Powershell (this is my first script) and I like the idea that it can be minified and turned into a one liner command, which is neat.

What the script does is pretty much as simple as the idea is dumb:

  1. It creates two threads:
    1. Thread 1: starts a local HTTP proxy, listening on the loopback interface on port 8080
    2. Thread 2: loads and executes, within the Powershell process memory, a generic meterpreter reverse_winhttp shellcode configured to connect to the local proxy started in thread 1 (that means the shellcode was generated using LHOST= and LPORT=8080).
  2. The local proxy (thread 1) is configured to connect to the actual C2 server, using the victim’s default proxy (corporate proxy) and if ever required, it takes care of the NTLM authentication using the default network credentials of the currently logged in user.
  3. When the meterpreter stager starts (thread 2), the first thing it does is to request the Meterpreter stage DLL
  4. This request goes through the local proxy (thread 1) which will take care of relaying the request to the C2 server, through the corporate proxy, and will also take care of removing the 64KB of random data (by consuming it) before delivering the rest of the stage to the stager
  5. From there, the whole communication between the meterpreter and the C2 goes through the local proxy unmodified, except proxy authentication which is added on the fly when required.

« Okay, enough gibberish, gimme the script !« 

The script is available here: proxyMeterpreterHideout.ps1. Be sure to :

  1. Set your own C2 server (in the $destUrl variable)
  2. Use the appropriate version of Powershell architecture version (32 or 64 bits). In the proposed script, I’ve embedded a x86 meterpreter payload that will be loaded in the Powershell process memory, so be sure to call this script using the WOW64 version of Powershell on the victim’s machine: C:\Windows\syswow64\WindowsPowerShell\v1.0\powershell.exe .\proxyMeterpreterHideout.ps1
    If you want to use the x64 version of meterpreter, you’ll have to regenerate the proper code for the thread 2 ($MeterpreterStager script object). This can be easily achieved using the metasploit framework and msfvenom command line.

This technique has been tested successfully in a restricted corporate environment equivalent to the one described above. Stay safe and be aware of this kind of evasion technique when configuring your proxy or your IDS/IPS.

If you liked this article or the provided script, I’ll be happy if you tip me with bitcoins !


6 réflexions sur “Meterpreter stage AV/IDS evasion with powershell

  1. l0ad 28 mai 2017 / 19 h 23 min

    hey, when I add this
    randomData = SecureRandom.random_bytes(65536)
    randomData + dll

    powershell crash on handler connection


  2. agix 18 avril 2016 / 8 h 46 min

    What about stage_encoder feature in metasploit that allow usage of encoder around the stager ?


    • arno0x0x 18 avril 2016 / 8 h 55 min

      I don’t know, it might very well work evading IDS/IPs and network based detection systems. I don’t know however how efficient it would against an inline antivirus, at a proxy level for instance. I shall give it a try soon and perform a few checks !


      • arno0x0x 25 avril 2016 / 13 h 21 min

        As suggested, I gave a try to the StageEncoding option of the meterpreter/reverse_winhttp payload and the resulting stage DLL indeed has 0/54 VT detection ratio which is perfect. So the stage_encoder feature works well, though it would still need to be formally tested against a properly configured IDS/IPS to see whether or not it triggers any detection pattern (not sure how…).

        Eventually, the technique described in this post is somehow different and complementary since it doesn’t use an encoding or encryption stub, but rather « random/non executable » data. It turns out to be yet another way to evade some AV and IDS/IPS detection 🙂


Votre commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:


Vous commentez à l’aide de votre compte Déconnexion /  Changer )

Image Twitter

Vous commentez à l’aide de votre compte Twitter. Déconnexion /  Changer )

Photo Facebook

Vous commentez à l’aide de votre compte Facebook. Déconnexion /  Changer )

Connexion à %s