02 Mar

What Happened With WordPress Plugin Vulnerabilities in February 2018

If you want the best information and therefore best protection against vulnerabilities in WordPress plugins we provide you that through our service.

Here is what we did to keep those are already using our service secure from WordPress plugin vulnerabilities during February (and what you have been missing out on if you haven’t signed up yet):

Plugin Vulnerabilities We Discovered and Publicly Disclosed This Month

We don’t just collect data on vulnerabilities in plugins that others have discovered, we also discover vulnerabilities through proactive monitoring of changes made to plugins, monitoring hackers’ activity, reviewing other vulnerabilities, and by doing additional checking on the security of plugins.

The most concerning vulnerabilities this month were several PHP object injection vulnerabilities. That is a type of vulnerability likely to be exploited. Two of them were in plugins with 10,000+ active installs according to wordpress.org. Another one, which may have been being exploited already when we ran across it, was in an even more popular plugin (with 300,000+ active installs), but it was only exploitable by those logged in to WordPress, which limited the threat. Our Plugin Security Checker (which is now accessible through a WordPress plugin of its own) can detect the possibility of those variants of PHP object injection, so anyone can check if plugins they use may be impacted by a similar vulnerability.

Plugin Vulnerabilities We Helped Get Fixed This Month

Letting you know that you are using a vulnerable version of plugin is useful, but it is much more useful if you can fully protect yourself by simple updating to a new version. So we work with plugin developers to make sure that vulnerabilities get fixed.

Plugin Vulnerabilities Added This Month That Are In The Current Version of the Plugins

Keeping your plugins up to date isn’t enough to keep you secure as these vulnerabilities in the current versions of plugins show:

Additional Vulnerabilities Added This Month

As usual, there were plenty of other vulnerabilities that we added to our data during the month. The most serious vulnerabilities here being two of the PHP object injection vulnerabilities we discovered during the month, with one of them possibly being exploited already.

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.