Patching AMSI
Last updated
Last updated
AMSI is primarily instrumented and loaded from amsi.dll
; this can be confirmed from the diagram we observed earlier. This dll can be abused and forced to point to a response code we want. The AmsiScanBuffer
function provides us the hooks and functionality we need to access the pointer/buffer for the response code.
AmsiScanBuffer
is vulnerable because amsi.dll
is loaded into the PowerShell process at startup; our session has the same permission level as the utility.
AmsiScanBuffer
will scan a "buffer" of suspected code and report it to amsi.dll
to determine the response. We can control this function and overwrite the buffer with a clean return code. To identify the buffer needed for the return code, we need to do some reverse engineering; luckily, this research and reverse engineering have already been done. We have the exact return code we need to obtain a clean response!
We will break down a code snippet modified by BC-Security and inspired by Tal Liberman; you can find the original code here. RastaMouse also has a similar bypass written in C# that uses the same technique; you can find the code here.
At a high-level AMSI patching can be broken up into four steps,
Obtain handle of amsi.dll
Get process address of AmsiScanBuffer
Modify memory protections of AmsiScanBuffer
Write opcodes to AmsiScanBuffer
We first need to load in any external libraries or API calls we want to utilize; we will load GetProcAddress, GetModuleHandle, and VirtualProtect from kernel32 using p/invoke.
The functions are now defined, but we need to load the API calls using Add-Type
. This cmdlet will load the functions with a proper type and namespace that will allow the functions to be called.
Now that we can call our API functions, we can identify where amsi.dll
is located and how to get to the function. First, we need to identify the process handle of AMSI using GetModuleHandle
. The handle will then be used to identify the process address of AmsiScanBuffer
using GetProcAddress
Next, we need to modify the memory protection of the AmsiScanBuffer
process region. We can specify parameters and the buffer address for VirtualProtect
.
Information on the parameters and their values can be found from the previously mentioned API documentation
We need to specify what we want to overwrite the buffer with; the process to identify this buffer can be found here. Once the buffer is specified, we can use marshal copy to write to the process.
At this stage, we should have an AMSI bypass that works! It should be noted that with most tooling, signatures and detections can and are crafted to detect this script.