15 Feb

Our Proactive Monitoring Caught a PHP Object Injection Vulnerability in Swift Help Desk Support Software Ticketing System

One of the ways we help to improve the security of WordPress plugins, not just for our customers, but for everyone using them, is the proactive monitoring of changes made to plugins in the Plugin Directory to try to catch serious vulnerabilities. That again has lead to us catching a vulnerability of a type that hackers are likely to exploit if they know about it. Since the check used to spot this is also included in our Plugin Security Checker (which  is now accessible through a WordPress plugin of its own), it is another of reminder of how that can help to indicate which plugins are in greater need of security review (for which we do as part of our service as well as separately).

In the plugin Swift Help Desk Support Software Ticketing System (Help Desk & Knowledgebase Software) the value of a cookie is passed through the unserialize() function, which could lead to PHP object injection. That occurs in two shortcodes accessed functions in the plugin. One of them being swift_helpdesk_support_callback(), which is located in the file /sections/shd-shortcodes.php. Some ways into the function it checks if the cookie “sc_lead_scoring” exists and then unserializes its value:

164
165
if (isset($_COOKIE['sc_lead_scoring']) && !empty($_COOKIE['sc_lead_scoring'])) {
	$sc_lead_scoring_cookie = unserialize(stripslashes($_COOKIE['sc_lead_scoring']));

Even if the shortcodes that cause those functions to run are not used on the website, any one logged in to WordPress could access them, like they can shortcodes in general, through WordPress AJAX functionality and the vulnerability is also exploitable that way as well.

We notified the developer of the issue a week ago. We haven’t heard back from them and no new version has been released to fix the issue. 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.

The Plugin Security Checker has flagged other possible issues in the plugin, so those using the plugin may want to have someone do a thorough review of the plugin’s security.

Proof of Concept

With our plugin for testing for PHP object injection installed and activated, set the value of the cookie “sc_lead_scoring” to “O:20:”php_object_injection”:0:{}” and then when you visit a page on the website using the “swift_helpdesk_support” shortcode the message “PHP object injection has occurred.” will be shown.

Timeline

  • February 8, 2017 – Developer notified.
15 Feb

Our Proactive Monitoring Caught an Authenticated PHP Object Injection Vulnerability in Autoship Cloud

One of the ways we help to improve the security of WordPress plugins, not just for our customers, but for everyone using them, is the proactive monitoring of changes made to plugins in the Plugin Directory to try to catch serious vulnerabilities. That sometimes leads to us catching a vulnerability of a more limited version of one of those serious vulnerability types, which isn’t as much concern for the average website, but could be utilized in a targeted attack. That happened with the authenticated PHP object injection vulnerability we found in the plugin Autoship Cloud. This vulnerability could have allowed an attacker that had access to a WordPress account that has access to admin pages, which would normally be Subscriber level users and above, to exploit a PHP object injection vulnerability.

Since the check used to spot this is also included in our Plugin Security Checker (which  is now accessible through a WordPress plugin of its own), it is another of reminder of how that can help to indicate which plugins are in greater need of security review (for which we do as part of our service as well as separately).

The vulnerability occurred in the function autoship_get_messages(). That function passed the base64 decoded value of the cookie “autoship_messages” through the unserialize() function, which could lead to PHP object injection:

3
4
5
6
7
function autoship_get_messages() {
	if ( empty( $_COOKIE['autoship_messages'] ) ) {
		return array();
	}
	$messages = unserialize( base64_decode( $_COOKIE['autoship_messages'] ) );

One of the locations that function gets called is in the function autoship_print_messages():

44
45
46
47
48
49
function autoship_print_messages() {
	if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
		return;
	}
 
	$messages = autoship_get_messages();

That function runs when admin notices are shown:

68
add_action( 'admin_notices', 'autoship_print_messages' );

After we notified the developer of the plugin they released version 1.0.14, which fixes the vulnerability. Though in a reminder that you can’t rely on changelogs to let you know if a new version of a plugin includes a security fix, the only changelog entry for that version is “Bug fixes.”. The only change made though was to fix the vulnerability. That was done by replacing the use of unserialize() with json_decode():

7
$messages = json_decode( base64_decode( $_COOKIE['autoship_messages'] ) );

and elsewhere in the same file, replacing related usage of serialize() with json_encode():

39
$messages_cookie = base64_encode( json_encode( $messages ) );

Proof of Concept

With our plugin for testing for PHP object injection installed and activated, set the value of the cookie “autoship_messages” to “TzoyMDoicGhwX29iamVjdF9pbmplY3Rpb24iOjA6e30=” and then when you visit an admin page on the website the message “PHP object injection has occurred.” will be shown.

Timeline

  • February 12, 2018 – Developer notified.
  • February 12, 2018 – Developer responds.
  • February 15, 2018 – Version 1.0.14  released, which fixes vulnerability.
14 Feb

Our Proactive Monitoring Caught a PHP Object Injection Vulnerability Returning to a Fairly Popular Plugin

One of the ways we help to improve the security of WordPress plugins, not just for our customers, but for everyone using them, is the proactive monitoring of changes made to plugins in the Plugin Directory to try to catch serious vulnerabilities. That again has lead to us catching a vulnerability in a fairly popular plugin, of a type that hackers are likely to exploit if they know about it. In this case the vulnerability is much worse because it was previously fixed, so some hacker could still be trying to exploit it based on the previous instance of it. Since the check used to spot this is also included in our Plugin Security Checker (which  is now accessible through a WordPress plugin of its own), it is another of reminder of how that can help to indicate which plugins are in greater need of security review (for which we do as part of our service as well as separately).

Back in September we noticed that PHP object injection vulnerability had been fixed the plugin Welcart e-Commerce, which has 10,000+ active installations according to wordpress.org (who had discovered vulnerability that wasn’t disclosed). That had been fixed by replacing the usage of unserialze() with json_decode() in version 1.9.4. The relevant line had previously looked like this (in the file /classes/usceshop.class.php):

$values = isset($_COOKIE[$key]) ? unserialize(stripslashes($_COOKIE[$key])) : NULL;

And was replaced with this:

$values = isset($_COOKIE[$key]) ? json_decode(stripslashes($_COOKIE[$key]), true) : NULL;

Then in version 1.9.5 it got changed to:

$values = isset($_COOKIE[$key]) ? usces_unserialize(stripslashes($_COOKIE[$key])) : NULL;

That function usces_unserialize() used there is as follows:

2498
2499
2500
2501
2502
2503
2504
2505
2506
function usces_unserialize( $data ) {
	if( is_serialized( $data ) ) {
		return @unserialize( $data );
	}
	if( is_array( $data ) ) {
		return $data;
	}
	return @json_decode( $data, true );
}

With that, if the value passed to the function is serialized then the value is unserialized. Since PHP object injection involves untrusted serialized data being unserialized, that code allows for PHP object injection again. This can easily be exploited because that code runs when visiting any frontend page of the website.

Since the vulnerability could be already be being exploited due to the previous instance of it, we are disclosing this without giving the developer a chance to fix it first, since we have a responsibility to warn our customers as soon as possible (and we don’t want to leave others without the ability to know about this and we don’t want to allow hackers to use our service to become aware of otherwise undisclosed vulnerabilities).

Proof of Concept

With our plugin for testing for PHP object injection installed and activated, set the value of the cookie “usces_cookie” to “O:20:”php_object_injection”:0:{}” and then when you visit any front end page the message “PHP object injection has occurred.” will be shown.

Timeline

  • February 14, 2018 – Developer notified.
13 Feb

Our Proactive Monitoring Caught an Authenticated Arbitrary File Upload Vulnerability in Church Admin

One of the ways we help to improve the security of WordPress plugins, not just for our customers, but for everyone using them, is the proactive monitoring of changes made to plugins in the Plugin Directory to try to catch serious vulnerabilities. That sometimes leads to us catching a vulnerability of a more limited version of one of those serious vulnerability types, which isn’t as much concern for the average website, but could be utilized in a targeted attack. That happened with the authenticated arbitrary file upload vulnerability we found in the plugin Church Admin. This vulnerability could have allowed someone that has access to a WordPress account that can access the admin area (which would normally be any user, Subscriber-level and above) to upload a malicious file to the website, which could they use to take additional actions on with the website.

Since the check used to spot this is also included in our Plugin Security Checker (which  is now accessible through a WordPress plugin of its own), it is another of reminder of how that can help to indicate which plugins are in greater need of security review (for which we do as part of our service as well as separately).

The vulnerability occurred in the function church_admin_bible_reading_plan(), which is located in the file /app/app-admin.php and would save any type of file sent with a request to the current year/month’s directory inside of the /wp-content/upload/ directory:

function church_admin_bible_reading_plan()
{
 global $wpdb;
 echo'<h2 class="plan-toggle">'.__('Which Bible Reading plan? (Click to toggle)','church-admin').'</h2>';
 
 echo'<div class="bible-plans" style="display:none">';
 echo '<p>'.__('The Bible reading post type for a particular day takes priority over any plan loaded below','church-admin').'</p>';
 if(!empty($_POST['save_csv']))
 {
 if(!empty($_FILES) && $_FILES['file']['error'] == 0)
 {
 $wpdb->query('TRUNCATE TABLE '.CA_BRP_TBL);
 $plan=stripslashes($_POST['reading_plan_name']);
 update_option('church_admin_brp',$plan);
 $filename = $_FILES['file']['name'];
 $upload_dir = wp_upload_dir();
 $filedest = $upload_dir['path'] . '/' . $filename;
 if(move_uploaded_file($_FILES['file']['tmp_name'], $filedest))echo '<p>'.__('File Uploaded and saved','church-admin').'</p>';

That function gets called in the function church_admin_app() if the website has a license number for the companion app set up:

function church_admin_app()
{

	//initialise
	global $wpdb;
	echo'>h1<Church Admin App Admin>/h1<';
	
	
	$licence=get_option('church_admin_app_licence');
	
	if(empty($licence)||$licence!=md5('licence'.site_url()))
	{
	
		//no licence yet
		echo '>div id="iphone" class="alignleft"<>iframe src="'.plugins_url('/app/demo/index.html',dirname(__FILE__) ).'" width=475 height=845 class="demo-app"<>/iframe<>/div<';
		
		if(!empty($_POST['app-licence']) && $_POST['app-licence']==md5('licence'.site_url()))
		{
			update_option('church_admin_app_licence',md5('licence'.site_url()));
			update_option("church_admin_app_id",intval($_POST['app-id']));
			update_option("church_admin_app_home",">h2<Welcome>/h2<");
			update_option("church_admin_app_giving",">h2<Giving>/h2<");
			update_option("church_admin_app_groups",">h2<Small groups>/h2<");
update_option("church_admin_app_api_key","AAAA50JK2is:APA91bE-SZWcUncaSxdbevuGOdochq7zS2fgJabNBAmbqBnmR8Lq4BoaQwG_p-JM2Ftx5rAKInlnG5RmxhWW_LcOPW9A9cQqpg7tUA1GFi1-NvX2q5YbFqnM9ZmV5xuE0PfeRWFUL1d4Te4zwzpu5qglwzZpg_JWzg");
	
		}
		
		echo'>h3<'.__('If you have subscribed, please fill in this form to activate','church-admin').'>/h3<>form action="" method="post"<>table<>tr<>th scope="row"<'.__('App Licence Key','church-admin').'>/th<>td<>input type="text" name="app-licence"/<>/td<>/tr<>tr<>th scope="row"<App ID>/th<>td<>input type="text" name="app-id"/<>/td<>/tr<>tr<>td colspacing=2<>input type="submit" value="'.__('Activate','church-admin').'"/<>/td<>/tr<>/table<>/form<';
		
		church_admin_app_signup();
		
		echo'>h3<'.__('Try out the app...','church-admin').'>/h3<>p<
>a href="https://itunes.apple.com/gb/app/wp-church/id1179763413?mt=8"<'.__('Install app on your iPhone now','church-admin').'>/a< and >a href="https://play.google.com/store/apps/details?id=com.churchadminplugin.wpchurch"<Android>/a<>/p<';

	}
	else
	{
		
		church_admin_app_content();
		church_admin_app_member_types();
		church_admin_bible_reading_plan();

An attacker can set that up that license number from the page shown if that hasn’t already been set up. They don’t even need to sign up for the service, as the value is just the md5 value of the website’s site_url:

11
if(empty($licence)||$licence!=md5('licence'.site_url()))

The function church_admin_app() is in turn accessible from the function church_admin_main() (located in the file /index.php):

914
case 'app': require_once(plugin_dir_path(__FILE__).'app/app-admin.php');church_admin_app();break;

Which is accessible to anyone with the “read” capability:

789
add_menu_page('church_admin:Administration', __('Church Admin','church-admin'),  'read', 'church_admin/index.php', 'church_admin_main');

We notified the plugin’s developer of the issue yesterday and they made changes that while not ideal, do fix the vulnerability. The function church_admin_bible_reading_plan() has now been restricted to those with the ability to “manage_options” (it seems that would be better suited to be a restriction placed in the function church_admin_app() though), which would normally limit it to only Administrators:

678
679
680
681
682
683
function church_admin_bible_reading_plan()
{
	global $wpdb;
	$current_user = wp_get_current_user();
 if(is_user_logged_in()&& current_user_can('manage_options'))
 {

In that function there has also been a nonce check added, which would prevent cross-site request forgery (CSRF), and a check of what type of files has been uploaded:

691
692
693
694
695
if(!empty($_POST['save_csv'])&& check_admin_referer( 'bible_upload', 'nonce' ) )
{
	$mimes = array('application/vnd.ms-excel','text/plain','text/csv','text/tsv');
	if(!empty($_FILES) && $_FILES['file']['error'] == 0 && in_array($_FILES['file']['type'],$mimes))
	{

The [‘type’] attribute of $_FILES is user specified so it shouldn’t be used a security check, but in this case, properly limiting the upload to Administrators and protecting against CSRF is enough protection.

There are some other upload functions in the plugin that could use a close check to make sure they are properly secured (something we mentioned to the developer).

Proof of Concept

The following proof of concept will upload the selected file to the current year/month’s directory inside of the /wp-content/upload/ directory, when logged in to WordPress and the license number set for the companion app set.

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=church_admin%2Findex.php&action=app" method="POST" enctype="multipart/form-data">
<input type="file" name="file" />
<input type="submit" name="save_csv" value="Submit" />
</form>
</body>
</html>

Timeline

  • February 12, 2018 – Developer notified.
  • February 12, 2018 – Developer responds.
  • February 12, 2018 – Version 1.2540 release, which fixes vulnerability.