PluginProbe ʕ •ᴥ•ʔ
Wordfence Security – Firewall, Malware Scan, and Login Security / 7.4.4
Wordfence Security – Firewall, Malware Scan, and Login Security v7.4.4
8.2.2 8.2.1 8.2.0 3.7.1 3.7.2 3.8.1 3.8.2 3.8.3 3.8.4 3.8.5 3.8.6 3.8.7 3.8.8 3.8.9 3.9.1 4.0.1 4.0.2 4.0.3 5.0.1 5.0.2 5.0.3 5.0.4 5.0.5 5.0.6 5.0.7 5.0.8 5.0.9 5.1.1 5.1.2 5.1.4 5.1.5 5.1.6 5.1.7 5.1.8 5.1.9 5.2.1 5.2.2 5.2.3 5.2.4 5.2.5 5.2.6 5.2.7 5.2.8 5.2.9 5.3.1 5.3.10 5.3.11 5.3.12 5.3.2 5.3.3 5.3.4 5.3.5 5.3.6 5.3.7 5.3.8 5.3.9 6.0.1 6.0.10 6.0.11 6.0.12 6.0.14 6.0.15 6.0.16 6.0.17 6.0.18 6.0.19 6.0.2 6.0.20 6.0.21 6.0.22 6.0.23 6.0.24 6.0.25 6.0.3 6.0.4 6.0.5 6.0.6 6.0.7 6.0.8 6.0.9 6.1.1 6.1.10 6.1.11 6.1.12 6.1.14 6.1.15 6.1.16 6.1.17 6.1.2 6.1.3 6.1.4 6.1.5 6.1.6 6.1.7 6.1.8 6.1.9 6.2.0 6.2.1 6.2.10 6.2.2 6.2.3 6.2.4 6.2.5 6.2.6 6.2.7 6.2.8 6.2.9 6.3.0 6.3.1 6.3.10 6.3.11 6.3.12 6.3.14 6.3.15 6.3.16 6.3.17 6.3.18 6.3.19 6.3.2 6.3.20 6.3.21 6.3.22 6.3.3 6.3.4 6.3.5 6.3.6 6.3.7 6.3.8 6.3.9 7.0.1 7.0.2 7.0.3 7.0.4 7.0.5 7.1.0 7.1.1 7.1.10 7.1.11 7.1.12 7.1.14 7.1.15 7.1.16 7.1.17 7.1.18 7.1.19 7.1.2 7.1.20 7.1.3 7.1.4 7.1.5 7.1.6 7.1.7 7.1.8 7.1.9 7.10.0 7.10.1 7.10.2 7.10.3 7.10.4 7.10.5 7.10.6 7.10.7 7.11.0 7.11.1 7.11.2 7.11.3 7.11.4 7.11.5 7.11.6 7.11.7 7.2.1 7.2.2 7.2.3 7.2.4 7.2.5 7.3.1 7.3.2 7.3.3 7.3.4 7.3.5 7.3.6 7.4.0 7.4.1 7.4.10 7.4.11 7.4.12 7.4.14 7.4.2 7.4.3 trunk 7.4.4 1.1 7.4.5 1.2 7.4.6 1.3 7.4.7 1.3.1 7.4.8 1.3.2 7.4.9 1.3.3 7.5.0 1.4.2 7.5.1 1.4.3 7.5.10 1.4.4 7.5.11 1.4.5 7.5.2 1.4.6 7.5.3 1.4.7 7.5.4 1.4.8 7.5.5 1.5.1 7.5.6 1.5.2 7.5.7 1.5.3 7.5.8 1.5.4 7.5.9 1.5.5 7.6.0 1.5.6 7.6.1 2.0.1 7.6.2 2.0.2 7.7.0 2.0.3 7.7.1 2.0.5 7.8.0 2.0.6 7.8.1 2.0.7 7.8.2 2.1.0 7.9.0 2.1.1 7.9.1 2.1.2 7.9.2 2.1.3 7.9.3 2.1.4 8.0.0 2.1.5 8.0.1 3.0.2 8.0.2 3.0.3 8.0.3 3.0.4 8.0.4 3.0.5 8.0.5 3.0.6 8.1.0 3.0.7 8.1.1 3.0.8 8.1.2 3.0.9 8.1.3 3.1.0 8.1.4 3.1.1 v1.4.1 3.1.2 3.1.4 3.1.6 3.2.1 3.2.3 3.2.4 3.2.5 3.2.6 3.2.7 3.3.2 3.3.3 3.3.4 3.3.5 3.3.6 3.3.7 3.4.1 3.4.4 3.4.5 3.5.1 3.5.2 3.6.1 3.6.3 3.6.4 3.6.5 3.6.6 3.6.7 3.6.8 3.6.9
wordfence / lib / wfScan.php
wordfence / lib Last commit date
Diff 6 years ago dashboard 7 years ago rest-api 6 years ago .htaccess 7 years ago Diff.php 6 years ago GeoLite2-Country.mmdb 6 years ago IPTraf.php 6 years ago IPTrafList.php 7 years ago WFLSPHP52Compatability.php 6 years ago compat.php 8 years ago conntest.php 7 years ago cronview.php 8 years ago dbview.php 8 years ago diffResult.php 8 years ago email_genericAlert.php 7 years ago email_newIssues.php 6 years ago email_unlockRequest.php 8 years ago email_unsubscribeRequest.php 7 years ago flags.php 7 years ago live_activity.php 8 years ago menu_dashboard.php 7 years ago menu_dashboard_options.php 7 years ago menu_firewall.php 6 years ago menu_firewall_blocking.php 7 years ago menu_firewall_blocking_options.php 8 years ago menu_firewall_waf.php 7 years ago menu_firewall_waf_options.php 7 years ago menu_options.php 6 years ago menu_scanner.php 6 years ago menu_scanner_credentials.php 8 years ago menu_scanner_options.php 6 years ago menu_support.php 7 years ago menu_tools.php 7 years ago menu_tools_diagnostic.php 6 years ago menu_tools_importExport.php 7 years ago menu_tools_livetraffic.php 6 years ago menu_tools_twoFactor.php 7 years ago menu_tools_whois.php 8 years ago menu_wordfence_central.php 7 years ago noc1.key 7 years ago sysinfo.php 8 years ago unknownFiles.php 8 years ago viewFullActivityLog.php 8 years ago wf503.php 7 years ago wfAPI.php 6 years ago wfActivityReport.php 6 years ago wfAdminNoticeQueue.php 8 years ago wfAlerts.php 6 years ago wfArray.php 7 years ago wfBrowscap.php 6 years ago wfBrowscapCache.php 7 years ago wfBulkCountries.php 7 years ago wfCache.php 6 years ago wfCentralAPI.php 6 years ago wfConfig.php 6 years ago wfCrawl.php 6 years ago wfCredentialsController.php 7 years ago wfCrypt.php 6 years ago wfDB.php 7 years ago wfDashboard.php 7 years ago wfDateLocalization.php 8 years ago wfDiagnostic.php 6 years ago wfDict.php 8 years ago wfDirectoryIterator.php 7 years ago wfHelperBin.php 11 years ago wfHelperString.php 11 years ago wfIPWhitelist.php 7 years ago wfImportExportController.php 7 years ago wfIssues.php 6 years ago wfJWT.php 7 years ago wfLockedOut.php 7 years ago wfLog.php 6 years ago wfMD5BloomFilter.php 8 years ago wfModuleController.php 7 years ago wfNotification.php 8 years ago wfOnboardingController.php 7 years ago wfPersistenceController.php 8 years ago wfRESTAPI.php 7 years ago wfScan.php 6 years ago wfScanEngine.php 6 years ago wfSchema.php 6 years ago wfStyle.php 7 years ago wfSupportController.php 6 years ago wfUnlockMsg.php 6 years ago wfUpdateCheck.php 6 years ago wfUtils.php 6 years ago wfVersionCheckController.php 8 years ago wfView.php 10 years ago wfViewResult.php 8 years ago wordfenceClass.php 6 years ago wordfenceConstants.php 6 years ago wordfenceHash.php 6 years ago wordfenceScanner.php 6 years ago wordfenceURLHoover.php 6 years ago
wfScan.php
308 lines
1 <?php
2 class wfScan {
3 public static $debugMode = false;
4 public static $errorHandlingOn = true;
5 public static $peakMemAtStart = 0;
6
7 /**
8 * Returns the stored cronkey or false if not set. If $expired is provided, will set to <timestamp>/false based
9 * on whether or not the cronkey is expired.
10 *
11 * @param null $expired
12 * @return bool|string
13 */
14 private static function storedCronKey(&$expired = null) {
15 $currentCronKey = wfConfig::get('currentCronKey', false);
16 if (empty($currentCronKey))
17 {
18 if ($expired !== null) {
19 $expired = false;
20 }
21 return false;
22 }
23
24 $savedKey = explode(',',$currentCronKey);
25 if (time() - $savedKey[0] > 86400) {
26 if ($expired !== null) {
27 $expired = $savedKey[0];
28 }
29 return $savedKey[1];
30 }
31
32 if ($expired !== null) {
33 $expired = false;
34 }
35 return $savedKey[1];
36 }
37
38 public static function wfScanMain(){
39 self::$peakMemAtStart = memory_get_peak_usage(true);
40 $db = new wfDB();
41 if($db->errorMsg){
42 self::errorExit("Could not connect to database to start scan: " . $db->errorMsg);
43 }
44 if(! wordfence::wfSchemaExists()){
45 self::errorExit("Looks like the Wordfence database tables have been deleted. You can fix this by de-activating and re-activating the Wordfence plugin from your Plugins menu.");
46 }
47 if( isset( $_GET['test'] ) && $_GET['test'] == '1'){
48 echo "WFCRONTESTOK:" . wfConfig::get('cronTestID');
49 self::status(4, 'info', "Cron test received and message printed");
50 exit();
51 }
52
53 self::status(4, 'info', "Scan engine received request.");
54
55 /* ----------Starting signature check -------- */
56 self::status(4, 'info', "Verifying start request signature.");
57 if (!isset($_GET['signature']) || !wfScanEngine::verifyStartSignature($_GET['signature'], isset($_GET['isFork']) ? wfUtils::truthyToBoolean($_GET['isFork']) : false, isset($_GET['scanMode']) ? $_GET['scanMode'] : '', isset($_GET['cronKey']) ? $_GET['cronKey'] : '', isset($_GET['remote']) ? wfUtils::truthyToBoolean($_GET['remote']) : false)) {
58 self::errorExit(__('The signature on the request to start a scan is invalid. Please try again.', 'wordfence'));
59 }
60
61 /* ----------Starting cronkey check -------- */
62 self::status(4, 'info', "Fetching stored cronkey for comparison.");
63 $expired = false;
64 $storedCronKey = self::storedCronKey($expired);
65 $displayCronKey_received = (isset($_GET['cronKey']) ? (preg_match('/^[a-f0-9]+$/i', $_GET['cronKey']) && strlen($_GET['cronKey']) == 32 ? $_GET['cronKey'] : __('[invalid]', 'wordfence')) : __('[none]', 'wordfence'));
66 $displayCronKey_stored = (!empty($storedCronKey) && !$expired ? $storedCronKey : __('[none]', 'wordfence'));
67 self::status(4, 'info', sprintf(__('Checking cronkey: %s (expecting %s)', 'wordfence'), $displayCronKey_received, $displayCronKey_stored));
68 if (empty($_GET['cronKey'])) {
69 self::status(4, 'error', "Wordfence scan script accessed directly, or WF did not receive a cronkey.");
70 echo "If you see this message it means Wordfence is working correctly. You should not access this URL directly. It is part of the Wordfence security plugin and is designed for internal use only.";
71 exit();
72 }
73
74 if ($expired) {
75 self::errorExit("The key used to start a scan expired. The value is: " . $expired . " and split is: " . $storedCronKey . " and time is: " . time());
76 } //keys only last 60 seconds and are used within milliseconds of creation
77
78 if (!$storedCronKey) {
79 wordfence::status(4, 'error', "Wordfence could not find a saved cron key to start the scan so assuming it started and exiting.");
80 exit();
81 }
82
83 self::status(4, 'info', "Checking saved cronkey against cronkey param");
84 if (!hash_equals($storedCronKey, $_GET['cronKey'])) {
85 self::errorExit("Wordfence could not start a scan because the cron key does not match the saved key. Saved: " . $storedCronKey . " Sent: " . $_GET['cronKey'] . " Current unexploded: " . wfConfig::get('currentCronKey', false));
86 }
87 wfConfig::set('currentCronKey', '');
88 /* --------- end cronkey check ---------- */
89
90 $scanMode = wfScanner::SCAN_TYPE_STANDARD;
91 if (isset($_GET['scanMode']) && wfScanner::isValidScanType($_GET['scanMode'])) {
92 $scanMode = $_GET['scanMode'];
93 }
94 $scanController = new wfScanner($scanMode);
95
96 wfConfig::remove('scanStartAttempt');
97 $isFork = ($_GET['isFork'] == '1' ? true : false);
98
99 if(! $isFork){
100 self::status(4, 'info', "Checking if scan is already running");
101 if(! wfUtils::getScanLock()){
102 self::errorExit("There is already a scan running.");
103 }
104
105 wfIssues::updateScanStillRunning();
106 wfConfig::set('wfPeakMemory', 0, wfConfig::DONT_AUTOLOAD);
107 wfConfig::set('wfScanStartVersion', wfUtils::getWPVersion());
108 wfConfig::set('lowResourceScanWaitStep', false);
109
110 if ($scanController->useLowResourceScanning()) {
111 self::status(1, 'info', "Using low resource scanning");
112 }
113 }
114 self::status(4, 'info', "Requesting max memory");
115 wfUtils::requestMaxMemory();
116 self::status(4, 'info', "Setting up error handling environment");
117 set_error_handler('wfScan::error_handler', E_ALL);
118 register_shutdown_function('wfScan::shutdown');
119 if(! self::$debugMode){
120 ob_start('wfScan::obHandler');
121 }
122 @error_reporting(E_ALL);
123 wfUtils::iniSet('display_errors','On');
124 self::status(4, 'info', "Setting up scanRunning and starting scan");
125 try {
126 if ($isFork) {
127 $scan = wfConfig::get_ser('wfsd_engine', false, false);
128 if ($scan) {
129 self::status(4, 'info', "Got a true deserialized value back from 'wfsd_engine' with type: " . gettype($scan));
130 wfConfig::set('wfsd_engine', '', wfConfig::DONT_AUTOLOAD);
131 }
132 else {
133 self::status(2, 'error', "Scan can't continue - stored data not found after a fork. Got type: " . gettype($scan));
134 wfConfig::set('wfsd_engine', '', wfConfig::DONT_AUTOLOAD);
135 wfConfig::set('lastScanCompleted', __('Scan can\'t continue - stored data not found after a fork.', 'wordfence'));
136 wfConfig::set('lastScanFailureType', wfIssues::SCAN_FAILED_FORK_FAILED);
137 wfUtils::clearScanLock();
138 self::status(2, 'error', "Scan terminated with error: " . __('Scan can\'t continue - stored data not found after a fork.', 'wordfence'));
139 self::status(10, 'info', "SUM_KILLED:Previous scan terminated with an error. See below.");
140 exit();
141 }
142 }
143 else {
144 $delay = -1;
145 $isScheduled = false;
146 $originalScanStart = wfConfig::get('originalScheduledScanStart', 0);
147 $lastScanStart = wfConfig::get('lastScheduledScanStart', 0);
148 $minimumFrequency = ($scanController->schedulingMode() == wfScanner::SCAN_SCHEDULING_MODE_MANUAL ? 1800 : 43200);
149 if ($lastScanStart && (time() - $lastScanStart) < $minimumFrequency) {
150 $isScheduled = true;
151
152 if ($originalScanStart > 0) {
153 $delay = max($lastScanStart - $originalScanStart, 0);
154 }
155 }
156
157 wfIssues::statusPrep(); //Re-initializes all status counters
158 $scanController->resetStages();
159 $scanController->resetSummaryItems();
160
161 if ($scanMode != wfScanner::SCAN_TYPE_QUICK) {
162 wordfence::status(1, 'info', "Contacting Wordfence to initiate scan");
163 $wp_version = wfUtils::getWPVersion();
164 $apiKey = wfConfig::get('apiKey');
165 $api = new wfAPI($apiKey, $wp_version);
166 $response = $api->call('log_scan', array(), array('delay' => $delay, 'scheduled' => (int) $isScheduled, 'mode' => wfConfig::get('schedMode')/*, 'forcedefer' => 1*/));
167
168 if ($scanController->schedulingMode() == wfScanner::SCAN_SCHEDULING_MODE_AUTOMATIC && $isScheduled) {
169 if (isset($response['defer'])) {
170 $defer = (int) $response['defer'];
171 wordfence::status(2, 'info', "Deferring scheduled scan by " . wfUtils::makeDuration($defer));
172 wfConfig::set('lastScheduledScanStart', 0);
173 wfConfig::set('lastScanCompleted', 'ok');
174 wfConfig::set('lastScanFailureType', false);
175 wfConfig::set_ser('wfStatusStartMsgs', array());
176 $scanController->recordLastScanTime();
177 $i = new wfIssues();
178 wfScanEngine::refreshScanNotification($i);
179 wfScanner::shared()->scheduleSingleScan(time() + $defer, $originalScanStart);
180 wfUtils::clearScanLock();
181 exit();
182 }
183 }
184
185 $malwarePrefixesHash = (isset($response['malwarePrefixes']) ? $response['malwarePrefixes'] : '');
186 $coreHashesHash = (isset($response['coreHashes']) ? $response['coreHashes'] : '');
187
188 $scan = new wfScanEngine($malwarePrefixesHash, $coreHashesHash, $scanMode);
189 $scan->deleteNewIssues();
190 }
191 else {
192 wordfence::status(1, 'info', "Initiating quick scan");
193 $scan = new wfScanEngine('', '', $scanMode);
194 }
195 }
196
197 $scan->go();
198 }
199 catch (wfScanEngineDurationLimitException $e) { //User error set in wfScanEngine
200 wfUtils::clearScanLock();
201 $peakMemory = self::logPeakMemory();
202 self::status(2, 'info', "Wordfence used " . wfUtils::formatBytes($peakMemory - self::$peakMemAtStart) . " of memory for scan. Server peak memory usage was: " . wfUtils::formatBytes($peakMemory));
203 self::status(2, 'error', "Scan terminated with error: " . $e->getMessage());
204 exit();
205 }
206 catch (wfScanEngineCoreVersionChangeException $e) { //User error set in wfScanEngine
207 wfUtils::clearScanLock();
208 $peakMemory = self::logPeakMemory();
209 self::status(2, 'info', "Wordfence used " . wfUtils::formatBytes($peakMemory - self::$peakMemAtStart) . " of memory for scan. Server peak memory usage was: " . wfUtils::formatBytes($peakMemory));
210 self::status(2, 'error', "Scan terminated with message: " . $e->getMessage());
211
212 $nextScheduledScan = wordfence::getNextScanStartTimestamp();
213 if ($nextScheduledScan !== false && $nextScheduledScan - time() > 21600 /* 6 hours */) {
214 $nextScheduledScan = time() + 3600;
215 wfScanner::shared()->scheduleSingleScan($nextScheduledScan);
216 }
217 self::status(2, 'error', wordfence::getNextScanStartTime($nextScheduledScan));
218
219 exit();
220 }
221 catch (wfAPICallSSLUnavailableException $e) {
222 wfConfig::set('lastScanCompleted', $e->getMessage());
223 wfConfig::set('lastScanFailureType', wfIssues::SCAN_FAILED_API_SSL_UNAVAILABLE);
224
225 wfUtils::clearScanLock();
226 $peakMemory = self::logPeakMemory();
227 self::status(2, 'info', "Wordfence used " . wfUtils::formatBytes($peakMemory - self::$peakMemAtStart) . " of memory for scan. Server peak memory usage was: " . wfUtils::formatBytes($peakMemory));
228 self::status(2, 'error', "Scan terminated with error: " . $e->getMessage());
229 exit();
230 }
231 catch (wfAPICallFailedException $e) {
232 wfConfig::set('lastScanCompleted', $e->getMessage());
233 wfConfig::set('lastScanFailureType', wfIssues::SCAN_FAILED_API_CALL_FAILED);
234
235 wfUtils::clearScanLock();
236 $peakMemory = self::logPeakMemory();
237 self::status(2, 'info', "Wordfence used " . wfUtils::formatBytes($peakMemory - self::$peakMemAtStart) . " of memory for scan. Server peak memory usage was: " . wfUtils::formatBytes($peakMemory));
238 self::status(2, 'error', "Scan terminated with error: " . $e->getMessage());
239 exit();
240 }
241 catch (wfAPICallInvalidResponseException $e) {
242 wfConfig::set('lastScanCompleted', $e->getMessage());
243 wfConfig::set('lastScanFailureType', wfIssues::SCAN_FAILED_API_INVALID_RESPONSE);
244
245 wfUtils::clearScanLock();
246 $peakMemory = self::logPeakMemory();
247 self::status(2, 'info', "Wordfence used " . wfUtils::formatBytes($peakMemory - self::$peakMemAtStart) . " of memory for scan. Server peak memory usage was: " . wfUtils::formatBytes($peakMemory));
248 self::status(2, 'error', "Scan terminated with error: " . $e->getMessage());
249 exit();
250 }
251 catch (wfAPICallErrorResponseException $e) {
252 wfConfig::set('lastScanCompleted', $e->getMessage());
253 wfConfig::set('lastScanFailureType', wfIssues::SCAN_FAILED_API_ERROR_RESPONSE);
254
255 wfUtils::clearScanLock();
256 $peakMemory = self::logPeakMemory();
257 self::status(2, 'info', "Wordfence used " . wfUtils::formatBytes($peakMemory - self::$peakMemAtStart) . " of memory for scan. Server peak memory usage was: " . wfUtils::formatBytes($peakMemory));
258 self::status(2, 'error', "Scan terminated with error: " . $e->getMessage());
259 exit();
260 }
261 catch (Exception $e) {
262 wfUtils::clearScanLock();
263 self::status(2, 'error', "Scan terminated with error: " . $e->getMessage());
264 self::status(10, 'info', "SUM_KILLED:Previous scan terminated with an error. See below.");
265 exit();
266 }
267 wfUtils::clearScanLock();
268 }
269 public static function logPeakMemory(){
270 $oldPeak = wfConfig::get('wfPeakMemory', 0, false);
271 $peak = memory_get_peak_usage(true);
272 if ($peak > $oldPeak) {
273 wfConfig::set('wfPeakMemory', $peak, wfConfig::DONT_AUTOLOAD);
274 return $peak;
275 }
276 return $oldPeak;
277 }
278 public static function obHandler($buf){
279 if(strlen($buf) > 1000){
280 $buf = substr($buf, 0, 255);
281 }
282 if(empty($buf) === false && preg_match('/[a-zA-Z0-9]+/', $buf)){
283 self::status(1, 'error', $buf);
284 }
285 }
286 public static function error_handler($errno, $errstr, $errfile, $errline){
287 if(self::$errorHandlingOn && error_reporting() > 0){
288 if(preg_match('/wordfence\//', $errfile)){
289 $level = 1; //It's one of our files, so level 1
290 } else {
291 $level = 4; //It's someone elses plugin so only show if debug is enabled
292 }
293 self::status($level, 'error', "$errstr ($errno) File: $errfile Line: $errline");
294 }
295 return false;
296 }
297 public static function shutdown(){
298 self::logPeakMemory();
299 }
300 private static function errorExit($msg){
301 wordfence::status(1, 'error', "Scan Engine Error: $msg");
302 exit();
303 }
304 private static function status($level, $type, $msg){
305 wordfence::status($level, $type, $msg);
306 }
307 }
308