In this blog post I will describe how we turned uploading a .zip file into a Cross-Site Scripting (XSS) attack during a penetration test on a customer’s web application, by leveraging a feature of Internet Explorer (IE) called MIME Sniffing. Before I go into the details of this attack, let’s start by looking at the background of this feature.
Files that are served by a web server are handled by your browser. How your browser handles a file depends on the type of file that is served. For example, images are handled differently than text files. In most cases the web server specifies the correct type of file by means of the Content-Type header. However, certain (legacy) web servers specify an incorrect Content-Type. For compatibility reasons, Microsoft has a feature for Internet Explorer that attempts to determine the correct content type, regardless of what is specified by the web server. This feature is known as MIME Sniffing. One of the steps of this feature is that it compares the first 256 bytes of a file to a list of known file headers. While this feature allows users to browse the web more successfully, it also introduces an attack vector.
The old vulnerability
Several of these security issues have been described in the past, with the main focus on web applications that allow users to upload images. The algorithm for MIME Sniffing works in such a way that it tends to think it knows best. For example, when a web application allows users to upload an image and only checks the file extension, the user can upload an image.jpg that actually contains HTML code. Older versions of Internet Explorer (especially versions 6 and 7) then render the file as HTML, which opened the possibility for a persistent Cross-Site Scripting (XSS) attack. The responsibility for such an attack lies with both the web application developer and with Microsoft as vendor of the browser. Several bugs have been found and fixed within web applications and within PHP that are related to MIME Sniffing.
It is applaudable that Microsoft developed protection mechanisms for IE8 (and above) for these kinds of security risks, such as preventing “upsniff”:
First, IE8 prevents “upsniff” of files served with image/* content types into HTML/Script. Even if a file contains script, if the server declares that it is an image, IE will not run the embedded script. This change mitigates the picture-sharing attack vector– with no code changes on the part of the server. We were able to make this change by default with minimal compatibility impact because servers rarely knowingly send HTML or script with an image/* content type.
Other new security features came in the form of support for new HTTP response headers:
X-Download-Options: noopen Content-Disposition: attachment; filename=untrustedfile.html
The nosniff header allows a web server to force the browser into disabling MIME Sniffing for the served file. The Content-Disposition header forces the browser to present the user with a file save dialog. When the noopen header is set, the user cannot open the file directly. The user is forced to save the file locally first, which prevents the file from being rendered in the current browser context.
The vulnerable web application
There are still some scenarios that allow for exploitation of MIME Sniffing. Let’s get back to the customer’s web application that we tested. The application was hosted on a Microsoft IIS server. It allowed users to upload files and was initially protected by a blacklist to prevent users from uploading potentially dangerous files, such as .asp files, that can result in unauthorized remote code execution. We were able to upload HTML files, which allowed for Cross-Site Scripting attacks.
We advised the following improvements to our customer:
- Use a whitelist instead of a blacklist method, to ensure that only a limited amount of file extensions are allowed;
- Store uploaded files outside the web root and use a secure download script that loads these files from disk and presents their contents to the user;
- Use non-predictable filenames and change the file extension.
It is not strictly necessary to apply all of the measures mentioned above to prevent this type of attack. However, the combination of these measures may very well also offer protection against other scenarios. In this case only the first measure was applied by our customer; implementing a whitelist. The web application now allows users to upload a limited set of file extensions, such as the images types .jpg and .gif, but also a number of extensions that might be considered relatively safe, such as .zip and.csv files. This could introduce certain vulnerabilities relating to the way that the web application handles these files, but in this case we will focus on a simple scenario: a user can upload files, other users can then view or download these files.
The new vulnerability
If the “suggested” (server-provided) MIME type is unknown (not known and not ambiguous), FindMimeFromData immediately returns this MIME type as the final determination.
The application/zip header that Apache presents to the browser is unknown to Internet Explorer, while the application/x-zip-compressed header of IIS leads the algorithm to step 2:
If the server-provided MIME type is either known or ambiguous, the buffer is scanned in an attempt to verify or obtain a MIME type from the actual content. If a positive match is found (one of the hard-coded tests succeeded), this MIME type is immediately returned as the final determination, overriding the server-provided MIME type
An example of a server-provided MIME type that is ambiguous is application/octet-stream, which we get when uploading a .csv file to our IIS web server.
As a result, the web application still left users of Internet Explorer vulnerable to persistent XSS attacks, by allowing a .csv file or a .zip file to be uploaded. This is a vulnerability that can be fixed or mitigated in the web application code, in the web server configuration and in the browser.
In regard to our customer’s web application, our initial recommendation still stands. Saving user-uploaded files outside the web root, randomizing file names and changing file extensions will prevent this type of attack. A quick workaround is to set the web server to add the MIME sniffing opt-out header:
This can be combined with the Content-Disposition: Attachment and X-Download-Options: noopen headers. Note however that nosniff doesn’t seem to be supported by IE7, so that probably leaves IE6 and IE7 vulnerable to this type of attack. I know these are relatively old browsers, but I also know they are still more frequently used than one would want them to be.
End users and system administrators can choose to disable MIME Sniffing in Internet Explorer altogether. Please note that the High security level of Internet Explorer already has this feature disabled. With MIME Sniffing disabled users who access a fake .zip file will be presented with the file save dialog.
In my opinion, the default MIME Sniffing behavior of Internet Explorer should not allow for this type of attack. From a security perspective, you do not want MIME Sniffing to overrule the content type that is provided by the server with unsafe content types, in this case text/html. In the same way that image types are no longer vulnerable to this kind of attack, other file types should also be handled in a more secure manner. I have reported this issue to Microsoft, they researched it and engaged in a constructive debate. However, Microsoft ultimately considers this behavior by design. They stated that web applications should safeguard file uploads and web servers can be set to add protective headers to the HTTP response.
As an obvious disclaimer: all changes to web applications, web servers or browsers should be tested before they are used in production. To summarize the primary recommendations per role:
Familiarize yourself with the risks of file uploads, implement safeguards and add relevant HTTP headers for uploaded files if necessary.
Web server administrators
Add the X-Content-Type-Options: nosniff header to your web server. This also applies to web servers other then Microsoft IIS.
System administrators and end users
Disable MIME Sniffing in Internet Explorer and/or set the security level to High. For IE9 MIME Sniffing can disabled at the following location:
Internet Options -> Security -> Custom level -> Miscellaneous -> Enable MIME Sniffing -> Disable
While testing file uploads in web applications, attempt to upload HTML code in files with different extensions and don’t forget to perform these tests using different browsers.
Please change the default MIME Sniffing behavior of Internet Explorer and refrain from handling files as HTML when the web server says otherwise. At least prevent this from happening for most ‘known file types’ and most ‘ambiguous file types’.
- Risky sniffing by Henry Sudhof
- OWASP: Cross-Site Scripting (XSS)
- “MIME/Content-Type-Sniffing” Issues in Image Uploads in Forum Scripts by Jacques Copeau
- PHP: XSS: incorrect mime type for bmp in getimagesize/image_type_to_mime_type()
- IE8 Security Part V: Comprehensive Protection
- MIME Type Detection in Internet Explorer
- OWASP: Unrestricted File Upload
Post written by Daniel Niggebrugge, Senior Security Expert at Fox-IT.