Wordfence Security – Firewall & Malware Scan - Version 7.1.17

Version Description

  • Improvement: Increased frequency of filesystem permission check and update of the WAF config files.
  • Improvement: More complete data removal when deactivating with remove tables and files checked.
  • Improvement: Better diagnostics logging for GeoIP conflicts.
  • Fix: Text fix in invalid username lockout message.
  • Fix: PHP 7.3 syntax compatibility fixes.
Download this release

Release Info

Developer wfryan
Plugin Icon 128x128 Wordfence Security – Firewall & Malware Scan
Version 7.1.17
Comparing to
See all releases

Code changes from version 7.1.16 to 7.1.17

Files changed (50) hide show
  1. css/{activity-report-widget.1539704326.css → activity-report-widget.1541524007.css} +0 -0
  2. css/{diff.1539704326.css → diff.1541524007.css} +0 -0
  3. css/{dt_table.1539704326.css → dt_table.1541524007.css} +0 -0
  4. css/{fullLog.1539704326.css → fullLog.1541524007.css} +0 -0
  5. css/{iptraf.1539704326.css → iptraf.1541524007.css} +0 -0
  6. css/{jquery-ui-timepicker-addon.1539704326.css → jquery-ui-timepicker-addon.1541524007.css} +0 -0
  7. css/{jquery-ui.min.1539704326.css → jquery-ui.min.1541524007.css} +0 -0
  8. css/{jquery-ui.structure.min.1539704326.css → jquery-ui.structure.min.1541524007.css} +0 -0
  9. css/{jquery-ui.theme.min.1539704326.css → jquery-ui.theme.min.1541524007.css} +0 -0
  10. css/{main.1539704326.css → main.1541524007.css} +0 -0
  11. css/{phpinfo.1539704326.css → phpinfo.1541524007.css} +0 -0
  12. css/{wf-adminbar.1539704326.css → wf-adminbar.1541524007.css} +0 -0
  13. css/{wf-colorbox.1539704326.css → wf-colorbox.1541524007.css} +0 -0
  14. css/{wf-font-awesome.1539704326.css → wf-font-awesome.1541524007.css} +0 -0
  15. css/{wf-ionicons.1539704326.css → wf-ionicons.1541524007.css} +0 -0
  16. css/{wf-onboarding.1539704326.css → wf-onboarding.1541524007.css} +0 -0
  17. css/{wf-roboto-font.1539704326.css → wf-roboto-font.1541524007.css} +0 -0
  18. css/{wfselect2.min.1539704326.css → wfselect2.min.1541524007.css} +0 -0
  19. css/{wordfenceBox.1539704326.css → wordfenceBox.1541524007.css} +0 -0
  20. js/{Chart.bundle.min.1539704326.js → Chart.bundle.min.1541524007.js} +0 -0
  21. js/{admin.1539704326.js → admin.1541524007.js} +0 -0
  22. js/{admin.ajaxWatcher.1539704326.js → admin.ajaxWatcher.1541524007.js} +0 -0
  23. js/{admin.liveTraffic.1539704326.js → admin.liveTraffic.1541524007.js} +0 -0
  24. js/{date.1539704326.js → date.1541524007.js} +0 -0
  25. js/{jquery-ui-timepicker-addon.1539704326.js → jquery-ui-timepicker-addon.1541524007.js} +0 -0
  26. js/{jquery.colorbox-min.1539704326.js → jquery.colorbox-min.1541524007.js} +0 -0
  27. js/{jquery.colorbox.1539704326.js → jquery.colorbox.1541524007.js} +0 -0
  28. js/{jquery.dataTables.min.1539704326.js → jquery.dataTables.min.1541524007.js} +0 -0
  29. js/{jquery.qrcode.min.1539704326.js → jquery.qrcode.min.1541524007.js} +0 -0
  30. js/{jquery.tmpl.min.1539704326.js → jquery.tmpl.min.1541524007.js} +0 -0
  31. js/{jquery.tools.min.1539704326.js → jquery.tools.min.1541524007.js} +0 -0
  32. js/{knockout-3.3.0.1539704326.js → knockout-3.3.0.1541524007.js} +0 -0
  33. js/{perf.1539704326.js → perf.1541524007.js} +0 -0
  34. js/{wfdashboard.1539704326.js → wfdashboard.1541524007.js} +0 -0
  35. js/{wfdropdown.1539704326.js → wfdropdown.1541524007.js} +0 -0
  36. js/{wfglobal.1539704326.js → wfglobal.1541524007.js} +0 -0
  37. js/{wfpopover.1539704326.js → wfpopover.1541524007.js} +0 -0
  38. js/{wfselect2.min.1539704326.js → wfselect2.min.1541524007.js} +0 -0
  39. lib/wfConfig.php +3 -0
  40. lib/wfDiagnostic.php +35 -2
  41. lib/wfUtils.php +73 -3
  42. lib/wordfenceClass.php +113 -5
  43. lib/wordfenceScanner.php +3 -2
  44. models/block/wfBlock.php +5 -5
  45. readme.txt +9 -2
  46. vendor/wordfence/wf-waf/src/lib/storage.php +2 -0
  47. vendor/wordfence/wf-waf/src/lib/storage/file.php +30 -0
  48. vendor/wordfence/wf-waf/src/lib/waf.php +9 -1
  49. waf/bootstrap.php +88 -13
  50. wordfence.php +3 -3
css/{activity-report-widget.1539704326.css → activity-report-widget.1541524007.css} RENAMED
File without changes
css/{diff.1539704326.css → diff.1541524007.css} RENAMED
File without changes
css/{dt_table.1539704326.css → dt_table.1541524007.css} RENAMED
File without changes
css/{fullLog.1539704326.css → fullLog.1541524007.css} RENAMED
File without changes
css/{iptraf.1539704326.css → iptraf.1541524007.css} RENAMED
File without changes
css/{jquery-ui-timepicker-addon.1539704326.css → jquery-ui-timepicker-addon.1541524007.css} RENAMED
File without changes
css/{jquery-ui.min.1539704326.css → jquery-ui.min.1541524007.css} RENAMED
File without changes
css/{jquery-ui.structure.min.1539704326.css → jquery-ui.structure.min.1541524007.css} RENAMED
File without changes
css/{jquery-ui.theme.min.1539704326.css → jquery-ui.theme.min.1541524007.css} RENAMED
File without changes
css/{main.1539704326.css → main.1541524007.css} RENAMED
File without changes
css/{phpinfo.1539704326.css → phpinfo.1541524007.css} RENAMED
File without changes
css/{wf-adminbar.1539704326.css → wf-adminbar.1541524007.css} RENAMED
File without changes
css/{wf-colorbox.1539704326.css → wf-colorbox.1541524007.css} RENAMED
File without changes
css/{wf-font-awesome.1539704326.css → wf-font-awesome.1541524007.css} RENAMED
File without changes
css/{wf-ionicons.1539704326.css → wf-ionicons.1541524007.css} RENAMED
File without changes
css/{wf-onboarding.1539704326.css → wf-onboarding.1541524007.css} RENAMED
File without changes
css/{wf-roboto-font.1539704326.css → wf-roboto-font.1541524007.css} RENAMED
File without changes
css/{wfselect2.min.1539704326.css → wfselect2.min.1541524007.css} RENAMED
File without changes
css/{wordfenceBox.1539704326.css → wordfenceBox.1541524007.css} RENAMED
File without changes
js/{Chart.bundle.min.1539704326.js → Chart.bundle.min.1541524007.js} RENAMED
File without changes
js/{admin.1539704326.js → admin.1541524007.js} RENAMED
File without changes
js/{admin.ajaxWatcher.1539704326.js → admin.ajaxWatcher.1541524007.js} RENAMED
File without changes
js/{admin.liveTraffic.1539704326.js → admin.liveTraffic.1541524007.js} RENAMED
File without changes
js/{date.1539704326.js → date.1541524007.js} RENAMED
File without changes
js/{jquery-ui-timepicker-addon.1539704326.js → jquery-ui-timepicker-addon.1541524007.js} RENAMED
File without changes
js/{jquery.colorbox-min.1539704326.js → jquery.colorbox-min.1541524007.js} RENAMED
File without changes
js/{jquery.colorbox.1539704326.js → jquery.colorbox.1541524007.js} RENAMED
File without changes
js/{jquery.dataTables.min.1539704326.js → jquery.dataTables.min.1541524007.js} RENAMED
File without changes
js/{jquery.qrcode.min.1539704326.js → jquery.qrcode.min.1541524007.js} RENAMED
File without changes
js/{jquery.tmpl.min.1539704326.js → jquery.tmpl.min.1541524007.js} RENAMED
File without changes
js/{jquery.tools.min.1539704326.js → jquery.tools.min.1541524007.js} RENAMED
File without changes
js/{knockout-3.3.0.1539704326.js → knockout-3.3.0.1541524007.js} RENAMED
File without changes
js/{perf.1539704326.js → perf.1541524007.js} RENAMED
File without changes
js/{wfdashboard.1539704326.js → wfdashboard.1541524007.js} RENAMED
File without changes
js/{wfdropdown.1539704326.js → wfdropdown.1541524007.js} RENAMED
File without changes
js/{wfglobal.1539704326.js → wfglobal.1541524007.js} RENAMED
File without changes
js/{wfpopover.1539704326.js → wfpopover.1541524007.js} RENAMED
File without changes
js/{wfselect2.min.1539704326.js → wfselect2.min.1541524007.js} RENAMED
File without changes
lib/wfConfig.php CHANGED
@@ -217,6 +217,9 @@ class wfConfig {
217
  'touppPromptNeeded' => array('value' => false, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_BOOL)),
218
  'touppBypassNextCheck' => array('value' => false, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_BOOL)),
219
  'autoUpdateAttempts' => array('value' => 0, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_INT)),
 
 
 
220
  ),
221
  );
222
  public static $serializedOptions = array('lastAdminLogin', 'scanSched', 'emailedIssuesList', 'wf_summaryItems', 'adminUserList', 'twoFactorUsers', 'alertFreqTrack', 'wfStatusStartMsgs', 'vulnerabilities_plugin', 'vulnerabilities_theme', 'dashboardData', 'malwarePrefixes', 'coreHashes', 'noc1ScanSchedule', 'allScansScheduled', 'disclosureStates', 'scanStageStatuses', 'adminNoticeQueue');
217
  'touppPromptNeeded' => array('value' => false, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_BOOL)),
218
  'touppBypassNextCheck' => array('value' => false, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_BOOL)),
219
  'autoUpdateAttempts' => array('value' => 0, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_INT)),
220
+ 'lastPermissionsTemplateCheck' => array('value' => 0, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_INT)),
221
+ 'previousWflogsFileList' => array('value' => '[]', 'autoload' => self::DONT_AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),
222
+ 'diagnosticsWflogsRemovalHistory' => array('value' => '[]', 'autoload' => self::DONT_AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),
223
  ),
224
  );
225
  public static $serializedOptions = array('lastAdminLogin', 'scanSched', 'emailedIssuesList', 'wf_summaryItems', 'adminUserList', 'twoFactorUsers', 'alertFreqTrack', 'wfStatusStartMsgs', 'vulnerabilities_plugin', 'vulnerabilities_theme', 'dashboardData', 'malwarePrefixes', 'coreHashes', 'noc1ScanSchedule', 'allScansScheduled', 'disclosureStates', 'scanStageStatuses', 'adminNoticeQueue');
lib/wfDiagnostic.php CHANGED
@@ -58,6 +58,7 @@ class wfDiagnostic
58
  'description' => __('General information about the Wordfence installation.', 'wordfence'),
59
  'tests' => array(
60
  'wfVersion' => __('Wordfence Version', 'wordfence'),
 
61
  ),
62
  ),
63
  'Filesystem' => array(
@@ -84,6 +85,7 @@ class wfDiagnostic
84
  'wafSubdirectoryInstall' => __('WAF subdirectory installation', 'wordfence'),
85
  'wafAutoPrependFilePath' => __('wordfence-waf.php path', 'wordfence'),
86
  'wafFilePermissions' => __('WAF File Permissions', 'wordfence'),
 
87
  ),
88
  ),
89
  'MySQL' => array(
@@ -161,6 +163,15 @@ class wfDiagnostic
161
  public function wfVersion() {
162
  return array('test' => true, 'message' => WORDFENCE_VERSION . ' (' . WORDFENCE_BUILD_NUMBER . ')');
163
  }
 
 
 
 
 
 
 
 
 
164
 
165
  public function isPluginReadable() {
166
  return is_readable(WORDFENCE_PATH);
@@ -180,7 +191,6 @@ class wfDiagnostic
180
  WFWAF_LOG_PATH . 'ips.php',
181
  WFWAF_LOG_PATH . 'config.php',
182
  WFWAF_LOG_PATH . 'rules.php',
183
- WFWAF_LOG_PATH . 'wafRules.rules',
184
  );
185
  $unreadable = array();
186
  foreach ($files as $f) {
@@ -209,7 +219,6 @@ class wfDiagnostic
209
  WFWAF_LOG_PATH . 'ips.php',
210
  WFWAF_LOG_PATH . 'config.php',
211
  WFWAF_LOG_PATH . 'rules.php',
212
- WFWAF_LOG_PATH . 'wafRules.rules',
213
  );
214
  $unwritable = array();
215
  foreach ($files as $f) {
@@ -347,6 +356,30 @@ class wfDiagnostic
347
  }
348
  return array('test' => true, 'infoOnly' => true, 'message' => __('0660 - using default', 'wordfence'));
349
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
350
 
351
  public function processOwner() {
352
  $disabledFunctions = explode(',', ini_get('disable_functions'));
58
  'description' => __('General information about the Wordfence installation.', 'wordfence'),
59
  'tests' => array(
60
  'wfVersion' => __('Wordfence Version', 'wordfence'),
61
+ 'geoIPVersion' => __('GeoIP Version', 'wordfence'),
62
  ),
63
  ),
64
  'Filesystem' => array(
85
  'wafSubdirectoryInstall' => __('WAF subdirectory installation', 'wordfence'),
86
  'wafAutoPrependFilePath' => __('wordfence-waf.php path', 'wordfence'),
87
  'wafFilePermissions' => __('WAF File Permissions', 'wordfence'),
88
+ 'wafRecentlyRemoved' => __('Recently removed wflogs files', 'wordfence'),
89
  ),
90
  ),
91
  'MySQL' => array(
163
  public function wfVersion() {
164
  return array('test' => true, 'message' => WORDFENCE_VERSION . ' (' . WORDFENCE_BUILD_NUMBER . ')');
165
  }
166
+
167
+ public function geoIPVersion() {
168
+ return array('test' => true, 'infoOnly' => true, 'message' => wfUtils::geoIPVersion());
169
+ }
170
+
171
+ public function geoIPError() {
172
+ $error = wfUtils::last_error('geoip');
173
+ return array('test' => true, 'infoOnly' => true, 'message' => $error ? $error : __('None', 'wordfence'));
174
+ }
175
 
176
  public function isPluginReadable() {
177
  return is_readable(WORDFENCE_PATH);
191
  WFWAF_LOG_PATH . 'ips.php',
192
  WFWAF_LOG_PATH . 'config.php',
193
  WFWAF_LOG_PATH . 'rules.php',
 
194
  );
195
  $unreadable = array();
196
  foreach ($files as $f) {
219
  WFWAF_LOG_PATH . 'ips.php',
220
  WFWAF_LOG_PATH . 'config.php',
221
  WFWAF_LOG_PATH . 'rules.php',
 
222
  );
223
  $unwritable = array();
224
  foreach ($files as $f) {
356
  }
357
  return array('test' => true, 'infoOnly' => true, 'message' => __('0660 - using default', 'wordfence'));
358
  }
359
+
360
+ public function wafRecentlyRemoved() {
361
+ $removalHistory = wfConfig::getJSON('diagnosticsWflogsRemovalHistory', array());
362
+ if (empty($removalHistory)) {
363
+ return array('test' => true, 'infoOnly' => true, 'message' => __('None', 'wordfence'));
364
+ }
365
+
366
+ $message = array();
367
+ foreach ($removalHistory as $r) {
368
+ $m = wfUtils::formatLocalTime('M j, Y', $r[0]) . ': (' . count($r[1]) . ')';
369
+ $r[1] = array_filter($r[1], array($this, '_filterOutNestedEntries'));
370
+ $m .= ' ' . implode(', ', array_slice($r[1], 0, 5));
371
+ if (count($r[1]) > 5) {
372
+ $m .= ', ...';
373
+ }
374
+ $message[] = $m;
375
+ }
376
+
377
+ return array('test' => true, 'infoOnly' => true, 'message' => implode("\n", $message));
378
+ }
379
+
380
+ private function _filterOutNestedEntries($a) {
381
+ return !is_array($a);
382
+ }
383
 
384
  public function processOwner() {
385
  $disabledFunctions = explode(',', ini_get('disable_functions'));
lib/wfUtils.php CHANGED
@@ -1387,16 +1387,22 @@ class wfUtils {
1387
  }
1388
 
1389
  if (!class_exists('wfGeoIP2')) {
 
1390
  require_once(dirname(__FILE__) . '/../models/common/wfGeoIP2.php');
 
1391
  }
1392
 
1393
  try {
 
1394
  $geoip = @wfGeoIP2::shared();
 
 
1395
  $code = @$geoip->countryCode($IP);
 
1396
  return is_string($code) ? $code : '';
1397
  }
1398
  catch (Exception $e) {
1399
- //Ignore
1400
  }
1401
 
1402
  return '';
@@ -1407,15 +1413,22 @@ class wfUtils {
1407
  }
1408
 
1409
  if (!class_exists('wfGeoIP2')) {
 
1410
  require_once(dirname(__FILE__) . '/../models/common/wfGeoIP2.php');
 
1411
  }
1412
 
1413
  try {
 
1414
  $geoip = @wfGeoIP2::shared();
1415
- return @$geoip->version();
 
 
 
 
1416
  }
1417
  catch (Exception $e) {
1418
- //Ignore
1419
  }
1420
 
1421
  return 0;
@@ -1465,6 +1478,63 @@ class wfUtils {
1465
  public static function isRefererBlocked($refPattern){
1466
  return fnmatch($refPattern, !empty($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '', FNM_CASEFOLD);
1467
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1468
 
1469
  /**
1470
  * @param $startIP
1387
  }
1388
 
1389
  if (!class_exists('wfGeoIP2')) {
1390
+ wfUtils::error_clear_last();
1391
  require_once(dirname(__FILE__) . '/../models/common/wfGeoIP2.php');
1392
+ wfUtils::check_and_log_last_error('geoip', 'GeoIP Error:');
1393
  }
1394
 
1395
  try {
1396
+ wfUtils::error_clear_last();
1397
  $geoip = @wfGeoIP2::shared();
1398
+ wfUtils::check_and_log_last_error('geoip', 'GeoIP Error:');
1399
+ wfUtils::error_clear_last();
1400
  $code = @$geoip->countryCode($IP);
1401
+ wfUtils::check_and_log_last_error('geoip', 'GeoIP Error:');
1402
  return is_string($code) ? $code : '';
1403
  }
1404
  catch (Exception $e) {
1405
+ wfUtils::check_and_log_last_error('geoip', 'GeoIP Error:', $e->getMessage());
1406
  }
1407
 
1408
  return '';
1413
  }
1414
 
1415
  if (!class_exists('wfGeoIP2')) {
1416
+ wfUtils::error_clear_last();
1417
  require_once(dirname(__FILE__) . '/../models/common/wfGeoIP2.php');
1418
+ wfUtils::check_and_log_last_error('geoip', 'GeoIP Error:');
1419
  }
1420
 
1421
  try {
1422
+ wfUtils::error_clear_last();
1423
  $geoip = @wfGeoIP2::shared();
1424
+ wfUtils::check_and_log_last_error('geoip', 'GeoIP Error:');
1425
+ wfUtils::error_clear_last();
1426
+ $version = @$geoip->version();
1427
+ wfUtils::check_and_log_last_error('geoip', 'GeoIP Error:');
1428
+ return $version;
1429
  }
1430
  catch (Exception $e) {
1431
+ wfUtils::check_and_log_last_error('geoip', 'GeoIP Error:', $e->getMessage());
1432
  }
1433
 
1434
  return 0;
1478
  public static function isRefererBlocked($refPattern){
1479
  return fnmatch($refPattern, !empty($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '', FNM_CASEFOLD);
1480
  }
1481
+
1482
+ public static function error_clear_last() {
1483
+ if (function_exists('error_clear_last')) {
1484
+ error_clear_last();
1485
+ }
1486
+ else {
1487
+ // set error_get_last() to defined state by forcing an undefined variable error
1488
+ set_error_handler('wfUtils::_resetErrorsHandler', 0);
1489
+ @$undefinedVariable;
1490
+ restore_error_handler();
1491
+ }
1492
+ }
1493
+
1494
+ /**
1495
+ * Logs the error given or the last PHP error to our log, rate limiting if needed.
1496
+ *
1497
+ * @param string $limiter_key
1498
+ * @param string $label
1499
+ * @param null|string $error The error to log. If null, it will be the result of error_get_last
1500
+ * @param int $rate Logging will only occur once per $rate seconds.
1501
+ */
1502
+ public static function check_and_log_last_error($limiter_key, $label, $error = null, $rate = 3600 /* 1 hour */) {
1503
+ if ($error === null) {
1504
+ $error = error_get_last();
1505
+ if ($error === null) {
1506
+ return;
1507
+ }
1508
+ else if ($error['file'] === __FILE__) {
1509
+ return;
1510
+ }
1511
+ $error = $error['message'];
1512
+ }
1513
+
1514
+ $rateKey = 'lastError_rate_' . $limiter_key;
1515
+ $previousKey = 'lastError_prev_' . $limiter_key;
1516
+ $previousError = wfConfig::getJSON($previousKey, array(0, false));
1517
+ if ($previousError[1] != $error) {
1518
+ if (wfConfig::getInt($rateKey) < time() - $rate) {
1519
+ wfConfig::set($rateKey, time());
1520
+ wfConfig::setJSON($previousKey, array(time(), $error));
1521
+ wordfence::status(2, 'error', $label . ' ' . $error);
1522
+ }
1523
+ }
1524
+ }
1525
+
1526
+ public static function last_error($limiter_key) {
1527
+ $previousKey = 'lastError_prev_' . $limiter_key;
1528
+ $previousError = wfConfig::getJSON($previousKey, array(0, false));
1529
+ if ($previousError[1]) {
1530
+ return wfUtils::formatLocalTime(get_option('date_format') . ' ' . get_option('time_format'), $previousError[0]) . ': ' . $previousError[1];
1531
+ }
1532
+ return false;
1533
+ }
1534
+
1535
+ public static function _resetErrorsHandler($errno, $errstr, $errfile, $errline) {
1536
+ //Do nothing
1537
+ }
1538
 
1539
  /**
1540
  * @param $startIP
lib/wordfenceClass.php CHANGED
@@ -285,6 +285,8 @@ class wordfence {
285
  if ($next - time() > 3600 && wfConfig::get('scheduledScansEnabled')) {
286
  wfScanEngine::startScan(false, wfScanner::SCAN_TYPE_QUICK);
287
  }
 
 
288
  }
289
  public static function _scheduleRefreshUpdateNotification($upgrader, $options) {
290
  $defer = false;
@@ -1832,7 +1834,8 @@ SQL
1832
  }
1833
 
1834
  try {
1835
- if (wfUtils::isAdmin()) {
 
1836
  $lastPermissionsTemplateCheck = wfConfig::getInt('lastPermissionsTemplateCheck', 0);
1837
  if (defined('WFWAF_LOG_PATH') && ($lastPermissionsTemplateCheck + 43200) < time()) { //Run no more frequently than every 12 hours
1838
  $timestamp = preg_replace('/[^0-9]/', '', microtime(false)); //We avoid using tmpfile since it can potentially create one with different permissions than the defaults
@@ -1866,10 +1869,41 @@ SQL
1866
  }
1867
 
1868
  wfConfig::set('lastPermissionsTemplateCheck', time());
1869
- }
1870
 
1871
- @chmod(WFWAF_LOG_PATH, (wfWAFWordPress::permissions() | 0755));
1872
- @chmod(rtrim(WFWAF_LOG_PATH, '/') . '/.htaccess', (wfWAFWordPress::permissions() | 0444));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1873
  }
1874
  }
1875
  catch (Exception $e) {
@@ -2034,6 +2068,80 @@ SQL
2034
  }
2035
  }
2036
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2037
 
2038
  public static function loginAction($username){
2039
  if(sizeof($_POST) < 1){ return; } //only execute if login form is posted
@@ -2648,7 +2756,7 @@ SQL
2648
  }
2649
  if(wfConfig::get('loginSec_lockInvalidUsers')){
2650
  if(strlen($username) > 0 && preg_match('/[^\r\s\n\t]+/', $username)){
2651
- self::lockOutIP($IP, "Used an invalid username '" . $username . "' to try to sign in.");
2652
  self::getLog()->logLogin('loginFailInvalidUsername', true, $username);
2653
  }
2654
  $customText = wpautop(wp_strip_all_tags(wfConfig::get('blockCustomText', '')));
285
  if ($next - time() > 3600 && wfConfig::get('scheduledScansEnabled')) {
286
  wfScanEngine::startScan(false, wfScanner::SCAN_TYPE_QUICK);
287
  }
288
+
289
+ wfConfig::remove('lastPermissionsTemplateCheck');
290
  }
291
  public static function _scheduleRefreshUpdateNotification($upgrader, $options) {
292
  $defer = false;
1834
  }
1835
 
1836
  try {
1837
+ $sapi = @php_sapi_name();
1838
+ if ($sapi != "cli") {
1839
  $lastPermissionsTemplateCheck = wfConfig::getInt('lastPermissionsTemplateCheck', 0);
1840
  if (defined('WFWAF_LOG_PATH') && ($lastPermissionsTemplateCheck + 43200) < time()) { //Run no more frequently than every 12 hours
1841
  $timestamp = preg_replace('/[^0-9]/', '', microtime(false)); //We avoid using tmpfile since it can potentially create one with different permissions than the defaults
1869
  }
1870
 
1871
  wfConfig::set('lastPermissionsTemplateCheck', time());
 
1872
 
1873
+ @chmod(WFWAF_LOG_PATH, (wfWAFWordPress::permissions() | 0755));
1874
+ wfWAFWordPress::writeHtaccess();
1875
+
1876
+ $contents = self::_wflogsContents();
1877
+ if ($contents) {
1878
+ $validFiles = wfWAF::getInstance()->fileList();
1879
+ foreach ($validFiles as &$vf) {
1880
+ $vf = basename($vf);
1881
+ }
1882
+ $validFiles = array_filter($validFiles);
1883
+
1884
+ $previousWflogsFileList = wfConfig::getJSON('previousWflogsFileList', array());
1885
+
1886
+ $wflogs = realpath(WFWAF_LOG_PATH);
1887
+ $filesRemoved = array();
1888
+ foreach ($contents as $f) {
1889
+ if (!in_array($f, $validFiles) && in_array($f, $previousWflogsFileList)) {
1890
+ $fullPath = $f;
1891
+ $removed = self::_recursivelyRemoveWflogs($f);
1892
+ $filesRemoved = array_merge($filesRemoved, $removed);
1893
+ }
1894
+ }
1895
+
1896
+ $contents = self::_wflogsContents();
1897
+ wfConfig::setJSON('previousWflogsFileList', $contents);
1898
+
1899
+ if (!empty($filesRemoved)) {
1900
+ $removalHistory = wfConfig::getJSON('diagnosticsWflogsRemovalHistory', array());
1901
+ $removalHistory = array_slice($removalHistory, 0, 4);
1902
+ array_unshift($removalHistory, array(time(), $filesRemoved));
1903
+ wfConfig::setJSON('diagnosticsWflogsRemovalHistory', $removalHistory);
1904
+ }
1905
+ }
1906
+ }
1907
  }
1908
  }
1909
  catch (Exception $e) {
2068
  }
2069
  }
2070
  }
2071
+
2072
+ private static function _wflogsContents() {
2073
+ $dir = opendir(WFWAF_LOG_PATH);
2074
+ if ($dir) {
2075
+ $contents = array();
2076
+ while ($path = readdir($dir)) {
2077
+ if ($path == '.' || $path == '..') { continue; }
2078
+ $contents[] = $path;
2079
+ }
2080
+ closedir($dir);
2081
+ return $contents;
2082
+ }
2083
+ return false;
2084
+ }
2085
+
2086
+ /**
2087
+ * Removes a path within wflogs, recursing as necessary.
2088
+ *
2089
+ * @param string $file
2090
+ * @param array $processedDirs
2091
+ * @return array The list of removed files/folders.
2092
+ */
2093
+ private static function _recursivelyRemoveWflogs($file, $processedDirs = array()) {
2094
+ if (preg_match('~(?:^|/|\\\\)\.\.(?:/|\\\\|$)~', $file)) {
2095
+ return array();
2096
+ }
2097
+
2098
+ if (stripos(WFWAF_LOG_PATH, 'wflogs') === false) { //Sanity check -- if not in a wflogs folder, user will have to do removal manually
2099
+ return array();
2100
+ }
2101
+
2102
+ $path = rtrim(WFWAF_LOG_PATH, '/') . '/' . $file;
2103
+ if (is_link($path)) {
2104
+ if (@unlink($path)) {
2105
+ return array($file);
2106
+ }
2107
+ return array();
2108
+ }
2109
+
2110
+ if (is_dir($path)) {
2111
+ $real = realpath($file);
2112
+ if (in_array($real, $processedDirs)) {
2113
+ return array();
2114
+ }
2115
+ $processedDirs[] = $real;
2116
+
2117
+ $count = 0;
2118
+ $dir = opendir($path);
2119
+ if ($dir) {
2120
+ $contents = array();
2121
+ while ($sub = readdir($dir)) {
2122
+ if ($sub == '.' || $sub == '..') { continue; }
2123
+ $contents[] = $sub;
2124
+ }
2125
+ closedir($dir);
2126
+
2127
+ $filesRemoved = array();
2128
+ foreach ($contents as $f) {
2129
+ $removed = self::_recursivelyRemoveWflogs($file . '/' . $f, $processedDirs);
2130
+ $filesRemoved = array($filesRemoved, $removed);
2131
+ }
2132
+ }
2133
+
2134
+ if (@rmdir($path)) {
2135
+ $filesRemoved[] = $file;
2136
+ }
2137
+ return $filesRemoved;
2138
+ }
2139
+
2140
+ if (@unlink($path)) {
2141
+ return array($file);
2142
+ }
2143
+ return array();
2144
+ }
2145
 
2146
  public static function loginAction($username){
2147
  if(sizeof($_POST) < 1){ return; } //only execute if login form is posted
2756
  }
2757
  if(wfConfig::get('loginSec_lockInvalidUsers')){
2758
  if(strlen($username) > 0 && preg_match('/[^\r\s\n\t]+/', $username)){
2759
+ self::lockOutIP($IP, "Used an invalid username '" . $username . "' to try to sign in");
2760
  self::getLog()->logLogin('loginFailInvalidUsername', true, $username);
2761
  }
2762
  $customText = wpautop(wp_strip_all_tags(wfConfig::get('blockCustomText', '')));
lib/wordfenceScanner.php CHANGED
@@ -365,7 +365,8 @@ class wordfenceScanner {
365
 
366
  $type = (isset($rule[4]) && !empty($rule[4])) ? $rule[4] : 'server';
367
  $logOnly = (isset($rule[5]) && !empty($rule[5])) ? $rule[5] : false;
368
- $commonStringIndexes = (isset($rule[8]) && is_array($rule[8])) ? $rule[8] : array();
 
369
  if ($type == 'server' && !$treatAsBinary) { continue; }
370
  else if (($type == 'both' || $type == 'browser') && $isJS) { $extraMsg = ''; }
371
  else if (($type == 'both' || $type == 'browser') && !$treatAsBinary) { continue; }
@@ -398,7 +399,7 @@ class wordfenceScanner {
398
  'ignoreP' => $this->path . $file,
399
  'ignoreC' => $fileSum,
400
  'shortMsg' => __('File appears to be malicious: ', 'wordfence') . esc_html($file),
401
- 'longMsg' => sprintf(__('This file appears to be installed or modified by a hacker to perform malicious activity. If you know about this file you can choose to ignore it to exclude it from future scans. The text we found in this file that matches a known malicious file is: <strong style="color: #F00;" class="wf-split-word">%s</strong>', 'wordfence'), wfUtils::potentialBinaryStringToHTML((wfUtils::strlen($matchString) > 200 ? wfUtils::substr($matchString, 0, 200) . '...' : $matchString))) . '<br><br>' . sprintf(__('The infection type is: <strong>%s</strong>', 'wordfence'), esc_html($rule[7])) . '<br>' . sprintf(__('Description: <strong>%s</strong>', 'wordfence'), esc_html($rule[3])) . $extraMsg,
402
  'data' => array_merge(array(
403
  'file' => $file,
404
  'shac' => $record->SHAC,
365
 
366
  $type = (isset($rule[4]) && !empty($rule[4])) ? $rule[4] : 'server';
367
  $logOnly = (isset($rule[5]) && !empty($rule[5])) ? $rule[5] : false;
368
+ $commonStringIndexes = (isset($rule[8]) && is_array($rule[8])) ? $rule[8] : array();
369
+ $customMessage = isset($rule[9]) ? $rule[9] : __('This file appears to be installed or modified by a hacker to perform malicious activity. If you know about this file you can choose to ignore it to exclude it from future scans.', 'wordfence');
370
  if ($type == 'server' && !$treatAsBinary) { continue; }
371
  else if (($type == 'both' || $type == 'browser') && $isJS) { $extraMsg = ''; }
372
  else if (($type == 'both' || $type == 'browser') && !$treatAsBinary) { continue; }
399
  'ignoreP' => $this->path . $file,
400
  'ignoreC' => $fileSum,
401
  'shortMsg' => __('File appears to be malicious: ', 'wordfence') . esc_html($file),
402
+ 'longMsg' => $customMessage . ' ' . __('The matched text in this file is:', 'wordfence') . ' ' . '<strong style="color: #F00;" class="wf-split-word">' . wfUtils::potentialBinaryStringToHTML((wfUtils::strlen($matchString) > 200 ? wfUtils::substr($matchString, 0, 200) . '...' : $matchString)) . '</strong>' . '<br><br>' . sprintf(__('The issue type is: <strong>%s</strong>', 'wordfence'), esc_html($rule[7])) . '<br>' . sprintf(__('Description: <strong>%s</strong>', 'wordfence'), esc_html($rule[3])) . $extraMsg,
403
  'data' => array_merge(array(
404
  'file' => $file,
405
  'shac' => $record->SHAC,
models/block/wfBlock.php CHANGED
@@ -549,10 +549,10 @@ class wfBlock {
549
 
550
  return $wpdb->query($wpdb->prepare("INSERT INTO `{$blocksTable}` (`type`, `IP`, `blockedTime`, `reason`, `lastAttempt`, `blockedHits`, `expiration`, `parameters`) VALUES (%d, %s, %d, %s, %d, %d, %d, NULL)", (int) $b['type'], wfUtils::inet_pton($ip), (int) $b['blockedTime'], $b['reason'], (int) $b['lastAttempt'], (int) $b['blockedHits'], self::DURATION_FOREVER)) !== false;
551
  case self::TYPE_COUNTRY:
552
- if (!isset($b['parameters'])) { continue; }
553
- if (wfUtils::inet_pton($ip) != self::MARKER_COUNTRY) { continue; }
554
  $parameters = @json_decode($b['parameters'], true);
555
- if (!isset($parameters['blockLogin']) || !isset($parameters['blockSite']) || !isset($parameters['countries'])) { continue; }
556
  $parameters['blockLogin'] = wfUtils::truthyToInt($parameters['blockLogin']);
557
  $parameters['blockSite'] = wfUtils::truthyToInt($parameters['blockSite']);
558
 
@@ -567,10 +567,10 @@ class wfBlock {
567
 
568
  return $wpdb->query($wpdb->prepare("INSERT INTO `{$blocksTable}` (`type`, `IP`, `blockedTime`, `reason`, `lastAttempt`, `blockedHits`, `expiration`, `parameters`) VALUES (%d, %s, %d, %s, %d, %d, %d, %s)", self::TYPE_COUNTRY, self::MARKER_COUNTRY, (int) $b['blockedTime'], $b['reason'], (int) $b['lastAttempt'], (int) $b['blockedHits'], self::DURATION_FOREVER, json_encode($parameters))) !== false;
569
  case self::TYPE_PATTERN:
570
- if (!isset($b['parameters'])) { continue; }
571
  if (wfUtils::inet_pton($ip) != self::MARKER_PATTERN) { return false; }
572
  $parameters = @json_decode($b['parameters'], true);
573
- if (!isset($parameters['ipRange']) || !isset($parameters['hostname']) || !isset($parameters['userAgent']) || !isset($parameters['referrer'])) { continue; }
574
 
575
  $hasOne = false;
576
  if (!empty($parameters['ipRange'])) {
549
 
550
  return $wpdb->query($wpdb->prepare("INSERT INTO `{$blocksTable}` (`type`, `IP`, `blockedTime`, `reason`, `lastAttempt`, `blockedHits`, `expiration`, `parameters`) VALUES (%d, %s, %d, %s, %d, %d, %d, NULL)", (int) $b['type'], wfUtils::inet_pton($ip), (int) $b['blockedTime'], $b['reason'], (int) $b['lastAttempt'], (int) $b['blockedHits'], self::DURATION_FOREVER)) !== false;
551
  case self::TYPE_COUNTRY:
552
+ if (!isset($b['parameters'])) { return false; }
553
+ if (wfUtils::inet_pton($ip) != self::MARKER_COUNTRY) { return false; }
554
  $parameters = @json_decode($b['parameters'], true);
555
+ if (!isset($parameters['blockLogin']) || !isset($parameters['blockSite']) || !isset($parameters['countries'])) { return false; }
556
  $parameters['blockLogin'] = wfUtils::truthyToInt($parameters['blockLogin']);
557
  $parameters['blockSite'] = wfUtils::truthyToInt($parameters['blockSite']);
558
 
567
 
568
  return $wpdb->query($wpdb->prepare("INSERT INTO `{$blocksTable}` (`type`, `IP`, `blockedTime`, `reason`, `lastAttempt`, `blockedHits`, `expiration`, `parameters`) VALUES (%d, %s, %d, %s, %d, %d, %d, %s)", self::TYPE_COUNTRY, self::MARKER_COUNTRY, (int) $b['blockedTime'], $b['reason'], (int) $b['lastAttempt'], (int) $b['blockedHits'], self::DURATION_FOREVER, json_encode($parameters))) !== false;
569
  case self::TYPE_PATTERN:
570
+ if (!isset($b['parameters'])) { return false; }
571
  if (wfUtils::inet_pton($ip) != self::MARKER_PATTERN) { return false; }
572
  $parameters = @json_decode($b['parameters'], true);
573
+ if (!isset($parameters['ipRange']) || !isset($parameters['hostname']) || !isset($parameters['userAgent']) || !isset($parameters['referrer'])) { return false; }
574
 
575
  $hasOne = false;
576
  if (!empty($parameters['ipRange'])) {
readme.txt CHANGED
@@ -3,8 +3,8 @@ Contributors: mmaunder
3
  Tags: security, firewall, malware scanner, web application firewall, antivirus, block hackers, country blocking, clean hacked site, blacklist, waf, login security
4
  Requires at least: 3.9
5
  Requires PHP: 5.3
6
- Tested up to: 4.9.8
7
- Stable tag: 7.1.16
8
 
9
  Secure your website with the most comprehensive WordPress security plugin. Firewall, malware scan, blocking, live traffic, login security & more.
10
 
@@ -171,6 +171,13 @@ Secure your website with Wordfence.
171
 
172
  == Changelog ==
173
 
 
 
 
 
 
 
 
174
  = 7.1.16 =
175
  * Improvement: Service whitelisting can now be selectively toggled on or off per service.
176
  * Improvement: Updated bundled GeoIP database.
3
  Tags: security, firewall, malware scanner, web application firewall, antivirus, block hackers, country blocking, clean hacked site, blacklist, waf, login security
4
  Requires at least: 3.9
5
  Requires PHP: 5.3
6
+ Tested up to: 5.0
7
+ Stable tag: 7.1.17
8
 
9
  Secure your website with the most comprehensive WordPress security plugin. Firewall, malware scan, blocking, live traffic, login security & more.
10
 
171
 
172
  == Changelog ==
173
 
174
+ = 7.1.17 =
175
+ * Improvement: Increased frequency of filesystem permission check and update of the WAF config files.
176
+ * Improvement: More complete data removal when deactivating with remove tables and files checked.
177
+ * Improvement: Better diagnostics logging for GeoIP conflicts.
178
+ * Fix: Text fix in invalid username lockout message.
179
+ * Fix: PHP 7.3 syntax compatibility fixes.
180
+
181
  = 7.1.16 =
182
  * Improvement: Service whitelisting can now be selectively toggled on or off per service.
183
  * Improvement: Updated bundled GeoIP database.
vendor/wordfence/wf-waf/src/lib/storage.php CHANGED
@@ -57,6 +57,8 @@ interface wfWAFStorageInterface {
57
  public function unsetConfig($key, $category = '');
58
 
59
  public function uninstall();
 
 
60
 
61
  public function isInLearningMode();
62
 
57
  public function unsetConfig($key, $category = '');
58
 
59
  public function uninstall();
60
+
61
+ //optional public function fileList();
62
 
63
  public function isInLearningMode();
64
 
vendor/wordfence/wf-waf/src/lib/storage/file.php CHANGED
@@ -668,6 +668,36 @@ class wfWAFStorageFile implements wfWAFStorageInterface {
668
  @unlink($this->getRulesDSLCacheFile());
669
  }
670
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
671
  public function removeConfigFiles() {
672
  @unlink($this->getConfigFile());
673
  $configDir = dirname($this->getConfigFile());
668
  @unlink($this->getRulesDSLCacheFile());
669
  }
670
 
671
+ public function fileList() {
672
+ $fileList = array();
673
+ $fileList[] = $this->getAttackDataFile();
674
+ $fileList[] = $this->getIPCacheFile();
675
+ if (defined('WFWAF_DEBUG') && WFWAF_DEBUG) {
676
+ $fileList[] = $this->getRulesDSLCacheFile();
677
+ }
678
+ $fileList[] = $this->getConfigFile();
679
+ $configDir = dirname($this->getConfigFile());
680
+ $dir = opendir($configDir);
681
+ if ($dir) {
682
+ $escapedPath = preg_quote($this->getConfigFile(), '/');
683
+ $components = explode('\\/', $escapedPath);
684
+ $pattern = $components[count($components) - 1];
685
+ if (preg_match('/^(.+?)(\\\..+$|$)/i', $pattern, $matches)) {
686
+ $pattern = $matches[1] . '\\-[a-z0-9]+' . $matches[2]; //Results in a pattern like config\-[a-z0-9]\.php
687
+ }
688
+
689
+ while ($path = readdir($dir)) {
690
+ if ($path == '.' || $path == '..') { continue; }
691
+ if (is_dir($configDir . '/' . $path)) { continue; }
692
+ if (preg_match('/^' . $pattern . '$/i', $path)) {
693
+ $fileList[] = $configDir . '/' . $path;
694
+ }
695
+ }
696
+ closedir($dir);
697
+ }
698
+ return $fileList;
699
+ }
700
+
701
  public function removeConfigFiles() {
702
  @unlink($this->getConfigFile());
703
  $configDir = dirname($this->getConfigFile());
vendor/wordfence/wf-waf/src/lib/waf.php CHANGED
@@ -726,7 +726,7 @@ if (!defined('WFWAF_VERSION')) {
726
  %s?>
727
  PHP
728
  , $this->buildRuleSet($rules)), 'rules');
729
- if (!empty($ruleString) && !WFWAF_DEBUG) {
730
  wfWAFStorageFile::atomicFilePutContents($this->getStorageEngine()->getRulesDSLCacheFile(), $ruleString, 'rules');
731
  }
732
 
@@ -1367,6 +1367,14 @@ HTML
1367
  @unlink($this->getCompiledRulesFile());
1368
  $this->getStorageEngine()->uninstall();
1369
  }
 
 
 
 
 
 
 
 
1370
 
1371
  /**
1372
  * @param int $ruleID
726
  %s?>
727
  PHP
728
  , $this->buildRuleSet($rules)), 'rules');
729
+ if (!empty($ruleString) && WFWAF_DEBUG && !file_exists($this->getStorageEngine()->getRulesDSLCacheFile())) {
730
  wfWAFStorageFile::atomicFilePutContents($this->getStorageEngine()->getRulesDSLCacheFile(), $ruleString, 'rules');
731
  }
732
 
1367
  @unlink($this->getCompiledRulesFile());
1368
  $this->getStorageEngine()->uninstall();
1369
  }
1370
+
1371
+ public function fileList() {
1372
+ $fileList = array($this->getCompiledRulesFile());
1373
+ if (method_exists($this->getStorageEngine(), 'fileList')) {
1374
+ $fileList = array_merge($fileList, $this->getStorageEngine()->fileList());
1375
+ }
1376
+ return $fileList;
1377
+ }
1378
 
1379
  /**
1380
  * @param int $ruleID
waf/bootstrap.php CHANGED
@@ -512,8 +512,79 @@ class wfWAFWordPress extends wfWAF {
512
 
513
  public function uninstall() {
514
  parent::uninstall();
515
- @unlink(rtrim(WFWAF_LOG_PATH . '/') . '/.htaccess');
516
- @rmdir(WFWAF_LOG_PATH);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
517
  }
518
 
519
  /**
@@ -560,6 +631,20 @@ class wfWAFWordPress extends wfWAF {
560
  }
561
  return $_cachedPermissions;
562
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
563
  }
564
 
565
  if (!defined('WFWAF_LOG_PATH')) {
@@ -571,17 +656,7 @@ if (!defined('WFWAF_LOG_PATH')) {
571
  if (!is_dir(WFWAF_LOG_PATH)) {
572
  @mkdir(WFWAF_LOG_PATH, (wfWAFWordPress::permissions() | 0755));
573
  @chmod(WFWAF_LOG_PATH, (wfWAFWordPress::permissions() | 0755));
574
- @file_put_contents(rtrim(WFWAF_LOG_PATH, '/') . '/.htaccess', <<<APACHE
575
- <IfModule mod_authz_core.c>
576
- Require all denied
577
- </IfModule>
578
- <IfModule !mod_authz_core.c>
579
- Order deny,allow
580
- Deny from all
581
- </IfModule>
582
- APACHE
583
- );
584
- @chmod(rtrim(WFWAF_LOG_PATH, '/') . '/.htaccess', (wfWAFWordPress::permissions() | 0444));
585
  }
586
 
587
  wfWAF::setSharedStorageEngine(new wfWAFStorageFile(WFWAF_LOG_PATH . 'attack-data.php', WFWAF_LOG_PATH . 'ips.php', WFWAF_LOG_PATH . 'config.php', WFWAF_LOG_PATH . 'wafRules.rules'));
512
 
513
  public function uninstall() {
514
  parent::uninstall();
515
+ @unlink(rtrim(WFWAF_LOG_PATH, '/') . '/.htaccess');
516
+ @unlink(rtrim(WFWAF_LOG_PATH, '/') . '/template.php');
517
+ @unlink(rtrim(WFWAF_LOG_PATH, '/') . '/GeoLite2-Country.mmdb');
518
+
519
+ self::_recursivelyRemoveWflogs(''); //Removes any remaining files and the directory itself
520
+ }
521
+
522
+ /**
523
+ * Removes a path within wflogs, recursing as necessary.
524
+ *
525
+ * @param string $file
526
+ * @param array $processedDirs
527
+ * @return array The list of removed files/folders.
528
+ */
529
+ private static function _recursivelyRemoveWflogs($file, $processedDirs = array()) {
530
+ if (preg_match('~(?:^|/|\\\\)\.\.(?:/|\\\\|$)~', $file)) {
531
+ return array();
532
+ }
533
+
534
+ if (stripos(WFWAF_LOG_PATH, 'wflogs') === false) { //Sanity check -- if not in a wflogs folder, user will have to do removal manually
535
+ return array();
536
+ }
537
+
538
+ $path = rtrim(WFWAF_LOG_PATH, '/') . '/' . $file;
539
+ if (is_link($path)) {
540
+ if (@unlink($path)) {
541
+ return array($file);
542
+ }
543
+ return array();
544
+ }
545
+
546
+ if (is_dir($path)) {
547
+ $real = realpath($file);
548
+ if (in_array($real, $processedDirs)) {
549
+ return array();
550
+ }
551
+ $processedDirs[] = $real;
552
+
553
+ $count = 0;
554
+ $dir = opendir($path);
555
+ if ($dir) {
556
+ $contents = array();
557
+ while ($sub = readdir($dir)) {
558
+ if ($sub == '.' || $sub == '..') { continue; }
559
+ $contents[] = $sub;
560
+ }
561
+ closedir($dir);
562
+
563
+ $filesRemoved = array();
564
+ foreach ($contents as $f) {
565
+ $removed = self::_recursivelyRemoveWflogs($file . '/' . $f, $processedDirs);
566
+ $filesRemoved = array($filesRemoved, $removed);
567
+ }
568
+ }
569
+
570
+ if (@rmdir($path)) {
571
+ $filesRemoved[] = $file;
572
+ }
573
+ return $filesRemoved;
574
+ }
575
+
576
+ if (@unlink($path)) {
577
+ return array($file);
578
+ }
579
+ return array();
580
+ }
581
+
582
+ public function fileList() {
583
+ $fileList = parent::fileList();
584
+ $fileList[] = rtrim(WFWAF_LOG_PATH, '/') . '/.htaccess';
585
+ $fileList[] = rtrim(WFWAF_LOG_PATH, '/') . '/template.php';
586
+ $fileList[] = rtrim(WFWAF_LOG_PATH, '/') . '/GeoLite2-Country.mmdb';
587
+ return $fileList;
588
  }
589
 
590
  /**
631
  }
632
  return $_cachedPermissions;
633
  }
634
+
635
+ public static function writeHtaccess() {
636
+ @file_put_contents(rtrim(WFWAF_LOG_PATH, '/') . '/.htaccess', <<<APACHE
637
+ <IfModule mod_authz_core.c>
638
+ Require all denied
639
+ </IfModule>
640
+ <IfModule !mod_authz_core.c>
641
+ Order deny,allow
642
+ Deny from all
643
+ </IfModule>
644
+ APACHE
645
+ );
646
+ @chmod(rtrim(WFWAF_LOG_PATH, '/') . '/.htaccess', (wfWAFWordPress::permissions() | 0444));
647
+ }
648
  }
649
 
650
  if (!defined('WFWAF_LOG_PATH')) {
656
  if (!is_dir(WFWAF_LOG_PATH)) {
657
  @mkdir(WFWAF_LOG_PATH, (wfWAFWordPress::permissions() | 0755));
658
  @chmod(WFWAF_LOG_PATH, (wfWAFWordPress::permissions() | 0755));
659
+ wfWAFWordPress::writeHtaccess();
 
 
 
 
 
 
 
 
 
 
660
  }
661
 
662
  wfWAF::setSharedStorageEngine(new wfWAFStorageFile(WFWAF_LOG_PATH . 'attack-data.php', WFWAF_LOG_PATH . 'ips.php', WFWAF_LOG_PATH . 'config.php', WFWAF_LOG_PATH . 'wafRules.rules'));
wordfence.php CHANGED
@@ -4,7 +4,7 @@ Plugin Name: Wordfence Security
4
  Plugin URI: http://www.wordfence.com/
5
  Description: Wordfence Security - Anti-virus, Firewall and Malware Scan
6
  Author: Wordfence
7
- Version: 7.1.16
8
  Author URI: http://www.wordfence.com/
9
  Network: true
10
  */
@@ -14,8 +14,8 @@ if(defined('WP_INSTALLING') && WP_INSTALLING){
14
  if (!defined('ABSPATH')) {
15
  exit;
16
  }
17
- define('WORDFENCE_VERSION', '7.1.16');
18
- define('WORDFENCE_BUILD_NUMBER', '1539704326');
19
  define('WORDFENCE_BASENAME', function_exists('plugin_basename') ? plugin_basename(__FILE__) :
20
  basename(dirname(__FILE__)) . '/' . basename(__FILE__));
21
 
4
  Plugin URI: http://www.wordfence.com/
5
  Description: Wordfence Security - Anti-virus, Firewall and Malware Scan
6
  Author: Wordfence
7
+ Version: 7.1.17
8
  Author URI: http://www.wordfence.com/
9
  Network: true
10
  */
14
  if (!defined('ABSPATH')) {
15
  exit;
16
  }
17
+ define('WORDFENCE_VERSION', '7.1.17');
18
+ define('WORDFENCE_BUILD_NUMBER', '1541524007');
19
  define('WORDFENCE_BASENAME', function_exists('plugin_basename') ? plugin_basename(__FILE__) :
20
  basename(dirname(__FILE__)) . '/' . basename(__FILE__));
21