Wednesday, September 21, 2016

AMSI: How Windows 10 Plans to Stop Script-Based Attacks and How Well It Does It

Update (23-Dec-2016) - I have implemented the publicly known AMSI bypasses described in this post in a PowerShell script Invoke-AmsiBypass. Check it out here https://github.com/samratashok/nishang/blob/master/Bypass/Invoke-AmsiBypass.ps1


Last month I gave a talk about Microsoft's AntiMalware Scan Interface (AMSI) at Black Hat USA. The talk and this post details my experiments with AMSI.

I first encountered AMSI while using some of the PowerShell scripts from Nishang on a Windows 10 box in my lab. I noticed that some of the scripts didn't work even if loaded from memory which was very interesting. Being a long time user of PowerShell in my pen tests, I was interested in the technique being used to detect scripts from Nishang in memory. After a quick search, I stumbled upon this excellent TechNet article which introduces AMSI. From that article, this article and documentation of AMSI, following detection abilities and features are claimed with AMSI:
  • Memory and Stream scanning. This means that the input method - disk, memory/stream or manual input makes no difference on the detection capabilities.
  • Scripts are submitted to the AntiVirus/AntiMalware product by AMSI when the de-obfuscated plain code is presented to the script host. This means that obfuscation should help only to a limited extent.
  • Since the scripts are "picked up" when submitted to the scripting host, code which doesn't utilize powershell.exe but uses System.Automation DLL will also be analyzed.

And when I tested AMSI with different tools and techniques, detection rate was indeed better than what I expected.

Major techniques which were tested and detected by AMSI:


Executing scripts from memory - Using the -EncodedCommand parameter of powershell.exe and the famous one liner download-execute.

Execution of everyone's favorite, Invoke-Mimikatz:
When AMSI was disabled:


When AMSI was enabled (default on Windows 10):


Executing scripts without using powershell.exe - Using separate runspace (p0wnedshell, psattack) and using System.Automation.Dll (nps, Powerpick)

Unusual Storage - Scripts loaded from WMI namespaces, Registry Keys and Event Logs.

Application whitelisting bypass methods - InstallUtil, regsrv32 and rundll32

All of the techniques were detected by AMSI! While the detection was no surprise given that AMSI steps in at the script host level, still, this looked intimidating! More so because Windows Defender supports AMSI by default on Windows 10.  I quickly started looking for different ways to avoid or bypass AMSI.  Turned out that there are bunch of techniques that can be used to bypass or avoid AMSI.

Bypass or Avoid AMSI


Force use PowerShell v2: PowerShell v2 doesn't support AMSI at the time of writing. If .Net 3.0 is available on a target Windows 10 machine - which is not default - PowerShell v2 can be started  with the -Version option.
 

Obfuscation
Another interesting way is to change the signature of the PowerShell script so that the AntiVirus to which AMSI submits our script doesn't detect it as malicious. To play with the signatures Windows Defender have for scripts, lets play with one of the scripts from Nishang, Gupt-Backdoor, which gets detected as malicious by AMSI.

Lets remove the help section, all the functionality and replace the function and variable names with random strings.

 And the result is:

Apparently, among other things, Windows Defender looks for specific function and variable names. Actually, this should not be a surprise as I know of few antiviruses which use Twitter handles of PowerShell hackers as a signature.

Manual obfuscation of a huge script such as Invoke-Mimikatz could not be done manually. Fortunately, the obfuscate functionality of the awesome ISE-Steroids module is very effective! Lets obfuscate Invoke-Mimikatz from Nishang.
Now, when the obfuscated version is loaded, there is no detection.
Bingo!

Make sure that the function calls are made from the script before obfuscation. 
This is very interesting! As per the articles mentioned at beginning of this post, AMSI has additional calls if any sort of obfuscation, even base64, is used in the script.This obfuscation getting past AMSI has been a sort of mystery for me.This probably has more to do with the signatures available with Windows Defender than with AMSI. I welcome comments on this specific thing as I am unable to understand why Invoke-Mimikatz was not detected if the plain de-obfuscated code was submitted to AMSI.

Unload AMSI

Set-MpPreference
This built-in cmdlet can be used to make AMSI ineffective by disabling protection offered by Windows Defender.

Below command can be used to disable real time monitoring for Windows Defender

There are some 'gotchas' with the technique though:
  • A notification is shown to the user
  • Needs to be run from an elevated shell
  • Event ID 5001 (Microsoft-Windows-Windows Defender/Operational) - Windows Defender Real-Time Protection was disabled.
Another command can be used, this is useful for avoiding detection of in-memory download execute one liner.
This command doesn't show any notification to the user but:
  • An elevated shell is still required and;
  • Event ID 5004 (Microsoft-Windows-Windows Defender/Operational)  - Windows Defender Real-Time Protection feature (IE Downloads and Outlook Express attachments) configuration has changed.
DLL Hijacking - Method used in p0wnedshell
Cornelis de Plaa (@Cneelis) discovered this brilliant method and implemented it in his awesome p0wnedshell. There is a detailed blog post about the method. It is a DLL hijacking method where amsi.dll is dropped in the current working directory while loading the p0wnedshell runspace. The dll is loaded by the runspace and exits immediately to unload AMSI. 

So p0wnedshell successfully bypasses AMSI. But there is another interesting part of the security mechanism, PowerShellv5 supports automatic script block logging. The scripts loaded by p0wnedshell generate Event ID 4104 (Microsoft-Windows-PowerShell/Operational) – Suspicious script block logging (due to successful loading of scripts in memory).

Reflection - Matt Graeber's method
Matt Graeber (@mattifestation) tweeted an awesome one line AMSI bypass. Like many other things by Matt, this is my favorite. It doesn't need elevated shell and there is no notification to the user but the automatic script block logging, like in the case of p0wnedshell, generates Event ID 4104. Turns out that it is the script block logging which is the real headache. There are a bunch of script logging bypasses I am aware of, discovered by other PowerShell hackers, but not public yet.


Anyway, I like this method because it can be used with existing PowerShell script execution methods.
For example, lets bypass AMSI using a client side attack and get a meterpreter on the target Windows 10 box. Lets generate a weaponized MS Word document using Nishang's Out-Word and instruct it to download and execute a PowerShell meterpreter.
As soon as a target opens the Word file and click on "Enable Content", this happens:
Sweet! We bypassed AMSI in a client side attack!

AMSI is certainly not the security silver bullet which many organizations (wrongly) keep looking for but it is indeed an improvement in Windows security.

My slides for the Black Hat preso are here:
http://www.slideshare.net/nikhil_mittal/amsi-how-windows-10-plans-to-stop-scriptbased-attacks-and-how-well-it-does-it


Hope this was useful. Please leave feedback and comments!