DOS through IP spoofing – (iThemes Security <= 8.1.2)

| in


Affected pluginiThemes Security
Active installs1+ million
Vulnerable version<= 8.1.2
Audited version8.1.2
Fully patched version
Recommended remediationRemoval of the plugin

Description


The plugin is wide open to IP spoofing, which an attacker can use to exploit to ban search-engine crawlers, the site’s reverse proxy, or legitimate users.

Proof of concept


The plugin uses the ITSEC_Lib::get_ip() method in almost all places where access to the current request’s IP address is needed.

Following the code path of ITSEC_Lib::get_ip() ultimately reveals that the plugin blindly reads the IP address from HTTP headers.

The relevant method is ITSEC_Lib_IP_Detector::get_ip()

private function get_ip() {
   foreach ( $this->headers as list( $header, $position ) ) {
      $ip = $this->get_for_header( $header, $position );
      if ( ! $ip ) {
         continue;
      }
      if ( $this->allow_private ) {
         $ip = filter_var( $ip, FILTER_VALIDATE_IP );
      } else {
         $ip = filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_RES_RANGE | FILTER_FLAG_NO_PRIV_RANGE );
      }
      if ( $ip ) {
         return (string) $ip;
      }
   }
   return '';
}

“$this->headers” can have two values, depending on how the site owner configured the plugin.

By default “$this->headers” will be equal to the below array of HTTP header names:

'HTTP_CF_CONNECTING_IP', // Cloudflare
'HTTP_X_FORWARDED_FOR',  // Squid, and most other forward and reverse proxies
'HTTP_X_REAL_IP',
'HTTP_X_CLIENT_IP',
'HTTP_CLIENT_IP',
'HTTP_X_CLUSTER_CLIENT_IP',

If the site owner manually configures an IP source, “$this->headers” will only contain the configured HTTP header name.

ITSEC_Lib_IP_Detector::get_for_header() looks like this:

private function get_for_header( $header, $position ) {
   if ( empty( $this->server[ $header ] ) ) {
      return '';
   }
   $value = trim( $this->server[ $header ] );
  
   if ( - 1 === $position ) {
      return explode( ',', $value )[0];
   }
   
   // EDITOR: Irrelevant, $position is always -1.
}}

The plugin is making the mistake of always returning the leftmost IP that is present in an “IP source header”.

Thus, IP spoofing is trivial.

The following scenarios are possible:

In automatic configuration (the default):

  • Sites not behind a reverse proxy are wide open since any header is trusted blindly
  • Sites behind Cloudflare are reasonably safe because the “CF-Connecting-IP” header is always checked first.
  • Sites behind any other reverse proxy are also wide open because an attacker can spoof the “CF-Connecting-IP” header which will always be checked first.

In manual configuration:

  • Sites behind Cloudflare are reasonably safe because the “CF-Connecting-IP” header is always checked first. Furthermore, Cloudflare will drop the header if an attacker sends a spoofed request to Cloudflare
  • In all other scenarios, the site is wide open to IP spoofing since the plugin always used the leftmost IP address in the header instead of the rightmost.

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.

Timeline


Vendor contactedSeptember 07, 2022
First Response (from a developer)
Fully patched at
Publicly disclosedApril 24, 2023

Miscellaneous


  • The vendor made us send the POC through third-party chat software to support staff despite asking explicitly for a security@ email.

Leave a Reply

Your email address will not be published. Required fields are marked *