msaari / relevanssi-light

Relevanssi Light fulltext search
17 stars 1 forks source link

subtle sql injection vulnerability in relevanssi_light_posts_request #13

Closed kkatpcc closed 1 year ago

kkatpcc commented 1 year ago

Versions

WP version: 6.0.3 & 6.1.1 (only ones tested) Relevanssi Light (this) plugin version: 1.2.1 (only one tested)

Description

The latest stable version of this plugin (1.2.1) seems to have as subtle sql injection vulnerability at https://github.com/msaari/relevanssi-light/blob/77fc47451f35a6af059d064637f74f9aa0f7bdaa/relevanssi-light.php#L257

None of the following errors occur with search when this plugin is disabled, i.e. no problems with stock WP search.

Proof of concept

raw query text: before') AND FAIL=(SELECT FAIL FROM FAIL(FAIL)) AND ('after'='after

encoded as search: /?s=before%27%29%20AND%20FAIL%3D%28SELECT%20FAIL%20FROM%20FAIL%28FAIL%29%29%20AND%20%28%27after%27%3D%27after

PHP error log result, indicating that some of the injected SQL made it through:

WordPress database error You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'before\') AND FAIL=(SELECT FAIL FROM FAIL(FAIL)) AND (\'after\'=\'after' ) AS re' at line 3 for query 
            SELECT SQL_CALC_FOUND_ROWS  wp__posts.*
            , MATCH(post_title,post_excerpt,post_content,relevanssi_light_data) AGAINST('before\') AND FAIL=(SELECT FAIL FROM FAIL(FAIL)) AND (\'after\'=\'after' ) AS relevance FROM wp__posts 
            WHERE 1=1  AND MATCH(post_title,post_excerpt,post_content,relevanssi_light_data) AGAINST('before\') AND FAIL=(SELECT FAIL , MATCH(post_title,post_excerpt,post_content,relevanssi_light_data) AGAINST('before\') AND FAIL=(SELECT FAIL FROM FAIL(FAIL)) AND (\'after\'=\'after' ) AS relevance FROM FAIL(FAIL)) AND (\'after\'=\'after' ) AND ((wp__posts.post_type = 'post' AND (wp__posts.post_status = 'publish')) OR (wp__posts.post_type = 'page' AND (wp__posts.post_status = 'publish')) OR (wp__posts.post_type = 'attachment' AND (wp__posts.post_status = 'publish')))

            ORDER BY relevance DESC, wp__posts.post_date DESC
            LIMIT 0, 10
         made by require('wp-blog-header.php'), wp, WP->main, WP->query_posts, WP_Query->query, WP_Query->get_posts
msaari commented 1 year ago

Ok, I see. The problem is the extra "FROM" in the search query. One of the hooks in Relevanssi Light works by replacing the "FROM" in the MySQL query with more MySQL. Since I was using str_replace(), it replaced all occurrences of "FROM", even the extra ones from the query, which breaks the MySQL code.

It looks like the fix here is to replace str_replace() with preg_replace(), as that can be set to replace only the first occurrence.

Hopefully, this vulnerability is hard to use for anything malicious. It's probably hard to formulate an attack that doesn't make the MySQL query simply fail.