I've created (using a script and some help from Stack and some help from friends; I know very little about PHP) a simple page for a local non-profit publication where people can upload photos.
I'm not great with security (from a basis of ignorance, not deliberate negligence) but I've taken the following steps to protect this page:
• the PHP script is set to only accept .jpg, .png and .tif files for upload;
• the subfolder that it saves the form content to has permissions set at 700, and the subfolder it saves uploaded photos to has permissions set at 700;
• according to documentation, my host has the following configuration to ensure that only .php files run as .php:
<FilesMatch \.php$>
SetHandler php52-fcgi
</FilesMatch>
• I’ve put an .htaccess file in the relevant (main and saved content) folders:
RemoveHandler .php
RemoveHandler .inc
RemoveHandler .pl
RemoveHandler .cgi
RemoveHandler .py
RemoveHandler .fcgi
Overnight, however, somebody found this test page and submitted what seems to be a perfectly benign test message and small .jpg. This is a private test page with a non-intuitive URL that only I and about three other people know about; none of the others sent this test.
This obviously has me worried that there's something hinky going on, and I'm worried that I don't know enough about security to make sure this page is safe.
Is there something obvious that I'm missing?
When dealing with uploaded you should keep in mind that all the data you can find in the $_FILES array can be faked. It's traveling through HTTP so it's pretty easy to give the image/jpg mime to an executable file for exemple.
1- Check the true mime
PHP come with some function to check the real mime of a file. For that you should use fileinfo
$finfo = new finfo(FILEINFO_MIME, "/usr/share/misc/magic");
$filename = "/var/tmp/afile.jpg";
echo $finfo->file($filename);
2- Check the image's properties
You apparently want to upload only image , so the received file must have a width and a height :
Use getImageSize() to get all the required information about the image. If it return false , the file is probably not an image and you can delete it.
getImageSize can also give you a mime type , but i don't know if it can be trusted.
2.5- Reprocess image
As suggested by user628405 , reprocessing the image with GD is probably the more secure thing to do.
$img = imagecreatefrompng('vulnerable.png');
imagepng($img, 'safe.png');
Obviously it has to be adapted according to the image type. See all the imagecreatefrom* in php documentation.
3- Upload folder
In addition of what you have already done :
Make sure your upload folder is not available from the web. Validate the uploaded file then move it to an other folder if needed and rename the file.
It will prevent hacker from executing a malicious file (can't execute it if it can't be reached by an url).
Further reading : https://www.owasp.org/index.php/Unrestricted_File_Upload
Don't rely on any data from the client, including content type!
Don't save uploaded files in the web root. Uploaded files should be only accessible via your scripts, for better control.
Don't save uploaded files with their original file names and extensions! Store this data in a database for retrieval later.
You can check the MIME type of the file, but don't worry as long as your php handler can only execute .php files and you're taking care of not saving uploaded .php files in your script, you're not exposing any security leak.
This is valid for .php files as well as any other server-side scripting language installed on your server of course.
A better idea is to keep a white of the extensions you're accepting to save on your filesystem.
I would ignore the MIME type and the file extension of the incoming file. These can be faked.
Store those files in a directory if you are going down that avenue.
Ensure that that directory is just for images (music) and then get a script to place the correct extension on them by looking at the files format.
Also ensure that that directory cannot execute PHP (or anything else).
This will keep you safe.
Related
I am trying to learn more about file upload in PHP. I faced with a problem.
I read some articles and watch some videos that hacker can attack with double extension however you check the file extension. like
something.php.jpg
How can it be prevented? Thank you in advance!
I have also been interested in this question. I have tested a double extension like something.php.jpg on multiple servers and I am starting to believe that it is not a real security vulnerability unless there is something else set incorrectly on the server. On all the Apache servers I tested it on it did not execute the php code in the file.
Most discussions on php upload vulnerabilities quote from this website: https://www.acunetix.com/websitesecurity/upload-forms-threat/ where the author first quotes from: http://httpd.apache.org/docs/2.4/mod/mod_mime.html#multipleext where it says:
Files can have more than one extension; the order of the extensions is normally irrelevant. For example, if the file welcome.html.fr maps onto content type text/html and language French then the file welcome.fr.html will map onto exactly the same information. If more than one extension is given that maps onto the same type of metadata, then the one to the right will be used, except for languages and content encodings. For example, if .gif maps to the media-type image/gif and .html maps to the media-type text/html, then the file welcome.gif.html will be associated with the media-type text/html.
Then the author of https://www.acunetix.com/websitesecurity/upload-forms-threat/ says:
Therefore, a file named filename.php.123, will be interpreted as a PHP file by Apache HTTP Server, and it will be executed. This of course, will only work if the last extension (in this case .123), is not specified in the list of MIME-types known to the web server...If AddHandler directive is used, all filenames containing the .php extension ( .php, .php.jpg) will be executed as a PHP script.
It seems like this is reverse as to what the Apache docs stated. Please correct me if I am missing something. The Apache docs stated, "welcome.gif.html will be associated with the media-type text/html", therefore I would assume that something.php.jpg would be associated with media-type image/jpeg.
Then the author of the article states that the vulnerability arises if the apache configuation file has this line:
AddHandler php5-script .php
I tried that line as well and the file still did not execute as php. But most AddHandler lines I have seen in the past 10 years are more like this:
AddHandler application/x-httpd-php .html .htm .php
So is the above line not vulnerable to the double extension vulnerability? Or is there particular versions of php or Apache that are vulnerable and certain versions of php or Apache that are not vulnerable?
Of course, I believe that the uploaded file should still have the mime type checked, but I have read that the mime type can be spoofed as well.
User uploads are problematic. There are things you can do to mitigate the risk. For instance, if you intend to allow only image uploads, then you can use the inbuilt mime_content_type() function to ensure that the user is actually uploading a valid image file.
// Let's assume that the name attribute of the file input field you have used is "myfile"
$tempFile = $_FILES['myFile']['tmp_name']; // path of the temp file created by PHP during upload
switch(mime_content_type($tempFile)) {
case "image/jpeg":
// your actions go here...
}
}
else {
echo "This is not a valid image file";
}
Further reading: https://security.stackexchange.com/questions/32852/risks-of-a-php-image-upload-form
I know similar questions have been asked, but none of it guided me to the right solution.
What I want to do
Use .htaccess in a /uploads folder to ensure that only file with appropriate extension can be uploaded. (e.g. jpg, png)
What I have done
modify /etc/httpd/conf/httpd.conf
to allow overwrite of .htaccess file
create .htaccess file in /uploads folder
To test if .htaccess has been read, I have tried to put garbage in .htaccess file and access it from the browser. Corresponding error has been generated, therefore, .htaccess file is working properly.
Problem
The following script has been added to .htaccess
order deny,allow
deny from all
However, I am still able to upload files with any extensions to /uploads folder.
I have tried different suggestions from similar posts with no luck. Looking for new directions from you guys.
Thanks.
The name of the uploaded file is part of the body of the POST request the browser is making to the server, thus the .htaccess rules can't be enforced in your situation. Unless you are using some uploading schema, like creating a placeholder on the server and then submitting the file to that placeholder.
if you are using a GET method with base64 encoded string in your url, you can use .htaccess to redirect to an upload script base on the mime-type of that string. however I guess this is not what you trynna achieve. .htaccess is not appropriate in your case. if you need to control the extension of an uploaded file, you should make the process directly in your uploading script (php, python, whatever).
Suppose that our web-hosting is linux and php is installed:
1- What could be the worst that happens when a php code can be uploaded instead of an image.
2- Can the intruder somehow retrieve my database password ? suppose that the directory on which images get stored has 777 file permissions.
3- What if when the image directory has 644 permission?
The answer to my question can be combined with the ones given to these two: Security: How to validate image file uploads? and Security issues in accepting image uploads
What could be the worst that happens when a php code can be uploaded instead of an image.
Worst case: Intruder can execute arbitrary PHP code, maybe even arbitrary code on the server. If the attacker is clever enough while the sysadmins aren't, he might even own the whole server/subnet/network/...
Can the intruder somehow retrieve my database password ? suppose that the directory on which images get stored has 777 file permissions.
If the attacker can execute PHP code (which of course depends on your security measures), he can definitely read files from the current user, so the answer is most probably yes.
What if when the image directory has 644 permission?
Unless you use PHP in CGI mode, the execute bit shouldn't be necessary for the webserver to execute a script, so that alone doesn't help.
Of course those are not the questions you should ask. The question you should ask is how to prevent an attacker from uploading an executable PHP file in the first place. My answer to that is that you should check the file extension against a white list and drop everything else, for example:
$pattern = "/\.(jpe?g|gif|png)$/iD";
if (!preg_match($pattern, $filename))
die("Please don't.");
You should make sure you don't allow parsing of php files in your image directory, since I'm assuming it's going to be open to the public.
You could do this in the /images/.htaccess file with
RemoveHandler .php .phtml .php3
RemoveType .php .phtml .php3
That way if they try to go to domain.com/images/hackdatabase.php it'll just return their code and not the file.
But you should check to make sure its' an image in the first place.
I'm working on a little project with a few friends, and have set up a pretty simple PHP upload script that only certain users can access. I am not worried about any type of attacks against the server, since this is for fun, but I do have a question.
I've made a subdomain (static.foo.bar) where the uploaded files are moved to. This subdomain had mod_php turned off, to prevent malicious upload and execution of php scripts. The script also checks for file extensions and mime content types, but I assume those can easily be bypassed/spoofed.
However, a user could easily upload an .html file and have it redirect somewhere else. Likewise, they could upload an image file instead and have it display an image in the browser, instead of being asked to download the image.
I assume this is the behavior of the browser, but I've also noticed that when uploading a file to sendspace (or any other service), even if the file is .html (and valid html) it will ask the user to download it instead of displaying it on the website.
I am running Apache on CentOS.
How do I accomplish this?
ForceType is probably what you're looking for.
# In your .htaccess file
<Location /uploads_directory>
ForceType application/octet-stream
</Location>
You want to set all files' mime type to application/octet-stream so the browser will download them instead of trying to show the content.
My ad server has been hacked over the weekend.
It seems to be a widespread problem, according to this article.
There is something in there that got me thinking...
Attackers used one attack to get login
rights to his server, and then
uploaded a maliciously encoded image
that contained a PHP script hidden
inside it, he said. By viewing the
image, attackers forced the script to
execute on the server
How is this possible? Does it rely on the image being opened with GD or similar? Do they upload a script posing as an image, and somehow include it?
It can be as simple as uploading a file like
GIF89a<?php
echo 'hi';
If your upload script tests the content type via fileinfo or mime_content_type() it is recognized as "GIF image data, version 89a" since GIF89a is the only pattern/magic number that is required to identify a file as gif.
And the OpenX upload script apparently kept the proposed filename, i.e. it was possible to save this "image" as foo.php on the server. Now, if you requested that file via http://hostname/uploaddir/foo.php the script was executed as a php script because webservers usually/often determine the content type only by the filename extension, e.g. via
<FilesMatch "\.php$">
SetHandler application/x-httpd-php
</FilesMatch>
php then echoes the leading GIF89a and executes the <?php ...code... block.
Putting the <?php block into a gif comment is slightly more sophisticated but basically the same thing.
Your server is parsing that file for w/e reason. The attackers are putting the PHP into the image comment.
How are you validating the file is an image? If you do it solely on mime type, then I believe they can fake the image header and include whatever they want after that. VolkerK has a practical example
In the perfect world, I wouldn't serve any public facing images via PHP for fear of such an issue.
Serve the image directly using the server; A good suggestion is to save those images to a directory where they can be served without PHP.
I think that's the gist of it, someone correct me if I'm wrong.
The only possibility I see for a server compromise is the image being included instead of read through e.g. readfile and other stream functions.