Security Vulnerability in Loginizer WordPress Plugin

Introduction

According to Loginizer’s WordPress Plugin page: “Loginizer is a WordPress plugin which helps you fight against bruteforce attack by blocking login for the IP after it reaches maximum retries allowed. You can blacklist or whitelist IPs for login using Loginizer. You can use various other features like Two Factor Auth, reCAPTCHA, PasswordLess Login, etc. to improve security of your website.”

According to WordPress, at the time of writing the Plugin had 700,000+ active installations. The vulnerability discovered could allow an unauthenticated attacker to compromise a WordPress blog if the administrative user views the Loginizer log file.

This issue was patched within hours by the vendor in version 1.4.0. CVE assigned as CVE-2018-11366.

Description

Versions 1.3.8 to 1.3.9 the Loginizer WordPress Plugin were found to be vulnerable to Stored Cross-Site Scripting (XSS). The vulnerability was due to the Plugin’s logging functionality using the $_SERVER['REQUEST_URI'] PHP variable to create a URL string that was logged to the database without any input validation. The URL that was saved to the database was later output within HTML without any output encoding.

Risk

An unauthenticated attacker could inject malicious JavaScript into the Loginizer - Brute Force Settings page where attempted brute force logs are displayed. When an administrative user visits the page, the JavaScript would be executed, which could allow an unauthenticated attacker to entirely compromise the WordPress application.

Affected Software

Loginizer 1.3.8-1.3.9 - https://wordpress.org/plugins/loginizer/

Technical Description

Source: On line 577 of the init.php file, the $_SERVER['REQUEST_URI'] variable is placed within the $url variable along with other information, and then saved to the database without any validation:

$url = @addslashes((!empty($_SERVER['HTTPS']) ? 'https://' : 'http://').$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']);
$sresult = $wpdb->query("UPDATE `".$wpdb->prefix."loginizer_logs` SET `username` = '".$username."', `time` = '".time()."', `count` = `count`+1, `lockout` = '".$lockout."', `url` = '".$url."' WHERE `ip` = '".$loginizer['current_ip']."';");

Sink: On line 1684 of the init.php file, the $iv['url'] variable, containing the unvalidated URL from the database is output within HTML without any output encoding:

<td>
  '.$iv['url'].'
</td>

Proof of Concept (PoC)

The following cURL request will inject a PoC XSS payload, which will be triggered when viewing the Brute Force settings page:

curl --data "log=admin&pwd=admin&wp-submit=Log+In&redirect_to=&testcookie=1" "http://www.example.com/wp-login.php?a=<script>alert(/XSS/)</script>" 

A fully weaponised XSS exploit was created that used the WordPress Theme Editor to insert a PHP backdoor into a WordPress site. The weaponised XSS payload has not been supplied with this advisory, however, it is trivial to create.

Remediation

Vendor: Pass the $url variable through WordPress’ esc_url() function. For example: $url = esc_url($url);

Users: Update to version 1.4.0, which fixes the vulnerability.

Timeline

  • 21/05/2018 01:36: Issue discovered by Leigh (Dewhurst Security).
  • 21/05/2018 11:00: Issue verified by Ryan (Dewhurst Security).
  • 21/05/2018 11:50: Vendor notified.
  • 21/05/2018 17:00: Vendor replies to ticket and releases a patched version, version 1.4.0.
  • 22/05/2018 09:30: Advisory publicly released.
  • 22/05/2018 14:10: CVE Assigned: CVE-2018-11366

References