In the case you're using a PowerShell‑based stager,
you may be confronted by AMSI.
AMSI consists of a DLL,
which is automatically loaded inside AMSI‑enabled applications.
PowerShell will therefore load the DLL when the process starts.
And once the PowerShell process starts executing code,
the code gets sent to a series of scanning APIs exposed by the AMSI DLL,
which in turn relays the data,
which needs scanning to the registered AMSI providers.
The AMSI providers will analyze the code and possibly
trigger a response by the antivirus if a signature is
matched on the code being scanned.
Since the AMSI DLL is inside a process, which we control,
we can attempt to tamper with the API.
There are many documented AMSI bypasses, which leverage this technique.
One very effective way of bypassing AMSI is patching the
AmsiScanBuffer API in such a way that it will simply return
immediately after being called, effectively blinding the AMSI provider,
which was registered by the antivirus.
If you recall,
a similar attack can be performed against API
monitoring components to unhook APIs,
effectively blinding the antivirus software.
There are other ways of evading AMSI‑based detection.
You can, for example,
attempt to apply string permutations and code modifications to your
PowerShell stage's code in an attempt to break signatures.
Alternatively, a more generic approach, which consists of disabling AMSI,
can also be leveraged.
Let's now take a look at how we could write a custom stager
similar to the one we wrote in C++ previously,
but this time using PowerShell.
Let's take a look at this custom implementation of a
PowerShell‑based Meterpreter stager, which I've already written.
As you can see, we start off by declaring several variables,
which will hold the IP address and TCP port of our Metasploit handler,
as well as the URI and the user agent string,
which we want to use.
PowerShell cannot directly call Win32 APIs.
Therefore,
we cannot call VirtualAlloc to allocate memory as we did
previously in our stager written in C++.
We can, however,
leverage C# from inside our PowerShell script to create custom types using
the Add‑Type cmdlet so that we can then make use of this custom type to
call the VirtualAlloc and CreateThread APIs.
We can then make use of the Invoke‑WebRequest cmdlet to
download the payload from our Metasploit handler,
as we did previously using WinINet in our C++ stager.
We can then allocate a read/write execute memory buffer using
VirtualAlloc and copy the payload into it.
Finally, we can leverage the CreateThread API to start a thread,
which will execute our payload and wait until the thread
terminates using the WaitForSingleObject API.
If we go ahead and run this code,
we get the following message stating that the code was blocked by the antivirus.
This is very interesting since we wrote this stager from scratch.
In an attempt to identify which part of the code triggered the detection,
we can go ahead and run this code one line at a time in an
attempt to pinpoint the line of code, which is causing the detection.
Interestingly, it appears that when we run the code one line at a time,
we do not trigger AMSI.
And if we check our Metasploit handler,
you will notice that we have a fully functional Meterpreter shell.
You may recall that during the antivirus and EDR modules,
we did indeed notice that every time a command was executed,
it was sent to the AmsiScanBuffer API.
We can therefore conclude that the detection is
caused by a combination of artifacts,
which are located in different parts of the script.
I have gone ahead and made some adjustments to the stager.
Instead of running the stager in one go,
I have decided to download the script and invoke it
one block of script at a time.
This will effectively avoid sending the entire script to the
AmsiSanBuffer API and hopefully break the detection.
If we take a look at the two files, which are downloadable executes,
we can see that the stager‑1.txt file contains the first half of the script,
and the stager‑2.txt file contains the second half.
I can then start up a simple web server so that
these two files can be downloaded.
If we now go back to our victim machine,
we can see that the antivirus is indeed enabled.
And if we go ahead and run our downloader, it doesn't trigger the antivirus.
If we go back to our Kali machine,
we will indeed see that a Meterpreter session has been opened.
Let's now take a look at another technique,
which we can use to bypass AMSI,
which consists of disabling AMSI by modifying the amsiInitFailed field,
which is set when the AMSI DLL is initialized.
By setting the value of this field to true,
we effectively disable AMSI inside the current PowerShell process.
This can be achieved using the following command.
When we run this command, it is blocked by AMSI.
If we go ahead and simply type AmsiUtills instead of the entire command,
it is also blocked.
At this point,
it is quite clear that we are dealing with a signature‑based detection.
If we break up the command and use string concatenations,
you will notice that we no longer trigger a detection.
And if we now type the AmsiUtil string, which was blocked previously,
you will notice that it is no longer flagged by the antivirus.
If we go back to the downloader we used previously,
we can reuse this code and simply modify the contents of the
stager‑1.txt file and replace it with the command,
which we used to disable AMSI.
In the stager‑2.txt file, we can now place our entire stager,
which won't be detected since by the time it runs,
AMSI will have been disabled by the first part of the script.
We can go ahead and start the web server so that our downloader
can retrieve the files containing the code,
and we can then run our downloader.
As you can see, the antivirus did not prevent it from executing.
And if we check our Kali machine,
you will notice that both the files have been downloaded successfully.
If we check our Metasploit handler,
you will also notice that we have a fully functional Meterpreter session.
If you want to learn more about AMSI bypasses,
I recommend the following document, which is freely available on the internet.
It demonstrates many more bypasses,
which involves using the registry to disable AMSI or
patching the AmsiScanBuffer API, as discussed previously.