top of page

Roller Skaters Anonymous ✌️💋

Public·24 Skate-Aholics
Gorislav Sobolev
Gorislav Sobolev

How To Bypass AMSI And Execute ANY Malicious Powershell Code ((FULL))

AMSI has several functions that are executed before any PowerShell code is run (from Powershell v3.0 onwards), so to bypass AMSI completely and execute any PowerShell malware, we need to memory patch them to COMPLETELY DISABLE it.

How to bypass AMSI and execute ANY malicious Powershell code


See that we are able to use the banned word freely. From this point onwards, THERE IS NO AMSI. We are free to load ANY powershell script, malicious or not. By combining this type of attack with your malicious tools you will 100% success against AMSI.

DLL Hijacking can be also used to evade AMSI from userland as it has been described by SensePost. The only requirement is to create a non-legitimate amsi.dll file and plant it on the same folder as PowerShell 64 bit which could be copied to a user writable directory. The proof of concept code has been released by SensePost and is also demonstrated below.

This bypass is now widely detected and blocked as malicious content (as any 5-year-old public exploit should be). However, malware actors still use versions of it that have been obfuscated in an attempt to evade signature-based scans. And the amsiInitFailed bypass still accounts for about 1 percent of detections, based on a 90-day chunk of telemetry data from February to May of 2021.

While manipulation of the properties of the AmsiUtils interface is still a common method of attempting AMSI bypass, over 98 percent of the bypass attempts we see in recent telemetry focus on a different approach: tampering with the code of the AMSI library itsef. already loaded into memory to make scan requests fail. In this attack, the malware locates the library AmsiScanBuffer in memory, and then overwrites the instructions at that address with new ones that redirect to an error message. An implementation of this attack in PowerShell, unobfuscated, would look like this:

The message This script contains malicious content and has been blocked by your antivirus software. is very clear and shows us, that this script is flagged by AMSI. So, if we build our own custom AMSI bypass or just grab one payload from and load the script afterwards, this will not result in any error message:

In this case, we successfully bypassed AMSI for the Powershell script-code itself, but [System.Reflection.Assembly]::Load($byteOutArray) triggers an AMSI-scan for the .NET binary which was base64 decoded and decompressed at runtime. But our bypass did not bypass the .NET AMSI-scan. Therefore the loading was blocked and [WireT4p.Program]::main() was not found. So lets take a look at how we can still execute the script.

I just created a Pull Request for, which automates the process of variable randomization and string obfuscation for the public code snippet. One of the resulting payloads looks like this and is not flagged at the time of writing:

PowerShell commands and scripts can be executed by loading the underlying System.Management.Automation namespace, exposed through the .NET framework and Windows Common Language Interface (CLI). As a result, this eliminates the need to spawn powershell.exe.

These tools rely on LOLBINs (living-off-the-land binaries) like rundll32.exe, installutil.exe, regsvcs.exe, regasm.exe, and regsvr32.exe to invoke the DLL. These LOLBINs are signed by Microsoft and often whitelisted. However, they are often known for proxy execution of malicious code.

To bypass AMSI signatures its possible to use automated obfuscator tools. Alternatively, the code can be modified manually. Using Invoke-Obfuscation from Daniel Bohannon or ISE-Steroids are automated obfuscation approaches for Powershell Scripts. I did not test many comparable open source .NET obfuscator tools so far. But there are a lot of commercial, free and open source .NET obfuscators. For C# binaries i made good experiences with encrypting the script or binary and decrypting it at runtime using an AMSI bypass before.

If you are using one of the automated obfuscator tools you will save time and if you are lucky the binary works so that the obfuscation did not break the functionality. But Invoke-Obfuscation for example is well known for defenders and a Powershell script obfuscated by it gets most likely detected in a monitored environment. By manually changing parts of a script or binary its more likely to not get detected. In addition many obfuscators increase the size of binaries a lot. Invoke-Mimikatz for example has a size of 3MB because of the embedded base64 encoded Mimikatz binary. Obfuscating Invoke-Mimikatz with ISE-Steroids makes it 8MB big because many strings are also base64 encoded here. At least using the automated tools is no guarantee to bypass AMSI.

If AMSI was a good old AV-Product from 5 years ago it would just have a database containing hashes of scripts/executables which are malicious and check everything loaded against this database. But thats not the case. Its not looking for hashes but for strings like Invoke-Mimikatz, AmsiScanBuffer, amsiInitFailed, AmsiUtils and many many more. So if a script/binary contains one of those strings it gets flagged as malicious and is blocked from loading. The in my personal opinion easiest way to break signatures like this is string concatenation. Lets see how this is done:

The strings itself get flagged but a concatenation of string parts is not flagged. Any string can be used by AMSI to trigger a script or binary as malicious. So thats function names, variable names, console output with Write-Host in Powershell or Console.Writeline() in C#. So if you want to find strings triggered by AMSI you have to test every single word or line of a script/code after each other. Executing every single word in Powershell is time consuming and annoying especially for large scripts. Importing Amsi.dll and Calling AmsiScanBuffer for each line of code to see if the result is flagged as malicious or not is much better. RythmStick wrote a really usefull tool called AMSITrigger which is doing exactly that. If we host our PoC as gist and fire AMSITrigger, we get the following result:

Most of the scripts should not trigger AMSI afterwards but some still do because the base64 encoded binary has some string triggers. Lets take another look at the bypass from 2016. We found that the two words amsiInitFailed and AmsiUtils are triggers. And there are regex like triggers for the whole oneliner if the two words are concatenated. In this case we cannot just change the words, because if we do that the bypass is not working anymore. But we have many many other options for that.

Its possible to encode them and that with any encoding you can think of. Base64 - or any other Base, HTML, ASCII or ROT13 encoding. Any number encodings like binary (base 2), hex(base 16), oktal(base 8) - this is an unlimited amount of possibilities. The only thing we obviously have to do is get the correct value for both words back at runtime, so that the bypass stays functional. Base64 encoding/decoding in powershell can be done like this:

If you want to change the signature for C# source code, changing the class name and function names as well as variable names worked many times for me. The triggers for C# AMSI bypass POCs are mainly the same, AmsiScanBuffer, amsi.dll, AmsiUtils and so on. Encoding or encryption with decoding or decryption at runtime works here as well.

We found out that single words as well as strings can be a trigger for AMSI. In many cases the simple replacement of variable/function names or the encoding of values as well as decoding at runtime is sufficient to bypass the trigger. Some triggers are regex like and therefore harder to find/bypass. However, if a fix part of this regex value is changed, AMSI returns a clean result again. I have made the experience that nowadays every AV vendor builds its own signatures which can be used to identify malware with amsi.dll. Therefore the trigger should be searched and modified for each individual vendor.

PowerShell remoting is a way to access remote machines across a network, and run PowerShell commands on them. Remoting builds on earlier implementations of this idea, and in fact, remoting has been part of PowerShell for quite some time. Some cmdlets have long supported a limited form of remoting, in which code can be executed on remote machines.

The easiest and most common way to bypass CLM is PowerShell downgrade. As CLM was introduced with PowerShell v5, switching to previous versions (v2) is an effective way of bypassing it. To prove that, it is enough to run the following code:

Script code signing is a protection technique which is used in a wider approach, where PowerShell scripts should be included in this security control. However there are multiple ways to execute scripts that are not-signed, which bypasses this restriction. Here are some examples:

appName points to a user-defined string in unicode format while amsiContext points to a handle of type HAMSICONTEXT. It returns S_OK if an AMSI context was successfully initialized. The following code is not a full implementation of the function, but should help you understand what happens internally.

Matt Graeber provided a PoC that corrupts the context CLR!g_amsiContext points to, thus causing AmsiScanBuffer to return E_INVALIDARG. As you can see from the CLR implementation, this works because the result of CLR!AmsiScan is never validated for success or failure. The assumption is that it will simply throw an error and terminate the host application upon any attempt to load unwanted software. However, an unmanaged application hosting a .NET assembly is likely to handle any C++ exception. Windows Defender would still log the detection of harmful code, but the unmanaged host application would in some cases continue to run. To disable AMSI via g_amsiContext, one can either search through the heap memory pointed to by PEB.ProcessHeap or through each pointer found in the virtual address space of the .data segment. The following code demonstrates the latter approach. This only works _after_ CLR has called AmsiScan.

Good thing you asked because I got some examples for you.String based detection are very easy to bypass - just refrain from using the banned string literally.Here are some ways to execute banned string without actually using it:By simply splitting the string you could fool AMSI and execute your banned string. This is a very common technique to use in obfuscation in general.You can also encode your string to base64 - in most cases that will be enough to fool AMSI.If all else fails we can encode the string to bytes and even use XOR to make it even harder for AMSI but we will discuss that towards the end of the post.The examples above are mere workarounds though, and to do this with every online public scripts we want to use is simply impractical.So how can we disable AMSI? 350c69d7ab


When in doubt... ROLL IT OUT!!⚡️ Weekly Meet Up - North Co...


bottom of page