Spoofing MIME types: Why you can’t trust the type field in $_FILES.

A lot of PHP developers make the mistake of trusting the type field in $_FILES array. It isn’t uncommon to see upload scripts that attempt to validate the file by checking this field.

In this post, I will tell you why this field cannot be trusted. I will also show you a working example of how you can use PHP and cURL to easily spoof the mime type of a file.

What is the “type” field in $_FILES?

The “type” field in the $_FILES array represent the mime type of the file that has been uploaded. A mime type is something that is supposed to describe the file and its structure. For example, if the file is an JPEG image, then the mime type should be “image/jpeg”. If it’s an Excel file, then the mime type will probably be “application/vnd.ms-excel”.

Think of it as a “hint” about the identity of the file.

Why can’t you trust the “type” field?

The problem with the type field in $_FILES is that it from the client. This means that the person who is uploading the file can change it to anything that they want to.

For example: They could change the mime type of a .exe file to “image/jpeg” or they could change a .php file to “text/csv”.

If that happens, your mime type validation check will let the file pass. As a result, an attacker will be free to upload any kind of file that they want to. Even PHP files…

Spoofing MIME types with cURL and PHP.

In a previous post, I wrote a guide on how to upload files with cURL and PHP. Today, I am going to take that code and modify it to spoof the mime type:

In the code above, I am attempting to upload a PHP file with a fake mime type.

On line 12, I instantiated the CURLFile object while setting the second parameter to “image/jpeg”. As a result, cURL will upload my PHP file with the type “image/jpeg”.

A var_dump of the $_FILES array, showing my upload:

Spoofed Mime Type

A screenshot showing the contents of the $_FILES array.

Despite the fact that our uploaded file is clearly a PHP file, the mime type is showing as “image/jpeg”. Fortunately, the PHP upload form script that I wrote actually checks the extension of the file. As a result, it did not get through.

However, when I modified the validation rules on that upload script to only check the mime type, the file got through. And I was able to browse to the uploaded file and execute it:

As you can see, the PHP file was moved to the uploads directory and I was able to run it.

If an attacker can do this on your web server, it is extremely bad news.

Facebook Comments