示例#1
0
 /**
  *
  */
 public static function processAttackData()
 {
     global $wpdb;
     $waf = wfWAF::getInstance();
     if ($waf->getStorageEngine()->getConfig('attackDataKey', false) === false) {
         $waf->getStorageEngine()->setConfig('attackDataKey', mt_rand(0, 0xfff));
     }
     $limit = 500;
     $lastSendTime = wfConfig::get('lastAttackDataSendTime');
     $attackData = $wpdb->get_results($wpdb->prepare("SELECT SQL_CALC_FOUND_ROWS * FROM {$wpdb->base_prefix}wfHits\nWHERE action in ('blocked:waf', 'learned:waf')\nAND attackLogTime > %.6f\nLIMIT %d", $lastSendTime, $limit));
     $totalRows = $wpdb->get_var('SELECT FOUND_ROWS()');
     if ($attackData) {
         $response = wp_remote_get(sprintf(WFWAF_API_URL_SEC . "waf-rules/%d.txt", $waf->getStorageEngine()->getConfig('attackDataKey')));
         if (!is_wp_error($response)) {
             $okToSendBody = wp_remote_retrieve_body($response);
             if ($okToSendBody === 'ok') {
                 // Build JSON to send
                 $dataToSend = array();
                 $attackDataToUpdate = array();
                 foreach ($attackData as $attackDataRow) {
                     $actionData = (array) wfRequestModel::unserializeActionData($attackDataRow->actionData);
                     $dataToSend[] = array($attackDataRow->attackLogTime, $attackDataRow->ctime, wfUtils::inet_ntop($attackDataRow->IP), array_key_exists('learningMode', $actionData) ? $actionData['learningMode'] : 0, array_key_exists('paramKey', $actionData) ? base64_encode($actionData['paramKey']) : false, array_key_exists('paramValue', $actionData) ? base64_encode($actionData['paramValue']) : false, array_key_exists('failedRules', $actionData) ? $actionData['failedRules'] : '', strpos($attackDataRow->URL, 'https') === 0 ? 1 : 0, array_key_exists('fullRequest', $actionData) ? $actionData['fullRequest'] : '');
                     if (array_key_exists('fullRequest', $actionData)) {
                         unset($actionData['fullRequest']);
                         $attackDataToUpdate[$attackDataRow->id] = array('actionData' => wfRequestModel::serializeActionData($actionData));
                     }
                     if ($attackDataRow->attackLogTime > $lastSendTime) {
                         $lastSendTime = $attackDataRow->attackLogTime;
                     }
                 }
                 $response = wp_remote_post(WFWAF_API_URL_SEC . "?" . http_build_query(array('action' => 'send_waf_attack_data', 'k' => $waf->getStorageEngine()->getConfig('apiKey'), 's' => $waf->getStorageEngine()->getConfig('siteURL') ? $waf->getStorageEngine()->getConfig('siteURL') : sprintf('%s://%s/', $waf->getRequest()->getProtocol(), rawurlencode($waf->getRequest()->getHost())))), array('body' => json_encode($dataToSend), 'headers' => array('Content-Type' => 'application/json'), 'timeout' => 30));
                 if (!is_wp_error($response) && ($body = wp_remote_retrieve_body($response))) {
                     $jsonData = json_decode($body, true);
                     if (is_array($jsonData) && array_key_exists('success', $jsonData)) {
                         // Successfully sent data, remove the full request from the table to reduce storage size
                         foreach ($attackDataToUpdate as $hitID => $dataToUpdate) {
                             $wpdb->update($wpdb->base_prefix . 'wfHits', $dataToUpdate, array('id' => $hitID));
                         }
                         wfConfig::set('lastAttackDataSendTime', $lastSendTime);
                         if ($totalRows > $limit) {
                             self::scheduleSendAttackData();
                         }
                     }
                 }
             } else {
                 if (is_string($okToSendBody) && preg_match('/next check in: ([0-9]+)/', $okToSendBody, $matches)) {
                     self::scheduleSendAttackData(time() + $matches[1]);
                 }
             }
             // Could be that the server is down, so hold off on sending data for a little while.
         } else {
             self::scheduleSendAttackData(time() + 7200);
         }
     }
     self::trimWfHits();
 }
    /**
     *
     */
    public static function processAttackData()
    {
        global $wpdb;
        $waf = wfWAF::getInstance();
        if ($waf->getStorageEngine()->getConfig('attackDataKey', false) === false) {
            $waf->getStorageEngine()->setConfig('attackDataKey', mt_rand(0, 0xfff));
        }
        //Send alert email if needed
        if (wfConfig::get('wafAlertOnAttacks')) {
            $alertInterval = wfConfig::get('wafAlertInterval', 0);
            $cutoffTime = max(time() - $alertInterval, wfConfig::get('wafAlertLastSendTime'));
            $wafAlertWhitelist = wfConfig::get('wafAlertWhitelist', '');
            $wafAlertWhitelist = preg_split("/[,\r\n]+/", $wafAlertWhitelist);
            foreach ($wafAlertWhitelist as $index => &$entry) {
                $entry = trim($entry);
                if (!preg_match('/^(?:\\d{1,3}(?:\\.|$)){4}/', $entry) && !preg_match('/^((?:[\\da-f]{1,4}(?::|)){0,8})(::)?((?:[\\da-f]{1,4}(?::|)){0,8})$/i', $entry)) {
                    unset($wafAlertWhitelist[$index]);
                    continue;
                }
                $packed = @wfUtils::inet_pton($entry);
                if ($packed === false) {
                    unset($wafAlertWhitelist[$index]);
                    continue;
                }
                $entry = bin2hex($packed);
            }
            $wafAlertWhitelist = array_filter($wafAlertWhitelist);
            $attackData = $wpdb->get_results($wpdb->prepare("SELECT SQL_CALC_FOUND_ROWS * FROM {$wpdb->base_prefix}wfHits\n\tWHERE action = 'blocked:waf' " . (count($wafAlertWhitelist) ? "AND HEX(IP) NOT IN (" . implode(", ", array_fill(0, count($wafAlertWhitelist), '%s')) . ")" : "") . "AND attackLogTime > %.6f\n\tORDER BY attackLogTime DESC\n\tLIMIT 10", array_merge($wafAlertWhitelist, array($cutoffTime))));
            $attackCount = $wpdb->get_var('SELECT FOUND_ROWS()');
            if ($attackCount >= wfConfig::get('wafAlertThreshold')) {
                $durationMessage = wfUtils::makeDuration($alertInterval);
                $message = <<<ALERTMSG
The Wordfence Web Application Firewall has blocked {$attackCount} attacks over the last {$durationMessage}. Below is a sample of these recent attacks:


ALERTMSG;
                $attackTable = array();
                $dateMax = $ipMax = $countryMax = 0;
                foreach ($attackData as $row) {
                    $row->longDescription = "Blocked for " . $row->actionDescription;
                    $actionData = json_decode($row->actionData, true);
                    if (!is_array($actionData) || !isset($actionData['paramKey']) || !isset($actionData['paramValue'])) {
                        continue;
                    }
                    $paramKey = base64_decode($actionData['paramKey']);
                    $paramValue = base64_decode($actionData['paramValue']);
                    if (strlen($paramValue) > 100) {
                        $paramValue = substr($paramValue, 0, 100) . chr(2026);
                    }
                    if (preg_match('/([a-z0-9_]+\\.[a-z0-9_]+)(?:\\[(.+?)\\](.*))?/i', $paramKey, $matches)) {
                        switch ($matches[1]) {
                            case 'request.queryString':
                                $row->longDescription = "Blocked for " . $row->actionDescription . ' in query string: ' . $matches[2] . '=' . $paramValue;
                                break;
                            case 'request.body':
                                $row->longDescription = "Blocked for " . $row->actionDescription . ' in POST body: ' . $matches[2] . '=' . $paramValue;
                                break;
                            case 'request.cookie':
                                $row->longDescription = "Blocked for " . $row->actionDescription . ' in cookie: ' . $matches[2] . '=' . $paramValue;
                                break;
                            case 'request.fileNames':
                                $row->longDescription = "Blocked for a " . $row->actionDescription . ' in file: ' . $matches[2] . '=' . $paramValue;
                                break;
                        }
                    }
                    $date = date_i18n('F j, Y g:ia', floor($row->attackLogTime));
                    $dateMax = max(strlen($date), $dateMax);
                    $ip = wfUtils::inet_ntop($row->IP);
                    $ipMax = max(strlen($ip), $ipMax);
                    $country = wfUtils::countryCode2Name(wfUtils::IP2Country($ip));
                    $country = empty($country) ? 'Unknown' : $country;
                    $countryMax = max(strlen($country), $countryMax);
                    $attackTable[] = array('date' => $date, 'IP' => $ip, 'country' => $country, 'message' => $row->longDescription);
                }
                foreach ($attackTable as $row) {
                    $date = str_pad($row['date'], $dateMax + 2);
                    $ip = str_pad($row['IP'] . " ({$row['country']})", $ipMax + $countryMax + 8);
                    $attackMessage = $row['message'];
                    $message .= $date . $ip . $attackMessage . "\n";
                }
                self::alert('Increased Attack Rate', $message, false);
                wfConfig::set('wafAlertLastSendTime', time());
            }
        }
        //Send attack data
        $limit = 500;
        $lastSendTime = wfConfig::get('lastAttackDataSendTime');
        $attackData = $wpdb->get_results($wpdb->prepare("SELECT SQL_CALC_FOUND_ROWS * FROM {$wpdb->base_prefix}wfHits\nWHERE action in ('blocked:waf', 'learned:waf', 'logged:waf', 'blocked:waf-always')\nAND attackLogTime > %.6f\nLIMIT %d", $lastSendTime, $limit));
        $totalRows = $wpdb->get_var('SELECT FOUND_ROWS()');
        if ($attackData && wfConfig::get('other_WFNet', true)) {
            $response = wp_remote_get(sprintf(WFWAF_API_URL_SEC . "waf-rules/%d.txt", $waf->getStorageEngine()->getConfig('attackDataKey')));
            if (!is_wp_error($response)) {
                $okToSendBody = wp_remote_retrieve_body($response);
                if ($okToSendBody === 'ok') {
                    // Build JSON to send
                    $dataToSend = array();
                    $attackDataToUpdate = array();
                    foreach ($attackData as $attackDataRow) {
                        $actionData = (array) wfRequestModel::unserializeActionData($attackDataRow->actionData);
                        $dataToSend[] = array($attackDataRow->attackLogTime, $attackDataRow->ctime, wfUtils::inet_ntop($attackDataRow->IP), array_key_exists('learningMode', $actionData) ? $actionData['learningMode'] : 0, array_key_exists('paramKey', $actionData) ? base64_encode($actionData['paramKey']) : false, array_key_exists('paramValue', $actionData) ? base64_encode($actionData['paramValue']) : false, array_key_exists('failedRules', $actionData) ? $actionData['failedRules'] : '', strpos($attackDataRow->URL, 'https') === 0 ? 1 : 0, array_key_exists('fullRequest', $actionData) ? $actionData['fullRequest'] : '');
                        if (array_key_exists('fullRequest', $actionData)) {
                            unset($actionData['fullRequest']);
                            $attackDataToUpdate[$attackDataRow->id] = array('actionData' => wfRequestModel::serializeActionData($actionData));
                        }
                        if ($attackDataRow->attackLogTime > $lastSendTime) {
                            $lastSendTime = $attackDataRow->attackLogTime;
                        }
                    }
                    $response = wp_remote_post(WFWAF_API_URL_SEC . "?" . http_build_query(array('action' => 'send_waf_attack_data', 'k' => $waf->getStorageEngine()->getConfig('apiKey'), 's' => $waf->getStorageEngine()->getConfig('siteURL') ? $waf->getStorageEngine()->getConfig('siteURL') : sprintf('%s://%s/', $waf->getRequest()->getProtocol(), rawurlencode($waf->getRequest()->getHost())), 't' => microtime(true)), null, '&'), array('body' => json_encode($dataToSend), 'headers' => array('Content-Type' => 'application/json'), 'timeout' => 30));
                    if (!is_wp_error($response) && ($body = wp_remote_retrieve_body($response))) {
                        $jsonData = json_decode($body, true);
                        if (is_array($jsonData) && array_key_exists('success', $jsonData)) {
                            // Successfully sent data, remove the full request from the table to reduce storage size
                            foreach ($attackDataToUpdate as $hitID => $dataToUpdate) {
                                $wpdb->update($wpdb->base_prefix . 'wfHits', $dataToUpdate, array('id' => $hitID));
                            }
                            wfConfig::set('lastAttackDataSendTime', $lastSendTime);
                            if ($totalRows > $limit) {
                                self::scheduleSendAttackData();
                            }
                            if (array_key_exists('data', $jsonData) && array_key_exists('watchedIPList', $jsonData['data'])) {
                                $waf->getStorageEngine()->setConfig('watchedIPs', $jsonData['data']['watchedIPList']);
                            }
                        }
                    }
                } else {
                    if (is_string($okToSendBody) && preg_match('/next check in: ([0-9]+)/', $okToSendBody, $matches)) {
                        self::scheduleSendAttackData(time() + $matches[1]);
                    }
                }
                // Could be that the server is down, so hold off on sending data for a little while.
            } else {
                self::scheduleSendAttackData(time() + 7200);
            }
        } else {
            if (!wfConfig::get('other_WFNet', true)) {
                wfConfig::set('lastAttackDataSendTime', time());
            }
        }
        self::trimWfHits();
    }