1

When securing image uploads there are basically three approaches I know of (of course, ideally, all three are used):

  1. check file extension
  2. store uploaded files in non-executable directory outside the webroot
  3. check content/mime type of the file

For the third point, there are various PHP functions which are suggested, most of which can be bypassed by encoding the code in IDAT chunks. Here are the results I get:

<?php $image = 'imageshell.png';

echo exif_imagetype($image);
// -> 3 (IMAGETYPE_PNG)

echo "<br>" . getimagesize($image)[2];
// -> 3 (IMAGETYPE_PNG)

echo "<br>" . mime_content_type($image);
// -> image/png

echo "<br>" . finfo_file(finfo_open(FILEINFO_MIME_TYPE), $image);
// -> image/png

echo "<br>" . finfo_file(finfo_open(FILEINFO_MIME_TYPE, "/usr/share/misc/magic"), $image);
// -> application/octet-stream

I basically have these questions now:

  1. Why is the result different if I pass a magic file (shouldn't it still accept the file as an image file, as that is what it actually is?), what exactly is a magic file, and what does PHPs inbuilt magic file look like?
  2. Can I check beforehand if the system has a magic file that will result in correctly identifying a non-image or an image which contains PHP code?
  3. If I can't, is there a better approach to check if an image file contains PHP code?
  4. Is it possibly to bypass the last check - the one resulting in application/octet-stream - as well?
tim
  • 29,018
  • 7
  • 95
  • 119

1 Answers1

2

Why is the result different if I pass a magic file (shouldn't it still accept the file as an image file, as that is what it actually is?), what exactly is a magic file, and what does PHPs inbuilt magic file look like?

A magic file is the description of some heuristics to determine the file type. Different results can be caused by different magic files but also different implementations of the heuristic engine.

Can I check beforehand if the system has a magic file that will result in correctly identifying a non-image or an image which contains PHP code?

The various file magic functions are designed to detect the file type only by looking at a few bytes at the beginning. They are not designed to find out if there is PHP code hidden inside the file. It should be possible to create a polyglot document which is both valid PHP and a valid image.

Which means checking the content/mime is not a sufficient validation.

If I can't, is there a better approach to check if an image file contains PHP code?

It's better not to just check but instead to make sure. This can be done by converting the image into a different format and stripping all meta information.

store uploaded files in non-executable directory outside the webroot

That's actually the best way. But make also sure that you cannot be tricked to include the file in another PHP script, i.e. Local File Inclusion.

Steffen Ullrich
  • 184,332
  • 29
  • 363
  • 424
  • 1
    Any POST containing a file to a php script will create a temporary file regardless of whether the php script does anything with the "uploaded" file. So if you have a lfi vuln, persistent storage may not be necessary for exploitation. – wireghoul Feb 22 '16 at 10:10
  • @wireghoul: if the name of the temporary name is predictable you would be right. I hope this is not the case with the PHP upload but I don't know for sure. – Steffen Ullrich Feb 22 '16 at 10:46
  • There are a few tricks that can help mitigate the temporary filename, but it's generally not trivial. – wireghoul Feb 22 '16 at 11:42