Prevent C99 attacks

Hey,

I recently implemented an image uploader for my website, and a filter that “supposed to” prevent uploading files with different extensions, except .jpg, .jpeg, .gif, and .png. Though even it sounds so smart and useful, people can still upload a modified .txt.png file, paste a php code in it, and hack the server.

Is there any way that might prevent it?

So you only want to allow image files to be uploaded?

One method could be to use the appropriate image loading function, saving the image afterwards. For example, with jpeg and jpg extentions, you can use ImageCreateFromJpeg to create an image resource, then save that image to its final location, perhaps all under the same extension if you wish (may help keep things uniform).

If you do that, then any non-image files would simply fail to create an image, and saving it would have no effect.

Is your server set up so that png files are parsed by PHP, or are you include()'ing those files at any point?

If not, you shouldn’t have to worry. Even if there is PHP in the file, since its not being parsed by the PHP interpreter, it doesnt matter.

I just tried uploading a modified .php.png file, and it has been uploaded, though it couldn’t find it in the folder. I guess the MIME-method


if (
   ($HTTP_POST_FILES['userfile']['type']=="image/gif")   ||         
   ($HTTP_POST_FILES['userfile']['type']=="image/jpg")   ||  
   ($HTTP_POST_FILES['userfile']['type']=="image/bmp")   ||
   ($HTTP_POST_FILES['userfile']['type']=="image/png")   ||
   ($HTTP_POST_FILES['userfile']['type']=="image/jpeg")
)
{

works fine.

You can not rely on ‘type’ in the $_FILES array since its passed by the browser, meaning it can easily be spoofed.

Speaking of $_FILES, you should be using that instead of $HTTP_POST_FILES.

Check the extension, use getimagesize(), and if you feel its necessary check the first few bytes of the file (see [url=http://forums.devshed.com/php-development-5/uploade-file-handling-604502.html]this thread for example).

getimagesize() can also be fooled (just change the first few char of your script with the first few char of an image and upload it…).

To be more “secure”, you can upload the image (in memory), create an image out of it (from jpg, png, whatever was uploaded), and save that image to disk.

If the create image fails, it’s because the user uploaded junk.

Your best bet is to do what Jake said. Re create the image again. If the image is no good it will generate a blank image.

As simshaun mentioned, as long as the server is not set to parse images as PHP this is nothing to worry about.

The only loophole there is in the event you include the image in your script, but if this is done the proper way this again is nothing to worry about.

I.e. as long as said code inside the file is not executed on the server, it is not a problem.

Thanks to all of you. The server is not to parse images as PHP.

Greets and have a beautiful weekend,

Phyxas

read
http://www.scanit.be/uploads/php-file-upload.pdf

One other minor note, you should never take any upload and accept it’s file name. It gives an inappropriate user knowledge of a filename they can attempt to access on your server. That does nothing especially, but it does let someone know details of your server structure that should remain secure. Always change the name of an incoming upload, and when this happens you should specify an appropriate extension which eliminates having files like .php.jpg lying around.

You run the risk with IE7 and below interpreting an image file as a HTML file (or anything else), so it is best if you send this header:

header("Content-Disposition: attachment");

The consequence is that you cannot link directly to images.

If you are not working with images (for future reference), then IE8 and up still suffer from this problem. However, you can send this header:

header("X-Content-Type-Options: nosniff");

Unfortunately, that alone still leaves IE7 and below vulnerable, so for file uploads, you should really always send:

header("Content-Disposition: attachment");

Checking whether a file fits the file format’s spec in full is still intrinsically flawed as far as creating a ‘safe’ file is concerned. With many formats, it is still possible to create fully conforming files containing arbitrary content. Verifying whether the file fits the format and/or recreating the file (i.e. through GD for images) helps mitigate the potential situation where you fail to secure another part of your site from arbitrary file execution, however, but it’s not a silver bullet. Re-creating JPG files also drops their quality.

And changing the variable to “$_FILES” prevents it? :confused:

No. $FILES, a super-global, is just another name for $HTTP_POST_FILES, except $HTTP_POST_FILES (and other $HTTP* variants) were deprecated in PHP 4.1, meaning they will be removed at some point.

$_FILES is the super-global variant of $HTTP_POST_FILES, just as $POST is the super-global variant of $HTTP_POST_VARS, and $GET is for $HTTP_GET_VARS. Take a look at the list on the left side of the manual. Most of the ones that start with $ have a deprecated $HTTP* variant.

You mean “were removed” since that point is now in the past - which is why the now deleted alternative no longer works.

No, I meant deprecated.

http://www.php.net/manual/en/reserved.variables.server.php
http://www.php.net/manual/en/reserved.variables.get.php
http://www.php.net/manual/en/reserved.variables.post.php
http://www.php.net/manual/en/reserved.variables.files.php
http://www.php.net/manual/en/reserved.variables.request.php
http://www.php.net/manual/en/reserved.variables.session.php
http://www.php.net/manual/en/reserved.variables.environment.php
http://www.php.net/manual/en/reserved.variables.cookies.php

4.1.0 - Introduced $* that deprecated $HTTP*_VARS.

And why they may not work:

Thanks for your suggestions and tips on secure image upload.

I’ve recently read about the “MIME-type”, though I have difficulties putting my old code together with the MIME-type, since I’m new to PHP.


<?

$path = "images/";     //Folder where uploaded files go
$max_size = "8000000000000";  // Max size for uploaded files

$filename = $_POST['userfile'];

if (!isset($_FILES['userfile'])) exit;

if (is_uploaded_file($_FILES['userfile']['tmp_name'])) {

if ($T_FILES['userfile']['size']>$max_size) { 
echo "<br><font color='#F4A198' size='2' face='Arial'><b>Fehler</b>: Deine Datei hat die maximale Groesse ($max_size Kb.) ueberschritten.</font>"; 
exit; 
}

if (
   ($_FILES['userfile']['type']=="image/gif")   ||         
   ($_FILES['userfile']['type']=="image/jpg")   ||  
   ($_FILES['userfile']['type']=="image/bmp")   ||
   ($_FILES['userfile']['type']=="image/png")   ||
   ($_FILES['userfile']['type']=="image/jpeg")
)
{

if (file_exists($path . $_FILES['userfile']['name'])) 
{ 
echo ""; 
exit; 
}

     //This line assigns a random number to a variable. You could also use a timestamp here if you prefer.
    $filename = rand () ;

    //This takes the random number (or timestamp) you generated and adds a . on the end, so it is ready of the file extension to be appended.
    $filename2 = $ran.".";

    //This assigns the subdirectory you want to save into... make sure it exists!
    $path = "images/";

    //This combines the directory, the random file name, and the extension
    $path = $path . $filename.$ext; 

$res = copy($_FILES['userfile']['tmp_name'], $path .

$_FILES['userfile']['name']);
if (!$res){ 
echo ""; 
exit; 
} 
else{ 
echo ""; 
}

echo "";
echo "";
echo "";
echo "<font face='Arial' size='2' color='black'><br><a href=$path".$_FILES['userfile']['name']."><img class='imgupls' width='120' height='120' src=$path".$_FILES['userfile']['name']."></a></font><br><br>
      <b>URL</b>: &nbsp;&nbsp;&nbsp;&nbsp;<textarea class='uplOutcome'>http://something.com/$path".$_FILES['userfile']['name']."</textarea><br><br>
      <b>HTML</b>: &nbsp;&nbsp;<textarea class='uplOutcome'>http://something.com/$path".$_FILES['userfile']['name']."</textarea>";
} 
else 
{
echo "<font color='#F4A198' size='2' face='Arial'><b>Fehler</b>: Deine Datei entspricht nicht den hervorgegeben Eigenschaften: (.jpg, .jpeg, .png, .gif + $max_size Kb.)</font>"; 
exit; 
}
}
?>


I’m trying to create an uploader that renames the file into a random number and a name behind it, .extension, and merges it into a gallery of recent uploaded photos. Ahw, I don’t like to ask for coding something for “me”, though the variables confuse me, so does the MIME-type, comparing it to the old type. If someone would like to change the code into the right type, you’re welcome to do that. If you have any “hints” on how to merge the uploaded image into a gallery of recent uploaded photos, please let me, and the audience know.

Thank you very much,

greets,

Phyxas.