Hanno Böck
XSS means an attacker is able to get a victim to execute attacker-controlled Javascript in the origin of a thirdparty web page
In the web Javascript always comes via HTML
<h1>Hello World</h1>
<p><?php echo $_GET['var1']; ?></p>
Usually we have an existing HTML document that dynamically includes data that we can control
But there's another way:
If we can convince the server to deliver a whole HTML document we also have XSS
File Upload XSS
How does a browser decide what's an HTML document?
Dangerous | Safe (usually) |
text/html text/xml application/xml |
text/plain image/jpg application/octet-stream bogus/contenttype |
Let's look at an attack
http://example.org/.well-known/acme-challenge/TOKEN1
Response: TOKEN1.TOKEN2
Some implementations reflect TOKEN1:
http://example.org/.well-known/acme-challenge/[anything]
Response: [anything].TOKEN2
This looks like a classic reflected XSS, except...
this is not an HTML document
This does not sound good
There are probably more problems with that
It's a module that enables XSS attacks by introducing MIME Sniffing on the server
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.
Parser code is based on an old fork of the "file" utility
Some 90s style C code is parsing files
Probably...
(the code is not testing friendly)
If we have...
we have XSS, because we can upload HTML and mod_mime_magic will autodetect it and set the Content-Type accordingly
text/html htm html shtml
image/jpeg jpe jpeg jpg
model/iges iges igs
Not standardized at all, every operating system and every Linux distribution maintains its own variation
This mod_mime_magic is dangerous, probably we should just disable it
Good idea, as long as you're not using shared hosting
mod_mime_magic can't be disabled via .htaccess or per virtual host, only for the whole Apache httpd server
But if we disable it server-wide we're good, right?
Not so fast...
What happens if the web server can't identify the MIME type?
It just won't send a Content-Type header
If you send a browser an HTML document without a Content-Type header it will render it
Same attack works just as well without mod_mime_magic
But there's a security header to save us:
X-Content-Type-Options: nosniff
The X-Content-Type-Options response HTTP header is a marker used by the server to indicate that the MIME types advertised in the Content-Type headers should not be changed and be followed. This allows to opt-out of MIME type sniffing, or, in other words, it is a way to say that the webmasters knew what they were doing.
So we can set X-Content-Type-Options: nosniff and we're safe from these attacks
Not so fast...
You have to read the fine print
Note: nosniff only applies to "script" and "style" types. Also applying nosniff to images turned out to be incompatible with existing web sites.
X-Content-Type-Options: nosniff applies to script and style files, it explicitly doesn't apply to images, but it says nothing about direct navigation
Chrome: Will display text
Safari: Will download file
Firefox and Edge: Will sniff the MIME type and render HTML
In both Firefox and Edge HTML will be sniffed despite X-Content-Type-Options:nosniff
Mozilla accepts that this is a bug and should be fixed in Firefox, but it hasn't happened yet
We have completed our investigation, and the behavior that you reported has minimal impact and therefore does not meet our bar for servicing at this time.
If a web application
we have XSS
A user with an "Author" role can upload media files
$misc_exts = array(
// Images.
'jpg', 'jpeg', 'png', 'gif',
// Video.
'mov', 'avi', 'mpg', '3gp', '3g2',
// "audio".
'midi', 'mid',
// Miscellaneous.
'pdf', 'doc', 'ppt', 'odt', 'pptx',
'docx', 'pps', 'ppsx', 'xls',
'xlsx', 'key',
);
Not in /etc/mime.types on Debian/Ubuntu systems
Wordpress will try to detect the MIME type (with PHP's libmagic bindings) and will not accept the file if it doesn't match, but it will accept the file if the MIME type can't be detected
We need a file that libmagic won't identify as any valid file type, but the browser will identify it as HTML
Mailman 2.x comes with a tool called Pipermail to create mailing list archives
An attachment with an unknown extension or no extension will be renamed to attachment.obj
Mailman tries to detect HTML, but the same bypass works:
<img src=x onerror=alert(1)><!---[+ binary garbage]Not in mime.types in Fedora, Redhat, Suse, Ubuntu, Debian, ...
Only Gentoo knows it (it's a tgif file)
XSS for almost all Mailman mailing lists with a public archive
Mailman changed the default extension from .obj to .bin, which is served as application/octet-stream by all major Linux distributions, but the fix hasn't been released yet
Let's set a safe MIME type (e.g. text/plain or application/octet-stream) for every unknown file extension
Has been removed in Apache 2.4
A standard to enable Cross Site Scripting.
Setting a default MIME type would prevent these attacks, but people writing standards really don't like it
nginx sends application/octet-stream by default
Web servers usually decide based on the file extension which MIME type to use
if ((pathinfo($_FILES['up']['name'], PATHINFO_EXTENSION) == 'jpg') ||
(pathinfo($_FILES['up']['name'], PATHINFO_EXTENSION) == 'png') ||
(pathinfo($_FILES['up']['name'], PATHINFO_EXTENSION) == 'gif')) {
die("Error: Only images allowed!)";
} else {
// copy uploaded file to upload dir
[...]
}
Is this code safe from XSS?
What's the file extension?
PHP and Apache disagree
/* [...]
* Leading dots are considered to be part of the base name (a file named
* ".png" is likely not a png file but just a hidden file called png).
*/
PHP's pathinfo() function returns "jpg", but Apache will serve it without a mime type
A file named ".jpg" (or .[extension]) will pass a check on the file extension in PHP, but Apache will serve it without a MIME type, leading to XSS
Languages | empty | .jpg |
PHP | - | ✓ |
Ruby | ✓ | - |
Python | ✓ | - |
Web servers | empty | .jpg |
Apache | ✓ | - |
Nginx | - | ✓ |
Caddy | ✓ | - |
Can we get MIME Sniffing if the server sends a file with a non-HTML MIME type like text/plain?
Internet Explorer supports displaying HTML emails in .eml format (RFC 822)
TESTEML
Content-Type: text/html
Iframes within .eml files ignore the Content-Type and will be MIME-sniffed
This blogpost is from 2017 and it works in the latest version of Internet Explorer 11
Internet Explorer 11 is the last version of Internet Explorer, and will continue to receive security updates, compatibility fixes, and technical support on Windows 7, Windows 8.1, and Windows 10.
I don't think that's true
Browsers will send a MIME type with file uploads
Obviously this is user-supplied data and can't be trusted
It's possible that this allows attacks if a web application trusts the supplied MIME type
Caddy does MIME Sniffing by default, it can't be switched off
Caddy developer told me they just use Go's functionality
Please fix X-Content-Type-Options:nosniff
Make a long term plan plan to deprecate MIME sniffing
Don't do server side MIME sniffing
Disable mod_mime_magic
Consider adding additional file types (.3g2, .obj, .fla, .xcf) to /etc/mime.types
Please standardize /etc/mime.types across distributions and operating systems
The safest option is a sandbox domain for file uploads, but it's often impractical
Always set X-Content-Type-Options: nosniff
(even though it's imperfect)
If you support any unusual file types consider forcing the MIME type
Reject file uploads starting with a dot
MIME Sniffing is dangerous and needs to go away
Any questions?