WordPress KingComposer Page Builder fixed multiple critical vulnerabilities.

The WordPress KingComposer Page Builder plugin (100,000+ active installations), fixed multiple critical vulnerabilities affecting version 2.9.2 and below that could lead to authenticated WordPress options change, content injection, stored XSS, arbitrary file deletion and remote code execution among other issues.

Broken Access Control

KingComposer is enabled by default for pages and has an option for posts as well in the ‘Generics Settings’ page:

When enabled, it leaks an important security nonce in the source of the ‘/wp-admin/index.php’ main page, accessible to any logged-in user:

The nonce is populated in the ‘kingcomposer/includes/kc.widgets.php’ script via the widgets_init hook and is the only security check used by many of the 30+ AJAX actions found in the ‘kingcomposer/includes/kc.ajax.php’ script.

Any authenticated user, including a subscriber, can perform several critical actions.

1. WordPress Options Change

The kc_update_option AJAX action can allow an authenticated attacker to modify any WordPress option in the options table of the database:

public function update_option(){

   check_ajax_referer( 'kc-nonce', 'security' );

   $data = json_decode(base64_decode($_POST['options']), true);

   if( count( $data ) >0 ){
      foreach( $data as $k => $v ){
         echo $k;
         if( !empty( $k ))
            update_option( $k, $v );
      }
   }
   ...
   ...

It is possible to enable registration (users_can_register) and to set the user default role to administrator, so that the user can register an admin account, or modify the value of siteurl in order to redirect all traffic to an external malicious website.

2. Arbitrary files/folders deletion

The kc_installed_extensions action AJAX is used to install extensions, but because it doesn’t properly validate paths, an attacker can recursively delete any folders and files, for instance by sending a name=../../../wp-admin/ POST request to delete the content of the ‘/wp-admin/’ folder.

3. Content Injection

The kc_push_section action AJAX can be used by the attacker to modify the content of any page or post on the website. The new content can either replace the existing one ($_POST['overwrite']) or be appended to it.

Several additional AJAX actions can be exploited too, for instance kc_load_section that could let an attacker view any page or post, even if they are private or password-protected.

Stored XSS via shortcode

In ‘/kingcomposer/kingcomposer.php’, several shortcode filters are registered:

public function init(){
   ...
   ...
   /*
   *   Register shortcode filters
   */

   $core_filters = apply_filters(
      'kc-core-shortcode-filters',
      array(
         'row',
         'row_inner',
         'column',
         'tabs',
         'tab',
         'box',
         'video_play',
         'counter_box',
         'carousel_images',
         'twitter_feed',
         'feature_box',
         'pie_chart',
         'carousel_post',
         'image_gallery',
         'blog_posts'
      )
   );

   foreach ($core_filters as $k => $v) {

      $this->add_filter ('kc_'.$v, 'kc_'.$v.'_filter');

   }

Some of them do not properly escape all attributes and thus can be used to inject JavaScript. For instance, in the ‘kingcomposer/shortcodes/kc_row_inner.php’ script, the $atts attribute isn’t always sanitized:

extract( $atts );
...
...
if( !empty( $atts['equal_height'] ) )
{
   $attributes[] = 'data-kc-equalheight="true"';
   $attributes[] = 'data-kc-row-action="true"';
   $attributes[] = 'data-kc-equalheight-align="'. $atts['column_align'] .'"';
}

An authenticated attacker can inject HTML events and JavaScript code:

[kc_row_inner id="my-id" style="1" column_align='left" onmousemove="alert(`Stored XSS via shortcode.`)' equal_height="1"] XSS test [/kc_row_inner]

Remote code execution

The ‘KingComposer > Extensions’ menu is used to manage extensions (upload, delete etc) and is only accessible to the administrator. The function handling the submitted data, process_bulk_action, is located in the ‘kingcomposer/includes/kc.extensions.php’ script:

add_action('init', array(&$this, 'process_bulk_action'));

public function process_bulk_action() {
      
   if (
      isset($_POST['action']) && 
      isset($_POST['kc-extension-action']) && 
      isset($_POST['kc-nonce']) && 
      wp_verify_nonce($_POST['kc-nonce'], 'kc-nonce')
   ){
         
      if (!is_admin() || !current_user_can('upload_files')) {
         header('HTTP/1.0 403 Forbidden');
         exit;
      }

It is loaded by the init hook (i.e., each time WordPress loads), uses the same leaked security nonce and is only restricted to users with upload_files capability. Users such as authors and editors also have that capability and thus can access the function. Several critical actions can be performed:

1. Remote Code Execution

The upload action can be used to upload any PHP script because KingComposer doesn’t validate the extraction of the extension ZIP file: all files are simply extracted into the ‘/uploads/kc_extensions/’ folder. An author can add a ‘script.php’ to a ZIP file, upload it and then access it at ‘https://example.com/wp-content/uploads/kc_extensions/script.php’.

2. Arbitrary files/folders deletion

The bulk-delete action can allow the user to recursively delete any folders and files by assigning the folder(s) relative path to the checked[] POST array.

Recommendations

Update immediately if you have version 2.9.2 or below installed. If you are using our web application firewall for WordPress, NinjaFirewall WP Edition (free) and NinjaFirewall WP+ Edition (premium), you are protected against this vulnerability.

Timeline

Due to unsuccessful attempts to contact the author on May 25th, 2020, the issue was escalated to the wordpress.org plugins team and a new version 2.9.4 was released on June 8th, 2020.

Stay informed about the latest vulnerabilities