The clean_query function is called from get_sql_for_clause. Reading the code of the function will see that the job of this function is to create clauses for the condition in an SQL query, specifically its job will be to process the received data, to combine that data into a condition in the SQL query. and return it to the parent function. So we can control the return data of this function, which means we can control the SQL query and perform SQL Injection.

Analysis

In version 5.8.3, wordpress has fixed this error, comparing commit changes, you can see in the clean_query function that the $query[‘field’] check has been added before processing the $query[‘terms’] variable.

sql injection in wordpress

The clean_query function is called from get_sql_for_clause. Reading the code of the function will see that the job of this function is to create clauses for the condition in an SQL query, specifically its job will be to process the received data, to combine that data into a condition in the SQL query. and return it to the parent function. So we can control the return data of this function, which means we can control the SQL query and perform SQL Injection.

sql injection in wordpress

Going back to the clean_query function, without this change, by default the values in $query[‘terms’] will just be de-duplicated and then call $this->transform_query( $query, ‘term_taxonomy_id’ ) ;.

To avoid an if, $query[‘taxonomy’] needs to be empty or a value for is_taxonomy_hierarchical to return false.

sql injection in wordpress

In function transform_query will check $query[‘field’] = = $resulting_field, if true will return and do no further processing, so if $query[‘field’] variable is term_taxonomy_id then we can exit the function without changing the $query[‘terms’] variable value.(The comparison here is using = = and suffers from the loophole of Loose comparisons, in some cases this error can be used to create a conditional sentence at will).

sql injection in wordpress

After exiting the function, the code flow will return to the location where the clean_query function was called which is the get_sql_for_clause function, the value in the $query[‘terms’] variable will be used directly as the condition of the SQL query and lead to SQL Injection.

sql injection in wordpress

So in summary, for SQL Injection to occur, two conditions must be met: $query[‘field’] is term_taxonomy_id $query[‘taxonomy’] is empty or is_taxonomy_hierarchical($query[‘taxonomy’]) === false Flow results in the following error:

sql injection in wordpress

Exploit

Although this is an error in the core of wordpress, the way the wordpress core uses it does not trigger the error, so I have turned to the direction of finding errors in plugins and themes. The plugin/theme will call the WP_Query class when you want to query the DB, the way to recognize the error from the source code is when using WP_Query($data) and $data is something you can control.

For example, new WP_Query(json_decode($_POST[‘query_vars’])) then the payload will look like:

query_vars={“tax_query”:{“0”:{“field”:”term_taxonomy_id”,”terms”:[“”]}}} or query_vars={“tax_query”:{“0”:{“taxonomy “:”nav_menu”,”field”:true,”terms”:[“”]}}}

When building an environment for error testing, enabling the DEBUG function will make it possible to detect SQL Injection via error-based:

Conclude

In wordpress patch added $query[‘field’] check first, otherwise $query[‘terms’] will be converted to integer so SQLI can’t happen.

Due to the large number of wordpress plugins and themes, our team only focuses on looking for those with downloads > 100k (free version), in addition to paid plugins/themes or < 100k downloads, we no time to continue.

As a result, quite a few plugins and themes were found affected by the vulnerability (both authen and unauthen).