Security and usability do not mix
PHP has a horrible reputation in the security industry based on a long history of vulnerabilities and vendor resistance to fixing them and improving security practices. It suffers from a common problem; the technology is designed to be easy to use, and therefore a high level of security is difficult to achieve. Many who are new to web application programming use PHP, but often do not pay attention to security. In addition poor developer coding practices, PHP itself presents many vulnerabilities in its default configuration even when seemingly harmless coding practice is in use. This leaves a plethora of vulnerable applications, some home grown, many open-source and some commercial. As a result, many of these applications suffer from web application specific vulnerabilities. To give you an idea of just how many PHP specific vulnerabilities there are, I ran some searches on the OSVDB web site. Below are the results:
Given the wide attack surface and history of vulnerabilities, organizations need to carefully deploy and monitor PHP applications and build in layers of security. One layer that can be used to improve security is the PHP configuration settings themselves. The php.ini file contains several parameters that allow you to control the behavior of all PHP applications. This blog post describes how some of the popular options can be used to protect your web applications and provides an example of how to audit the php.ini file to ensure your settings match your security policies.
PHP contains several functions that are known to be vulnerable to command injection attacks. You can add the following line to your php.ini file to prevent these functions from executing (they can still be called, but the calling application will receive an error):
|disable_functions = exec, passthru, shell_exec, system, proc_open, popen, curl_exec, curl_multi_exec, parse_ini_file, show_source|
With these functions disabled there is a chance that some applications may no longer function correctly. Before implementing this defensive measure I ran the following command on my server to see if any of my applications were in fact using these functions:
|egrep -r '(exec| passthru| shell_exec| system| proc_open| popen| curl_exec| curl_multi_exec| parse_ini_file| show_source)' *.php|
Depending on your policy, risk evaluation and the importance of the application, you may want to remove the offending application all together. If the application is critical, you can adjust the code to eliminate the functionality or ensure good coding practice to avoid inadvertent remote code execution. If the application is from a third-party, hopefully a patch is available to fix the problem. If there is no patch, sometimes a workaround can be put in place, often involving the php.ini file settings.
Lets look at a "before and after" scenario for an offending application. I setup Mutillidae in my lab, a PHP application that has been written to be insecure by design for testing purposes. It contains a "command execution" vulnerability in the DNS lookup feature. If you enter an IP address, followed by a ";" and an operating system command, the command will execute and the results will be displayed on the page. For example, I entered "192.168.1.1;ls" in the IP address field and got the following results:
Nessus was also able to detect this vulnerability during a scan that had the web application tests configured:
|Using the GET HTTP method, Nessus found that :
+ The following resources may be vulnerable to arbitrary command execution:
uid=33(www-data) gid=33(www-data) groups=33(www-data)
</pre> <!-- End Content -->
In the plugin output above, we can see that Nessus constructed a query to the web server, that when executed, allowed the "id" command to run. In the output section, Nessus displays the section of the web page that contained the results of our operating system command.
After disabling the vulnerable functions via php.ini modification, we get an error when attempting to execute the attack:
After the php.ini change, Nessus no longer reports this vulnerability as the application has lost the ability to execute operating system commands. Disabling specific functions works really well when trying to secure PHP, however, be certain to check how it will impact all of your applications.
PHP's Safe Mode provides a similar functionality compared to "disable_functions". When you enable "safe_mode", PHP restricts specific functions and certain types of functionality that could be deemed a security threat. However, there are many ways around these restrictions, as demonstrated in an article by HD Moore titled "PHP Safe Mode Considered Harmful". The other thing to note about "Safe Mode" is that it will not be included in PHP version 6.0. The fact that the PHP developers themselves realized this was not an effective security measure should raise a red flag. However, if you are running a PHP version less than 6.0, having some extra security (if your applications will function) may help thwart certain attacks. In the php.ini file you can turn "Safe Mode" on with the following parameter:
|safe_mode = On|
File Operating Limits
In most cases there is no reason to allow your web application to read files outside of the web root directory. Typically, web server files are located in a directory such as "/var/www", and each application is installed as a subdirectory. If this is the case, you can limit PHP applications ability to reach outside this directory with the "open_basedir" option:
|open_basedir = /var/www|
Nessus contains generic CGI tests that will detect the ability to reach files outside of the base web directory:
Once "open_basedir" is set, Nessus will no longer flag this as a vulnerability and you will get the following error when trying to access the vulnerability manually:
"Register globals" is a scary concept that is best described with the following quote from the PHP manual:
"When on, people use variables yet really don't know for sure where they come from and can only assume."
Reference: "PHP Using Register Globals Manual"
Much of programming securely relies on knowing and setting the correct values for your variables. With "register globals" enabled, you may lose control of the value of you variables. This tends to rear its ugly head with respects to session handling.
|register_globals = Off|
As of version 4.2.0, released April 22, 2002, PHP no longer ships with register_globals on by default.
Allow URLs (or not)
Remote file inclusion (RFI) vulnerabilities allow an attacker to include PHP code from a third-party remote site in an existing page on the target web server. A popular method for exploiting RFI vulnerabilities is having the application call a "PHP Shell", which is a PHP script that provides expanded functionality to upload files, execute commands and perform directory listings. There are two options in the php.ini file that can be set to prevent this from happening:
|allow_url_fopen = Off|
|allow_url_include = Off|
Both of the above configuration settings control different aspects of file handling and work to prevent remote file inclusion. Nessus can detect the Remote File Inclusion vulnerabilities as part of the CGI generic tests. When scanning Mutillidae, Nessus finds an example:
With the "allow_url*" options set to "On", it is possible to include PHP code from other sites onto the target page:
When we change the two options to "Off", we get the following error:
In this case it is the “page” variable that is being set to a remote URL and including code from a third party web site. This variable is set using the “include” function within PHP, so the “allow_url_include” directive is preventing the attack.
The "magic_quotes" directive represents functionality in PHP that automatically escapes quotes passed from the user to the application. For example, in the following configuration:
|magic_quotes_gpc = On|
will automatically escape all ' (single-quote), " (double quote), \ (backslash) and NUL's with a backslash for GET, POST and cookies sent. The other magic quotes directive, magic_quotes_runtime
|magic_quotes_runtime = On|
will escape quotes for a select list of functions. For more information, including a list of the affected functions, refer to the PHP Runtime Configuration Manual. The above settings prevent basic SQL injection from occurring. For example, with the magic quote settings above turned to "Off", Nessus found a SQL injection vulnerability:
|Using the GET HTTP method, Nessus found that :
+ The following resources may be vulnerable to SQL injection:
<form method="POST" action="/mut/index.php?password_confirm=&page= [...]
In the above output, Nessus has sent a URL to the web application with the "user_name" parameter set to "%27". "%27" is the URL encoded format for a ' (single quote). The resulting page in the "output" section then lists an SQL error, stating that our syntax was incorrect and indicating that we were able to manipulate the web application parameter to run SQL code.
Size limits and logging are two other areas of the php.ini file that contain options that prevent denial of service conditions and control logging. They are not directly related to web application attacks, and therefore not covered here. To read more about these options refer to the OWASP PHP recommended configuration guide.
Auditing your php.ini Config File
Now that we have explored the various settings, their recommended value and the attacks they can prevent, we now need to audit the php.ini files in our environment. Nessus ProfessionalFeed customers can use the configuration auditing features to accomplish this. Available on the Tenable Nessus customer support site is an audit file written to compare your php.ini file against the OWASP PHP recommended configuration. You can find an example of how to configure and run this scan in a previous post titled, "Auditing PHP Settings to OWASP Recommendations with Nessus".
There are many different options in the php.ini file. After rigorous testing and configuration changes, the various settings do affect security in a positive way, often rendering several attacks useless. Command injection, remote file includes and path traversal vulnerabilities can be successfully thwarted by adjusting the settings in the php.ini file. Several of these settings are being deprecated in PHP version 6.0 and later, which means you need to be certain that your applications are implementing security properly and not relying on settings in PHP. You can use Nessus to detect the vulnerabilities in your web applications, using generic testing techniques and audit your configurations to be certain they are in line with your policy. It is important to tune the parameters in your php.ini file to meet your own organizations requirements, and balance security with functionality.