Tuesday, October 18, 2011

Exploiting Powershell's Features (Not Flaws)

UPDATE (10/13/2012)

Feel free to continue reading but just be aware that the technique described here is extremely outdated and the code that follows is garbage and as far from PowerShell coding best practices as possible. My Invoke-Shellcode script which is part of the PowerSploit project is vastly superior to this garbage proof-of-concept code.

tl;dr version

Using the features built in to Microsoft Powershell one can execute arbitrary shellcode. The method described in this post is both 32 and 64 bit compatible. Because we are exploiting the features of the .NET framework, ASLR and DEP doesn't even come into play here. Just copy and paste your shellcode and you're good to go.

lengthy, pedantic version

Those us that use Powershell know just how powerful it can be in automating administrative tasks. However, with great power comes great responsibility and the Powershell developers certainly assumed that it would be used responsibly. Unfortunately, (get ready for another clichéd expression/pun) absolute power corrupts absolutely. ;D I'll show you how you can use Powershell's integrated features to execute arbitrary shellcode.

Powershell's true power comes in the form of access to the .NET framework. One of the greatest features of Powershell, IMHO is the ability to add custom classes to the .NET framework. This can be accomplished using the Add-Type cmdlet. The great thing about Add-Type is that it will compile CSharp code on the fly for you. Why is this so great? It allows you to import functions from any DLL. The Add-Type documentation provides some pretty good examples on how to create your own classes using CSharp source code.

It's pretty easy to import a function from a DLL. You just have to alter the C-style function prototype a bit to a CSharp-style prototype. Since we'll be importing the VirtualAlloc function later, I'll use it as an example.

Here's what the VirtualAlloc C-style prototype would look like:

LPVOID VirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect);

Here's what it would look like in CSharp:

IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);

Finally, here's how you would be able to reference VirtualAlloc in Powershell:
The .NET framework doesn't deal too well with directly referencing memory. For security reasons, this is a good thing. However, since you can import functions that deal with unmanaged memory, we should in theory have all the tools necessary to allocate executable memory, copy shellcode to it, and then execute it as a thread. So without further ado, let's do just that in Powershell. The following code will execute any arbitrary 32 or 64 bit payload within Powershell. All you have to do is copy and paste the relevant 32 and 64 bit payloads and the code will determine on the fly if it is running in a 32 vs. 64 bit context. And because it's copy and paste, it should be popular with the skiddies. ;D
As you can see in the Powershell script, I'm doing a few things:

1) Importing the VirtualAlloc, CreateThread, and memset methods and adding them to my 'winFunc' class
2) Inserting both the 32 and 64 bit payloads as byte arrays
3) Determining whether PS is running as 32 vs. 64 bit by using the [IntPtr]::Size property
4) Allocating enough memory to accommodate the shellcode
5) Copying the shellcode to the executable region of memory
6) Executing the shellcode in its own thread

Here are some pretty pictures:

Popping a calc on 32-bit Powershell

Popping a calc on 64-bit Powershell

Now if you wanted to be even more stealthy in executing this attack, you could base64 encode the entire payload and execute it using the '-encodedCommand' option in PS. You could take this one step further and execute the encoded payload within a batch file thus bypassing the Powershell execution policy. I'll spare you details on how to accomplish this since this method is already well documented.

Lastly, I am by no means a CSharp developer or even a developer for that matter so you can certainly spare me any criticisms of my poor coding practices. The bottom line is, it works and it works extremely reliably and that's all I care about. Also, there's absolutely more than one way to accomplish this. I would love to hear suggestions on alternate ways to execute shellcode from within Powershell. And please feel free to leave comments and questions below. Enjoy!