• WP-Statistics Plugin Version <= 12.0.7
  • Least Permission account : Subscriber account (with post edit permission)

Why it is easy to exploit?

This vulnerability is caused by the lack of sanitization in user provided data. An attacker with at least a subscriber account could leak sensitive data and under the right circumstances/configurations compromise your WordPress installation.

How it actually Works?

WordPress provides an API that enables developers to create content that users can inject to certain pages just using a simple shortcode:

Shortcode: [shortcode atts_1=”test” atts_2=”test”]

Among other functionalities, WP Statistics allows admin users to get detailed information related with the number of visits by just calling the shortcode below:

As you can see on the above code shortcode.php, some attributes of the shortcode wpstatistics are being passed as parameters for important functions and this shouldn’t be a problem if those parameters were sanitized,but as we’ll see this is not the case.

Example: result = wp_statistics_searchengine( $atts[‘provider’], $atts[‘time’] );

One of the vulnerable functions wp_statistics_searchengine_query() in the file “includes/functions/functions.php” is accessible through WordPress’ AJAX functionality through function wp_ajax_parse_media_shortcode().

This function doesn’t check for additional privileges, allowing subscribers to execute this shortcode and inject malicious data to its attributes.

In a number places in the code, user input coming from attributes of the wpstatistics’ shortcode are included in SQL queries without being sanitized. Below one of the queries that were exploitable:

The wp_statistics_searchengine_query() basically returns the same value as the one passed in the shortcode attribute provider and its content is added directly to the raw SQL query.

Exploit Phase:

When user (subscriber) enter shortcode in post as [wpstatistics stat=”searches” provider=”Google”]

it will call wp_statistics_searchengine() with provider=”Google”, then it call another function wp_statistics_searchengine_query( ), as a result it form a SQL query and stored in variable in $search_query.

Example: $search_query .= “engine = ‘{$search_engine}’”;
Here search engine = “Google”. which will be as $search_query = “engine = ‘Google’” It is directly input in most of the SQL queries i.e see below SQL queries statement

$result = $wpdb->query( “SELECT * FROM {$tablename} WHERE last_counter = ‘{$WP_Statistics->Current_Date( ‘Y-m-d’ )}’ AND {$search_query}” );

so user input is not sanitized on parameter provider, so which allow user to injection any malicious queries to fetch data from database

Example: This payload will get username, password and email from database and stored into test.txt file.
[wpstatistics stat=”searches” provider=”123’ union select 1,2,user_login,user_pass,user_email,6 from wp_users into outfile ‘/var/www/html/waf-demo/wp-content/uploads/test.txt’#”]

Demo Video