Introduction
Windows developed the Antimalware
Scan Interface (AMSI) standard that allows a developer to integrate malware
defense in his application. AMSI allows an application to interact with any
anti-virus installed on the system and prevent dynamic, script-based malwares
from executing. We’ll learn more about AMSI, implementation in code and some of
the well-known bypasses in this article.
Table of content
·
Background
·
Malware naming
convention
·
How AMSI works
·
AMSI Bypass
methods:
·
Method 1:
Powershell downgrade
·
Method 2:
Obfuscation
·
Method 3: Forcing
an error
·
Method 4: Memory
Hijacking
·
Method 5: Memory
Hijacking (obfuscated opcodes)
·
Method 6: AMSI
bypass by reflection
·
Method 7:
Nishang All in One script
·
Conclusion
Background
In one sentence, it is a
script-based malware scanning API provided by Microsoft that can be integrate
in any application to scan and detect integrity of user input in order to
safeguard the application and thus, consumers against malwares. For example, a
messenger app may scan messages with AMSI for malware before sending it forward
to the receiver.
AMSI is vendor independent and
provides open Win32 API and COM interfaces for the developer to use. Since,
Microsoft manages AMSI itself, the latest malware signatures are auto updated
in it. Hence, a developer can integrate AMSI quite easily to protect its
consumers from dynamic, script-based malwares. You can read the developer guide
here.
AMSI works on signature-based
detection. This means that for every particular malicious keyword, URL,
function or procedure, AMSI has a related signature in its database. So, if an
attacker uses that same keyword in his code again, AMSI blocks the execution
then and there.
Malware naming convention
Before reading more about the
working of AMSI, let’s understand how malwares are named. Often in analysis,
Windows detects malware but analysts are unable to identify exact details and behaviour
of the malware. Computer Antivirus Research Organisation (CARO) has given a
standard naming convention for malwares. For example, a shortcut based caphaw
backdoor is named like:
Read more about malware here.
How AMSI works
As a developer you can use AMSI
to provide malware defense using AMSI. Let’s say you create an application that
inputs a script and executes it using a scripting engine like Powershell. At
the point when input is being taken, AMSI can be called in to check for malware
first. Windows provides COM and Win32 APIs to call AMSI. The workflow of AMSI
is as follows:
Explanation: As you can see, the AMSI API is open, so any AV can
read the data from its functions. Here, a windows script is being run. When it
is passed through AMSI, amsi.dll is injected in the same virtual memory as that
of our program. This amsi.dll has various functions that can evaluate code.
These functions can be found here. However, the actual scanning task is conducted by
these two functions:
·
AmsiScanString()
·
AmsiScanBuffer()
These functions evaluate the
code. If the code is clean, the results are finally passed to the AV provider
class and from there to the AV service using RPC call. If the code is
suspicious, it is blocked by the AMSI itself.
AMSI Bypass methods
Now that we have discussed basics
about AMSI, we will be discussing about some of the very well-known techniques
to bypass AMSI. Bypassing AMSI is often necessary for red-teamers in order to
execute arbitrary code for lateral movement/privilege escalation.
To cover all of the bypass
methods extend beyond the scope of this article as there are new methods coming
in each day. The prominent ones are discussed here and tested on Windows 10
version 1809. It is to be noted that latest versions of Windows (beyond 1903) block
almost all of the methods available on the internet as signatures keep getting
updated.
NOTE: AMSI blocks certain keywords like “invoke-mimikatz” or
“amsiutils” since they are widely known to be used for exploitation and so, as
a proof of concept, we will only be running these commands post bypass. Actual
payloads won’t be bypassed here.
Microsoft has integrated AMSI in
powershell terminal (powershell.exe application) which takes in input and
parses it through Powershell engine. If we open process hacker and search for
amsi.dll we will see that amsi is running in the powershell terminal and any
input will first be scanned by it.
Method 1: Powershell downgrade
If you’re running a powershell
based payload and AMSI blocks it, you can downgrade your powershell version to
2.0 as AMSI is only supported beyond v2.0. First, you can see that our keywords
are being blocked by amsi.
Let’s check the current version
of PS and then downgrade to version 2 and run these blocked commands again.
$PSVersionTable
“amsiutils”
powershell -version 2
“amsiutils”
But as you would imagine, the
biggest drawback here is that many modern functions or scripts won’t run on
Powershell 2.0. So, let’s see some other methods.
Method 2: Obfuscation
Obfuscation refers to the trick
of making your code complex and un-readable. AMSI detects signatures on the
basis of certain keywords, and so, obfuscating these keywords work. For
example, let’s obfuscate invoke-mimikatz command
Invoke-Mimikatz
“Inv”+”o+”ke”+”-Mimi”+”katz”
As you can see, simply by
breaking a string and concatenating them using + operator we were able to
bypass AMSI.
However, this technique has its
own demerits. A payload may trigger AMSI one or more times. It is virtually
very time consuming and noise creating to keep obfuscating keyword by keyword
after each run of a payload. Hence, we follow this manual obfuscation guide by @ShitSecure.
RhytmStick developed this tool “AmsiTrigger”
which can scan a script/payload against AMSI and tell us which lines exactly
would trigger AMSI and then we can obfuscate them! You can download the tool here.
Now, we have created a script
called demo.ps1 with the following commands
I want to check this against AMSI
using AmsiTrigger. Which can be done like:
.\demo.ps1
.\AmsiTrigger.ps1 -i
.\demo.ps1
Now, the tool has told me the
lines where AMSI blocks execution. We can go ahead and obfuscate them using
string concatenation method like:
“am”+”si”+”ut”+”ils”
“in”+”vok”+”e”+”-“+”mi”+”mik”+”atz”
Now, they can be run and
successfully bypass AMSI!
You can also try https://amsi.fail to obfuscate your code.
Method 3: Forcing an error
Matt Graeber talked about a
method to bypass AMSI in his tweet here. A function called amsiInitFailed() exists which
throws 0 if AMSI scan is initiated in scenarios shown above. This bypass is
basically assigning amsiInitFailed a boolean True value so that AMSI
initialization fails - no scan will be done at all for the current process! The
code is:
$mem = [System.Runtime.InteropServices.Marshal]::AllocHGlobal(9076)
[Ref].Assembly.GetType("System.Management.Automation.AmsiUtils").GetField("amsiSession","NonPublic,Static").SetValue($null,
$null);[Ref].Assembly.GetType("System.Management.Automation.AmsiUtils").GetField("amsiContext","NonPublic,Static").SetValue($null,
[IntPtr]$mem)
Ever since that time, many people
have posted different variants of the same method. In some methods bytecode is
used, in others, functions are replaced or strings are replaced but the logic
prevails the same.
Method 4: Memory Hijacking
Daniel Duggan posted about memory
hijacking techniques that can bypass AMSI in his blog here. The logic is to hook (read about hooking here) the function AmsiScanBuffer() so that it always
returns the handle AMSI_RESULT_CLEAN indicating that AMSI has found no
malware. The API responses could be monitored using API monitor tool by
Rohitab.
First, let’s download the
Invoke-Mimikatz script and see that AMSI is working properly.
Now, the actual code is provided here. However, to reduce your hassle of compiling the code
as DLL, you can check my fork here. After it is downloaded, make sure you change the
main package’s name from “AmsiScanBufferBypass” to “Project” or whatever you
like as AMSI blocks the string “AmsiScanBufferBypass” too!
After downloading, you go to
release folder and see the presence of a DLL called ASBBypass.dll
Please note that since we now
have a DLL, it can be integrated with our EXE payload as well and will bypass
AMSI on the go!
However, here, we will be using in-line
C# code to activate the patch using powershell terminal only! This can be done
like:
[System.Reflection.Assembly]::LoadFile("C:\users\hex\Project\ASBBypass.dll")
[Amsi]::Bypass()
As you can see, amsi has now been
bypassed!
Method 5: Memory Hijacking (obfuscated opcodes)
After the Rasta Mouse (Daniel
Duggan) technique started getting detected, people made various changes in the
code to make it FUD again. Fatrodzianko posted about one such technique in his
blog here. He obfuscated the same code using opcodes and put
the script on gist here.
To run the script, just download
it, rename it (to avoid keyword detection by AMSI) and run like:
“invoke-mimikatz”
.\my-am-bypass.ps1
“invoke-mimikatz”
As you can see, we have
successfully bypassed AMSI now.
Method 6: AMSI bypass by reflection
According to Microsoft, “Reflection
provides objects (of type Type) that describe assemblies, modules, and types.
You can use reflection to dynamically create an instance of a type, bind the
type to an existing object, or get the type from an existing object and invoke
its methods or access its fields and properties. If you are using attributes in
your code, reflection enables you to access them.” Read more here.
Paul Laine posted the original memory
hijacking method on contextis.com blog here. Shantanu Khandelwal converted the same code to
become full in-memory patch by using Matt Graeber’s reflection technique
mentioned here. Shantanu made the code stealthier as no on-disk
artefact was left now. See his site here.
We won’t demonstrate the original
patch but the reflection update downloaded from here. Make sure you download and rename the script and
avoid keywords like “amsibypass” etc since they get blocked. I have renamed it
to “am-bp-reflection.ps1”
“invoke-mimikatz”
.\am-bp-reflection.ps1
“invoke-mimikatz”
Method 7: Nishang All in One script
Nikhil Mittal added an AMSI
bypass script in his well known tool “Nishang,” which can be found here. The script combines 6 different methods to bypass
AMSI under one run. These are:
·
unload - Method by
Matt Graeber. Unloads AMSI from current PowerShell session.
·
unload2 - Another
method by Matt Graeber. Unloads AMSI from current PowerShell session.
·
unloadsilent -
Another method by Matt Graeber. Unloads AMSI and avoids WMF5 autologging.
·
unloadobfuscated -
'unload' method above obfuscated with Daneil Bohannon's Invoke-Obfuscation -
which avoids WMF5 autologging.
·
dllhijack - Method by
Cornelis de Plaa. The amsi.dll used in the code is from p0wnedshell
(https://github.com/Cn33liz/p0wnedShell)
·
psv2 - If .net
2.0.50727 is available on Windows 10. PowerShell v2 is launched which doesn't
support AMSI.
We just have to download the
script and run and the tool automatically will bypass AMSI using a valid
method. For example, here WMF5 autologging bypass has worked. This method
unloads AMSI from the current terminal and bypasses it.
Download the script from here and rename it to “nishang.ps1” and run it like so:
Import-Module
.\nishang.ps1
Invoke-AmsiBypass -Verbose
“invoke-mimikatz”
Conclusion
In this article, we talked about
the basics of AMSI, how to use them in a program, workflow and 7 ways to bypass
them. It is to be noted that there are more ways than shown here but the aim of
the article was to talk about most-widely known 7 methods to bypass AMSI and
how this AMSI evasion game has developed over time and how complexity has only
increased. Hope you liked the article. Thanks for reading.
0 comments:
Post a Comment