Bypassing Amsi using PowerShell 5 DLL Hijacking

Share this…

While doing some research on the inner workings of Microsofts new Antimalware Scan Interface technology within Windows 10, i found a DLL loading vulnerabilty within PowerShell 5. The reason i did some research is because some offensive PowerShell scripts i use within my own Red Teaming tool called p0wnedShell are getting blocked by Windows Defender on Windows 10 “despite of running from memory”, so i wanted to know if it was possible to bypass this technology.

From the Microsoft technet blog below, we could see the following diagram on how this technology hooks up within PowerShell/VBScript e.g.

While running Process Monitor with a Path filter on amsi.dll i saw that p0wnedShell was first trying to find/load the amsi.dll in it’s current path.
When it doesn’t find the dll over there, it loads the dll from the System32 path.
So that could give us some opportunities.

In IDA i checked which WinAPI functions the original DLL actually exports and noticed the DllMain entry point, so i thought that i could try to create an simple DLL in C with a simple WinAPI MessageBox function.

Fake Amsi.dll sourcecode in C

As you can see in the screenshot below; when running p0wnedShell normally on Windows 10 with Windows Defender enabled, Amsi/Defender kicks in when loading some of the offensive PowerShell scripts from memory (Blocked by Anti-Virus).

Now when running p0wnedShell again, but with the compiled “fake” version of amsi.dll in C:\p0wnedShell folder, we see some magic happen.

After clicking the MessageBox, we can run all the offensive scripts without any problems anymore.
When searching within Process Explorer for the Amsi.dll (find DLL or Handle), i noticed that the dll is unloaded, while normally it’s loaded within the p0wnedShell process.

Next i wanted to try if PowerShell.exe itself is also vulnerable for the DLL loading issue, so i copied the PowerShell executable to the C:\p0wnedShell folder and run Process Monitor with a Path filter on C:\p0wnedShell
As you can see in the screenshot below, PowerShell tries to load several dll’s from the current path.

And as expected, it also loads the fake Amsi.dll from the current path.
So this DLL hijacking trick also works for PowerShell.exe itself.

While trying some more dll’s i found out that i could also successfully hijack urlmon.dll

So with these findings, we can conclude that PowerShell 5 is vulnerable for dll hijacking and we can control code execution when copied to a location where we have write access.

With this knowledge we could now use PowerShell to run custom code like backdoors, keyloggers, malware e.d. within a Windows 10 system. As an example i created the Amsi.dll in the screenshot below and copied it together with PowerShell.exe into a folder that’s within the %path% environment variable.
Now when a local admin user runs PowerShell.exe from a command prompt, and clicked Yes on the UAC prompt, a new admin user is added to the local administrator group within the system.

PowerShell and amsi.dll copied in folder within %path% env

Run PowerShell from command prompt

UAC Prompt

New local admin added.

Proof of Concept:

In the latest version of p0wnedShell i’ve included the Amsi bypass by dropping a Amsi.dll from memory to the current working directory (using BinaryWriter method). This DLL is being loaded by the p0wnedShell process and exits immediatly, so basicly does nothing but unloading Amsi.