Affected plugin | WordFence |
Active installs | 4+ million |
Vulnerable version | <= 7.6.2 |
Audited version | 7.6.1 |
Fully patched version | – |
Recommended remediation | Ensure that nobody can bypass your site’s reverse proxy and connect directly to the server. Use something like Cloudflare’s authenticated origin pulls. |
Description
The plugin is vulnerable to IP spoofing if the target site is behind a reverse proxy and if WordFence is configured to fetch the IP address from any source besides REMOTE_ADDR (the default).
An attacker can exploit this to ban legitimate users, search-engine crawlers, or the site’s reverse proxy.
Proof of concept
WordFence handles IP detection better than most WordPress plugins.
However, the plugin is vulnerable to IP spoofing if a site is behind a reverse proxy and if the attacker can directly connect to the target server where WordFence runs.
This advanced attack scenario is described here.
The most common scenario for this attack is the following:
Most WordPress hosts that offer integrations with popular reverse proxies like Cloudflare do not configure the server to only be accessible through the reverse proxy.
In most cases, the only thing preventing an attacker from directly connecting to the server is uncovering its IP address. Often, this is easier than it should be using automated pentesting tools like theHarvester
Suppose WordFence is configured to get the IP address from the “X-Forwarded-For” header (XFF).
To verify that IP spoofing is possible, create the following must-use plugin on a local WordPress installation where WordFence is installed.
<?php
declare(strict_types=1);
// This code runs before WordFence.
// There should be no difference between running this code and a reverse proxy. WF should not be able to tell
// the difference.
define('REAL_USER_IP', '157.29.91.106'); // Hardcode the real user ip.
/*
* Simulates a direct connection where all headers are passed as is.
*
* There might be web server configurations that drop any extra
* headers such as X-Forwarded-For. But we can't know that
* nor rely on it.
*/
$_SERVER['REMOTE_ADDR'] = REAL_USER_IP;
if (isset($_SERVER['HTTP_X_TEST'])) {
add_action('wp_loaded', function () {
$ip = wfUtils::getIP();
echo "$ip\n";
die();
});
}
curl -X GET https://local.test -H "X-Forwarded-For: 147.93.33.75" -H "X-TEST: 1"
147.93.33.75 # IP spoofed
The entire WordFence plugin is now using a spoofed IP which an attacker can use to:
- Bypass the WordFence WAF
- Bypass 2FA requirements
- Bypass country blocking
- Getting search-engine crawlers banned and thus potentially getting the target site delisted
- Ban the site’s reverse proxy
- …
- …
Proposed patch
The needed patch is described in great length in this article of us.
Summary: Only ever use REMOTE_ADDR to access to current IP.
However, if WordFence wants to keep using a PHP implementation to detect the IP, it needs to have some mechanism to prevent reading IP addresses from HTTP headers if the connecting IP is not from a trusted proxy.
A sample implementation might look light this (pseudo code):
function verifyConnectingIPisTrustedProxy(array $trusted_proxies, string $connection_ip) :void {
foreach ($trusted_proxies as $proxies) {
$trusted = /* Check if $connection_ip is in subnet */
if($trusted){
return;
}
}
// Educate the users about why this happened. Probably their web host already did the conversion to REMOTE_ADDR, or an attacker can directly connect to the server
return throw BrokenConfigurationException();
}
Timeline
Vendor contacted | September 08, 2022 |
First Response | September 08, 2022 |
Fully patched at | – |
Publicly disclosed | April 24, 2023 |
Miscellaneous
- The vendor did not consider this a security vulnerability that needs immediate attention or patches.
Leave a Reply