SQL Injection (SQLi)
Introduction
This article covers cases of possible SQLi on WordPress. This includes improper usage of functions and user input handling inside of the plugin/theme which can be used to inject a malicious query into the SQL execution to leak sensitive data.
Useful Functions
Several functions could be useful to identify a possible SQLi vulnerability:
Example Cases
Below is an example of vulnerable code:
The vulnerable variable, in this case, is the $question_sql
variable where the value is passed from $_COOKIE[ 'question_ids_'.$quiz_id ]
value without proper sanitization or escaping. The sanitize_text_field
function is not enough to prevent SQL Injection since the $question_sql
variable is constructed inside an ORDER BY clause without proper escaping.
To exploit this, any unauthenticated user just needs to perform a POST request to the /wp-admin/admin-ajax.php
endpoint specifying the needed action and parameter to trigger the SQL Injection (letβs say that the {$wpdb->prefix}custom_questions
table has 5 columns):
Below are some of the findings related to SQLi:
- Critical Vulnerabilities Patched in REHub Theme and Plugin
- Critical SQL Injection Found in Porto Themeβs Plugin
- Multiple High and Critical Vulnerabilities in Avada Theme and Plugin
- Critical Unauthenticated SQL Injection in Quiz And Survey Master <= 8.1.4
- Multiple Vulnerabilities Fixed In WP Statistics Plugin Version <= 13.2.10
- Multiple Critical Vulnerabilities Fixed In LearnPress Plugin Version <= 4.1.7.3.2
Magic Quotes
Magic Quotes is/was a feature in PHP designed to automatically escape certain characters in user input to prevent SQL injection (SQLi) attacks. Specifically, it would escape single quotes (β), double quotes (β), backslashes (), and NULL characters by automatically adding backslashes before them. This was done to protect against common vulnerabilities like SQL injection, where an attacker might try to insert malicious SQL code into a query.
It is not the perfect solution. It is mostly inconsistent, meaning that it only escapes certain characters. Depending on how the code works it might still allow for SQL injections or corrupted data in the database.
It was optional for PHP but it is disabled. Why we are mentioning it here? It still lives in WordPress via wp_magic_quotes()
.
As mentioned on that page, it is a private function so developers donβt need to implement it. If any code is executed inside WordPress hooks, inputs ($_GET
, $_POST
, $_COOKIE
, and $_SERVER
) will go through the add_magic_quotes()
and gets sanitized due to addslashes()
.
So even a super simple vulnerable-looking code like select * from users where '$injection_here';
will be escaped and turn into something like SELECT * FROM users where '\'testpayload';
inside a WordPress hook and you will not be able to exploit it in almost all scenarios.
Safe Code:
Vulnerable Code:
If the input is unslashed using wp_unslash()
it will still be exploitable.