It is important to understand the implications of allowing a Drupal user to execute PHP.

This usually happens when a user can type PHP code into a form, submit the form, and have that PHP run on the server. It can also happen if the site allows file uploads and doesn't protect against the upload and execution of PHP files.

Note, the Security Team security policy identifies a number of permissions which can allow full site takeover. "Administer Users" permission is discussed further down the page.

The damage

PHP can be used to modify a Drupal site. When it is executed on the server, PHP runs as the same user that the webserver runs as. This user (often www-data) will be able to modify files (including deletion) of any file the webserver has access to modify. In most cases that are just files under the Drupal site's "files" directory.

PHP can also be used to modify the Drupal database itself or steal data. In this way tables can be deleted, node content can be modified, and private user details can be changed or extracted (such as email addresses and hashed passwords). If you have an e-commerce site then your user's financial information is at risk should an attacker be able to execute PHP code on your server. There are a million ways to take control of a site when PHP can be executed.

Even with many secured servers, it may be possible to scan the server for additional files. If you can read the settings.php file of another Drupal installation, then you will be able to access its database as well. (See Configuring Apache and PHP ... for suggestions on how to use the open_basedir directive to lock this down.)

A frequent goal of a hacker is to use your server to send spam. Gaining access to PHP will allow the user to send emails at will.

Ways PHP can be executed

There are two general ways PHP can be executed that poses a risk to your site. The first is via existing code on your site that evaluates incoming text as PHP, such as the PHP text format module. The second way that dangerous PHP code gets evaluated is via user-uploaded PHP code to the file system.

Modules that allow the execution of PHP should limit access to trusted roles (or even just to user/1). If you discover a module that allows PHP, without appropriate warnings and control, you should avoid using this module, or consider creating a bug report on this module.

Common modules that provide PHP:

  • Drupal core ships with the PHP filter module. Providing this filter will allow injection of PHP into a node body. The PHP will be executed when the node is viewed.
  • Devel module provides an execute PHP block
  • Various CCK fields and options
  • Various Views options, like argument handling
  • Webform

Additionally, if the site allows file uploads or writes incoming user data to the file system an attacker could write a file containing PHP code. The attacker then just needs to be able to execute the file.

Drupal core upload file functionality (upload module in Drupal 6 and any filefield in Drupal 7) helps protect against PHP code execution by limiting the allowed file extensions. By default files ending in .php are not allowed. However, if PHP code is included in a file with a different extension, and the webserver is configured to execute that file as PHP, then an attacker who exploited this misconfiguration could carry out an attack against the server.

Drupal protects against the execution of PHP in the Drupal files directory on Apache webservers using a .htaccess directive that disallows any handlers. This was introduced from DRUPAL-SA-2013-003.

For Drupal to protect against PHP file execution in the Drupal files directory then a .htaccess file needs to exist with the following content and not be writeable by the webserver.

For Drupal 6:

# Turn off all options we don't need.
Options None
Options +FollowSymLinks

# Set the catch-all handler to prevent scripts from being executed.
SetHandler Drupal_Security_Do_Not_Remove_See_SA_2006_006
<Files *>
  # Override the handler again if we're run later in the evaluation list.
  SetHandler Drupal_Security_Do_Not_Remove_See_SA_2013_003
</Files>

# If we know how to do it safely, disable the PHP engine entirely.
<IfModule mod_php5.c>
  php_flag engine off
</IfModule>
# PHP 4, Apache 1.
<IfModule mod_php4.c>
  php_flag engine off
</IfModule>
# PHP 4, Apache 2.
<IfModule sapi_apache2.c>
  php_flag engine off
</IfModule>

For Drupal 7:

# Turn off all options we don't need.
Options None
Options +FollowSymLinks

# Set the catch-all handler to prevent scripts from being executed.
SetHandler Drupal_Security_Do_Not_Remove_See_SA_2006_006
<Files *>
  # Override the handler again if we're run later in the evaluation list.
  SetHandler Drupal_Security_Do_Not_Remove_See_SA_2013_003
</Files>

# If we know how to do it safely, disable the PHP engine entirely.
<IfModule mod_php5.c>
  php_flag engine off
</IfModule>

Special note regarding PHP-FPM

If you run Apache 2.4 but process your PHP requests with PHP-FPM over FastCGI, you may be achieving that with a directive such as this:

ProxyPassMatch ^/(.*\.php(/.*)?)$ "fcgi://127.0.0.1:9000/var/www/drupal"

Avoid doing this. This directive takes precedence over most other ones, and the protections that the .htaccess file in the files directory affords you will largely be nullified.

Instead, try:

<FilesMatch \.php$>
   SetHandler "proxy:fcgi://127.0.0.1:9000"
</FilesMatch>

This functions the same way, but it allows other directives to override the configuration later (such as in .htaccess files).

Gaining access to PHP

Be aware of the following ways that a user might gain access to PHP execution.

  1. Most obviously, user/1 can install PHP modules and then execute PHP - being unrestricted by permissions.
  2. Giving a user Administer Permissions will allow them to give themselves permission to install modules, and so on.
  3. Giving a user Administer Users will allow them to edit user/1, change the email or password, and hence log in as user/1.

A note about "Administer Users"

Many Drupal implementations need to allow a user, for example an office administrator, to be able to create accounts for other users. This is unavoidable for many real-world projects, and also problematic as we have seen it allows those users to become user/1.

You might consider these additional modules to lock down your site against these exploits:

  • User Protect will prevent deletion and editing of various fields.
  • Paranoia mainly blocks PHP filter module from being installed.

Comments

nerdcore’s picture

How can this be accomplished in IIS?

nerdcore’s picture

Oh hey! Seems I patched the answer to my own question. :)

https://www.drupal.org/node/1543392#comment-9710013

rockts’s picture

Don't know how to solve this problem nginx?

dgtlmoon’s picture

Something like the following

	location ~ sites/default/files/.*php {
	    return 403;
        }
reshetov.alexey’s picture

MarkFinance’s picture

I added the code for drupal 7 to the .htaccess file on my local machine and put it at the end of the file. After I pulled the file over to my website, all I now get is a blank white screen. How do I handle this as I am new to Drupal?

bkat’s picture

I know its been a long time since you asked your question but the directives go in the .htaccess file that is in the "files" directory and not in the main .htaccess file. The page isn't very clear on that. Its also a bit out of date, you also need these directives to handle php7 and php8 in addition to the directive that is there for php 5.

<IfModule mod_php7.c>
  php_flag engine off
</IfModule>
# From PHP 8 there is no number in the module name.
<IfModule mod_php.c>
  php_flag engine off
</IfModule>