How Does It Work?File uploads are allowed by default for users with Author permissions and above. WordPress uses a list of file extensions to determine whether a particular upload should be allowed or not. It has a general set of extensions that are allowed for single-site WordPress installs and a more restrictive set of extensions for multi-site WordPress installations (formerly known as WordPress MU). Individual administrators may also change the allowed extensions using the plugin system. There is no validation to make sure the content of an uploaded file matches its extension.
Due to this behavior, a hostile user can mount an XSS attack using the file upload feature in a number of ways; I’ve provided a list of some possibilities below. In cases where an attack will work on a single-site install, I’ve marked it Single-Site: in cases where an attack will work on a multi-site install, I’ve marked it Multi-Site:
- (Single-Site) WordPress allows files with .htm/.html extensions to be uploaded. This is an obvious XSS vector.
- (Single-Site) WordPress allows files with a .txt extension (and other files that can be served up as text/plain by a web browser) to be uploaded. IE6, IE7, IE8, and Safari will all perform content sniffing on files served up as text/plain (source: http://code.google.com/p/browsersec/wiki/Part2#Survey_of_content_sniffing_behaviors). That means HTML included in those files will be executed in IE and Safari.
- (Single-Site, Multi-Site) WordPress allows files with a .swf extension to be uploaded on single-site installs. In addition, SWF applets can be uploaded to the server using any other file extension. If the file is on the same domain as the WordPress installation, it can make requests back to the WordPress installation without the need for explicit authorization via a crossdomain.xml file.
- (Single-Site, Multi-Site) IE6/7 will sniff for HTML when they encounter “corrupted” images (files served with image/* headers that don’t actually contain valid image data). So, lets say you upload a file with a GIF extension that contains all HTML: WordPress will accept it, the web server will serve it up as image/gif, and IE6/7 will parse the HTML and be vulnerable to an attack.
- (Single-Site, Multi-Site) The configuration of the webserver for certain file extensions may trigger unexpected content-sniffing behaviors in specific browsers. For example, if a file (regardless of extension) gets served up as application/octet-stream, IE, Safari, and Opera will all sniff for HTML (see http://code.google.com/p/browsersec/wiki/Part2#Survey_of_content_sniffing_behaviors).
Where do we go from here?(Solution)There are a couple different workarounds for people who are hosting uploads from the same domain as their WordPress installation:
- Move your uploaded files to a separate domain (or a subdomain)
Thanks to the way browsers handle cross-domain communication, moving uploaded files off of your main domain will prevent them from having access to your WordPress installation, mitigating the impact of this vulnerability. Once you’ve moved your content, you will need to update your WordPress settings.
If you’re considering moving your files to a subdomain, keep in mind that under certain circumstances, different subdomains of the same website may actually be able to communicate (ie: by setting document.domain equal to the same value). If you need to allow that kind of communication with your main domain, host your uploads on an entirely separate domain.
- Disable file uploads
If an attacker can’t upload files, they can’t exploit the vulnerability.