PHP, Powershell and Shell_Exec()

Over in /r/powershell I have been seeing an increase in posts about using PHP as a front end. The general consensus has been to use shell_exec to launch the script and pass the variables to powershell. Looking around online I haven’t seen any of the tutorials address the security concerns that come with shell_exec.

In this post I’ll show an example of an attack done on shell_exec as it relates to launching powershell. Before we start a quick note: All of the mitigation techniques I am going to show you should be part of a security profile. Some examples of things to consider when deciding on your security profile:
1) Proper delegation of Service account permissions in active directory and on the local system.
2) Installation of tools such as Mod_security
3) Installation of Anti-virus
4) Limiting access of the PHP interface to only authorized users.

The Attack:

First we’ll need a php page that launches a powershell script. A txt copy of the code for the examples can be found here in pastebin or on my github Pictures were used because wordpress formatting was driving me nuts.
PHP

Powershell

Ideally a user enters data into the php form. The data is logged and returned to the user.

For this example I submitted “test123”. The text was logged in log.txt and the expected response was sent back:

Now lets send the attack string to the form:

test11;” dir c:\ >> C:\inetpub\wwwroot\dir_list.txt

This time the response isn’t exactly what we expected. The webpage output the same response but 1/2 of the attack string is missing:

The log file is also only showing test11. If we go to C:\inetpub\wwwroot\dir_list.txt or simply download it from the root of our webserver we get a directory listing like so:

This is a very basic proof of concept. The attacks can become much more complex leading to a fully compromised Web server or a compromised Active Directory instance if the Service Account is a domain admin, etc.

Mitigating the attacks:
One of the most common defenses, but hardest to do correctly, is to use a combination of regular expressions, escapeshellcmd, and escapeshellarg.
An example like this might work updating a title, firstname or last name:

A better solution would be to submit your information to Mysql, or a file format of your choosing ( XML, Json, CSV) on the local drive. Then use shell_Exec to launch the powershell script without any direct user input. Let the powershell script parse the data and submit it. You can also use a scheduled task to launch this method which has the added advantage of not letting the Service Account user anywhere near IIS.

In some cases you need to allow the full range of characters and absolutely must take user input and the data can not be allowed to rest in a file or mysql table. For these rare cases I would suggest encoding the data. In this example Base64 is used:
Php:

Powershell:

Text version found on pastebin or the github still contains everything
When we submit the attack code again: test11;” dir c:\ >> C:\inetpub\wwwroot\dir_list.txt
We see the full attack returned as well as logged:

Base64 encoding can be a bit system heavy and probably wouldn’t work for a bigger site.
I hope some part of this has proven to be informative. All code examples can be found here: https://github.com/ryanlangley4/ps_and_php_sec

*None of the examples done here limit the length of user input, or any number of other things like accept spaces when sending to powershell. The goal is to focus on shell_exec and not get too bogged down with details.