7 Feb 2017

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.

Concerned About The Security of the Plugins You Use?

When you are a paying customer of our service, you can suggest/vote for the WordPress plugins you use to receive a security review from us. You can start using the service for free when you sign up now. We also offer security reviews of WordPress plugins as a separate service.

Leave a Reply

Your email address will not be published.