While looking into a recent security fix for a SQL injection vulnerability in version 2.0 of the plugin Save Contact Form 7 we noticed a much larger issue in the relevant code, all the contact form submissions saved by the plugin are publicly accessible.
Normally the submissions saved by the plugin are viewed through the plugin’s admin page which is only accessible to those logged in to WordPress with as a user with the “manage_options” capability, which normally only Administrator level users have. The submissions shown to those users are served through an AJAX request, but the handling of AJAX request is configured to allow those not even logged in to access it (in the file /save-contact-form-7.php):
add_action('wp_ajax_nimble_ajax_datatable', 'nimble_populate_datatable'); // ajax for logged in users add_action('wp_ajax_nopriv_nimble_ajax_datatable', 'nimble_populate_datatable'); // ajax for not logged in users
The comment in the second line that it is “for not logged in users” is not something we added, so the developer should have been aware that they were making the function available to those not logged in.
The requests causes the function nimble_populate_datatable(), which is located in the same file, to execute. That function doesn’t check to see if the request is coming from a user with “manage_options” capability, so anyone can make a request to it and view the submissions of a specified contact form.
The contact form whose results will be shown is specified by the plugin’s ID number for the contact form, which is set a 1 for the first contact form with a saved submission and subsequent integers for additional contact forms. So someone could easily enumerate through all of the contact form IDs to view all results.
We contacted the developer about the vulnerability over a month ago but have not heard back from them and the vulnerability has not been fixed.
Proof of Concept
The following proof of concept will cause all the contact form submissions for the first contact form that the plugin saved submissions to be shown.
Make sure to replace “[path to WordPress]” with the location of WordPress.
<html> <body> <form action="http://[path to WordPress]/wp-admin/admin-ajax.php" method="POST"> <input type="hidden" name="action" value="nimble_ajax_datatable" /> <input type="hidden" name="id" value="1" /> <input type="submit" value="Submit" /> </form> </body> </html>
- May 3, 2017 – Developer notified.