[Univ of Cambridge] [Dept of Engineering]

PHP security

Most of this is adapted from A Study In Scarlet: Exploiting Common Vulnerabilities in PHP Applications by Shaun Clowes (SecureReality)

Global Variables

Variables in PHP don't have to be declared, they're automatically created the first time they are used. Nor do they have a specific type, they're typed automatically based on the context in which they are used. This is an extremely convenient way to do things from a programmer's perspective (and is obviously a useful feature in a rapid application development language). Once a variable is created it can be referenced anywhere in the program (except in functions where it must be explicitly included in the namespace by using global). The result of these characteristics is that variables are rarely initialized by the programmer; after all, when they're first created they are empty (i.e "").

Obviously the main function of a PHP based web application is usually to take in some client input (form variables, uploaded files, cookies etc), process the input and return output based on that input. In order to make it as simple as possible for the PHP script to access this input, it's actually provided in the form of PHP global variables. Take the following example HTML snippet:

 <FORM METHOD="GET" ACTION="test.php">
 <INPUT TYPE="TEXT" NAME="hello">
 <INPUT TYPE="SUBMIT">
 </FORM>

Obviously this will display a text box and a submit button. When the user presses the submit button the PHP script test.php will be run to process the input. When it runs, the variable $hello will contain the text the user entered into the text box. It's important to note the implications of this, this means that a remote attacker can create any variable they wish and have it declared in the global namespace. If instead of using the form above to call test.php, an attacker calls it directly with a url like "http://server/test.php?hello=hi&setup=no", not only will $hello = "hi" when the script is run but $setup will be "no" also.

An example of how this can be a real problem might be a script that was designed to authenticate a user before displaying some important information. For example:

  if ($pass = "hello")
   $auth = 1;
  ...
  if ($auth == 1)
   echo "some important information";

In normal operation the above code will check the password to decide if the remote user has successfully authenticated then later check if they are authenticated and show them the important information. The problem is that the code incorrectly assumes that the variable $auth will be empty unless it sets it. Remembering that an attacker can create variables in the global namespace, a url like 'http://server/test.php?auth=1' will fail the password check but the script will still believe the attacker has successfully authenticated.

To summarize the above, a PHP script cannot trust ANY variable it has not EXPLICITLY set. When you've got a rather large number of variables, this can be a much harder task than it may sound.

Once common approach to protecting a script is to check that the variable is not in the array HTTP_GET/POST_VARS[] (depending on the method normally used to submit the form, GET or POST). When PHP is configured with track_vars enabled (as it is by default) variables submitted by the user are available both from the global variables and also as elements in the arrays mentioned above. However, it's important to note that there are FOUR different arrays for remote user input

It is completely the end users choice which method they use to submit variables, one request can easily place variables in all four different arrays, a secure script needs to check all four (though again, the HTTP_POST_FILES array shouldn't be an issue except in exceptional circumstances).

Session Files

Later versions of PHP (4 and above) provide built-in support for 'sessions'. Their basic purpose is to be able to save state information from page to page in a PHP application. For example, when a user logs in to a web site, the fact that they are logged in (and who they are logged in) could be saved in the session. When they move around the site this information will be available to all other PHP pages. What actually happens is that when a session is started (it's typically set in the configuration file to be automatically started on first request) a random session id is generated, the session persists as long as the remote browser always submits this session id with requests. This is most easily achieved with a cookie but can also be done by achieved by putting a form variable (containing the session id) on every page. The session is a variable store, a PHP application can choose to register a particular variable with the session, its value is then stored in a session file at the end of every PHP script and loaded into the variable at the start of every script. A trivial example is as follows:

  session_destroy(); // Kill any data currently in the session
  $session_auth = "shaun";
  session_register("session_auth"); // Register $session_auth as a session variable

Any later PHP scripts will automatically have the variable $session_auth set to "shaun", if they modify it later scripts will receive the modified value. This is obviously a very handy facility to have in a stateless environment like the web but caution is also necessary.

One obvious problem is with insuring that variables actually come from the session. For example, given the above code, if a later script does the following:

  if (!empty($session_auth))
   // Grant access to site here

This code makes the assumption that if $session_auth is set, it must have come from the session and not from remote input. If an attacker specified $session_auth in form input they can gain access to the site. Note that the attacker must use this attack before the variable is registered with the session, once a variable is in a session it will override any form input.

Session data is saved in a file (in a configurable location, usually /tmp) named 'sess_<session id>'. This file contains the names of the variables in the session, their loose type, value and other data. On multi host systems this can be an issue since the files are saved as the user running the web server (typically nobody), a malicious site owner can easily create a session file granting themselves access on another site or even examine the session files looking for sensitive information.

Miscellaneous

Fixes

When looking for holes in PHP applications (when you have the source code) it's useful to have a list of functions that are frequently misused or are good targets if they happen to be used in a vulnerable manner in the target application. If a remote user can affect the parameters to these functions exploitation is often possible. The following is a non exhaustive breakdown.

PHP Code Execution

Command Execution

File Disclosure

Configuration

(these features might be beyond an ordinary user's control, but if you're looking after a system you can adjust them)

See Also


[Languages] [Help]

Updated 13/12/02
Tim Love