Fortinet’s FortiGuard Labs discovered and reported SQL injection vulnerabilities in nine different popular WordPress plugins. All nine vulnerabilities were given a CVSS score of 9.0 and rated with critical severity. These popular plugins belonged to various categories such as advertisement, donation, gallery, forms, newsletter, video player, etc… and are being widely used by many websites.

The vulnerabilities were discovered by security researchers from Fortinet’s FortiGuard Labs and were made public in a detailed report. All the identified vulnerabilities were assigned with a FortiGuard Labs CVE identity. The following are the list of the CVE ID with respect to the nine identified vulnerabilities.

  • CVE-2019-13570
  • CVE-2019-13572
  • CVE-2019-13569
  • CVE-2019-13575
  • CVE-2019-13573
  • CVE-2019-13578
  • CVE-2019-14314
  • CVE-2019-14313
  • CVE-2019-14695

An interesting point is eight out of nine vulnerabilities were found with the same simple code pattern that made them vulnerable to a SQL injection. While most of the Vulnerabilities had the same code pattern FortiGuard researchers explained in detail about the three major vulnerabilities with CVEs FG-VD-19-098, FG-VD-19-099, and FG-VD-19-092. In spite of the potential for exploit, many developers simply do not carefully filter user-supplied data. And in this case, this happened despite WordPress Core’s efforts, since they support various built-in methods to ensure that any user-supplied data is well-sanitized.

Background

A SQL injection occurs when user input is used to construct a SQL query without being properly sanitized. Consider the following example:

$edit_banner=$wpdb->get_row(“SELECT * FROM ‘{$wpdb->prefix}some_table’ WHERE ‘id’ = ‘$id’;”);

At first glance, one would say this code is vulnerable to a SQL injection attack, since $id is retrieved from $_GET and passed into the SQL query without any sanitization. The good news is, in the latest version of WordPress, magic quotes are always added to $_POST/$_GET/$_REQUEST/$_COOKIE by default [1]. This helps WordPress maintain consistency and provide the best possible security capabilities. Therefore, the above code is not actually vulnerable.

Beside enforcing the adding of slashes to all input values, WordPress also provides several built-in sanitization and escape functions for cleaning user input and/or securing output [2]. Developers can use sanitize_email() to sanitize email addresses, or sanitize_text_field() to clean text field values, or sanitize_sql_orderby() to validate the SQL ORDER BY clauses, and more. Most common types of user input are covered by the WordPress sanitize_*() class of helper functions.

Although WordPress Core is doing its best to help developers prevent common attacks caused by malformed user-input, bad coding practices and misusing escaping functions still lead to simple but critical vulnerabilities.

Analysis

FG-VD-19-092 – SQL Injection in AdRotate Plugin through 5.2 for WordPress

This vulnerability is a classic SQL Injection which exists in the AdRotate plugin through v5.2, in both the FREE and PRO versions. The flaw can be spotted in dashboard/publisher/adverts-edit.php, at line 25.

$edit_banner = $wpdb->get_row(“SELECT * FROM ‘{ $wpdb->prefix}adrotate’ WHERE ‘id’ = {$ad_edit_id};”);

The variable $ad_edit_id is used to construct a SQL query. This variable is retrieved from $_GET, in the adrotate_manage function:

If (isset($_GET [‘ad’])) $ad_edit_id = esc_attr ($GET[‘ad’]);

Since esc_attr only escapes HTML attributes and $ad_edit_id is not escaped with double quotes in the SQL query, we can execute an arbitrary SQL statement by injecting payloads into $ad_edit_id.

Although the management interface is only available for the Administrator role, a lack of a CSRF token makes it possible for unauthenticated attackers to remotely steal information, including session tokens, with a minimum user interaction by using this SQL injection vulnerability to cause a XSS.

The patch from the developers is simply adding quotes to $ad_edit_id in the query.

$edit_banner = $wpdb->get_row(“SELECT * FROM ‘{$wpdb->prefix}adrotate’ WHERE ‘id’ = ‘{$ad_edit_id}’;”);

Timeline:

  • Fortinet reported the vulnerability to AJDG Solutions on July 09, 2019.
  • AJDG Solutions asked for more information and confirmed the vulnerability on July 10, 2019.
  • AJDG Solutions released patch for the vulnerability on July 12, 2019.