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!

32 comments:

  1. What's so special?
    Or is this one of those redundant post exploitation "techniques"?
    If so, why is ASLR/DEP even mentioned?

    ReplyDelete
  2. nice trick, you introduced the ability to make primitive api calls from your .net shell... y'know that .net means platform independance, and shellcode is intended to achieve address-space independence. you have a variety of other higher-level and potentially more useful functionality available to you. regardless, it's great that you're learning how to execute other people's shellcode everywhere and all.

    ReplyDelete
  3. If you watch Dave Kennedy's Powershell talk that he gave in 2010 you would see that an ideal use case for this would be in a teensy payload. The teensy payload that's built into SET first drops an encoded payload onto the file system. This would eliminate that step and execute the payload entirely within memory. By your wording, yes this would be one "one of those redundant post exploitation techniques." If you don't find the value in it, so be it.

    ReplyDelete
  4. That's awesome stuff. May I use this in one of my upcoming preso? And yes the best usage is with Teensy. I have also used your "exe-to-text" blog post in my code. Thanks a lot.

    ReplyDelete
  5. By all means. This was all meant for public consumption. Glad you enjoy it.

    ReplyDelete
  6. Awesome! Realy usefull in described scenario.

    ReplyDelete
  7. As you're not a CSharp developer, I'm not a bash scripter, however this worked for me to automatically translate msfpayload to the format needed in your powershell script:

    msfpayload windows/exec CMD="cmd /k calc" EXITFUNC=process C | sed '1,6d' | sed 's/[";]//g' | sed 's/\\/,0/g' | tr -d '\n' | cut -c2-

    Use the same piped commands for the 64 bit as well.

    ReplyDelete
  8. Matt,

    That's extremely handy. Thanks for sharing that. :D

    ReplyDelete
  9. Actually you can apparently reduce it more (thanks g0tm1lk)

    msfpayload windows/exec CMD="cmd /k calc" EXITFUNC=process C | sed '1,6d;s/[";]//g;s/\\/,0/g' | tr -d '\n' | cut -c2-

    ReplyDelete
  10. Cute, but what exactly is this supposed to demonstrate? You're already at a shell fully capable of executing arbitrary processes under the context of the current user. Trying to hack that through some kind of shell script would be silly, especially since PowerShell will not, by default, execute any scripts that are not trusted. If you've already exploited the system to this extent you don't need PowerShell to carry out any of these tasks.

    ReplyDelete
    Replies
    1. Laugh, its apparent this dude has no idea what he's talking about. The implications are huge on this as far as evasion techniques and previous ways of injecting straight into memory without the need to interface an executable or dropper. What you may not realize in the exploit world is compromising the initial system is half the battle, the payload is what you want afterwards. Please read security books before posting stuff like this.

      Delete
  11. Cute, huh? I'm flattered by your compliment. And I find your comment to be simply adorable. ;D

    But just to clarify some of your criticisms:

    1) "PowerShell will not, by default, execute any scripts that are not trusted"

    Yes it will. It is trivial to bypass the execution policy by including an encoded powershell command within a batch script. As I said in my post, this technique is well documented and you can easily find it on Google.

    2) "If you've already exploited the system to this extent you don't need PowerShell to carry out any of these tasks."

    Take the time to read my previous comment. The whole point is that you can use this to execute shellcode that is entirely memory resident. The ideal use case was the teensy payload and the java applet payload in SET. In fact, Dave Kennedy has already indicated that he is implementing this technique into the next version of SET. Additionally, from my testing, launching a payload such as a meterpreter callback using this method doesn't flag AV or HIPS.

    As in my previous comment, if you don't find the use in this, so be it. By all means, develop something that's useful for the community.

    As was mentioned in my first blog post, the whole point of my blog is primarily for my own self-edification. If other people benefit from it, great. If not, I wouldn't waste your time.

    ReplyDelete
  12. In fact, I posted an almost identical script to use with PowerShell Remoting some time ago. So, in case you have pwned a user in a domain that is not local admin but has the privilege to "remote" to another host with PowerShell, you can use it to drop your shellcode on the second host.

    ReplyDelete
  13. Damn. That's cool. And here I thought that was actually contributing something original. heh ;D Could you provide a link for comparison?

    Yeah. Using this to execute code remotely on machines w/ PS remoting enabled was definitely a good use for this that occurred to me.

    ReplyDelete
  14. Congratulations, as it looks like SET 2.2 was released with your powershell attack vector included!

    ReplyDelete
  15. you labeled this "exploit", so I am wondering where the exploit is. I cannot see privilege escalation, and hiding code or executing it in-memory is something that PS can do by default. There may be use cases but as far as I can see right now, I cannot identify security implications.

    ReplyDelete
    Replies
    1. The definition of an exploit:

      "An exploit (from the verb to exploit, in the meaning of using something to one’s own advantage) is a piece of software, a chunk of data, or sequence of commands that takes advantage of a bug, glitch or vulnerability in order to cause unintended or unanticipated behavior to occur on computer software, hardware, or something electronic (usually computerised). "

      I would say that this was an unintended side effect of powershell and the ability to leverage direct code execution without a direct buffer overflow or memory-based exploit and not drop a PE file onto disk where it can be detect.

      What's up with the trolls here that don't know squat about security?

      Delete
  16. I'm wondering where the exploit is as well. I was careful not to outright call this an exploit because it's not. If you're referring to "Powershell Code Execution 'Exploit'" in the code, note that exploit is in quotes.

    The use cases are certainly there. Please refer to the previous comments for those. As for the security implications, this already assumes that you compromised a machine with Powershell on it. As I've stated previously, if you don't find the use in this, so be it.

    ReplyDelete
  17. Can't get it working if I do a get-content -encoding byte from a file containing the shell code...my powershell just crashes..could you please have a look?

    ReplyDelete
  18. Nikhil,

    I assume you have your shellcode in a text file in the form 0xXX,0xXX,0xXX. Right?

    1) Read the text file in and save as a string
    PS> Get-Content ./sc.txt
    2) Parse the string using comma as a delimiter and cast it as a byte array
    PS> $sc = $str -split ','

    That's it. Now it's in the byte array form that's needed for it to execute. No need for me to look at anything. Hope that helps.

    ReplyDelete
  19. Nice one...
    (not the same anonymous from previous posts...)

    ReplyDelete
  20. Hey Matt,

    That worked like a charm, so silly of me. Thanks a lot!!

    ReplyDelete
  21. What about:

    - Open cmd.exe
    - Type these commands:

    echo MZ>test.txt
    call test.txt
    del test.txt

    After watching the results of the above commands, you'll notice how the OS will try to parse test.txt as an executable.

    As proof of concept, try:

    copy %systemroot%\notepad.exe .\test.txt
    call test.txt

    And watch your notepad popping up.

    The above won't work with calc.exe, don't ask me why, but it seems the calc.exe is checking the extension in the filename (curious).

    Now, knowing that most AVs won't check .txt files, imagine the implications.

    For those who think the bottleneck will be writing your payload to disk, I' ll tell you that the echo command is capable of doing so, just type "echo [ALT+10]>test.txt" without quotes and pressing ALT+NUMPAD 1+NUMPAD 0 where the string "[ALT.." is. Then open the file and see what's inside. It will work with any other character and I m almost sure this can be achieved programmatically and remotely, a way or the other.

    ReplyDelete
    Replies
    1. Thanks for the comment.

      I'm aware of the technique for manually entering arbitrary characters via echo. I however, have been unable to find a way of performing that process programmitically without using debug.exe, vbscript, or powershell. If you come up with a way, please share. Thanks.

      Delete
  22. I love this. Using powershell to build C# with P/Invoke's is just cool. I've started playing around with the compiler API's for a project at work. I was thinking that something like this would be possible and awesome...awessible? The tards that keep saying "will this getz me r00tz?" really lack imagination. Even if this was running as an unprivileged user there is a lot of information that could be gathered using combinations of .net and win32. And like you mentioned it would, by and large, be invisible to host security software.

    ReplyDelete
  23. Why is dwSize the third parameter to VirtualAlloc when in the win32 API it is the second parameter?

    ReplyDelete
    Replies
    1. Sorry. I'm not seeing where dwSize is being used as the 3rd parameter.

      Delete
    2. The following line, you pass $size as the third parameter instead of the second:

      $x=$winFunc::VirtualAlloc(0,0x1000,$size,0x40)

      Delete
    3. Ah. Yep. Good find. Thanks for pointing that out.

      Delete
    4. Thanks for posting the code! It works beautifully and AV doesn't say a word about it! Awesomeness.

      Delete