PHP Inside Image Files

Interesting new hack in the wild – embedding PHP (or other*) code inside an otherwise valid image file. And why would anyone do that? Think of a site that allows users to upload avatars or icons or other images, then displays those images back to the public. If the site isn’t taking sufficient precautions during the upload and display stages, a hacker could create an image file with PHP embedded in the byte stream, then name their file myfile.gif.php. A site that then sloppily displayed whatever images were uploaded to it would then display the image inline, and its embedded code would be executed.

The kicker is that even if your site is doing common checks to verify that it’s dealing with a standard image file, such as running the getimagesize() function on it first, those tests may yield a false positive, since the first n bytes check out just fine. You need to verify the filename extension as well, and not serve images from a directory that’s PHP-interpreted. Other suggestions in the article at PHP Classes.

* There’s no reason this same hack wouldn’t work with .ASP or .NET or ColdFusion sites as well, or with image formats other than GIFs.

Music: Tom Verlaine :: Rings

23 Replies to “PHP Inside Image Files”

  1. Would the standard GD-Lib function to check image types work to secure the hole?

  2. The GD functions can do all sorts of things with images, including scanning image headers, etc, but I don’t think any of them currently in existence have the awareness to read through the whole image file and scan for embedded code. I think the answer really is keep uploaded images outside of a dir capable of interpreting PHP.

  3. I was just wondering if a example.gif.php would return as a gif when you call the image type with GD-Lib :)

  4. The major danger here is in storing files inside the public Web root with an extension the user chooses.

    I expect you could make a completely valid GIF file with code in by using some comments field. You’ll have a hard time finding that by testing for patterns on the file.

    Better is to store it outside the Web root, and serve it back with a simple script that just sends the bytes back. Or, if you must keep it in the Web root, have a strict list of acceptable extensions, and consider restricting the characters in the name portion too (depending on how you are using the names in pages and scripts).

  5. In case anyone is wondering why anyone would allow images to end with a .php extension to begin with, this actually isn’t uncommon from a legit development perspective when generating images from within PHP. For example, if you view source on a page that includes a captcha image, you’ll probably see something like:

    ... img src="captcha.php" ...

    But there’s a big difference between the developer doing this intentionally and allowing strangers to upload images with .php extensions to their site.

  6. I took one of my regular .jpg’s that normally works when uploaded and renamed it to name.jpg.php. When i then tried to upload it and used the

    $_FILES['pictureupload']['type']

    it returned

    application/x-php

  7. Justin – That would have to be test.gif.php, not test.php.gif, and again, this would only work if the site allowed uploading of images with .php extensions, and only if the site stored those images in a php-enabled directory, but yes – this is a pretty wide (and interesting) hole.

  8. If the upload script only checks extension and not mime-type you can write php code in whatever extension you want and execute it — at least I was able to on my test server. I’m sure with some Apache wizardry you can fix that problem, but nevertheless the problem is abundant in publicly accessible image uploading functions.

  9. I don’t follow. While it would be possible to configure apache to parse .gif files for php directives, I think you’d be hard pressed to find any server that actually did that. It certainly won’t out of the box, and no admin would ever set things up that way on purpose. No – you really do have to use image.gif.php, not the other way around. Go ahead and try it on your server – you’ll see that no parsing takes place with a request like /image.php.gif?file=…

    This security hole really only pertains to gif files with a .php extension.

  10. But i suppose if you do allow public uploading of files with a .php extension, you’ve got it comming :) The regular type and extensionschecks should well not close the hole, but block it :)

  11. Agreed! Though I don’t think any common file type checking will find this hole (since they never scan the entire image file), disallowing irregular extensions should be a no-brainer.

  12. I don’t quite get it. Isn’t it enough to just check and allow files with image extensions? I only allow files ending in .gif, .jpg, and .png. Shouldn’t that do it?

  13. Will, yep – That’s the gist of it. But a lot of sites actually don’t. (I’m sure that’ll change quickly).

  14. Yeas ago, circa Netscape 1.2 or 2.0, I encouraged their product manager to allow use of embedded comments in GIF files to allow customized control and animation hooks on GIF files.

    The files specs supported insertion or proprietary code or, and you may recall that GIF animations originally appeared in Netscape only because a programmer implemented part of the GIF89A filepsec that wasn’t commonly used at the time. I thought using programming hooks in file comments would be a simple and easy way to allow more interactivity with states of layered images – the kind of stuff that eventually got done through Flash, Shockwave, and scripts to swap images on rollovers.

    But this was just as the partnership with Macromedia was trumpeted as the first browser plug-in so there didn’t seem to be much interest in encouraging a free or cheap alternative to the pricey toolkit their business partner was hawking.

    Anyway, I’m surprised its taken this long for someone to figure out a hack like this when dropping code in images seemed obvious to me, a non-programmer who curiously read the file specs 12 years ago looking for ways to expand on the animation potential and to control animations and layered images.

    The problem then was getting something to parse the image to get something to run the script. Now it looks like the the opposite problem – getting something to not parse a file automatically.

  15. Mal, very interesting. Makes you wonder whether/how things would have unfolded differently had that capability been there. Or whether it would have unleashed misc. security issues along the way.

  16. Bala Krishna Says:
    > We need to just take care of the extension check as well as the image validity check with available GD function.

    How about also checking that the image size reported in the GIF header matches the file size reported by the OS? If you have a 1×1-pixel GIF with a much-larger file size, then that’s a pretty-big clue something’s up.

    shacker Says:
    > This security hole really only pertains to gif files with a .php extension.

    Then it’s simple: Check the file extension; check the header for filetype; and then flag any mismatch — “Oh, this file has a GIF header, but a PHP extension”.

    I’ve never understood why modern OSes don’t natively check headers on all files, instead of futzing with unreliable half-measures like file extensions and MIME types. It’s not as if code to identify filetypes from their headers doesn’t exist.

  17. Mark, in the case of a server, it would require way too much CPU to try and identify files by examining headers, rather than extensions/mime types. It’s not feasible. And remember, in the case of this exploit, the image header still checks out fine! However, you could certainly do something like this kind of cross-checking just on directories out of which user-submitted images are served.

    Yes, the methods to protect against this one are readily available and not difficult to implement. But a lot of code gets released into the wild for years before anyone even conceptualizes a possible exploit, so the warnings here are directed both at new code and at fixing up old code.

  18. This is exactly the problem i am having. I’ve made this as secure as i possibly can, checking for bad file extensions and mime types on upload, on display checking image validity with GD library and i have disabled php in the folder containing the images.

    If anyone wants to know how php can be disabled in a folder of choice just create a htaccess file in the folder and add “php_flag engine off” into it, works like a charm :)

  19. I’ve disabled all php execution in all image and video storage directories as Rick said above using a .htaccess file. So far so good.

    I’m not trawling through my code to ensure I’m checking everything properly. Better safe than sorry.

    Good blog post, thanks!

Leave a Reply

Your email address will not be published. Required fields are marked *