Пример #1
0
 /**
  * Expects an array of items. The items are either IPs or IPs separated by comma, space or tab. Or an array of IP's.
  * We then examine all IP's looking for a public IP and storing private IP's in an array. If we find no public IPs we return the first private addr we found.
  *
  * @param array $arr
  * @return bool|mixed
  */
 private function _getCleanIPAndServerVar($arr)
 {
     $privates = array();
     //Store private addrs until end as last resort.
     foreach ($arr as $entry) {
         list($item, $var) = $entry;
         if (is_array($item)) {
             foreach ($item as $j) {
                 // try verifying the IP is valid before stripping the port off
                 if (!$this->_isValidIP($j)) {
                     $j = preg_replace('/:\\d+$/', '', $j);
                     //Strip off port
                 }
                 if ($this->_isValidIP($j)) {
                     if ($this->_isIPv6MappedIPv4($j)) {
                         $j = wfWAFUtils::inet_ntop(wfWAFUtils::inet_pton($j));
                     }
                     if ($this->_isPrivateIP($j)) {
                         $privates[] = array($j, $var);
                     } else {
                         return array($j, $var);
                     }
                 }
             }
             continue;
             //This was an array so we can skip to the next item
         }
         $skipToNext = false;
         foreach (array(',', ' ', "\t") as $char) {
             if (strpos($item, $char) !== false) {
                 $sp = explode($char, $item);
                 foreach ($sp as $j) {
                     $j = trim($j);
                     if (!$this->_isValidIP($j)) {
                         $j = preg_replace('/:\\d+$/', '', $j);
                         //Strip off port
                     }
                     if ($this->_isValidIP($j)) {
                         if ($this->_isIPv6MappedIPv4($j)) {
                             $j = wfWAFUtils::inet_ntop(wfWAFUtils::inet_pton($j));
                         }
                         if ($this->_isPrivateIP($j)) {
                             $privates[] = array($j, $var);
                         } else {
                             return array($j, $var);
                         }
                     }
                 }
                 $skipToNext = true;
                 break;
             }
         }
         if ($skipToNext) {
             continue;
         }
         //Skip to next item because this one had a comma, space or tab so was delimited and we didn't find anything.
         if (!$this->_isValidIP($item)) {
             $item = preg_replace('/:\\d+$/', '', $item);
             //Strip off port
         }
         if ($this->_isValidIP($item)) {
             if ($this->_isIPv6MappedIPv4($item)) {
                 $item = wfWAFUtils::inet_ntop(wfWAFUtils::inet_pton($item));
             }
             if ($this->_isPrivateIP($item)) {
                 $privates[] = array($item, $var);
             } else {
                 return array($item, $var);
             }
         }
     }
     if (sizeof($privates) > 0) {
         return $privates[0];
         //Return the first private we found so that we respect the order the IP's were passed to this function.
     }
     return false;
 }
Пример #2
0
 /**
  * @param string $ip
  * @return bool
  */
 public function isIPBlocked($ip)
 {
     $this->open();
     $ipBin = wfWAFUtils::inet_pton($ip);
     fseek($this->ipCacheFileHandle, wfWAFUtils::strlen(self::LOG_FILE_HEADER), SEEK_SET);
     self::lock($this->ipCacheFileHandle, LOCK_SH);
     while (!feof($this->ipCacheFileHandle)) {
         $ipStr = fread($this->ipCacheFileHandle, 20);
         $ip2 = wfWAFUtils::substr($ipStr, 0, 16);
         if ($ipBin === $ip2 && unpack('V', wfWAFUtils::substr($ipStr, 16, 4)) >= time()) {
             self::lock($this->ipCacheFileHandle, LOCK_UN);
             return true;
         }
     }
     self::lock($this->ipCacheFileHandle, LOCK_UN);
     return false;
 }
Пример #3
0
 function geoip_name_by_addr_v6($gi, $addr)
 {
     if ($addr == NULL) {
         return 0;
     }
     $ipnum = wfWAFUtils::inet_pton($addr);
     return _get_org_v6($gi, $ipnum);
 }
 /**
  * Return a set of where clauses to use in MySQL.
  *
  * @param string $column
  * @return false|null|string
  */
 public function toSQL($column = 'ip')
 {
     /** @var wpdb $wpdb */
     global $wpdb;
     $ip_string = $this->getIPString();
     if (strpos($ip_string, '.') !== false && preg_match('/\\[\\d+\\-\\d+\\]/', $ip_string)) {
         $whiteParts = explode('.', $ip_string);
         $sql = "(SUBSTR({$column}, 1, 12) = LPAD(CHAR(0xff, 0xff), 12, CHAR(0)) AND ";
         for ($i = 0, $j = 24; $i <= 3; $i++, $j -= 8) {
             // MySQL can only perform bitwise operations on integers
             $conv = sprintf('CAST(CONV(HEX(SUBSTR(%s, 13, 8)), 16, 10) as UNSIGNED INTEGER)', $column);
             if (preg_match('/^\\[(\\d+)\\-(\\d+)\\]$/', $whiteParts[$i], $m)) {
                 $sql .= $wpdb->prepare("{$conv} >> {$j} & 0xFF BETWEEN %d AND %d", $m[1], $m[2]);
             } else {
                 $sql .= $wpdb->prepare("{$conv} >> {$j} & 0xFF = %d", $whiteParts[$i]);
             }
             $sql .= ' AND ';
         }
         $sql = substr($sql, 0, -5) . ')';
         return $sql;
     } else {
         if (strpos($ip_string, ':') !== false) {
             $ip_string = strtolower(self::expandIPv6Range($ip_string));
             if (preg_match('/\\[[a-f0-9]+\\-[a-f0-9]+\\]/i', $ip_string)) {
                 $whiteParts = explode(':', $ip_string);
                 $sql = '(';
                 for ($i = 0; $i <= 7; $i++) {
                     // MySQL can only perform bitwise operations on integers
                     $conv = sprintf('CAST(CONV(HEX(SUBSTR(%s, %d, 8)), 16, 10) as UNSIGNED INTEGER)', $column, $i < 4 ? 1 : 9);
                     $j = 16 * (3 - $i % 4);
                     if (preg_match('/^\\[([a-f0-9]+)\\-([a-f0-9]+)\\]$/i', $whiteParts[$i], $m)) {
                         $sql .= $wpdb->prepare("{$conv} >> {$j} & 0xFFFF BETWEEN 0x%x AND 0x%x", hexdec($m[1]), hexdec($m[2]));
                     } else {
                         $sql .= $wpdb->prepare("{$conv} >> {$j} & 0xFFFF = 0x%x", hexdec($whiteParts[$i]));
                     }
                     $sql .= ' AND ';
                 }
                 $sql = substr($sql, 0, -5) . ')';
                 return $sql;
             }
         }
     }
     return $wpdb->prepare("({$column} = %s)", wfWAFUtils::inet_pton($ip_string));
 }
 /**
  * @param wfWAFRequest $request
  * @return bool|string If not blocked, returns false. Otherwise a string of the reason it was blocked or true. 
  */
 public function shouldBlockRequest($request)
 {
     // Checking the user whitelist is done before reaching this call
     $ip = $request->getIP();
     //Check the system whitelist
     if ($this->checkForWhitelisted($ip)) {
         return false;
     }
     //Let the plugin handle these
     $wfFunc = $request->getQueryString('_wfsf');
     if ($wfFunc == 'unlockEmail' || $wfFunc == 'unlockAccess') {
         // Can't check validity here, let it pass through to plugin level where it can
         return false;
     }
     $logHuman = $request->getQueryString('wordfence_logHuman');
     if ($logHuman !== null) {
         return false;
     }
     //Start block checks
     $ipNum = wfWAFUtils::inet_pton($ip);
     $hostname = null;
     $ua = $request->getHeaders('User-Agent');
     if ($ua === null) {
         $ua = '';
     }
     $referer = $request->getHeaders('Referer');
     if ($referer === null) {
         $referer = '';
     }
     $isPaid = false;
     try {
         $isPaid = wfWAF::getInstance()->getStorageEngine()->getConfig('isPaid');
         $pluginABSPATH = wfWAF::getInstance()->getStorageEngine()->getConfig('pluginABSPATH');
         $patternBlocksJSON = wfWAF::getInstance()->getStorageEngine()->getConfig('patternBlocks');
         $countryBlocksJSON = wfWAF::getInstance()->getStorageEngine()->getConfig('countryBlocks');
         $otherBlocksJSON = wfWAF::getInstance()->getStorageEngine()->getConfig('otherBlocks');
     } catch (Exception $e) {
         // Do nothing
     }
     if (isset($_SERVER['SCRIPT_FILENAME']) && (strpos($_SERVER['SCRIPT_FILENAME'], $pluginABSPATH . "wp-admin/") === 0 || strpos($_SERVER['SCRIPT_FILENAME'], $pluginABSPATH . "wp-content/") === 0 || strpos($_SERVER['SCRIPT_FILENAME'], $pluginABSPATH . "wp-includes/") === 0)) {
         return false;
         //Rely on WordPress's own access control and blocking at the plugin level
     }
     // Pattern Blocks from the Advanced Blocking page (IP Range, UA, Referer)
     $patternBlocks = @wfWAFUtils::json_decode($patternBlocksJSON, true);
     if (is_array($patternBlocks)) {
         // Instead of a long block of if/else statements, using bitshifting to generate an expected value and a found value
         $ipRangeOffset = 1;
         $uaPatternOffset = 2;
         $refPatternOffset = 3;
         foreach ($patternBlocks as $b) {
             $expectedBits = 0;
             $foundBits = 0;
             if (!empty($b['ipRange'])) {
                 $expectedBits |= 1 << $ipRangeOffset;
                 list($start_range, $end_range) = explode('-', $b['ipRange']);
                 if (preg_match('/[\\.:]/', $start_range)) {
                     $start_range = wfWAFUtils::inet_pton($start_range);
                     $end_range = wfWAFUtils::inet_pton($end_range);
                 } else {
                     $start_range = wfWAFUtils::inet_pton(long2ip($start_range));
                     $end_range = wfWAFUtils::inet_pton(long2ip($end_range));
                 }
                 if (strcmp($ipNum, $start_range) >= 0 && strcmp($ipNum, $end_range) <= 0) {
                     $foundBits |= 1 << $ipRangeOffset;
                 }
             }
             if (!empty($b['hostnamePattern'])) {
                 $expectedBits |= 1 << $ipRangeOffset;
                 if ($hostname === null) {
                     $hostname = wfWAFUtils::reverseLookup($ip);
                 }
                 if (preg_match(wfWAFUtils::patternToRegex($b['hostnamePattern']), $hostname)) {
                     $foundBits |= 1 << $ipRangeOffset;
                 }
             }
             if (!empty($b['uaPattern'])) {
                 $expectedBits |= 1 << $uaPatternOffset;
                 if (wfWAFUtils::isUABlocked($b['uaPattern'], $ua)) {
                     $foundBits |= 1 << $uaPatternOffset;
                 }
             }
             if (!empty($b['refPattern'])) {
                 $expectedBits |= 1 << $refPatternOffset;
                 if (wfWAFUtils::isRefererBlocked($b['refPattern'], $referer)) {
                     $foundBits |= 1 << $refPatternOffset;
                 }
             }
             if ($foundBits === $expectedBits && $expectedBits > 0) {
                 return array('action' => self::WFWAF_BLOCK_UAREFIPRANGE, 'id' => $b['id']);
             }
         }
     }
     // End Pattern Blocks
     // Country Blocking
     if ($isPaid) {
         $countryBlocks = @wfWAFUtils::json_decode($countryBlocksJSON, true);
         if (is_array($countryBlocks)) {
             $blockedCountries = $countryBlocks['countries'];
             $bareRequestURI = wfWAFUtils::extractBareURI($request->getURI());
             $bareBypassRedirURI = wfWAFUtils::extractBareURI($countryBlocks['bypassRedirURL']);
             $skipCountryBlocking = false;
             if ($bareBypassRedirURI && $bareRequestURI == $bareBypassRedirURI) {
                 // Run this before country blocking because even if the user isn't blocked we need to set the bypass cookie so they can bypass future blocks.
                 if ($countryBlocks['bypassRedirDest']) {
                     setcookie('wfCBLBypass', $countryBlocks['cookieVal'], time() + 86400 * 365, '/', null, null, true);
                     return array('action' => self::WFWAF_BLOCK_COUNTRY_BYPASS_REDIR);
                 }
             }
             $bareBypassViewURI = wfWAFUtils::extractBareURI($countryBlocks['bypassViewURL']);
             if ($bareBypassViewURI && $bareBypassViewURI == $bareRequestURI) {
                 setcookie('wfCBLBypass', $countryBlocks['cookieVal'], time() + 86400 * 365, '/', null, null, true);
                 $skipCountryBlocking = true;
             }
             $bypassCookieSet = false;
             $bypassCookie = $request->getCookies('wfCBLBypass');
             if (isset($bypassCookie) && $bypassCookie == $countryBlocks['cookieVal']) {
                 $bypassCookieSet = true;
             }
             if (!$skipCountryBlocking && $blockedCountries && !$bypassCookieSet) {
                 $isAuthRequest = strpos($bareRequestURI, '/wp-login.php') !== false;
                 $isXMLRPC = strpos($bareRequestURI, '/xmlrpc.php') !== false;
                 $isUserLoggedIn = wfWAF::getInstance()->parseAuthCookie() !== false;
                 // If everything is checked, make sure this always runs.
                 if ($countryBlocks['loggedInBlocked'] && $countryBlocks['loginFormBlocked'] && $countryBlocks['restOfSiteBlocked']) {
                     if ($blocked = $this->checkForBlockedCountry($countryBlocks, $ip, $bareRequestURI)) {
                         return $blocked;
                     }
                 }
                 // Block logged in users.
                 if ($countryBlocks['loggedInBlocked'] && $isUserLoggedIn) {
                     if ($blocked = $this->checkForBlockedCountry($countryBlocks, $ip, $bareRequestURI)) {
                         return $blocked;
                     }
                 }
                 // Block the login form itself and any attempt to authenticate.
                 if ($countryBlocks['loginFormBlocked'] && $isAuthRequest) {
                     if ($blocked = $this->checkForBlockedCountry($countryBlocks, $ip, $bareRequestURI)) {
                         return $blocked;
                     }
                 }
                 // Block requests that aren't to the login page, xmlrpc.php, or a user already logged in.
                 if ($countryBlocks['restOfSiteBlocked'] && !$isAuthRequest && !$isXMLRPC && !$isUserLoggedIn) {
                     if ($blocked = $this->checkForBlockedCountry($countryBlocks, $ip, $bareRequestURI)) {
                         return $blocked;
                     }
                 }
                 // XMLRPC is inaccesible when public portion of the site and auth is disabled.
                 if ($countryBlocks['loginFormBlocked'] && $countryBlocks['restOfSiteBlocked'] && $isXMLRPC) {
                     if ($blocked = $this->checkForBlockedCountry($countryBlocks, $ip, $bareRequestURI)) {
                         return $blocked;
                     }
                 }
                 // Any bypasses and other block possibilities will be checked at the plugin level once WordPress loads
             }
         }
     }
     // End Country Blocking
     // Other Blocks
     $otherBlocks = @wfWAFUtils::json_decode($otherBlocksJSON, true);
     if (is_array($otherBlocks)) {
         $blockedTime = $otherBlocks['blockedTime'];
         $blocks = $otherBlocks['blocks'];
         $bareRequestURI = wfWAFUtils::extractBareURI($request->getURI());
         $isAuthRequest = strpos($bareRequestURI, '/wp-login.php') !== false;
         foreach ($blocks as $b) {
             if (!$b['permanent'] && $b['blockedTime'] + $blockedTime < time()) {
                 continue;
             }
             if (base64_decode($b['IP']) != $ipNum) {
                 continue;
             }
             if ($isAuthRequest) {
                 return array('action' => self::WFWAF_BLOCK_WFSN);
             }
             return array('action' => empty($b['reason']) ? '' : $b['reason']);
         }
     }
     // End Other Blocks
     return false;
 }