Friday, April 23, 2010

The Dangers of Internet Explorer Mime-Type Sniffing

Internet explorer 4+ has a unique feature called Mime-Type sniffing. It sometimes doesn't pay attention to the extension of your file, but instead wants to determine what kind of file it is for itself. This can be easily exploited via various sites that allow images to be uploaded and provide links to those images.

If the first few bytes of an image file are changed - say.. after bytes 12, to
<script>alert('bip');</script>
Internet Explorer now thinks this is content type text/html and not image/gif.
So if you were to click on a link to this image you would run whatever script was there in your browser.

Thanksfully, mime type detection for images has been disabled in IE8.
You can also turn off all Mime sniffing by doing:
Response.Headers.Add("X-Content-Type-Options", "nosniff");to get: X-Content-Type-Options: nosniff
to the client browser.

The lesson: never ever ever trust image uploads. You can actually check the mime type yourself upon file upload by using the following:



//goes in the beginning of your class
[DllImport("urlmon.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = false)]
static extern int FindMimeFromData(IntPtr pBC,
[MarshalAs(UnmanagedType.LPWStr)] string pwzUrl,
[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.I1, SizeParamIndex = 3)]
byte[] pBuffer,
int cbSize,
[MarshalAs(UnmanagedType.LPWStr)] string pwzMimeProposed,
int dwMimeFlags,
out IntPtr ppwzMimeOut,
int dwReserved);

//calling code would be like:
string mimeType = GetMimeFromFile(txtFileName.Text);
MessageBox.Show(mimeType);


//method to check would be:


///
/// Ensures that file exists and retrieves the content type
///

///
/// Returns for instance "images/jpeg"
public static string GetMimeFromFile(string file)
{
IntPtr mimeout;
if (!System.IO.File.Exists(file))
throw new FileNotFoundException(file + " not found");

int MaxContent = (int)new FileInfo(file).Length;
if (MaxContent > 4096) MaxContent = 4096;
FileStream fs = File.OpenRead(file);


byte[] buf = new byte[MaxContent];
fs.Read(buf, 0, MaxContent);
fs.Close();
int result = FindMimeFromData(IntPtr.Zero, file, buf, MaxContent, null, 0, out mimeout, 0);

if (result != 0)
throw Marshal.GetExceptionForHR(result);
string mime = Marshal.PtrToStringUni(mimeout);
Marshal.FreeCoTaskMem(mimeout);
return mime;
}


1 comment:

  1. This comment has been removed by a blog administrator.

    ReplyDelete