Arbitrary file upload vulnerability in WordPress Crelly Slider plugin.

The WordPress Crelly Slider plugin, which has 20,000+ active installations, was prone to an arbitrary file upload vulnerability in version 1.3.4 and below that could allow an authenticated user, such as a subscriber, to upload PHP scripts in order to take over the site and its database.

Reference

CVE-2019-15866

Vulnerability

On lines 45-59 , the ‘crellyslider.php’ script relies on the (un)famous is_admin() WordPress function to load the ‘wordpress/ajax.php’ script:

if(is_admin()) {
	// Tables
	if(CS_DEBUG || CS_VERSION != get_option('cs_version')) {
		CrellySliderTables::setTables();
	}
	if(CS_VERSION != get_option('cs_version')) {
		CrellySliderTables::setVersion();
	}

	CrellySliderAdmin::setEnqueues();
	CrellySliderAdmin::showSettings();

	// Ajax functions
	require_once CS_PATH . 'wordpress/ajax.php';
}

Unlike its name tends to suggest, is_admin() does not check whether a user is an administrator or not, but only whether the WordPress Dashboard is accessed.
The ‘ajax.php’ script contains 8 wp_ajax_* calls that do not check user capabilities, thus allowing an authenticated user such as a subscriber to perform actions like adding, deleting, exporting or
removing sliders. But the most problematic action is the wp_ajax_crellyslider_importSlider called line 520:

// Imports a slider given a .zip in $_FILES
add_action('wp_ajax_crellyslider_importSlider', 'crellyslider_importSlider_callback');
function crellyslider_importSlider_callback() {echo 'a';
	foreach($_FILES as $file) {
		$real_output = crellyslider_importSlider($file['tmp_name']);

		if($real_output == false) {
			echo false;
			die();
		}

		$real_output = json_encode($real_output);
		if(is_array($real_output)) print_r($real_output);
		else echo $real_output;

		die();
	}
}

// Imports a slider given a .zip file path
function crellyslider_importSlider($filePath) {
	global $wpdb;

	// Clear the temp folder
	array_map('unlink', glob(CS_PATH . '/wordpress/temp/*'));

	$output = true;
	$real_output = true;

	$zip = new ZipArchive();
	if($zip->open($filePath) !== TRUE) {
		return false;
	}

	$zip->extractTo(CS_PATH . '/wordpress/temp/');

It will accept any uploaded ZIP file and extract its content into the ‘wp-content/plugins/crelly-slider/wordpress/temp/’ folder, which will be accessible to unauthenticated users as well.
Therefore, an attacker can add a PHP script to a ZIP file, send a action=crellyslider_importSlider request to the ‘wp-admin/admin-ajax.php’ along with the file and the authentication cookie. The PHP script will be accessible at ‘http://example.com/wp-content/plugins/crelly-slider/wordpress/temp/’.

Timeline

The vulnerability was discovered and reported to the wordpress.org team on May 31, 2019.

Recommendations

Update as soon as possible if you have version 1.3.4 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 type of vulnerability.

Stay informed about the latest vulnerabilities in WordPress plugins and themes: @nintechnet