Information Security Stack Exchange is a question and answer site for information security professionals. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I'm working in a PHP system where the user can upload files.

I'm trying to protect the system from malicious codes, so I'm thinking about some type of blacklist of files that I've to block from upload.

I know that a Whitelist is better than a Blacklist and this is my common approach, but in this case I need to do a blacklist of files for many reasons (out of my control), but I still looking for safety (if possible).

This is my current script (I'm checking the MIME type to get the file type):

        $finfo = finfo_open(FILEINFO_MIME_TYPE);
        $check= finfo_file($finfo,$file["tmp_name"]);
        finfo_close($finfo);

        $dangerMime = array('application/x-bsh', 'application/x-sh', 'application/x-shar', 'text/x-script.sh');
        if (in_array($check, $dangerMime)) {
            //block upload
        }
        else {
            //allow upload
        }

The current list of MIME types to block is:

  • 'application/x-bsh', 'application/x-sh', 'application/x-shar', 'text/x-script.sh'

I'm trying to block any .sh file, since the system is running in a CentOS under Apache. Are there any other filetype that I also should block?

Following are some importante information:

The Server is a CentOS 7.2 with Apache 2.4.6. Following are the permissions of the uploads directory:

drwxr-xr-x  4 apache apache 4096 Jan  8 12:23 uploads

Note: In this project, I'm acting just as developer, so I can't change the file permissions.

share|improve this question
14  
I guess the best rule is to never execute anything that your users upload. Also add isolation( i.e don't store anything your users upload in "primary server" create another for this purpose only and secure it according, and have your primary server act as a relay to the upload files only) – Freedo Jan 31 at 21:03
11  
Files aren't dangerous. Running commands found in files is dangerous. Any file can contain commands really. Just don't run them and you'll be fine. – PyRulez Jan 31 at 22:29
4  
I really don't comprehend how blocking mime-types of files will stop users uploading malicious files, there simply isn't any solid method to determine if a file is malicious or not. How exactly are these files going to get executed on the server? That's a far more important thing to concentrate on. – Zv_oDD Feb 1 at 2:31
2  
As others have mentioned. This is useless. One can easily open notepad, write a bash script, name it foo.jpg or foo.mp3 and upload it. Filenames have no real meaning on unix except to humans. – slebetman Feb 1 at 4:34
3  
The correct solution is to learn about permission mask (umask) and set it correctly so that users cannot CREATE files with executable bit set (thought they can make them executable later on, still that prevents uploads from being executable) – slebetman Feb 1 at 4:36
up vote 20 down vote accepted

It is not clear from your description why you want block these files exactly. I see the following possibilities:

  • You want to block files that might infect the server itself. Unfortunately this can be about anything: shell, perl, python, awk, ... and of course compiled binaries. But to get these files executed without explicitly calling them with an interpreter the executable bit must be set, which should not be the case if the file gets uploaded from inside a web application. This is at least the case on UNIX systems, because on Windows the extension is enough and there you have also PoweShell, JavaScript, Batch and all the other files. Still, something must at least trigger the execution of the file or have the upload directory in the path for DLL's and shared libraries.
  • Or you want to block files which might be executed by the web server itself, i.e. from inside the web application. These are PHP, ASP, CGI ... files which will be executed via a URL and cause harm for the user or for the server. Of course the only works if your upload directory is reachable by a URL or if the attacker manages to break out of the upload directory with path traversal attacks or similar or if the attacker manages some server side code to include these files (i.e. local file inclusion attack).
  • Or you want to block files which might be included to serve malware to the user, i.e. corrupt PDF documents, javascript redirecting to malware sites. In this case you have probably a upload directory which is reachable by a URL because you want users to download these files. Unfortunately for such files not only the file type you see is important but also the context in which they are called (i.e. as image, script, css, object ...) and you are not able to control this usage.

... but in this case I need to do a blacklist of files for many reasons,

Since you obviously don't know which files can be dangerous at all such kind of blacklist will not work, ever. There will always be file types you miss or the attacker will hide its file behind some other type, i.e. construct a polyglot.

share|improve this answer
    
Indeed, I don't know which file types should I block, but my maind concern is according to your first assumption. I want to protect the server in the first place. In the other hand, I had not thought in the others two scenarios yet...Apparently, my blacklist will fail anyway. – James Jan 31 at 21:17
1  
> because on Windows the extension is enough and there you have also PoweShell, JavaScript, Batch and all the other files -- not quite true. While Windows allows execute by default, you can still explicitly deny execute wherever you want. Heck, you could also remove the default execute, then add it back as traverse applying to folders & subfolders only - which would mimic default *nix behaviour. Basically, whatever traditional Unix permissions can do, NT ACLs (and POSIX ACLs) can do - usually with more granularity. – Bob Feb 1 at 5:11
    
@Bob: thanks for pointing out that you can explicitly set the execute permission on files or folders in Windows - although I still prefer if things are not executable by default. Counting on the user/admin to do this correctly often fails and then leads to all these dll hijacks in download folder. – Steffen Ullrich Feb 1 at 7:04

Don't block any specific MIME types. Block any kind of execution of the uploaded files. A simple way is to store uploaded files outside of the web root and serve them via scripting. If that's not possible, store files in a subdirectory and configure your server not to execute any scripts in that directory. Remember to do this for any scripting language that might possibly be enabled on the server.

If you can't modify the configuration for various reasons, check the file name, and do it properly. PHP strings can contain NULL bytes, filenames cannot, so if an attacker uploads a file called "hack.php\0.jpg", you might view the extension as ".jpg" which is valid, but it would get saved as "hack.php", making you vulnerable again. Check characters in a filename against a whitelist.

share|improve this answer
    
This is the correct solution. Just make sure people cannot upload anything to your webroot (or any folder that contain templates or CGI scripts) – slebetman Feb 1 at 4:38
    
Also, for PHP, CSS, Javascript, XML, HTML and other text-based types, you can use something like: <FilesMatch "\.(?:[pm]?html?|s?php[\ds]?|css|js(?:on)?)$">ForceType text/plain</FilesMatch> on the .htaccess file. – Ismael Miguel Feb 1 at 13:05

Are there any other filetype that I also should block?

It doesn't matter, as finfo_file can be bypassed, see for example here: Encoding Web Shells in PNG IDAT chunks. mime_content_type doesn't seem to be more reliable either.

You need to check for file extension in addition to the mimetype check, as it is a lot more reliable, as file names are a lot less complex than file contents.

An additional mime-type check is still a good idea as defense in depth, to filter out simple attacks. Like you said, a whitelist would be the correct approach, but if you definitely need to go with a blacklist, I would at least add PHP mimetypes to the blocklist:

  • text/php
  • text/x-php
  • application/php
  • application/x-php
  • application/x-httpd-php
  • application/x-httpd-php-source

Additionally, do you really need execution right in the uploads directory? If not, remove it for added security.

share|improve this answer
    
This list seems rather incomplete. What about ASP or CGI files? And all of the others? The problem is that there is no good answer to "What's a secure blacklist?" because, at least in this situation, blacklists aren't secure. – Neil Smithline Jan 31 at 19:48
1  
@NeilSmithline sure, and I did mention that a whitelist should be used (although without special configuration, an attacker should not be able to gain anything by uploading asp or cgi files in the OPs case). I don't think it really matters though, as PHP files can easily bypass a mimetype check, so it's not the correct approach anyways, and should only be done in addition to an extension check (and then a whitelist should be used). – tim Jan 31 at 20:22
    
Thanks for the tip about the execution right. In this project I'm just the developer, so my user can't change, but I'll ask for it changes for the sysadm. – James Jan 31 at 21:34
1  
The file extension is "more reliable"? You're joking, right? It may be reliable in terms of classifying benign files. But in terms of a malicious user, who's deliberately trying to break your security? No. Just no. Putting any stock in the file extension is just asking for trouble. – aroth Feb 1 at 3:24
2  
@aroth well, like I showed, a PHP mimetype check can be bypassed, but executing PHP files with an image extension is quite difficult and requires unsecure code. So if you have a PHP application like the OP, and want to protect the server from code execution, a file extension check would be more reliable (given no other security issues), while a mimetype check would be easily bypassed. Of course, additionally, you should secure the location of the upload (eg no execute right, outside webroot, etc), like I mentioned. – tim Feb 1 at 9:05

I suggest a short-term quarantine of all uploaded files. You can use local systems scanning and AV tools in a temporary jail. This way you could add a routine to scan for malicious files and ignore all the different names of files. This stops the whack-a-mole game.

This would add some latency to the application.

I know this is not a coding solution but it addresses the fundamental flaws with blacklisting and does not force you to adjust the permissions- as you said you do not have control.

I have come across an application that did blacklisting the way you propose. I found it when we were doing the forensic analysis after the adversary had taken control and had been feeding off the corporate assets for nine months. If this is not a good enough reason to stop blacklisting then have fun. whack-whack.

share|improve this answer
    
This is a good approach, but does not address the case where the uploaded file is part of an attack on the uploading server itself. – John Deters Feb 2 at 16:53
2  
And now John and I drift away from this "patch" into a real security architecture. James may never have the ability to suggest or get his people to think about the full scope of a solution. At least we can get him away from his problem and dump the fundamental flaw back on the core team. – D0c0z Feb 2 at 17:58

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.