An Easy Way to Mess Up File Type Verification
Recently I wanted to try my skills at code review. Fortunately, there’s lots of open source code out there just looking for some new contributor to find bugs. Rather than go after WordPress, Joomla, or one of the other common targets I decided to go for something less popular without being totally obscure. In the end the magic selection dart landed on a web based project management application called Collabtive.
In general Collabtive has a good security track record. Variables in SQL statements are properly sanitized, session IDs are checked nearly everywhere, and it is obvious that thought was given to good security practices. However, there was one small mistake and one feature with unintended consequences that combined to produce a significant vulnerability.
The mistake is an oldie, but not so common as to be on the OWASP top 10. Simply put, the file type check in the avatar image upload feature can be bypassed which allows a malicious user to upload any file, including a script based shell and then execute it as the web user.
The code involved is found in the manageuser.php file, lines 204 and 217:
$typ = $_FILES['userfile']['type']; ... if ($typ != "image/jpeg" and $typ != "image/png" and $typ != "image/gif" and $typ != "image/pjpeg") // if the type is one of the types listed above abort the upload // otherwise continue.
Seems like a good test, but the trouble comes from how they are using the PHP provided
$_FILES['userfile']['type'] variable. Referring to the PHP documentation, and scrolling down to the notes on ‘type’ we see:
The mime type of the file, if the browser provided this information. An example would be "image/gif". This mime type is however not checked on the PHP side and therefore don't take its value for granted.
Collabtive unfortunately takes that value for granted here. One way for a malicious user to take advantage of the fact is to write a script that creates the POST request manually and forces an ‘image/xxxx’ mime type label to be provided for a malicious script payload. Since I’m more interested in proof of concept than automation, I’ll opt for a second method and use my favorite intercepting proxy to change it at submit time.
Below is the image of the post request that is submitted when a new user avatar image is uploaded to Collabtive. Instead of an image, I’m uploading a php script and then modifying the mime type to hide the fact. In this case I’m using a harmless phpinfo script, but a malicious user would choose a web shell or any other custom script.
Once uploaded, a random number is appended to the script name (before the extension) and the file is placed in a world readable directory “[collabtive root]/files/standard/avatar”. Since the avatar image is displayed many places, a quick view of the source or “page info” will show you the URL to the file.
If the web admin has been extremely conscientious and disabled script execution from the “files” directory tree or at least to this directory then a malicious user could be foiled. That could be done through the .htaccess file for Apache or similar web servers.
Sample contents of the .htaccess file are:
Options -Indexes Options -ExecCGI AddHandler cgi-script .php .php3 .php4 .phtml .pl .py .jsp .asp .htm .shtml .sh .cgi
Note ‘AllowOverride Options AddHandler’ or ‘AllowOverride All’ must be enabled in the main httpd.conf file for this directory or inherited from a parent directory. See http://www.mysql-apache-php.com/fileupload-security.htm for more information.
The manageuser.php script requires a valid session ID to execute it, which essentially limits exploitation to people who already have valid user credentials. However, the way Collabtive has structured their OpenID support gives an attacker the foothold they need. This is not a frequently used feature as evidenced by the lack of support for the current version of the OpenID protocol (2.0). However, when a valid OpenID 1.0 URL is provided as the userid on the login pgae, Collabtive will check for an existing user with that URL and if none exists, will automatically create a new one. This new user will not have access to any projects or project files, but they will be able to access their own user settings page and upload an avatar image which gives them the ability to exploit the previous vulnerability.
The combination of these two flaws allows a remote attacker to gain web-shell access to most servers hosting Collabtive versions less than 0.7.6. Since the database credentials would be visible via that shell, database exploitation is almost guaranteed. User information as well as all project files would be exposed in addition to giving the attacker a foothold to launch further attacks.
The Collabtive team was notified of the issue on April 18, 2012 and had committed patches for these vulnerabilities the next day. There were some unrelated delays in the next official release (0.7.6) which was not published until May 30, 2012.