Affected plugin | Stream |
Active installs | 80,000+ |
Vulnerable version | <= 3.9.3 |
Audited version | 3.9.3 |
Fully patched version | 4.0.0 |
Recommended remediation | Upgrade to version 4.0.0 or higher. |
Description
The plugin, utilized for audit and security logging, exhibits a vulnerability whereby malicious actors can easily spoof IP addresses.
This is less than ideal, given the plugin’s widespread use in compliance and security monitoring contexts.
In a compliance scenario, this undermines the reliability of logs, and in security contexts, this may compromise incident response and forensics efforts by providing misleading information.
Proof of concept
The plugin uses the following code to determine the client IP for each log record that is stored:
/**
* Class constructor.
*
* @param Plugin $plugin Instance of plugin object.
*/
public function __construct( $plugin ) {
$this->plugin = $plugin;
// Support proxy mode by checking the `X-Forwarded-For` header first.
$ip_address = wp_stream_filter_input( INPUT_SERVER, 'HTTP_X_FORWARDED_FOR', FILTER_VALIDATE_IP );
$ip_address = $ip_address ? $ip_address : wp_stream_filter_input( INPUT_SERVER, 'REMOTE_ADDR', FILTER_VALIDATE_IP );
$this->ip_address = $ip_address;
// Ensure function used in various methods is pre-loaded.
if ( ! function_exists( 'is_plugin_active_for_network' ) ) {
require_once ABSPATH . '/wp-admin/includes/plugin.php';
}
}
The wp_stream_filter_input function ultimately ends up calling Core’s
WP_Http::is_ip_address function, which returns the passed value if it’s a valid IPv4 or IPv6 IP address.
The issue here is that the plugin blindly reads from the X-Forwarded-For header, which can be spoofed.
This can be exploited in one of two ways:
1. Sites without a reverse proxy or behind a reverse proxy that does not use the X-Forwarded-For header:
If an attacker spoofs the X-Forwarded-For header for any action, it will be used in the log record.
curl 'https://wp.test/wp-login.php?action=lostpassword'
-X POST
--data-raw 'user_login=admin&redirect_to=&wp-submit=Get+New+Password'
-H "X-Forwarded-For: 165.54.171.228"
The above request triggers a password reset for the admin user.
The plugin will use the spoofed IP 165.54.171.228 in the recorded log entry.
2. Sites behind a reverse proxy that uses the X-Forwarded-For header:
As per the HTTP spec, a reverse proxy always prepends an existing header to the left of the actual client IP.
If the real client IP is 165.54.171.221 and the attacker sends the IP 170.54.171.221 to the reverse proxy, WordPress will see the header as so:
X-Forworded-For: 170.54.171.221, 165.54.171.221
In this case, wp_stream_filter_input
will return false
which means the value of $this->ip_address will always be the IP of the 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 the current IP.
Everything else is conceptually insecure.
Timeline
Vendor contacted | October 08, 2023 |
First Response | October 09, 2023 |
Fully patched at | January 9, 2024 |
Publicly disclosed | January 25, 2024 |
Miscellaneous
XWP patched the vulnerability as per our recommendations and now only uses REMOTE_ADDR.
Leave a Reply