Antivirus Evasion for Penetration Testing Engagements

August 21, 2018 | Nathu Nandwani
X

Get the latest security news in your inbox.

Subscribe via Email

No thanks. Close this now.

During a penetration testing engagement, it’s quite common to have antivirus software applications installed in a client’s computer. This makes it quite challenging for the penetration tester to run common tools while giving the clients a perception that their systems are safe, but that’s not always the case. Antivirus software applications do help in protecting systems but there are still cases where these defenses can be bypassed. 

Antivirus evasion is a broad topic and this article only presents very basic methods to bypass detection when the program is resting as a file in a non-volatile storage. Evasion techniques for a run-time state are quite different and challenging because of behavior monitoring done by antivirus programs.

In this article, I will be discussing a few techniques that can be used to bypass antivirus software applications like string manipulation and code substitution. Before anything else however, an understanding of programming is required because I’ll assume that the detected software application has its source code available for modification. I’ll probably work out another separate article for evasion of programs that don’t have their source code available.

There will be two basic steps to do. First will be finding the cause of the detection while the next step goes into how the detection can be bypassed. This is because we won’t be able to fix something if we don’t know what the problem is. 

Looking for the Origin of the Detection

For the demonstration, I will be using an object-oriented language, specifically C#, with the help of Visual Studio 2012. I grabbed a snippet from here specifically the functions “startup” and “USBSpread” while creating a new project to put both of these. This is what it looks like after creating a console project in C#:

creating a console project in C# Penetration Testing
Please note that I have minimized the region of the code in the screenshot above to make it short. I’ll leave the credits where it is due for both those functions. After compiling the project and scanning it in VirusTotal, the result shows two antiviruses detecting it namely ESET and Sophos.  
 

result shows two antiviruses detecting it namely ESET and Sophos


Please forgive me. If any of you are not familiar, VirusTotal actually distributes copies of a scanned file, especially if a few antiviruses detect it. Chances are that if you are reading this right now, the scan results might have changed already when you visit the link. This endangers your tool to become detected very fast and should not be used for scanning when you are developing a penetration testing tool to be used for legal assessments.

Now here comes the fun part. How can we find out what’s causing the detection? Since we have a copy of the source code, what we can do is remove parts of the code line by line and rescan it. To start off, I have commented out the whole “USBSpread” function as seen below:
 

commented out the whole “USBSpread” function Penetration Testing


Compiling this and scanning in VirusTotal will give us a result of: 

 

Compiling this and scanning in VirusTotal Penetration Testing

 
Notice that only ESET is now detecting it and the detection previously shown by Sophos disappeared. Uncomment the function “USBSpread” and then comment out the function “startup” as seen below:
 

Uncomment the function “USBSpread” and then comment out the function “startup” Penetration Testing


The result after rescanning in VirusTotal will be:
 

The result after rescanning in VirusTotal


As you may have guessed, the detection found by ESET now disappeared and Sophos has reappeared. From what we did, we can conclude that having the “startup” function actually triggers detection from ESET while having the “USBSpread” function actually triggers detection from Sophos. Sounds easy to identify the detection right? 

Bypassing the Detection

After being able to identify where the detection came from, we can now try to work out how it can be bypassed. Note that the identification process shown above is in general terms. To successfully bypass the antivirus detecting it, we need to continuously do the previous step while working on a fix line by line. There are a few methods like string manipulation and code substitution that usually work but sometimes also trigger more detection so these methods are quite “experimental”.

String Manipulation

This method simply points to how a normal string can be converted into another form while being evaluated with the same meaning. To understand this better, suppose we have a registry path:

Code:

SOFTWARE\Microsoft\Windows\CurrentVersion\Run


In C#, if we declare this, it should look something like:
 

method simply points to how a normal string can be converted into another form while being evaluated with the same meaning Penetration Testing


There are numerous ways on how we can change the form of that string while maintaining the original meaning when the code executes. Here are some very basic ways to do it:

Base64

Using an encoder tool, enter the string “SOFTWARE\Microsoft\Windows\CurrentVersion\Run” and click “encode”. You should get something like this as a result: 
 

Using an encoder tool, enter the string “SOFTWARE\Microsoft\Windows\CurrentVersion\Run” and click “encode”


Now we copy that string back to the source code with the following evaluator and notice that when the program runs, the string still gets evaluated to the original form:
 

Now we copy that string back to the source code with the following evaluator and notice that when the program runs, the string still gets evaluated to the original form Penetration Testing


ASCII Representation

This is a pretty simple solution and it actually works sometimes too! Converting the string to its numeric ASCII form looks like this:
 

Converting the string to its numeric ASCII form


In the image above, I have converted the “\” character into its numeric ASCII form. If we check out the ASCII table, the character “\” is equivalent to 92 in decimal. Doing some other simple calculations basically differentiate the original code from the current one.

Encryption can also take part in this like having your string encrypted and written down to a binary file. The program can then load it by browsing and decrypting the contents during execution or so. There are lots of possible methods for string manipulation and this is basically where your creativity comes into play.

Code Substitution

This method requires more in-depth knowledge of programming because it requires understanding of what a specific line of code or what a specific function does. For example, suppose we have a code that downloads the contents of a web page:
 

understanding of what a specific line of code or what a specific function does Penetration Testing


With code substitution, an understanding of what the code does is essential because we will need to find a replacement of the code by commands while achieving the same logic and goal at the end. In this case, the goal of the code above tries to get the client IP address in the network where the program is running. This can also be achieved with the use of this code:
 

With code substitution, an understanding of what the code does is essential because we will need to find a replacement of the code by commands while achieving the same logic and goal at the end


Notice that the output is the same, which means the code logic does the same functionality and goal but the way it is done is different. If ever the first code is detected by a few antiviruses, it can be substituted with the next one or vice-versa. There are other more ways to grab the IP address but I’ll leave that part as a research for the readers. 

Going back to the example program, let’s start with Sophos. At this point, the function “startup” is commented out to stop ESET from detecting it while we fix the first one. This antivirus was previously detecting the method “USBSpread” and after some trial and error, the detection was still popping up even after commenting out the whole function contents:
 

Going back to the example program, let’s start with Sophos. At this point, the function “startup” is commented out to stop ESET from detecting it while we fix the first one Penetration Testing

This antivirus was previously detecting the method “USBSpread” and after some trial and error, the detection was still popping up even after commenting out the whole function contents

Result


This simply means that Sophos notices when the function name is “USBSpread” so we change it to “ThisIsATest” and by scanning it again, we get:
 

Sophos gets angry when the function name is “USBSpread” so we change it to “ThisIsATest”  Penetration Testing


By doing the process again, we uncomment out the function contents as seen here:
 

By doing the process again, we uncomment out the function contents as seen here


Once uploaded for scanning in VirusTotal, the result was 0/65!
 

Once uploaded for scanning in VirusTotal, the result was 0/65 Penetration Testing


Sophos in this case was basically finding that function name and flagged it as malicious. To proceed, we now do the same steps for the “startup” function and the specific line that started the detection by ESET was:

 

we now do the same steps for the “startup” function


Since there are parameters in the line and one of the parameters is a string, we will need to separate it to another line so we can confirm what is being detected by ESET. A variable “temp” was assigned to hold the string representation of the registry path for this:
 

A variable “temp” was assigned to hold the string representation of the registry path Penetration Testing


Scanning on the other hand still leaves us with an angry ESET here: 
 

Scanning on the other hand still leaves us with an angry ESET

Result


This confirms that the string is the one being detected by ESET. Below is a short test case that I have tried so far:

Test Cases:

  1. Reversing the string making it “nuR\\noisreVtnerruC\\swodniW\\tfosorciM\\ERAWTFOS” -  Another detection popped up
  2. Moving the variable outside the function making it a global variable:

Code:

static string temp = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run";

- ESET still detecting

  1. Converting each characters to their decimal number equivalent in the ASCII table:

Code:

static string temp = ((char)83).ToString() + ((char)79).ToString() ... ;

- ESET still detecting

  1. Removing the string contents after “SOFTWARE” leaving: string temp = “SOFTWARE”; - ESET still detecting

At this point, ESET was still detecting the program even if the registry path doesn’t really make sense, so this might not be the “real” thing being flagged by ESET or there is another line of code in which if combined with the current string, gets detected. Once this happens, we need to carefully go back each step and see what could probably be the issue. While leaving the code uncommented:
 

Code:

string temp = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run";

Plus having this code commented out:

Code:

destination = System.IO.Path.Combine(destination, "nvdisp.exe");

We actually get 0/65 from VirusTotal!
 

ESET was still detecting the program even if the registry path doesn’t really make sense anymore so this might not be the “real” thing being flagged by ESET or there is another line of code in which if combined with the current string, gets detected

Result


At this point, new test cases were applied because the string “nvdisp.exe” appears to be the real reason behind the trigger:

Test Cases:

Changing the string “nvdisp.exe” to “ThisIsAnotherTest.exe” -  ESET still detecting

  1. Moving variable outside the function making it a global variable: static string dest = “nvdisp.exe” -  ESET still detecting
  2. Encoding the string to base64 deriving to the code: 

Code:

destination = System.IO.Path.Combine(destination, System.Text.Encoding.Default.GetString(Convert.FromBase64String("Im52ZGlzcC5leGUi")));

-  Another detection popped up

Now, there should be a lot of test cases here but to cut the testing short, since some basic string and variable manipulation don’t work, we can try to do some code substitution. Most programmers can understand what the “startup” function does. It simply adds the program to the Windows start up so it can execute once Windows boots. There are numerous ways to add a program in the Windows start up. This could be through copying the executable in “C:\Users\<USER>\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup” or maybe by using a scheduled task. 

The “startup” function in this case was replaced by this simple code:
 

there should be a lot of test cases here but to cut the testing short, since some basic string and variable manipulation don’t work, we can try to do some code substitution


This basically does a similar job by logic but different in terms of instructions. The final program looks similar to this:
 

This basically does a similar job by logic but different in terms of instructions


Once compiled and scanned in VirusTotal, the result gives us a rate of 0/65.
 

While being able to achieve a fully undetected program which helps in penetration testing engagements, it is essential to understand that running this program will probably catch the attention of antiviruses that monitor its actions during run time


While being able to achieve a fully undetected program which helps in penetration testing engagements, it is essential to understand that running this program will probably catch the attention of antiviruses that monitor its actions during run time. This is why antivirus evasion is challenging to do with automated tools because the scope is very wide.

P.S. The code presented above might have different scan results as time goes on because as mentioned, VirusTotal distributes copies of applications being scanned and other antiviruses might decide to put a flag on them.

Nathu Nandwani

About the Author: Nathu Nandwani
Nathu Nandwani is a Computer Engineer from the Philippines holding various industry certifications like MCP, MCTS, OSCP, and CCNA CyberOps. He is currently part of the red team of Cyber Security Philippines CERT.Blog: nandtech.co Twitter: @nandwaninathu
Read more posts from Nathu Nandwani ›

‹ BACK TO ALL BLOGS

Watch a Demo ›
GET PRICE FREE TRIAL