When securing image uploads there are basically three approaches I know of (of course, ideally, all three are used):
- check file extension
- store uploaded files in non-executable directory outside the webroot
- 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:
- 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?
- 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?
- If I can't, is there a better approach to check if an image file contains PHP code?
- Is it possibly to bypass the last check - the one resulting in
application/octet-stream
- as well?