Unpatched High-Severity Vulnerability in Widget Settings Importer/Exporter Plugin

On March 12, 2020, our Threat Intelligence team discovered a stored Cross-Site Scripting (XSS) vulnerability in Widget Settings Importer/Exporter, a WordPress plugin with over 40,000 installations. This flaw allowed an authenticated attacker with minimal, subscriber-level permissions to import and activate custom widgets containing arbitrary JavaScript into a site with the plugin installed.

We reached out to the plugin vendor the same day, March 12, 2020, but have not yet received a response. On March 20, 2020, we reached out to the WordPress plugin team and sent them the full disclosure of the vulnerability, and after following up with them on April 13, 2020, the plugin has been removed from the WordPress repository. As there is no patch currently available, we highly recommend deactivating and removing this plugin.

Wordfence Premium users received a new firewall rule on March 12, 2020 to protect against exploits targeting these vulnerabilities. Free Wordfence users received this rule on April 11, 2020.


Description: Authenticated Stored Cross-Site Scripting(XSS)
Affected Plugin: Widget Settings Importer/Exporter
Plugin Slug: widget-settings-importexport
Affected Versions: <=1.5.3
CVE ID: Pending
CVSS Score: 7.4 (high)
CVSS Vector: CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:L
Fully Patched Version: N/A

Widget Settings Importer/Exporter is a WordPress plugin that offers the ability to import and export WordPress Widgets – a WordPress feature that adds functionality to a site’s header, sidebars and footer. The plugin registers an AJAX action that is used to perform widget import:

add_action( 'wp_ajax_import_widget_data', array( __CLASS__, 'ajax_import_widget_data' ) );

As is the case with many similar vulnerabilities, the function called by the AJAX action fails to use capability checks or nonce checks. This means that any authenticated user, regardless of their permissions, can use it to import widgets into the site, including widgets containing malicious JavaScript, which would be executed in the browser of any visitor to the site.

Specifically, the ajax_import_widget_data function obtains the widget data to be imported by calling file_get_contents on the supplied import_file parameter. Most sites are configured with a setting, allow_url_fopen, that allows this function to get the contents of a remotely hosted file. This makes it possible for an attacker to import a malicious widget to the site by sending a $_POST request to wp-admin/admin-ajax.php with the action parameter set to import_widget_data, the import_file parameter set to the URL of a crafted, remotely hosted JSON file, and the widgets parameter set to describe the widget to be imported.

If the clear_current parameter is set, any currently active widgets on the site would also be removed. If the imported widget contains malicious JavaScript, it could be used to redirect site visitors to malvertising sites, or even to steal an administrator’s session, potentially leading to site takeover.

The vulnerable function:

   public static function ajax_import_widget_data() {
       $response = array(
           'what' => 'widget_import_export',
           'action' => 'import_submit'
       );

       $widgets = isset( $_POST['widgets'] ) ? $_POST['widgets'] : false;
       $import_file = isset( $_POST['import_file'] ) ? $_POST['import_file'] : false;

       if( empty($widgets) || empty($import_file) ){
           $response['id'] = new WP_Error('import_widget_data', 'No widget data posted to import');
           $response = new WP_Ajax_Response( $response );
           $response->send();
       }

       $clear_current = isset( $_POST['clear_current'] );

       if ( $clear_current )
           self::clear_widgets();

       $json_data = file_get_contents( $import_file );
       $json_data = json_decode( $json_data, true );
       $sidebar_data = $json_data[0];
       $widget_data = $json_data[1];
       foreach ( $sidebar_data as $title => $sidebar ) {
           $count = count( $sidebar );
           for ( $i = 0; $i < $count; $i++ ) {
               $widget = array( );
               $widget['type'] = trim( substr( $sidebar[$i], 0, strrpos( $sidebar[$i], '-' ) ) );
               $widget['type-index'] = trim( substr( $sidebar[$i], strrpos( $sidebar[$i], '-' ) + 1 ) );
               if ( !isset( $widgets[$widget['type']][$widget['type-index']] ) ) {
                   unset( $sidebar_data[$title][$i] );
               }
           }
           $sidebar_data[$title] = array_values( $sidebar_data[$title] );
       }

       foreach ( $widgets as $widget_title => $widget_value ) {
           foreach ( $widget_value as $widget_key => $widget_value ) {
               $widgets[$widget_title][$widget_key] = $widget_data[$widget_title][$widget_key];
           }
       }

       $sidebar_data = array( array_filter( $sidebar_data ), $widgets );
       $response['id'] = ( self::parse_import_data( $sidebar_data ) ) ? true : new WP_Error( 'widget_import_submit', 'Unknown Error' );

       $response = new WP_Ajax_Response( $response );
       $response->send();
   }

What Should I Do?

It is likely that this plugin will not be patched, so we strongly recommend deactivating and removing this plugin from your site. Plugins with similar functionality, such as Widget Importer & Exporter, are available and should be reasonably safe, though it should be considered best practice to deactivate and remove any plugins that are not actively in use.

Disclosure Timeline

March 12, 2020 – Vulnerability initially discovered and analyzed. Firewall rule released for Wordfence Premium users. Initial outreach to plugin vendor.
March 20, 2020 – We reach out to the WordPress plugins team and provide them with full disclosure.
April 11, 2020 – Wordfence free users receive firewall rule.
April 13, 2020 – We follow up with the WordPress plugins team and the plugin is removed from the WordPress repository.
April 15, 2020 – Vulnerability disclosed after more than 30 days with no response from plugin vendor.

Conclusion

In today’s post, we detailed a stored Cross-Site Scripting (XSS) vulnerability in the Widget Settings Importer/Exporter WordPress plugin. These flaws have not yet been patched, so we recommend that users deactivate and delete this plugin immediately until a patch is made available. Sites running Wordfence Premium have been protected from attacks against this vulnerability since March 12, 2020. Sites running the free version of Wordfence received a firewall rule update on April 11, 2020.

This article was written by Ramuel Gall, a former Wordfence Senior Security Researcher.

Did you enjoy this post? Share it!

Comments

2 Comments
  • Thankfully my sites aren't affected by this vunerability, but I've been wondering how the firewall rules are rolled out? With the latest free version 7.4.6 being rolled out in February, and now we're in April, are the firewall rules updated automatically without a change in Wordfence version?

    • Hi Nicola!

      The Wordfence plugin actually fetches Firewall rules directly from our servers without needing to be updated. Sites running the premium version of Wordfence automatically check for and receive updates twice a day, while sites running the free version of Wordfence automatically check for and receive updates once a week. It is also possibly to manually update firewall rules, though sites running the free version of Wordfence will still only receive rules that have been released for more than 30 days. Even with firewall rules in place, the most effective way to keep your site safe is to remove or upgrade vulnerable plugins.