10 Aug

Our Plugin Security Checker Identified Another Reflected XSS Vulnerability in WordPress Plugin with 100,000+ Active Installs

In a reminder of the rather poor state of security of WordPress plugins and how our Plugin Security Checker tool (which is accessible through a WordPress plugin of its own) can help you to get a better idea if they are in need of additional security scrutiny recently the plugin Ultimate Member, which has 100,000+ active installs according to wordpress.org, was run through the tool and it identified a possible reflected cross-site scripting (XSS) vulnerability in the plugin.

Looking at the details of the issue identified, which are available to users of our service through the tool’s Developer Mode, it certainly looked like there was that type of vulnerability as user input was being output without being escaped:

A quick check confirmed that this was an exploitable vulnerability (though far from a serious issue for the average website), as can be seen with the proof of concept below.

The vulnerability has been in the plugin since April without anyone noticing it, despite the fact that an automated tool was able to spot it. While the vulnerability isn’t a serious issue, it is due to a failure to do a security basic and shouldn’t be something that should be in a plugin developed by an “experienced plugin developer” and has generated over a million dollars worth of revenue. Maybe, not all that surprisingly the plugin also contained a much more serious vulnerability that was being widely exploited before being belated fixed by the developer in same release that fixed this one.

A “Reputable” Plugin Isn’t a Secure Plugin

There is no shortage of advice when it comes to the security of WordPress websites, though much of it is quite bad. That is unfortunately true of so much coming from security companies that people incorrectly trust not just to get accurate information but also to provide them security. We often find that suggestions are made on how to choose plugins that are secure where there is no supporting evidence being provided for the suggestions and that those with even a cursory understanding of the security issues surrounding WordPress plugins would likely find questionable at best.

This plugin is a good example of where a plugin that would meet many common suggestions is at the same time contains an easily spottable vulnerability. Here for example, were suggestions made by Wordfence last November:

Choose Reputable Plugins

The WordPress.org plugin directory makes it really easy to evaluate plugins by providing a nice summary that gives you almost everything you need. Here’s what we suggest you pay attention to:

  • The more recent the last update, the better.
  • Check the number of active installs the plugin has. Some reliable and useful plugins have low install numbers, but you should still examine a plugin carefully if it has a low install base (below 1,000 active installs). It may not be maintained.
  • It should be compatible with the current version of WordPress, though please note that immediately after a WordPress core release, a lot of reputable plugins will show a “Test up to:” value that is behind, as authors finish testing their plugin with the latest WordPress version.
  • The average plugin rating should be high enough to instill confidence. The higher the rating, the better, obviously.

You should also periodically review your installed plugins to make sure they have maintained their good standing.

This plugin meet all of those at the time we looked in to the issue:

A plugin being recently updated, popular, maintained, and highly rated doesn’t mean in any way it is secure. While this vulnerability was fixed after a month we have found that security vulnerabilities in other popular and recently updated plugins are not always fixed in a timely or ever.

Proof of Concept

The following proof of concept will cause an alert box with the message “XSS” to be shown when logged in WordPress as an Administrator. Major web browsers other than Firefox provide XSS filtering, so this proof of concept will not work in those web browsers.

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

http://[path to WordPress]/wp-admin/admin.php?page=um_options&tab=email&section=%22%3E%3Cscript%3Ealert%28document.cookie%29%3B%3C%2Fscript%3Eylo

Timeline

  • July 12, 2018 – Developer notified.
  • July 13, 2018 – Developer responds.
  • August 9, 2018 – Version 2.0.22 released, which fixes vulnerability.
10 Aug

Our Proactive Monitoring Caught an Authenticated PHP Object Injection Vulnerability in a 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 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 PHP object injection vulnerability we found in a brand new plugin, Woocommerce Aliexpress Dropshipping Lite. This vulnerability could allow an attacker that had access to a WordPress account to exploit a PHP object injection vulnerability. It also could have allowed an attacker that could get a user logged in to WordPress 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 CedWad_addProductToBunch(). That function, which is located in the file /admin/class-CedWad-admin.php, passes the value of the POST input “productData” through the unserialize() function, which could lead to PHP object injection:

460
461
462
463
464
465
public function CedWad_addProductToBunch(){
	$products = array();
	$filterId = isset( $_POST['filterId'] ) ? sanitize_text_field($_POST['filterId']) : "";
	$bunchId = isset( $_POST['bunchId'] ) ? sanitize_text_field($_POST['bunchId']) : "";
	$productId = isset( $_POST['productId'] ) ? sanitize_text_field($_POST['productId']) : "";
	$productData = isset( $_POST['productData'] ) ? unserialize(stripslashes($_POST['productData'])) : array();

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

71
add_action('wp_ajax_CedWad_addProductToBunch', array($this, 'CedWad_addProductToBunch'));

We notified the developer of the issue a month ago. They responded four days later and said an update was in the works, but 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, 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.

<html>
<body>
<form action="http://[path to WordPress]/wp-admin/admin-ajax.php?action=CedWad_addProductToBunch" method="POST">
<input type="hidden" name="productData" value='O:20:"php_object_injection":0:{}' />
<input type="submit" value="Submit" />
</form>
</body>

Timeline

  • July 12, 2018 – Developer notified.
  • July 16, 2018 – Developer responds.
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

When A Security Vulnerability Is Only One of the Issues With a WordPress Security Plugin

We don’t think too highly of the security industry and we are often reminded of why that is, as was the case when we did a quick check of the plugin Sitesassure WP Malware Scanner. We had run across the plugin on the website of a company, 911websiterepair.com, which offers to clean up hacked websites, where it was listed as their plugin. The plugin didn’t mention anything about that website instead it was connected to another website and the look of that website didn’t exactly give us a good feeling about the potential quality of the plugin:

We then did a quick check of the plugin. What we found was poor security and a minor security vulnerability in the plugin. We will get to those in a moment, but first we want to bring up a couple of questionable items.

In looking over the code one thing that we quickly noticed was that there was a significant amount of code in the plugin for accessing a scanner from a company named Quttera. Oddly, nowhere in the description of the plugin or in the plugin is there any mention of that company. As far as we can tell that is actually who is doing the scanning. Considering that Quttera provides their own plugin (which we also recently found contained a vulnerability) it looks like Sitesassure’s plugin mainly serves as advertisement for them and to collect information on people using it, rather than providing a capability that isn’t available elsewhere.

As to the data collection, when you take various actions not only does the plugin connect to the Sitesassure website but it also sends out an email to someone. That seems like it might be a violation of one of the developer guidelines for WordPress plugins, but what seems odder is that the current email address doesn’t have an obvious connection with the plugin. As an example of that is the code run when the plugin is deactivated:

function swms_sitesassureDeactivate()
{
	$site_domain = get_bloginfo('url');
	$req_url = SWMS_REQUEST_URL;
	$response = wp_remote_post( $req_url, array(
	'method' => 'POST',
	'timeout' => 45,
	'redirection' => 5,
	'httpversion' => '1.0',
	'blocking' =>; true,
	'headers' => array(),
	'body' => array("action" => SWMS_UPDATE_REQUEST, 'domain' => $site_domain, "status" => SWMS_INACTIVE_STATUS),
	'cookies' => array()
    )
	);
	if ( is_wp_error( $response ) ) {
	   $error_message = $response->get_error_message();
	   _e("Something went wrong: $error_message","swms");
	} else {
	   if($response['response']['code'] == 200 && $response['response']['message'] == "OK")
	   {
	   		$message = 'Hi SA Admin,
'.$site_domain.' is deactivated the WPSASCANNER plugin';
	   		swms_sendEmail(array('to' => 'nagaraj@spinzsoft.com','subject' => $site_domain.' Deactivated Message','message' => $message));
 
	}
}

That code first sends a request to the Sitesassure website and if that request is successful an email is sent to nagaraj@spinzsoft.com. The website at spinzsoft.com doesn’t seem to be connected to the Sitesassure website. Up until June 13, when version 2.0 of the plugin was released, emails were instead sent to support@sitesassure.com. Prior to release of 2.0, the last update made to the plugin was in December of 2015.

One common area of security issues in plugins is functionality accessed through WordPress’ AJAX functionality. Often due to allowing those not logged in to WordPress to access functionality only intended for those logged in or due to allowing low level users access to functionality they are not intended to have access to. In the case of this plugin both of those issues occur.

In one of the functions that is accessible to anyone logged in WordPress despite only being intended to be accessed by Administrators there was a security issue not related to allowing lower level users to access it. Instead the issue was that user input is output without being sanitized or escaped, which could allow reflected cross-site scripting (XSS) to occur. That occurred in the function swms_get_admin_url(), which is located in the file /sitesassure-wp-malware-scanner.php:

494
495
496
497
498
499
function swms_get_admin_url(){
	$swms_scanned_url = $_POST['data'];
	$swms_admin_url = admin_url("admin.php?page=swms_scanner_report_page&swms_url=$swms_scanned_url");
	echo $swms_admin_url;
	exit;
}

Two days after we notified the developer of the issue a change was to fix it, but the version number was not changed, so no one already using version 2.0 will be prompted to update. We had also notified of the developer of the more general lack of security in the plugin, lack of restriction on who can access AJAX accessible functions and lack of protection against cross-site request forgery (CSRF), but no changes have been made related to those yet. We have yet to receive any response from the developer.

The vulnerability was fixed by passing the user input through the esc_url() function:

494
495
496
497
498
499
500
function swms_get_admin_url(){
	$swms_scanned_url = $_POST['data'];
	$swms_scanned_url = esc_url($swms_scanned_url);
	$swms_admin_url = admin_url("admin.php?page=swms_scanner_report_page&swms_url=$swms_scanned_url");
	echo $swms_admin_url;
	exit;
}

Proof of Concept

The following proof of concept will cause any available cookies to be shown in alert box, when logged in to WordPress. Major web browsers other than Firefox provide XSS filtering, so this proof of concept will not work in those web browsers.

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=swms_get_admin_url" method="POST">
<input type="hidden" name="data" value="<script>alert(document.cookie);</script>" />
<input type="submit" value="Submit" />
</form>
</body>

Timeline

  • June 25, 2018 – Developer notified.
  • June 27, 2018 – Change made to version 2.0 to fix vulnerability.
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.
19 Jun

Authenticated Local File Inclusion (LFI) Vulnerability in ChimpMate

In seeking to continue to improve our Plugin Security Checker, which does automated checks to try spot potential security issues in WordPress plugins, we log the results of checks of plugins in the Plugin Directory. The plugin ChimpMate was recently run through that and one of the issues identified in that was a possible local file inclusion vulnerability:

Since the check for that issue is based on a fairly limited number of previously identified vulnerabilities we decided to check on that to see if what was flagged was correctly identified.

For someone with the necessary knowledge to review possible security issues more closely they can use the Developer Mode of the tool, which is available to customers of our service, to see the details of what lead to the tool warning of the possible issue. What was shown was this:

In both of the instances shown there, user input is used to include a file through the function include_once(), in the first instance the user input is directly used and in the second it used through a variable. Those both would be accurate identifications of a possible issue.

When then decided to take a look to see if there was a vulnerability caused by either of those.

The first instance was located in the function preview() in the file /admin/class-chimpmate-wpmc-assistant-admin.php and looked like this:

219
220
221
222
223
public function preview(){
	if(!isset($_GET['type']) || !isset($_GET['theme']))die();
	include_once( 'includes/'.$_GET['type'].$_GET['theme'].'.php' );
	die();
}

That code simply checks if the GET inputs “type” and “theme” exist and if they do, it uses those with the include_once() function.

That function is accessible to anyone logged in to WordPress through its AJAX functionally:

52
add_action('wp_ajax_chimpmate_prev', array( $this, 'preview' ) );

That means there is authenticated local file inclusion vulnerability, which could allow an attacker who is able to log in to WordPress to cause any .php file on the website to be run. Through cross-site request forgery (CSRF) it would also be possible for an attacker to cause anyone logged in to WordPress do the same thing.

The second instance identified by the tool could be exploited in the same way.

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

The following proof of concept will cause a file named test.php in the root directory of the WordPress installation to be included, 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=chimpmate_prev&type=../../../../../&theme=test

Timeline

  • June 11,2018 – Developer notified.
12 Jun

Privilege Escalation Vulnerability in Quttera Web Malware Scanner

One of the big problems we see in trying to improve security is that so often security companies are promoting product and services that they claim will protect websites, but really only try to deal with the after effects of them being hacked. What seems like could explain a lot of that is that most of those companies don’t know or care about security and they are just trying to make a buck with little to no concern whether they are providing anything of value in exchange for that money. One of the things that seems to back that up is how often security companies fail to handle basic security when it comes to their own websites and product/services.

The latest example of that was something we ran across while discussing an example of security companies’ frequent misleading to outright false claims made about their products and services. As discussed over at our main blog the makers of the plugin Quttera Web Malware Scanner had recently claimed that the plugin had over 400,000 installations despite it actually only having 10,000+ active install according to wordpress.org. After running across that we started to take a quick look at the plugin’s security and immediately found it was failing to take some basic security measures.

The plugin makes a number of functions available through WordPress’ AJAX functionality to anyone logged in to WordPress:

42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
add_action( 'wp_ajax_scanner-run_scan', 'CQtrAjaxHandler::RunExternalScan' );
 
 
/*
 * setup action @scanner-run_internal_scan mapped to callback qtr_wm_scanner_ajax_run_internal_scan
 * wp_ajax_ prefix used only for logged in users
 */ 
add_action( 'wp_ajax_scanner-run_internal_scan', 'CQtrAjaxHandler::RunInternalScan' );
 
add_action( 'wp_ajax_scanner-is_internal_scan_running', 'CQtrAjaxHandler::IsInternalScanNowRunning' );
 
add_action( 'wp_ajax_scanner-get_log_lines', 'CQtrAjaxHandler::GetLogLines' );
 
add_action( 'wp_ajax_scanner-clean_log', 'CQtrAjaxHandler::CleanLogLines' );
 
add_action( 'wp_ajax_scanner-get_stats', 'CQtrAjaxHandler::GetStats' );
 
add_action( 'wp_ajax_scanner-stop_internal_scan', 'CQtrAjaxHandler::StopInternalScan' );
 
add_action( 'wp_ajax_scanner-get_detected_threats', 'CQtrAjaxHandler::GetDetectedThreatsReport' );
 
add_action( 'wp_ajax_scanner-get_ignored_threats', 'CQtrAjaxHandler::GetIgnoredThreatsReport' );
 
add_action( 'wp_ajax_scanner-ignore_threat', 'CQtrAjaxHandler::IgnoreThreat' );
 
add_action( 'wp_ajax_scanner-get_file_report', 'CQtrAjaxHandler::ScannerReport' );
 
/* 
 * return threat back to report
 */
add_action( 'wp_ajax_scanner-unignore_threat', 'CQtrAjaxHandler::RemoveFromIgnoreList' );
 
add_action( 'wp_ajax_scanner-clean_ignore_list', 'CQtrAjaxHandler::CleanIgnoreList');
 
add_action( 'wp_ajax_scanner-whitelist_threat','CQtrAjaxHandler::WhiteListThreat' );
 
add_action( 'wp_ajax_scanner-clean_threats_whitelist', 'CQtrAjaxHandler::CleanThreatsWhiteList');
 
add_action( 'wp_ajax_scanner-whitelist_file', 'CQtrAjaxHandler::WhiteListFile');
 
add_action( 'wp_ajax_scanner-clean_files_whitelist', 'CQtrAjaxHandler::CleanFilesWhiteList');

The plugin’s admin pages, where at least most of those are intended to be accessed from, is only accessible to those with the “activate_plugins” capability, which would normally be only Administrator-level users. So there should be a check to make sure that users requesting those have that capability.

The first of the functions RunExternalScan() was restricted to those with the “manage_options” capability, which is also normally a capability only Administrator-level users have:

32
33
34
35
36
37
public static function RunExternalScan()
{
	if(!current_user_can('manage_options'))
	{
		wp_die(__('You do not have sufficient permissions to access this page.') );
	}

But that was missing from other functions. For example the GetLogLines() contains no check, so anyone logged in to WordPress could access it:

237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
public static function GetLogLines()
{
	$index  = 0;
	$logger = new CQtrLogger();
 
	if( isset( $_GET['start_line']) ) 
	{
		$index = intval( $_GET['start_line']);
	}
 
	else if( isset( $_POST['start_line']) ) 
	{
		$index = intval( $_POST['start_line']);
	}
 
 
	// $lines = $logger->GetFromLine($index);
	$lines = $logger->GetAllLines();
	echo json_encode($lines);
	exit();
}

In that case of that function, it would lead to a full path disclosure since it will display the full path to files that have been scanned.

What also was missing in all the functions we looked at was protection against cross-site request forgery (CSRF), so an attacker could cause someone logged in to WordPress to access the various functions without intending it.

After we notified the developer they released version 3.0.9.1, which partially resolves this.

The new version introduces a function __can_access() that ends the running of the code using exit() if the user doesn’t have the “manage_options” capability:

32
33
34
35
36
private static function __can_access(){
	if(!current_user_can('manage_options')){
		wp_die(__('You do not have sufficient permissions to access this page.') );
	}
}

That function is called first when those AJAX accessible functions mentioned above are run. Here, for example, is that with GetLogLines():

231
232
233
public static function GetLogLines()
{
	self::__can_access();

There still is a lack of protection against CSRF.

Proof of Concept

The following proof of concept will show the last few log lines from the plugin’s scanner, 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=scanner-get_log_lines

Timeline

  • June 7, 2018 – Developer notified.
  • June 7, 2018 – Developer responds.
  • June 8, 2018 – Version 3.0.9.1 released, which partially fixes the issue.