Headline
CVE-2022-3141: Authenticated SQL injection vulnerability in “Translatepress Multilingual” Wordpress plugin
The Translate Multilingual sites WordPress plugin before 2.3.3 is vulnerable to an authenticated SQL injection. By adding a new language (via the settings page) containing specific special characters, the backticks in the SQL query can be surpassed and a time-based blind payload can be injected.
While investigating Wordpress plugins, I stumbled upon “Translatepress Multilingual”, which is used to make Wordpress pages available in multiple languages and has 200,000 active installations.
It is not so easy to find SQL injections in Wordpress plugins, as wordpress has a feature called “magic quotes”, which means it automatically applies the addslashes PHP function to all GET and POST input, escaping quotes and backslashes. Therefore, many of the classic SQL injection attacks cannot work against wordpress, as it is impossible to break out of quotes. Still, there are some scenarios when user input is not surrounded by quotes, for example when it is supposed to be an integer. Today, we will have a closer look at another case.
In the Translatepress source code, there are a couple of functions that look like this:
The language code taken from the input parsed by a function called get_table_name and in addition to the magic quotes protection, we also have to bypass sanitize_text_field .
The language code is prefixed with a constant string and a filter is applied. However, I could not find this filter, so this seems to have no effect.
When looking at the SQL query, you can see that the table name is only surrounded by backticks. However, neither sanitize_text_field nor the magic quotes escape backticks.
I fired up a brand new Wordpress instance using docker-compose as described in this tutorial: https://docs.docker.com/samples/wordpress/. If you want to try this, make sure to also use a new Wordpress instance, as the exploit will mess up your database.
I installed and activated the at the time latest version of Translatepress Multilingual, 2.3.2. Then, I went to the Translatepress settings page, added a random language, English (UK), and intercepted the request with Burp Suite. Time to start injecting some payloads!
I started with `x=%23 , where %23 refers to # , which is needed to comment out the rest of the query. This should trigger an error if we can escape the backticks.
And yes, we can see a couple of SQL syntax errors flooding the window where we ran sudo docker-compose up :
We can see from these errors that our payload gets inserted into multiple statements, namely CREATE TABLE , CREATE_INDEX and CREATE FULLTEXT INDEX . However, these commands seemed uncommon to achieve a useful SQL injection attack vector, so I kept looking.
I went to the “Pages” section, opened “Sample Page” and clicked “Translate”. An editor opened up where I could translate strings, and I noticed more error messages in the Wordpress log.
Note that this happened without submitting another payload. My previous payload got inserted in some other statements, e.g. SELECT . As we can control the full SQL query after the table name, I concluded it should be easy to utilize a time-based payload.
I copied the POST request that adds a language from Burp Suite to translatepress_req.txt :
I also copied the GET request where we can execute the payload in a SELECT statement to translatepress_req_2.txt :
Time to launch sqlmap to execute a so-called second-order attack (because we have different pages for submitting the payload and viewing the result). This is the right command to use, specifying a few non-default option to speed up the detection:
sqlmap -r translatepress_req.txt -p trp_settings%5Btranslation-languages%5D%5B%5D — dbms=mysql — second-req translatepress_req_2.txt — technique=T — level 5 — risk 3 — fresh-queries
Now it is possible to use sqlmap at the full extent to download tables, for example the wp_users table, or do whatever is possible in the context of your database configuration.
It might also be possible to exploit this vulnerability using a boolean-based blind or UNION technique. It did not work out of the box, probably because the payload is inserted in many statements and breaks at least one of the queries that are necessary to show proper output. I did not spend much time trying to improve this, as I already had a time-based PoC.
This exploit can only be executed by an authenticated user, as you need to add a new language. I don’t know the Translatepress ecosystem well enough to know if only the administrator can add languages, or also some other roles. This might also depend on installed addons and custom configurations.
It is also worth noting that above PoC might need to be modified a little when the Pro version of Translatepress is attacked. Both Pro and Free are vulnerable, as the code responsible for the sanitization is the same, but I have not actually tried this yet with a Pro installation.
Shortly after I reported this vulnerability to the vendor, they released a patched update (version 2.3.3) which is using a regular expression to block malicious language codes.
You can find this exploit also on Github:
If you want to read about more vulnerabilities I discover, make sure you follow me on LinkedIn, Medium & Twitter:
If you run a company and are looking for an expert to make sure your web applications are secure, feel free to send an email to [email protected] to receive an offer.