MIME Types, XSS as a module and XSS as a standard

Hanno Böck
https://hboeck.de/
Twitter: @hanno

ACME http-01 validation

http://example.org/.well-known/acme-challenge/TOKEN1

Response: TOKEN1.TOKEN2

Some implementations reflect TOKEN1, thus this can lead to XSS.

But only if the browser interprets it as HTML.

However, there is an old mod to Apache called Magic MIME that tries to figure out the content-type depending on the first bytes of the response. [...] For example <b> would lead to content type text/html [...]

Wait, what?!?

Apache mod_mime_magic

It's a module that enables XSS attacks.

Apache mod_mime_magic

This module determines the MIME type of files in the same way the Unix file(1) command works: it looks at the first few bytes of the file. (Apache documentation)

mod_mime_magic parser

Parser code is based on an old fork of the "file" utility.

What does that mean?

  • If file extension is in /etc/mime.types use that.
  • Else try to guess MIME type.

Any web application that allows uploading files with an unusual extension not in /etc/mime.types has Cross Site Scripting.

Why?

Upload file containing HTML and Javascript.

Server will guess MIME type (e.g. if it starts with <html>) and send it as text/html.

Can we disable mod_mime_magic?

Only globally, no option to disable it per host or directory (can't be disabled by customers on shared hosting).

But if we disable mod_mime_magic we're good?

Not so fast...

There's still the browser

It can guess MIME types, too!

If file with HTML is sent without a MIME type the browser will render it.

But there's

X-Content-Type-Options: nosniff

So we can disable MIME sniffing in the browser?

Firefox and Edge will render HTML without a MIME type even with "X-Content-Type-Options: nosniff".

What can web applications do?

Only allow file extensions that are in /etc/mime.types

Good luck with that: Every Linux distribution has its own version of mime.types.

What could server administrators do?

Always send a MIME type?

Let's set a safe MIME type (e.g. text/plain or application/octet-stream) for every unknown file extension.

Apache "DefaultType" Directive

Has been removed in Apache 2.4.

WHY???

W3C Standard Authoritative Metadata

Software doesn't have to follow stupid standards

nginx sends application/octet-stream by default.

Vulnerabilities

Mailman / Pipermail

  • Attachments without an extension are saved as .obj
  • .obj is not in mime.types in most distributions
  • Send a mail with an attachment without a filename and with HTML in it -< XSS

Joomla

  • User with file upload permission can upload .xcf file
  • xcf is not in mime.types on Fedora
  • But wait, Joomla thought about this: They sniff the content themselves and block HTML uploads.

Bypassing Joomla

Joomla uses libmagic (through PHP), which has a different HTML sniffing algorithm than browsers and Apache mod_mime_magic.

It's possible to create an HTML file that libmagic won't detect as HTML, but browsers and Apache will.

Wordpress

User with upload permission can upload .3g2 file.

Debian and Ubuntu don't have it in mime.types.

Conclusions

MIME sniffing - server and client side - can easily lead to XSS.

Disable mod_mime_magic. It's inherently bad.

Web application developers have no easy way of avoiding this issue.

W3C standards tell us we shouldn't mitigate this server-side.

"X-Content-Type-Options: nosniff" doesn't help in half of the browsers.

Please set "X-Content-Type-Options: nosniff" anyway, it helps in Chrome, that's better than nothing.

"X-Content-Type-Options: nosniff" standard should be clarified and Firefox and Edge should interpret it more strictly

This is a big mess

I'd like to hear more ideas what to do about it.