18 Jul

Our Proactive Monitoring Caught an Authenticated Arbitrary File Upload Vulnerability in MapSVG Lite

One of the ways we help to improve the security of WordPress plugins, not just for our customers, but for everyone using them, is the proactive monitoring of changes made to plugins in the Plugin Directory to try to catch serious vulnerabilities before they are exploited. That sometimes leads to us catching a vulnerability of a more limited variant of one of those serious vulnerability types, which isn’t as much concern for the average website, but could be utilized in a targeted attack. That happened with the authenticated arbitrary file upload vulnerability we found in the plugin MapSVG Lite. This vulnerability could allow an attacker that had access to a WordPress account to upload arbitrary files to the website. It also could allow an attacker that could get a user logged in to visit a URL the attacker controls, to exploit the vulnerability as well.

Since the check used to spot this is also included in our Plugin Security Checker (which  is accessible through a WordPress plugin of its own), it is another of reminder of how that can help to indicate which plugins are in greater need of security review (for which we do as part of our service as well as separately).

The vulnerability occurs in the function mapsvg_upload(). That function, which is located in the file /mapsvg.php, would create a file with a filename and contents specified by user input that will be placed in the directory /wp-content/uploads/mapsvg/:

2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
function mapsvg_upload () {
    $mapsvg_error = mapsvg_check_upload_dir();
 
    if(!$mapsvg_error){
        $filename = sanitize_file_name(basename($_POST["filename"]));
        $target_file = MAPSVG_MAPS_UPLOADS_DIR . "/".$filename;
 
//        $file_parts = pathinfo($_FILES['svg_file']['name']);
 
        $file = fopen($target_file, 'w');
        fwrite($file, stripslashes($_POST['data']));
        fclose($file);
 
        echo $filename;
 
    }
    die();
}

That function is accessible through WordPress’ AJAX functionality to anyone logged in to WordPress:

add_action('wp_ajax_mapsvg_upload', 'mapsvg_upload');

There is a similar issue with another AJAX accessible function, ajax_mapsvg_save_svg().

We notified the developer of the issue a week ago. We haven’t heard back from them and no new version has been released to fix the issue. In line with our disclosure policy, which is based on the need to provide our customers with information on vulnerabilities on a timely basis, we are now disclosing this vulnerability.

If you were using our service not only would you be warned about this issue promptly after it was disclosed if you were using the plugin, but we would be there to help you deal with the issue on your website.

Proof of Concept

The following proof of concept will place the specified PHP code in to the file test.php in the directory /wp-content/uploads/mapsvg/.

Make sure to replace “[path to WordPress]” with the location of WordPress and “[PHP code]” with the PHP code you want in the uploaded file.

<html>
<body>
<form action="http://[path to WordPress]/wp-admin/admin-ajax.php?action=mapsvg_upload" method="POST">
<input type="hidden" name="filename" value="test2.php" />
<input type="hidden" name="data" value="[PHP code]" />
<input type="submit" value="Submit" />
</form>
</body>

Timeline

  • July 11, 2018 – Developer notified.
09 Jul

Our Proactive Monitoring Caught a PHP Object Injection Vulnerability in Advanced Advertising System

One of the ways we help to improve the security of WordPress plugins, not just for our customers, but for everyone using them, is the proactive monitoring of changes made to plugins in the Plugin Directory to try to catch serious vulnerabilities. That again has lead to us catching a vulnerability of a type that hackers are likely to exploit if they know about it. Since the check used to spot this is also included in our Plugin Security Checker (which is accessible through a WordPress plugin of its own), it is another of reminder of how that can help to indicate which plugins are in greater need of security review (for which we do as part of our main service as well as separately).

In the plugin Advanced Advertising System the value of a cookie, “view_aas_campaigns”, is passed through the unserialize() function in a couple of locations, which could lead to PHP object injection. One of those locations is in the function is_available() in the file /shortcode.php:

198
$person = unserialize(stripslashes($_COOKIE['view_aas_campaigns'])); // Check a person from his cookie.

That code will run on pages where the plugin’s zone shortcode is used as long as it has a campaign attached to it.

We notified the developer of the issue a week ago. We haven’t heard back from them and no new version has been released to fix the issue. In line with our disclosure policy, which is based on the need to provide our customers with information on vulnerabilities on a timely basis, we are now disclosing this vulnerability.

Proof of Concept

With our plugin for testing for PHP object injection installed and activated, set the value of the cookie “view_aas_campaigns” to “O:20:”php_object_injection”:0:{}” and then when you visit a page using the plugin’s zone shortcode (with a campaign attached to the zone) the message “PHP object injection has occurred.” will be shown.

Timeline

  • July 2, 2018 – Developer notified.
09 Jul

Our Proactive Monitoring Caught a PHP Object Injection Vulnerability in Giveaway Boost

One of the ways we help to improve the security of WordPress plugins, not just for our customers, but for everyone using them, is the proactive monitoring of changes made to plugins in the Plugin Directory to try to catch serious vulnerabilities. That again has lead to us catching a vulnerability of a type that hackers are likely to exploit if they know about it. Since the check used to spot this is also included in our Plugin Security Checker (which is accessible through a WordPress plugin of its own), it is another of reminder of how that can help to indicate which plugins are in greater need of security review (for which we do as part of our main service as well as separately).

In the plugin Giveaway Boost the value of a cookie is passed through the unserialize() function, which could lead to PHP object injection. That occurs in the function gb_getcookie(), which is located in the file /includes/cookies.functions.php:

11
12
function gb_getcookie($name, $default = false) {
	$value = isset($_COOKIE[$name]) ? maybe_unserialize(stripslashes($_COOKIE[$name])) : $default;

That code will run on the plugin’s promotion pages.

We notified the developer of the issue a week ago. We haven’t heard back from them and no new version has been released to fix the issue. In line with our disclosure policy, which is based on the need to provide our customers with information on vulnerabilities on a timely basis, we are now disclosing this vulnerability.

Proof of Concept

With our plugin for testing for PHP object injection installed and activated, set the value of the cookie “gb_tracking_” plus the post ID number to “O:20:”php_object_injection”:0:{}” when on one of the plugin’s promotion pages then the message “PHP object injection has occurred.” will be shown. The post ID can be found to the right of the text “gb_entry_” in the page’s source code.

Timeline

  • July 2, 2018 – Developer notified.
02 Jul

Our Proactive Monitoring Caught a Cross-Site Request Forgery (CSRF)/Arbitrary File Upload Vulnerability in wpShopGermany Free

One of the ways we help to improve the security of WordPress plugins, not just for our customers, but for everyone using them, is the proactive monitoring of changes made to plugins in the Plugin Directory to try to catch serious vulnerabilities. That sometimes leads to us catching a vulnerability of a more limited variant of one of those serious vulnerability types, which isn’t as much concern for the average website, but could be utilized in a targeted attack. That happened with the cross-site request forgery (CSRF)/arbitrary file upload vulnerability we found in the plugin wpShopGermany Free. This vulnerability could have allowed an attacker that could get a logged in Administrator to visit a URL the attacker controls, to unintentionally upload arbitrary files.

Since the check used to spot this is also included in our Plugin Security Checker (which  is accessible through a WordPress plugin of its own), it is another of reminder of how that can help to indicate which plugins are in greater need of security review (for which we do as part of our service as well as separately).

The vulnerability occurred in the function widerrufsbelehrungAction() in the file /controller/wpsg_AdminController.class.php. That function runs when accessing the page /wp-admin/admin.php?page=wpsg-Admin&subaction=widerrufsbelehrung, which is accessible to Administrator-lever users. When that function was run as of version 4.0.10, if the GET or POST input “submit” existed and file attached to an input named “wpsg_widerrufsformular” existed then the file would have been saved to the directory /wp-content/uploads/wpsg/wpsg_revocation/:

1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
public function widerrufsbelehrungAction()
{
 
	if (isset($_REQUEST['submit']))
	{
 
		$this->shop->update_option('wpsg_ps_mailwiderruf', $_REQUEST['wpsg_ps_mailwiderruf']);
		$this->shop->addTranslationString('wpsg_ps_mailwiderruf', $_REQUEST['wpsg_ps_mailwiderruf']);
 
		if (file_exists($_FILES['wpsg_widerrufsformular']['tmp_name']))
		{
 
			if (!file_exists(WPSG_PATH_UPLOADS.'wpsg_revocation/')) mkdir(WPSG_PATH_UPLOADS.'wpsg_revocation/', 0775, true);
 
			$this->clearRevocationForm();
 
			move_uploaded_file($_FILES['wpsg_widerrufsformular']['tmp_name'], WPSG_PATH_UPLOADS.'wpsg_revocation/'.$_FILES['wpsg_widerrufsformular']['name']);

There was no check for a valid nonce, which would prevent cross-site request forgery (CSRF) from occurring. There also was no restriction on what types of files can be uploaded.

After we notified the developer they released version 4.0.11, which fixes the vulnerability by checking for a valid nonce before allowing files:

1731
1732
1733
1734
1735
1736
1737
public function widerrufsbelehrungAction()
{
 
	if (isset($_REQUEST['submit']))
	{
 
		\check_admin_referer('wpsg-save-revocation');

A check of the mime type of the file being uploaded was also added.

There are other locations in the plugin without proper protection against CSRF and the developer said that those would be fixed in the next 4 weeks.

Proof of Concept

The following proof of concept will upload the selected file to the directory/wp-content/uploads/wpsg/wpsg_revocation/, when logged in to WordPress as Administrator.

Make sure to replace “[path to WordPress]” with the location of WordPress.

<html>
<body>
<form action="http://[path to WordPress]/wp-admin/admin.php?page=wpsg-Admin&subaction=widerrufsbelehrung&noheader=1" method="POST" enctype="multipart/form-data">
<input type="file" name="wpsg_widerrufsformular" />
<input type="submit" name="submit" value="Submit" />
</form>
</body>
</html>

Timeline

  • June 25, 2018 – Developer notified.
  • June 26, 2018 – Developer responds.
  • June 29, 2018 – Version 4.0.11 released, which fixes vulnerability.
25 May

Our Proactive Monitoring Caught a PHP Object Injection Vulnerability in WordPress Survey & Poll

One of the ways we help to improve the security of WordPress plugins, not just for our customers, but for everyone using them, is the proactive monitoring of changes made to plugins in the Plugin Directory to try to catch serious vulnerabilities. That again has lead to us catching a vulnerability of a type that hackers are likely to exploit if they know about it. Since the check used to spot this is also included in our Plugin Security Checker (which is accessible through a WordPress plugin of its own), it is another of reminder of how that can help to indicate which plugins are in greater need of security review (for which we do as part of our main service as well as separately).

In the plugin WordPress Survey & Poll the value of a cookie, “wp_sap”, was passed through the unserialize() function in several locations, which could lead to PHP object injection. One of those locations was in the function enqueue_custom_scripts_and_styles() in the file /wordpress-survey-and-poll.php:

208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
function enqueue_custom_scripts_and_styles() {
	global $wpdb;
	wp_enqueue_style( 'wp_sap_style', plugins_url( '/templates/assets/css/wp_sap.css', __FILE__ ) );
	wp_enqueue_style( 'jquery_ui_style', plugins_url( '/templates/assets/css/jquery-ui.css', __FILE__ ) );
	wp_enqueue_script( 'jquery' );
	wp_enqueue_script( 'jquery-ui-core', array( 'jquery' ) );
	wp_enqueue_script( 'jquery-effects-core', array( 'jquery' ) );
	wp_enqueue_script( 'jquery-effects-slide', array( 'jquery-effects-core' ) );
	wp_enqueue_script( 'jquery-visible',plugins_url( '/templates/assets/js/jquery.visible.min.js', __FILE__ ), array( 'jquery' ), '1.10.2' );
	wp_register_script('wp_sap_script', plugins_url( '/templates/assets/js/wp_sap.js' , __FILE__ ), array( 'jquery' ), '1.0.0.2', true );
		$survey_viewed = array();
		$sv = '';
		$sv_condition = '';
			if ( isset( $_COOKIE[ 'wp_sap' ] ) ) {
				$survey_viewed = unserialize( stripslashes( $_COOKIE[ 'wp_sap' ] ) );

That function gets called during init if the page being requested is not an admin page of WordPress and if the GET or POST input “sspcmd” exists:

24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
if ( is_admin() ) {
	require_once( sprintf( "%s/settings.php", dirname( __FILE__ ) ) );
	$wp_sap_settings = new wp_sap_settings();
	$plugin = plugin_basename( __FILE__ );
	add_filter( "plugin_action_links_$plugin", array( &$this, 'plugin_settings_link' ) );
}
else {
	$wp_sap_url = $_SERVER[ 'HTTP_HOST' ] . $_SERVER[ 'REQUEST_URI' ];
	$wp_sap_load = true;
	if ( ( strpos( $wp_sap_url, 'wp-login' ) ) !== false ) {
		$wp_sap_load = false;
	}
	if ( ( strpos( $wp_sap_url, 'wp-admin' ) ) !== false ) {
		$wp_sap_load = false;
	}
	if ( $wp_sap_load || isset( $_REQUEST[ 'sspcmd' ] ) ) {
		//integrate the public functions
		add_action( 'init', array( &$this, 'enqueue_custom_scripts_and_styles' ) );

That made the vulnerable code accessible to anyone.

We notified the developer of the issue yesterday and a couple of hours later they released version 1.5.6, which resolves the vulnerability by replacing usage of unserialize() with and json_decode() (along with related usage of serialize() with json_encode()).

Proof of Concept

With our plugin for testing for PHP object injection installed and activated, set the value of the cookie “wp_sap” to “O:20:”php_object_injection”:0:{}” and then when you visit the following URL the message “PHP object injection has occurred.” will be shown.

Make sure to replace “[path to WordPress]” with the location of WordPress.

http://[path to WordPress]/?sspcmd=test

Timeline

  • May 24, 2018 – Developer notified.
  • Mary 24, 2018 – Developer responds.
  • May 24, 2018 – Version 1.5.6 released, which fixes vulnerability.
16 May

Our Proactive Monitoring Caught a Newly Introduced Arbitrary File Upload Vulnerability in a Plugin with 50,000+ Active Installations

One of the ways we help to improve the security of WordPress plugins, not just for our customers, but for everyone using them, is the proactive monitoring of changes made to plugins in the Plugin Directory to try to catch serious vulnerabilities. That again has lead to us catching a vulnerability in a fairly popular plugin, of a type that hackers are likely to exploit if they know about it. Since the check used to spot this is also included in our Plugin Security Checker (which  is now accessible through a WordPress plugin of its own), it is another of reminder of how that can help to indicate which plugins are in greater need of security review (for which we do as part of our service as well as separately).

In the plugin KingComposer, which has 50,000+ active installations according to wordpress.org, version 2.7 introduced functionality for uploading extensions. That functionality is accessible to anyone, even those without access to admin page that is intended to be initiated from. That currently allows uploading arbitrary files, including malicious files, if the Extensions admin page of the plugin has ever been visited prior to the attempted exploitation.

The plugin runs the function init_first() whenever WordPress loads:

205
add_action( 'init', array( &$this, 'init_first' ), 0 );

That function, which is located in the file /kingcomposer.php, will cause the file /includes/kc.extensions.php to be included:

227
228
229
230
231
232
233
234
235
236
237
238
239
240
public function init_first(){
	/*
	*	Register maps
	*/
	require_once KC_PATH.'/includes/kc.maps.php';
	/*
	*	Register params
	*/
	require_once KC_PATH.'/includes/kc.param.types.php';
	/*
	*	This init action has highest priority
	*/
	require_once KC_PATH.'/includes/kc.extensions.php';
}

That file will cause a new instance of the class kc_extensions to be created:

380
new kc_extensions();

The construct function in that will run the function process_bulk_action() if is_admin() is true:

29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
function __construct(){
 
	$this->path = untrailingslashit(ABSPATH).KDS.'wp-content'.KDS.'uploads'.KDS.'kc_extensions'.KDS;
 
	$this->scheme = is_ssl() ? 'https' : 'http';
	$this->api_url = $this->scheme.'://extensions.kingcomposer.com/';
 
	if (is_admin()) {
 
		add_action ('admin_menu', array( &$this, 'admin_menu' ), 1);
		if (isset($_GET['tab']) && !empty($_GET['tab']))
			$this-&gt;tab = $_GET['tab'];
		if (isset($_GET['page']) && !empty($_GET['page']))
			$this-&gt;page = $_GET['page'];
 
		add_action('kc_list_extensions_store', array(&$this, 'extensions_store'));
		add_action('kc_list_extensions_installed', array(&$this, 'extensions_installed'));
		add_action('kc_list_extensions_upload', array(&$this, 'extensions_upload'));
 
		$this->process_bulk_action();

is_admin() will return true if an admin page is being requested and can be true even if the request is coming from someone that is not logged in.

The function process_bulk_action() will run different code depending of the value of the POST input “action” specified:

248
249
250
251
252
253
254
255
256
257
public function process_bulk_action() {
 
	if( isset($_POST['action']) ){
 
		$actives = (array) get_option( 'kc_active_extensions', array() );
 
		$checked = isset($_POST['checked']) ? (array) $_POST['checked'] : array();
		$path = untrailingslashit(ABSPATH).KDS.'wp-content'.KDS.'uploads'.KDS.'kc_extensions'.KDS;
 
		switch ($_POST['action']){

If that input is set to “upload” the following code will run:

291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
case 'upload' : 
 
	$this->tab = 'upload';
 
	if (!class_exists('ZipArchive')) {
		$this->errors[] = 'Server does not support ZipArchive';
	} else if (
		(
			($_FILES["extensionzip"]["type"] == "application/zip") || 
			($_FILES["extensionzip"]["type"] == "application/x-zip") || 
			($_FILES["extensionzip"]["type"] == "application/x-zip-compressed")
		) && 
		($_FILES["extensionzip"]["size"] < 20000000) ) { if (move_uploaded_file($_FILES['extensionzip']['tmp_name'], $path.$_FILES['extensionzip']['name']) === true) { $zip = new ZipArchive; $res = $zip->open($path.$_FILES['extensionzip']['name']);
			if ($res === TRUE) {
 
				$ext = $zip->extractTo($path);

That code will unzip the contents of zip file and place them in the directory /wp-content/uploads/kc_extensions/. If that directory doesn’t currently exist then the zip file and its content cannot be placed in the directory. That directory is created during the first visit to the plugin’s Extensions admin page, which can be accessed by Administrator and Editor-level users.

We notified the developer of the plugin of the issue on April 16. They responded the same day with a proposed fix for the vulnerability, which didn’t do anything to fix it. The change, which was included in version 2.7.1, replaced the following line:

48
$this->process_bulk_action();

with

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

They explained that would cause the function “process_bulk_action()” to “run after WP core”. We are not sure what was supposed to be the point of that since the starting point of this code running already ran during “init”, when that function is now set to run.

We responded twice, first explaining that code didn’t resolve the issue and then in response to a response to that reply, that version 2.7.1 didn’t fix the issue. After our second response we didn’t receive any further response from the developer and the issue still has not been fixed despite a couple of versions being released since then. In line with our disclosure policy, which is based on the need to provide our customers with information on vulnerabilities on a timely basis, we are now disclosing this vulnerability.

Proof of Concept

The following proof of concept will place the files in a specified zip file in to the directory /wp-content/uploads/kc_extensions/.

Make sure to replace “[path to WordPress]” with the location of WordPress.

<html>
<body>
<form action="http://[path to WordPress]/wp-admin/admin-post.php" method="POST" enctype="multipart/form-data">
<input type="hidden" name="action" value="upload" />
<input type="file" name="extensionzip" />
<input type="submit" value="Submit" />
</form>
</body>
</html>

Timeline

  • April 16, 2018 – Developer notified.
  • April 16, 2018 – Developer responds.
27 Apr

Our Proactive Monitoring Caught a Cross-Site Request Forgery (CSRF)/PHP Object Injection Vulnerability in WP Docs

One of the ways we help to improve the security of WordPress plugins, not just for our customers, but for everyone using them, is the proactive monitoring of changes made to plugins in the Plugin Directory to try to catch serious vulnerabilities. That sometimes leads to us catching a vulnerability of a more limited variant of one of those serious vulnerability types, which isn’t as much concern for the average website, but could be utilized in a targeted attack. That happened with the cross-site request forgery (CSRF)/PHP object injection vulnerability we found in the plugin WP Docs. This vulnerability could have allowed an attacker that could get a logged in Administrator to visit a URL the attacker controls, to unintentionally exploit a PHP object injection vulnerability.

What lead us to that was the possibility of a file upload vulnerability in the plugin, but before we got to the code for that we noticed the possibility that a PHP object injection would occur first, in a way that we haven’t seen before, so we focused on that.

The plugin makes its admin page available to users with the “wpdocs-dashboard” capability (which is only given to Administrator-level users by default):

20
add_menu_page( __('WP Docs','wpdocs'), __('WP Docs','wpdocs'), 'wpdocs-dashboard', 'wpdocs-engine.php', 'wpdocs_dashboard', WPDOCS_URL.'includes/imgs/folder.png'  );

The function that runs when that page is accessed is wpdocs_dashboard(), which would run the function wpdocs_import_zip() if the POST input “action” is set to “wpdocs-import”

37
38
39
elseif(isset($_POST['action']) && $_POST['action'] == 'wpdocs-import') {
	if(wpdocs_file_upload_max_size() < $_FILES['size']) wpdocs_errors(WPDOCS_ERROR_7, 'error');
	else wpdocs_import_zip();

In the function wpdocs_import_zip() , which is located in the file /includes/wpdocs-import.php, a zip file will be unzipped and then if either of two files exists in that zip file they will be run through the unserialize() function, which can cause PHP object injection:

56
57
58
59
60
61
62
63
move_uploaded_file($_FILES['wpdocs-import-file']['tmp_name'], $wpdocs_zip_file);
$zip_result = wpdocs_unzip($wpdocs_zip_file, sys_get_temp_dir());
if(is_array($zip_result)) {
	if(file_exists(sys_get_temp_dir().'/wpdocs/wpdocs-list.txt')) {
		$wpdocs_list_file = unserialize(file_get_contents(sys_get_temp_dir().'/wpdocs/wpdocs-list.txt'));
	} else $error = true;
	if(file_exists(sys_get_temp_dir().'/wpdocs/wpdocs-cats.txt')) {
		$wpdocs_cats_file = unserialize(file_get_contents(sys_get_temp_dir().'/wpdocs/wpdocs-cats.txt'));

In some other instances we have found that possible PHP object injection vulnerabilities have not been exploitable due to escaping, so we were not sure if something like that might happen with the code used to get the contents of a file. But a quick test with our plugin for testing for PHP object injection showed that this was exploitable.

There was no protection against cross-site request forgery (CSRF) in any of the code leading up to the code that does the serialization, allowing for exploitation.

After we contacted the developer they released version 1.1.8, which fixes the vulnerability by commenting out the line that calls the function wpdocs_import_zip():

40
//wpdocs_import_zip();

Proof of Concept

With our plugin for testing for PHP object injection installed and activated, use the following proof of concept to upload a zip file containing a file named wpdocs-list.txt that contains ‘O:20:”php_object_injection”:0:{}’ as it content and the message “PHP object injection has occurred.” will be shown, when logged in to WordPress as an Administrator.

Make sure to replace “[path to WordPress]” with the location of WordPress.

<html>
<body>
<form action="http://[path to WordPress]/wp-admin/admin.php?page=wpdocs-engine.php" method="POST" enctype="multipart/form-data">
<input type="hidden" name="action" value="wpdocs-import" />
<input type="file" name="wpdocs-import-file" />
<input type="submit" value="Submit" />
</form>
</body>

Timeline

  • April 16, 2018 – Developer notified.
  • April 16, 2018 – Developer responds.
  • April 16, 2018 – Version 1.1.8 released, which fixes vulnerability.
16 Apr

Our Proactive Monitoring Caught a PHP Object Injection Vulnerability in a Another Brand New Plugin

One of the ways we help to improve the security of WordPress plugins, not just for our customers, but for everyone using them, is the proactive monitoring of changes made to plugins in the Plugin Directory to try to catch serious vulnerabilities. That again has lead to us catching a vulnerability of a type that hackers are likely to exploit if they know about it.

This vulnerability is in a brand new plugin, Disc Golf Manager, and should have been something that the security review that is supposed to be done before new plugins can be added to the Plugin Directory should have caught. It is something that would have been flagged by our Plugin Security Checker, so it would make sense to run plugins through that during that security review to avoid this type of situation continuing to happen. That it continues to happen speaks to the continued lack of interest in improving security by the leadership of WordPress (starting at the top with Matt Mullenweg) and the continued role we play in limiting the impact of that for everyone else. We would be happy to provide the Plugin Directory team free access to the upload and developer mode capabilities to facilitate that.

The vulnerability occurs in function flashProcess() in the file /main.php where the value of the cookie “disc_golf_flash” is passed through the unserialize() function, which can lead to PHP object injection:

4043
4044
4045
function flashProcess() {
	if(isset($_COOKIE[$this->key . '_flash'])) {
		$temp = unserialize(base64_decode($_COOKIE[$this->key . '_flash']));

That function will run anytime a WordPress page is being accessed:

3811
add_action('init', array($this, 'flashProcess'));

We notified the developer of the issue a week ago. We haven’t heard back from them and no new version has been released to fix the issue. In line with our disclosure policy, which is based on the need to provide our customers with information on vulnerabilities on a timely basis, we are now disclosing this vulnerability.

Proof of Concept

With our plugin for testing for PHP object injection installed and activated, set the value of the cookie “disc_golf_flash” to “TzoyMDoicGhwX29iamVjdF9pbmplY3Rpb24iOjA6e30=” and then when you visit a page on the webiste the message “PHP object injection has occurred.” will be shown.

Timeline

  • April 9, 2018 – Developer notified.
23 Mar

Our Proactive Monitoring Caught a PHP Object Injection Vulnerability in DukaPress

One of the ways we help to improve the security of WordPress plugins, not just for our customers, but for everyone using them, is the proactive monitoring of changes made to plugins in the Plugin Directory to try to catch serious vulnerabilities. That again has lead to us catching a vulnerability of a type that hackers are likely to exploit if they know about it. Since the check used to spot this is also included in our Plugin Security Checker (which  is now accessible through a WordPress plugin of its own), it is another of reminder of how that can help to indicate which plugins are in greater need of security review (for which we do as part of our main service as well as separately).

In the plugin DukaPress, the value of a cookie was passed through the unserialize() function, which could lead to PHP object injection. That occurred in the function get_cart_cookie() (in the file /classes/dukapress-cart.php):

33
34
35
36
37
38
static function get_cart_cookie() {
 
	$cookie_id = self::$cookie_id_string . COOKIEHASH;
 
	if ( isset( $_COOKIE[ $cookie_id ] ) ) {
		$cart = unserialize( stripslashes( $_COOKIE[ $cookie_id ] ) );

The value of COOKIEHASH in that is set by WordPress with the following code:

define( 'COOKIEHASH', md5( $siteurl ) );

That function is accessible through WordPress’ AJAX functionality whether someone is logged in to WordPress or not:

12
13
add_action('wp_ajax_nopriv_dpsc_update_cart', array(__CLASS__, 'update_cart'));
add_action('wp_ajax_dpsc_update_cart', array(__CLASS__, 'update_cart'));

We contacted the developer about the vulnerability yesterday and within hours they had released version 3.2 that resolved it by replacing use of unserialize() with json_decode() (and replaces related use of serialize() with json_encode()):

38
$cart = json_decode(  $_COOKIE[ $cookie_id ] , true );

Proof of Concept

With our plugin for testing for PHP object injection installed and activated, set the value of the cookie “dpsc_cart_” plus the md5 hashed version of the website’s site URL to “O:20:”php_object_injection”:0:{}” and then when you visit the following URL  the message “PHP object injection has occurred.” will be shown if you are not logged in to WordPress.

Make sure to replace “[path to WordPress]” with the location of WordPress.

http://[path to WordPress]/wp-admin/admin-ajax.php?action=wsfl_add_product_to_cart

Timeline

  • March 23, 2018 – Developer notified.
  • March 23, 2018 – Version 3.2 released, which fixes vulnerability.
  • March 23, 2018 – Developer responds.