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