WEBVTT

00:00:00.340 --> 00:00:03.130
In the case you're using a PowerShell‑based stager,

00:00:03.380 --> 00:00:06.660
you may be confronted by AMSI.

00:00:06.660 --> 00:00:08.020
AMSI consists of a DLL,

00:00:08.029 --> 00:00:12.120
which is automatically loaded inside AMSI‑enabled applications.

00:00:12.390 --> 00:00:16.250
PowerShell will therefore load the DLL when the process starts.

00:00:16.250 --> 00:00:19.660
And once the PowerShell process starts executing code,

00:00:19.840 --> 00:00:25.350
the code gets sent to a series of scanning APIs exposed by the AMSI DLL,

00:00:25.360 --> 00:00:27.580
which in turn relays the data,

00:00:27.590 --> 00:00:31.220
which needs scanning to the registered AMSI providers.

00:00:31.290 --> 00:00:34.740
The AMSI providers will analyze the code and possibly

00:00:34.740 --> 00:00:37.840
trigger a response by the antivirus if a signature is

00:00:37.840 --> 00:00:39.690
matched on the code being scanned.

00:00:39.690 --> 00:00:44.050
Since the AMSI DLL is inside a process, which we control,

00:00:44.140 --> 00:00:46.790
we can attempt to tamper with the API.

00:00:47.010 --> 00:00:51.640
There are many documented AMSI bypasses, which leverage this technique.

00:00:51.710 --> 00:00:55.430
One very effective way of bypassing AMSI is patching the

00:00:55.440 --> 00:01:00.650
AmsiScanBuffer API in such a way that it will simply return

00:01:00.660 --> 00:01:05.340
immediately after being called, effectively blinding the AMSI provider,

00:01:05.349 --> 00:01:07.480
which was registered by the antivirus.

00:01:07.740 --> 00:01:08.700
If you recall,

00:01:08.710 --> 00:01:11.570
a similar attack can be performed against API

00:01:11.570 --> 00:01:14.320
monitoring components to unhook APIs,

00:01:14.330 --> 00:01:16.860
effectively blinding the antivirus software.

00:01:17.240 --> 00:01:20.610
There are other ways of evading AMSI‑based detection.

00:01:20.760 --> 00:01:21.910
You can, for example,

00:01:21.910 --> 00:01:26.240
attempt to apply string permutations and code modifications to your

00:01:26.240 --> 00:01:30.230
PowerShell stage's code in an attempt to break signatures.

00:01:30.440 --> 00:01:35.070
Alternatively, a more generic approach, which consists of disabling AMSI,

00:01:35.070 --> 00:01:36.350
can also be leveraged.

00:01:37.040 --> 00:01:40.450
Let's now take a look at how we could write a custom stager

00:01:40.460 --> 00:01:43.440
similar to the one we wrote in C++ previously,

00:01:43.450 --> 00:01:45.210
but this time using PowerShell.

00:01:45.210 --> 00:01:48.470
Let's take a look at this custom implementation of a

00:01:48.470 --> 00:01:52.000
PowerShell‑based Meterpreter stager, which I've already written.

00:01:52.000 --> 00:01:56.060
As you can see, we start off by declaring several variables,

00:01:56.240 --> 00:02:00.320
which will hold the IP address and TCP port of our Metasploit handler,

00:02:00.320 --> 00:02:03.810
as well as the URI and the user agent string,

00:02:03.810 --> 00:02:05.000
which we want to use.

00:02:05.310 --> 00:02:09.050
PowerShell cannot directly call Win32 APIs.

00:02:09.180 --> 00:02:09.710
Therefore,

00:02:09.710 --> 00:02:12.940
we cannot call VirtualAlloc to allocate memory as we did

00:02:12.940 --> 00:02:15.590
previously in our stager written in C++.

00:02:15.590 --> 00:02:16.840
We can, however,

00:02:16.840 --> 00:02:21.820
leverage C# from inside our PowerShell script to create custom types using

00:02:21.820 --> 00:02:26.720
the Add‑Type cmdlet so that we can then make use of this custom type to

00:02:26.720 --> 00:02:29.730
call the VirtualAlloc and CreateThread APIs.

00:02:30.480 --> 00:02:34.330
We can then make use of the Invoke‑WebRequest cmdlet to

00:02:34.330 --> 00:02:36.950
download the payload from our Metasploit handler,

00:02:36.960 --> 00:02:40.980
as we did previously using WinINet in our C++ stager.

00:02:40.980 --> 00:02:45.040
We can then allocate a read/write execute memory buffer using

00:02:45.040 --> 00:02:47.940
VirtualAlloc and copy the payload into it.

00:02:47.950 --> 00:02:52.530
Finally, we can leverage the CreateThread API to start a thread,

00:02:52.540 --> 00:02:55.470
which will execute our payload and wait until the thread

00:02:55.470 --> 00:02:59.150
terminates using the WaitForSingleObject API.

00:02:59.290 --> 00:03:00.970
If we go ahead and run this code,

00:03:00.980 --> 00:03:05.460
we get the following message stating that the code was blocked by the antivirus.

00:03:05.540 --> 00:03:08.790
This is very interesting since we wrote this stager from scratch.

00:03:08.790 --> 00:03:12.910
In an attempt to identify which part of the code triggered the detection,

00:03:12.910 --> 00:03:17.030
we can go ahead and run this code one line at a time in an

00:03:17.030 --> 00:03:22.060
attempt to pinpoint the line of code, which is causing the detection.

00:03:22.060 --> 00:03:26.570
Interestingly, it appears that when we run the code one line at a time,

00:03:26.580 --> 00:03:28.010
we do not trigger AMSI.

00:03:28.010 --> 00:03:30.300
And if we check our Metasploit handler,

00:03:30.320 --> 00:03:33.560
you will notice that we have a fully functional Meterpreter shell.

00:03:33.570 --> 00:03:37.320
You may recall that during the antivirus and EDR modules,

00:03:37.320 --> 00:03:41.230
we did indeed notice that every time a command was executed,

00:03:41.240 --> 00:03:44.750
it was sent to the AmsiScanBuffer API.

00:03:44.840 --> 00:03:47.710
We can therefore conclude that the detection is

00:03:47.710 --> 00:03:49.930
caused by a combination of artifacts,

00:03:49.940 --> 00:03:52.620
which are located in different parts of the script.

00:03:52.750 --> 00:03:55.680
I have gone ahead and made some adjustments to the stager.

00:03:55.690 --> 00:03:57.900
Instead of running the stager in one go,

00:03:57.910 --> 00:04:00.950
I have decided to download the script and invoke it

00:04:00.960 --> 00:04:02.860
one block of script at a time.

00:04:02.940 --> 00:04:05.950
This will effectively avoid sending the entire script to the

00:04:05.950 --> 00:04:10.210
AmsiSanBuffer API and hopefully break the detection.

00:04:10.280 --> 00:04:13.970
If we take a look at the two files, which are downloadable executes,

00:04:13.980 --> 00:04:19.899
we can see that the stager‑1.txt file contains the first half of the script,

00:04:19.970 --> 00:04:23.850
and the stager‑2.txt file contains the second half.

00:04:23.940 --> 00:04:26.610
I can then start up a simple web server so that

00:04:26.610 --> 00:04:28.520
these two files can be downloaded.

00:04:28.640 --> 00:04:30.860
If we now go back to our victim machine,

00:04:30.870 --> 00:04:33.480
we can see that the antivirus is indeed enabled.

00:04:33.480 --> 00:04:37.810
And if we go ahead and run our downloader, it doesn't trigger the antivirus.

00:04:37.820 --> 00:04:39.820
If we go back to our Kali machine,

00:04:39.830 --> 00:04:43.160
we will indeed see that a Meterpreter session has been opened.

00:04:43.350 --> 00:04:45.540
Let's now take a look at another technique,

00:04:45.550 --> 00:04:48.050
which we can use to bypass AMSI,

00:04:48.240 --> 00:04:53.750
which consists of disabling AMSI by modifying the amsiInitFailed field,

00:04:53.750 --> 00:04:57.470
which is set when the AMSI DLL is initialized.

00:04:57.470 --> 00:05:00.470
By setting the value of this field to true,

00:05:00.550 --> 00:05:05.260
we effectively disable AMSI inside the current PowerShell process.

00:05:05.340 --> 00:05:08.080
This can be achieved using the following command.

00:05:08.220 --> 00:05:11.670
When we run this command, it is blocked by AMSI.

00:05:11.680 --> 00:05:17.020
If we go ahead and simply type AmsiUtills instead of the entire command,

00:05:17.200 --> 00:05:18.450
it is also blocked.

00:05:18.450 --> 00:05:19.510
At this point,

00:05:19.520 --> 00:05:23.170
it is quite clear that we are dealing with a signature‑based detection.

00:05:23.180 --> 00:05:26.360
If we break up the command and use string concatenations,

00:05:26.600 --> 00:05:29.430
you will notice that we no longer trigger a detection.

00:05:29.700 --> 00:05:34.660
And if we now type the AmsiUtil string, which was blocked previously,

00:05:34.940 --> 00:05:38.660
you will notice that it is no longer flagged by the antivirus.

00:05:39.040 --> 00:05:42.450
If we go back to the downloader we used previously,

00:05:42.460 --> 00:05:46.150
we can reuse this code and simply modify the contents of the

00:05:46.150 --> 00:05:50.530
stager‑1.txt file and replace it with the command,

00:05:50.530 --> 00:05:52.750
which we used to disable AMSI.

00:05:52.750 --> 00:05:57.660
In the stager‑2.txt file, we can now place our entire stager,

00:05:57.840 --> 00:06:01.000
which won't be detected since by the time it runs,

00:06:01.010 --> 00:06:04.700
AMSI will have been disabled by the first part of the script.

00:06:04.840 --> 00:06:08.540
We can go ahead and start the web server so that our downloader

00:06:08.550 --> 00:06:11.130
can retrieve the files containing the code,

00:06:11.300 --> 00:06:13.320
and we can then run our downloader.

00:06:13.320 --> 00:06:17.760
As you can see, the antivirus did not prevent it from executing.

00:06:17.940 --> 00:06:19.860
And if we check our Kali machine,

00:06:19.940 --> 00:06:23.630
you will notice that both the files have been downloaded successfully.

00:06:23.770 --> 00:06:25.700
If we check our Metasploit handler,

00:06:25.710 --> 00:06:29.910
you will also notice that we have a fully functional Meterpreter session.

00:06:29.950 --> 00:06:33.040
If you want to learn more about AMSI bypasses,

00:06:33.050 --> 00:06:37.160
I recommend the following document, which is freely available on the internet.

00:06:37.640 --> 00:06:39.800
It demonstrates many more bypasses,

00:06:39.800 --> 00:06:43.580
which involves using the registry to disable AMSI or

00:06:43.580 --> 00:06:47.860
patching the AmsiScanBuffer API, as discussed previously.
