8

I noticed that it's possible to run a file via PHP even if its extension wasn't .php, for example file test.xyz.php.whatever.zyx can be still run with PHP even when the extension isn't .php! It just happens to have .php. in the filename, and that's enough for my Apache to run the PHP script.

I tried (as someone suggested) to put this in a .htaccess file on that folder:

php_flag engine off

But it didn't work on my machine.

The only solutions I know for now are:

  • Rename to known file extension, which is not run via PHP, such as .txt.
  • Remove all dots from the filename, thus making it extensionless.

But I'm still not sure how these solutions would work on other servers than my Windows server (with Apache).

Is there any other solutions which doesn't need the filenames to be renamed in any way?

Peter O.
  • 32,158
  • 14
  • 82
  • 96
Rookie
  • 4,064
  • 6
  • 54
  • 86
  • renaming files is recommended from a security standpoint. also, check http://stackoverflow.com/questions/3499173/my-php-site-was-hacked-by-codes-uploaded-as-image for why you should also add certain commands to your php.ini file – SeanC Nov 07 '12 at 21:03
  • @SeanCheshire, thanks for the tip. now if i combine it with the findings i told, i bet many more sites will be hackable with it. (too lazy to test myself, also, its illegal;). – Rookie Nov 07 '12 at 21:49
  • not always illegal: http://www.hackthissite.org/ – SeanC Nov 07 '12 at 21:51
  • From what this tells me you haven't got PHP installed as mod_php? – Alfo Jan 02 '13 at 18:15
  • @Alfo, and mod_php is: http://stackoverflow.com/questions/2712825/what-is-mod-php/2712839#2712839 . Edit: i ran phpinfo() and got this `GATEWAY_INTERFACE CGI/1.1 ` damn! which method of running is the best in means of performance / stability? – Rookie Jan 02 '13 at 21:16
  • I would say you want `mod_php`, in my experience it sometimes runs faster. If you changed, the method you mentioned above would start working. – Alfo Jan 02 '13 at 22:28
  • 3
    You probably are interested in how apache handles files with multiple extension which might be related to the issue you have and you can control that, too: http://httpd.apache.org/docs/current/content-negotiation.html – hakre Jan 05 '13 at 20:50

10 Answers10

5

for uploading by users I suggest that you upload a folder in a layer above the root path in this case Only You Have Access To upload folder( In direct addressing) and an attacker have not access to any files in this folder Thus you disable an attacker action to run malicious file

5

To be completely secure, you'll need to do a couple of things:

Set your upload directory above your "public" folder, making it inaccessible from a browser. This setting is in php.ini (php config file). You'll need to restart Apache for this to take effect. On most Redhat / Fedora / CentOS web servers, this can be:

upload_tmp_dir = "/var/tmp/"

OR, on my local Windows 7 WAMP install, it is set to:

upload_tmp_dir = "c:/wamp/tmp"

Disable scripts from running on that directory (c:/wamp/tmp), in .htaccess:

RemoveHandler .php .phtml .php3
RemoveType .php .phtml .php3
php_flag engine off

In your PHP script, get the uploaded file, filter it based on mimetype (not filetype extension), change the filename, and put it into a secured publicly accessible folder. In more detail:

Preferably use an MVC framework, such as Zend Framework, which includes filetype filtering.

If you do all of that, you should be secure. Obviously you'll never be 100% safe, since there are countless obscure exploits targeting PHP, MySQL, the command line, etc, particularly on older systems. On larger company webservers (what I work on), they disable everything, and selectively enable only what is required for the project. With a system such as WAMP, they enable everything, to ease local development.

Good practice for working on a professional project is to get a cloud server account with Rackspace or Amazon, and learn how to configure php.ini, and httpd.conf settings, as well as PHP security best practices. In general, do not trust the users input, expect it to be corrupt / malicious / malformed, and in the end you'll be secure.

Apollo Clark
  • 806
  • 9
  • 16
3

First of all you need to understand what happens here:

test.xyz.php.whatever.zyx

Such a file on a webserver on it's own would do nothing. Only added configuration does tell Apache to execute PHP on that file.

So if you remove that added configuration, Apache won't care to find .php in there - be it at the very end or part of a stacked file-extension.

Check which handler you have set for php in your server configuration. Remove it for the upload directory. This then won't resolve any other configuration issues you might have with uploaded files, however PHP files aren't executed by PHP any longer then - which is what you want if I understood you right.

If you've got a problem to find out what this is about, you need to post your PHP configuration in your httpd.conf file and associated Apache HTTPD configuration files for your system.

The directive somebody told you for .htaccess:

php_flag engine off

does only work if you're running PHP as an apache SAPI module.

hakre
  • 193,403
  • 52
  • 435
  • 836
  • Something came into my mind now: i think the reason for that to work is to allow such files as `funny.php.lib` to be executed too? – Rookie Jan 06 '13 at 10:55
  • 1
    No, that is not the reason. Also to name PHP files in such a way is awful and bad practice. Such file-names need fixing. The reason why Apache does it are more because of [*Content Negotiation*](http://httpd.apache.org/docs/2.2/content-negotiation.html). This is basically all server-configuration, so configure your Apache webserver that way so it does what you want. – hakre Jan 06 '13 at 10:56
1

Instead of php_flag engine off you could remove the handler for PHP files using an .htaccess file for a single directory.

In the directory you are disabling PHP in, your .htaccess should include:

RemoveHandler .php .phtml .php3 .php4 .php5
RemoveType .php .phtml .php3 .php4 .php5

You can likely get away with the below however, depending on which AddHandler types you have configured in your default Apache configuration, which, on windows, should be in C:\Program Files\Apache<version>\conf\httpd.conf

RemoveHandler .php 
RemoveType .php 

You will also need to ensure that in your main apache configuration file, that the directory containing the .htaccess file is in, is covered by a Directory statement which has AllowOverride FileInfo set. You may wish to consider AllowOverride All if you will be using .htaccess files for other purposes - see the Apache documentation for AllowOverride for an explanation of the differences.

  • Thats a big list of types to remove, how do i know which types i should list in there? What does the `AllowOverride FileInfo` actually do? and which one would be better `All` or `FileInfo` ? – Rookie Jan 03 '13 at 18:41
  • Regarding your first question - you should list any types that are registered as handlers for PHP script. This will vary based on your setup. You can check this by examining the main HTTPd (Apache) configuration for existing `AddHandler` lines. Assuming you installed to the standard location, Apache for Windows places this in `C:\Program Files\Apache2.2\conf\httpd.conf`. –  Jan 03 '13 at 20:19
  • Regarding your second question - AllowOverride controls the types of Apache configuration directives you can override using a .htaccess file for a given directory. For security purposes, you should keep this as restricted as possible in a production environment. I've updated my answer with reference to the differences. –  Jan 03 '13 at 20:23
1

Personally, this is the main reason I no longer upload files to the web server under any circumstances. Instead, I use S3 / Amazon SDK to move the uploaded temp file directly to a bucket on S3 with Private permissions (I use S3, any other CDN will work just as well). If the file needs to be viewed or viewed by a web client, I use a "getter" function of sorts that integrates with the SDK to get the file and display it.

There are just so many uncontrollable variables that come into play whenever you allow any kind of file upload to a web server, it can be difficult to manage permissions, filtering, and even just space. With S3 (or any other CDN), that is all very easy to manage, and all files are effectively quarantined from the server by default.

Jonathan Coe
  • 1,485
  • 4
  • 18
  • 36
  • this might not directly help with the question but definitely an alternative worth considering. – Ajowi Aug 09 '20 at 10:21
1

On Apache you could disable all dynamic handlers for the directory that contains the untrusted files.

SetHandler default-handler
Kontrollfreak
  • 1,800
  • 12
  • 24
  • I believe this is the winner.. or could there be anything not so good with this one? – K. Kilian Lindberg Apr 11 '14 at 15:44
  • 1
    @Kilian It depends... If some script engine is not accessed through a handler (e.g. PHP-FPM via [ProxyPass](http://httpd.apache.org/docs/current/mod/mod_proxy.html#proxypass)), it won't help. To be on the safe side, I'd recommend using a [private folder above the document root](http://stackoverflow.com/a/14171951/2032498) or renaming file extensions by using a whitelist (beware of [Apache's multi extension handling](http://httpd.apache.org/docs/current/mod/mod_mime.html#multipleext)). – Kontrollfreak Apr 12 '14 at 09:21
  • Thanks kontrolfreak ^^ for your answer, +1 – K. Kilian Lindberg Apr 13 '14 at 09:49
0

this is not really good answer but hope useful in some special cases ...

you can use mod_rewrite in .htaccess file like this :

RewriteRule ^(.+).xyz.php.whatever.zyx$ index.php?openfile=$1 [NC,L]

and inside your index.php file :

$file = secure_this_string($_GET['openfile']);
include($file.'.xyz.php.whatever.zyx');  # or some other files

remember to see this answer for security reasons StackOverFlow

and in test.xyz.php.whatever.zyx file :

<?php echo 'hello';

now if client requests /test.xyz.php.whatever.zyx file , out put should be 'hello'

Community
  • 1
  • 1
M Rostami
  • 4,035
  • 1
  • 35
  • 39
  • so this works only if the filename is `xyz.php.whatever.zyz` or some other predefined filename? – Rookie Jan 06 '13 at 10:56
  • every thing can be match with this line : ^(.+).xyz.php.whatever.zyx$ and you can change it to other type like this : ^(.+).txt$ – M Rostami Jan 08 '13 at 06:39
0

A simple regex would do the job

<?php
$a = strtolower($_FILES["file"]["name"]);
$replace = array(".php", ".phtml", ".php3", ".php4", ".php5");
$_FILES["file"]["name"] = str_replace($replace, "", $a);
?>

This works fine on any server

kingW3
  • 439
  • 10
  • 20
  • currently i just do `str_replace(".", "-", $basename)`, no need to think all the possible extensions. – Rookie Jan 07 '13 at 15:37
0

I could reproduce your issue quite easily on our server. There is a way to fix this, you need to edit /etc/mime.types and comment out lines

#application/x-httpd-php                                phtml pht php
#application/x-httpd-php-source                 phps
#application/x-httpd-php3                       php3
#application/x-httpd-php3-preprocessed          php3p
#application/x-httpd-php4                       php4
#application/x-httpd-php5                       php5

These lines cause anything with .php in name to be processed. Once you comment out the entries in mime.types, mod_php config in /etc/apache2/mods-enabled/php5.conf has this entry which correctly only processes files ENDING with .php

<FilesMatch "\.ph(p3?|tml)$">
    SetHandler application/x-httpd-php
</FilesMatch>

What is REALLY SCARY is that this is a default config (Ubuntu 10.04 in our case).


EDIT

On Windows the mime.types file should be in apache_home/conf/mime.types

Swav
  • 841
  • 8
  • 24
0

The following .htaccess-code could work and deny access to files containing "php":

<FilesMatch "php">
    Deny from all
</FilesMatch>
Cobra_Fast
  • 15,671
  • 8
  • 57
  • 102