WARNING: WordPress File Delete to Code Execution


WordPress Unlink to RCE

WordPress is the most popular CMS on the web. According to w3tech, it is used by approximately 30% of all websites1. This wide adoption makes it an interesting target for cyber criminals. In this blog post we are going to introduce an authenticated arbitrary file deletion vulnerability in the WordPress core that can lead to attackers executing arbitrary code. The vulnerability was reported 7 months ago to the WordPress security team but still remains unpatched. The long time elapsed since the initial reporting without any patch or concrete plans has led us to the decision to make it public.

Who is affected

At the time of writing no patch preventing this vulnerability is available. Any WordPress version, including the current 4.9.6 version, is susceptible to the vulnerability described in this blogpost.

For exploiting the vulnerability discussed in the following an attacker would need to gain the privileges to edit and delete media files beforehand. Thus, the vulnerability can be used to escalate privileges attained through the takeover of an account with a role as low as Author, or through the exploitation of another vulnerability/misconfiguration.

Impact - What can an attacker do

Exploiting the vulnerability grants an attacker the capability to delete any file of the WordPress installation (+ any other file on the server on which the PHP process user has the proper permissions to delete). Besides the possibility of erasing the whole WordPress installation, which can have desastrous consequences if no current backup is available, an attacker can make use of the capability of arbitrary file deletion to circumvent some security measures and to execute arbitrary code on the webserver. More precisely, the following files can be deleted:

  • .htaccess: In general, deleting this file does not have any security consequences. However, in some occasions, the .htaccess file contains security related constraints (e.g., access constraints to some folders). Deleting this file would deactivate those security constraints.
  • index.php files: Oftentimes empty index.php files are placed into directories to prevent directory listing for the case the webserver fails to do so. Deleting those files would grant an attacker a listing of all files in directories protected by this measure.
  • wp-config.php: Deleting this file of a WordPress installation would trigger the WordPress installation process on the next visit to the website. This is due to the fact that wp-config.php contains the database credentials, and without its presence, WordPress acts as if it hasn’t been installed yet. An attacker could delete this file, undergo the installation process with credentials of his choice for the administrator account and, finally, execute arbitrary code on the server.

Technical Details

An arbitrary file deletion vulnerability occurs when unsanitized user input is passed to a file deletion function. In PHP this happens when the unlink() function is called and user input can affect parts of or the whole parameter $filename, which represents the path of the file to delete, without undergoing proper sanitization.

The code section which made this vulnerability possible in the WordPress Core is found in the wp-includes/post.php file:

/wp-includes/post.php

 1 2 3 4 5 6 7 8 9101112131415
function wp_delete_attachment( $post_id, $force_delete = false ) {
	
	$meta = wp_get_attachment_metadata( $post_id );
	
	if ( ! empty($meta['thumb']) ) {
		// Don't delete the thumb if another attachment uses it.
		if (! $wpdb->get_row( $wpdb->prepare( "SELECT meta_id FROM $wpdb->postmeta WHERE meta_key = '_wp_attachment_metadata' AND meta_value LIKE %s AND post_id <> %d", '%' . $wpdb->esc_like( $meta['thumb'] ) . '%', $post_id)) ) {
			$thumbfile = str_replace(basename($file), $meta['thumb'], $file);
			/** This filter is documented in wp-includes/functions.php */
			$thumbfile = apply_filters( 'wp_delete_file', $thumbfile );
			@ unlink( path_join($uploadpath['basedir'], $thumbfile) );
		}
	}
	
}

In the wp_delete_attachement() function shown above, the content of $meta[‘thumb’] gets used in the call to unlink() without undergoing any sanitization. The purpose of this snippet of code is to delete the thumbnail of an image alongside its deletion. Images uploaded through the media manager in WordPress are represented as a post of type attachement. The value $meta[‘thumb’] gets retrieved from the database where it is saved as a Custom Field2 of the post representing the image. So, between retrieval from the database and usage in the critical function call to unlink(), the value representing the thumbnail filename doesn’t undergo any sanitizations or checks. If the value also doesn’t undergo any or unsufficient security measures before being saved to the database, which is the case as we will see in the next code listing, we have a second-order arbitrary file deletion vulnerability.

/wp-admin/post.php

 1 2 3 4 5 6 7 8 9101112

switch($action) {

	case 'editattachment':
		check_admin_referer('update-post_' . $post_id);
		
		// Update the thumbnail filename
		$newmeta = wp_get_attachment_metadata( $post_id, true );
		$newmeta['thumb'] = $_POST['thumb'];

		wp_update_attachment_metadata( $post_id, $newmeta );

The latter code snippet, which resides in /wp-admin/post.php, represents how the filename of the thumbnail belonging to an attachement gets saved to the database. Between retrieval from user input saved in $_POST[‘thumb’] and saving to the database with wp_update_attachment_metadata() there are no security measures in place to assure that the value really represents the thumbnail of the attachement being edited. The value of $_POST[‘thumb’] could hold the, to the WordPress upload directory relative, path of any file, and when the attachement gets deleted, the file will get deleted with it as seen in the first listing.

Temporary Hotfix

The described vulnerability remains unpatched in the WordPress core as the time of writing. Because of this, we have developed a temporary fix provided in the snipped below. The fix can be integrated into an existing WordPress installation by adding it to the functions.php file of the currently active theme/child-theme.

123456789
add_filter( 'wp_update_attachment_metadata', 'rips_unlink_tempfix' );

function rips_unlink_tempfix( $data ) {
    if( isset($data['thumb']) ) {
        $data['thumb'] = basename($data['thumb']);
    }

    return $data;
}

All the provided Hotfix does is to hook into the wp_update_attachement_metadata() call and making sure that the data provided for the meta-value thumb does not contain any parts making path traversal possible. Thus, no security relevant files can be deleted.

The provided fix shall ultimately be seen as a temporary fix in order to prevent attacks. We cannot oversee all possible backwards compatibility problems with WordPress plugins and advise to make any modifications to your WordPress files with caution.

Time Line

DateWhat
2017/11/20Vulnerability reported to the WordPress security team on Hackerone.
2017/11/22The vulnerability was triaged and verified by the security team.
2017/12/12Asked for progress.
2017/12/18Wordpress is working on a patch. Asked for release date. No response.
2018/01/09Asked for release date. No response.
2018/01/20Asked for mediation on Hackerone due to the severity of the issue and the lack of communication.
2018/01/24The WordPress security team estimates the time to fix to be 6 months.
2018/05/24Asked for progress and/or plans on the issue, and given a reminder that we would publish it soon. No response.
2018/05/24Sent twitter DM to a member of the security team to make sure they do not overlook the message on Hackerone.
2018/06/26The issue remains unpatched more than 7 months after reporting.
2018/07/05WordPress released a fix in version 4.9.7.

Summary

In this blog post we have introduced an arbitrary file deletion vulnerability in the WordPress core that allows any user with privileges of an Author to completely take over the WordPress site and to execute arbitrary code on the server. The vulnerability was reported to the WordPress security team last year but still remains unpatched at the time of writing.

In order to raise awareness of this vulnerability we decided to publish some details and a hotfix. The vulnerability can be easily spotted with our security analysis solution and we are certain that this issue is already known to many researchers. Although the requirement of a user account prevents the exploitation of arbitrary WordPress sites at scale, those sites that share multiple user accounts should apply a hotfix.

Update 2018/07/05

The WordPress team published an update in their security and maintenance release 4.9.7 that fixes the vulnerability described in this blog post and a related one discovered later by Wordfence.

Update 2018/08/14

A new PHP exploiting technique was released that also allows to turn this bug into a PHP object injection vulnerability. Find out more about Phar Deserialization


Tags: karim el ouerghemmi, php, security, wordpress, code execution, file delete,

Author: Karim El Ouerghemmi

Security Researcher

Karim is a security researcher and bug hunter at RIPS Technologies and is passionate about web security in all its facets, ranging from server security to browser security. He is currently pursuing a master's degree in IT Security at the Ruhr-University Bochum.

Comments

comments powered by Disqus