Home > PHP Security > PHP Upload Security & The 1×1 jpeg Hack

PHP Upload Security & The 1×1 jpeg Hack

Far too often, I’ve seen example PHP code, or live PHP code, where file upload checks exclusively using
$_FILES['userfile']['type'] == ‘image/jpeg’
or
getimagesize($filename)
or
strpos(‘.jpg’, $_FILES['userfile']['name'] or strstr(‘jpg’, $_FILES['userfile']['name']
followed by something like
move_uploaded_file($_FILES['userfile']['tmpname'], PUBLIC_WEB_UPLOAD_DIR.$_FILES['userfile']['name']);
All of these methods leave the server completely vulnerable to remote script uploading and execution with the 1×1 jpeg hack.
 

How this can be exploited
To execute the 1×1 jpeg hack on a PHP server:
Create a 1×1 jpeg
Put the PHP code you want executed on the server in the embedded jpeg header, surrounded by tags
Name your file some_random_name.jpg.php
Tell your browser/os that a .php file is of type image/jpeg.
Upload the file
When that file is uploaded your file against a server that uses the above method(s) as a “security” check to prevent remote file upload & execution it will pass all checks, and will be executed whenever that file is requested by a client browser, whether it’s a direct request in the browser address or an embedded request in a <img> tag.

Why this works
$_FILES['userfile']['type'] comes from the client browser. There is no server-side check to see what type of file it is, there’s no comparison of that file’s extension with the server extension list. It’s simply part of the HTTP header from the browser. By changing the file type association on a client machine that .php files are of type image/jpeg, the browser will upload files with a .php extension with a header type of image/jpeg, passing the first check.
The getimagesize() function will tell you if the uploaded file is a valid image or not. A 1×1 jpeg is a valid image, and could be displayed just fine in a browser. The problem here is what happens when the page is requested by the user. When Apache recieves a request and serves a file, Apache simply looks at the final extension of the file, and decides how to process that file based on that. In all of these cases, $_FILES['userfile']['name'] will be used, and ends with a .php extension. So Apache will process this file as a php file, and run it through the PHP interpreter prior to serving the file, executing the PHP code that was embedded in the jpeg header.

How to secure
The simple fix that works on 99.9% of the servers out there is to manually change the file extension to .jpg, .png, .gif or whatever type it’s supposed to be when the file is moved from the temp directory to the public web directory. A very simple, basic step that is too often overlooked when dealing with upload security. But it’s more effective and less processor intensive than any of the above techniques.
The <0.1% of servers this will not work on are servers that run all files, or image files, through the PHP processor, regardless of extension. Weird, but yes, they are out there. On these servers, to prevent image header script execution, the GD (or Imagemagick) library should be used to recreate the image, and that new file should be saved. This will wipe the image headers, and any embedded code present.
There are more steps that can, and should be taken when dealing with file uploads, such as not putting them directly into a public web folder in the first place, but rather make a link to a file handler. There’s a whole new set of secure issues with that method for a later post, but done right, it is more effective. But by taking the simple precautions listed here, it will security the majority of sites and servers from most upload attacks.

Categories: PHP Security
  1. May 15th, 2009 at 18:42 | #1

    I actually considered doing this – renaming, reprocessing the image and appending a new extension. I was not, however, aware of this attack – or of the fix. Thanks for this article! Keep it up! I’m enjoying very much the security and optimization focus of your first few entries. And as promised, I’m subscribing!

  2. Nikos
    December 12th, 2010 at 02:02 | #2

    This handles nicely that php code will not be executed. how about xss?

  3. January 6th, 2011 at 11:04 | #3

    Never even gave that a thought…naively thought mime types could be relied on….now changing my image upload class. There must be a hell of a lot of unsecured upload scripts out there!

  4. Makavillian
    February 22nd, 2011 at 12:14 | #4

    Great post, I wasn’t aware of this either.

  5. Johnd446
    June 27th, 2014 at 10:20 | #5

    Awesome article post.Thanks Again. Much obliged. kgbdadbekeed

  1. No trackbacks yet.