Wordfence Security – Firewall & Malware Scan - Version 6.2.0

Version Description

  • Improvement: Massive performance boost in file system scan.
  • Improvement: Added low resource usage scan option for shared hosts.
  • Improvement: Aggregated login attempts when checking the Wordfence Security Network for brute force attackers to reduce total requests.
  • Improvement: Now displaying scan time in a more readable format rather than total seconds.
  • Improvement: Added PHP7 compatible .htaccess directives to disable code execution within uploads directory.
  • Fix: Added throttling to sync the WAF attack data.
  • Fix: Removed unnecessary single quote in copy containing "IP's".
  • Fix: Fixed rare, edge case where cron key does not match the key in the database.
  • Fix: Fixed bug with regex matching carriage returns in the .htaccess based IP block list.
  • Fix: Fixed scans failing in subdirectory sites when updating malware signatures.
  • Fix: Fixed infinite loop in scan caused by symlinks.
  • Fix: Remove extra slash from "File restored OK" message in scan results.
Download this release

Release Info

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

Code changes from version 6.1.17 to 6.2.0

css/main.css CHANGED
@@ -124,6 +124,9 @@ div.wordfenceScanButton input.button-wf-grey {
124
  min-height: 200px;
125
  -webkit-font-smoothing: antialiased;
126
  }
 
 
 
127
  #wfTabs::after {
128
  content: ".";
129
  display: block;
@@ -1049,6 +1052,10 @@ tr.wf-table-filters input {
1049
  max-width: 140px;
1050
  }
1051
 
 
 
 
 
1052
  #wordfenceLiveActivityDisabled {
1053
  background: #fff;
1054
  border-left: 4px solid #ffb900;
@@ -1076,4 +1083,45 @@ tr.wf-table-filters input {
1076
 
1077
  #wfTwoFactorDownload .dashicons {
1078
  line-height: 26px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1079
  }
124
  min-height: 200px;
125
  -webkit-font-smoothing: antialiased;
126
  }
127
+ .wfTabsContainer.wfScanIssuesTabs {
128
+ max-width: 800px;
129
+ }
130
  #wfTabs::after {
131
  content: ".";
132
  display: block;
1052
  max-width: 140px;
1053
  }
1054
 
1055
+ #waf-rules-wrapper {
1056
+ max-width: 900px;
1057
+ }
1058
+
1059
  #wordfenceLiveActivityDisabled {
1060
  background: #fff;
1061
  border-left: 4px solid #ffb900;
1083
 
1084
  #wfTwoFactorDownload .dashicons {
1085
  line-height: 26px;
1086
+ }
1087
+
1088
+ #wfConfigForm {
1089
+ max-width: 1035px;
1090
+ }
1091
+
1092
+ .wordfenceRightRail {
1093
+ position: absolute;
1094
+ margin-left: 840px;
1095
+ width: 269px;
1096
+ }
1097
+
1098
+ .wordfenceRightRail img {
1099
+ width: 100%;
1100
+ }
1101
+
1102
+ .wordfenceRightRailLiveTraffic, .wordfenceRightRailOptions, .wordfenceRightRailDiagnostics {
1103
+ margin-left: 1055px;
1104
+ }
1105
+
1106
+ .wordfenceRightRailBlockedIPs, .wordfenceRightRailWAF, .wordfenceRightRailCountryBlocking, .wordfenceRightRailScanSchedule {
1107
+ margin-left: 950px;
1108
+ }
1109
+
1110
+ .wordfenceRightRail ul {
1111
+ list-style-type: none;
1112
+ margin: 0;
1113
+ }
1114
+
1115
+ .wordfenceRightRail .center {
1116
+ text-align: center;
1117
+ }
1118
+ .wordfenceRightRail .button-primary {
1119
+ text-align: center;
1120
+ text-transform: uppercase;
1121
+ font-weight: bold;
1122
+ background-color: #00709E;
1123
+ }
1124
+
1125
+ .wordfenceWrap.wordfence-community {
1126
+ min-height: 760px;
1127
  }
images/rr_premium.png ADDED
Binary file
images/rr_sitecleaning.jpg ADDED
Binary file
js/admin.liveTraffic.js CHANGED
@@ -357,6 +357,7 @@
357
  return 'locked out from logging in';
358
 
359
  case 'blocked:wordfence':
 
360
  desc = self.actionDescription();
361
  if (desc && desc.toLowerCase().indexOf('block') === 0) {
362
  return 'b' + desc.substring(1);
@@ -403,7 +404,7 @@
403
 
404
  self.cssClasses = ko.pureComputed(function() {
405
  var classes = 'wfActEvent';
406
- if (self.statusCode() == 403) {
407
  classes += ' wfActionBlocked';
408
  }
409
  if (self.statusCode() == 404) {
357
  return 'locked out from logging in';
358
 
359
  case 'blocked:wordfence':
360
+ case 'blocked:wfsnrepeat':
361
  desc = self.actionDescription();
362
  if (desc && desc.toLowerCase().indexOf('block') === 0) {
363
  return 'b' + desc.substring(1);
404
 
405
  self.cssClasses = ko.pureComputed(function() {
406
  var classes = 'wfActEvent';
407
+ if (self.statusCode() == 403 || self.statusCode() == 503) {
408
  classes += ' wfActionBlocked';
409
  }
410
  if (self.statusCode() == 404) {
lib/email_genericAlert.php CHANGED
@@ -6,7 +6,7 @@ The Wordfence administrative URL for this site is: <?php echo $adminURL; ?>admin
6
  <?php if($IPMsg){ echo "\n$IPMsg\n"; } ?>
7
 
8
  <?php if(! $isPaid){ ?>
9
- NOTE: You are using the free version of Wordfence. Upgrade to Premium today for just $8.25 per month!
10
  - Advanced features like IP reputation monitoring, country blocking, an advanced comment spam filter and cell phone sign-in give you the best protection available
11
  - Remote, frequent and scheduled scans
12
  - Access to Premium Support
6
  <?php if($IPMsg){ echo "\n$IPMsg\n"; } ?>
7
 
8
  <?php if(! $isPaid){ ?>
9
+ NOTE: You are using the free version of Wordfence. Upgrade today:
10
  - Advanced features like IP reputation monitoring, country blocking, an advanced comment spam filter and cell phone sign-in give you the best protection available
11
  - Remote, frequent and scheduled scans
12
  - Access to Premium Support
lib/email_newIssues.php CHANGED
@@ -44,14 +44,14 @@
44
 
45
 
46
  <?php if(! $isPaid){ ?>
47
- <p>NOTE: You are using the free version of Wordfence. Upgrade to Premium today for just $8.25 per month!</p>
48
 
49
  <ul>
50
  <li>Receive real-time Firewall and Scan engine rule updates for protection as threats emerge</li>
51
  <li>Other advanced features like IP reputation monitoring, country blocking, an advanced comment spam filter and cell phone sign-in give you the best protection available</li>
52
  <li>Remote, frequent and scheduled scans</li>
53
  <li>Access to Premium Support</li>
54
- <li>Discounts of up to 75% for multiyear and multi-license purchases</li>
55
  </ul>
56
 
57
  <p>
44
 
45
 
46
  <?php if(! $isPaid){ ?>
47
+ <p>NOTE: You are using the free version of Wordfence. Upgrade today:</p>
48
 
49
  <ul>
50
  <li>Receive real-time Firewall and Scan engine rule updates for protection as threats emerge</li>
51
  <li>Other advanced features like IP reputation monitoring, country blocking, an advanced comment spam filter and cell phone sign-in give you the best protection available</li>
52
  <li>Remote, frequent and scheduled scans</li>
53
  <li>Access to Premium Support</li>
54
+ <li>Discounts of up to 90% for multiyear and multi-license purchases</li>
55
  </ul>
56
 
57
  <p>
lib/menu_activity.php CHANGED
@@ -30,7 +30,11 @@
30
  </tr>
31
  </table>
32
  </div>
33
- <div class="wordfenceWrap">
 
 
 
 
34
  <?php if (!wfConfig::liveTrafficEnabled()): ?>
35
  <div id="wordfenceLiveActivityDisabled"><p><strong>Live activity is disabled.</strong> <?php if (wfConfig::get('cacheType') == 'falcon') { ?>This is done to improve performance because you have Wordfence Falcon Engine enabled.<?php } ?> Login and firewall activity will still appear below.</p></div>
36
  <?php endif ?>
@@ -273,7 +277,7 @@
273
  <span data-bind="if: statusCode() == 200 && !action()">
274
  visited
275
  </span>
276
- <span data-bind="if: statusCode() == 403">
277
  was <span data-bind="text: firewallAction" style="color: #F00;"></span> at
278
  </span>
279
 
30
  </tr>
31
  </table>
32
  </div>
33
+ <div class="wordfenceWrap<?php if (!wfConfig::get('isPaid')) { echo " wordfence-community"; }?>">
34
+ <?php
35
+ $rightRail = new wfView('marketing/rightrail', array('additionalClasses' => 'wordfenceRightRailLiveTraffic'));
36
+ echo $rightRail;
37
+ ?>
38
  <?php if (!wfConfig::liveTrafficEnabled()): ?>
39
  <div id="wordfenceLiveActivityDisabled"><p><strong>Live activity is disabled.</strong> <?php if (wfConfig::get('cacheType') == 'falcon') { ?>This is done to improve performance because you have Wordfence Falcon Engine enabled.<?php } ?> Login and firewall activity will still appear below.</p></div>
40
  <?php endif ?>
277
  <span data-bind="if: statusCode() == 200 && !action()">
278
  visited
279
  </span>
280
+ <span data-bind="if: statusCode() == 403 || statusCode() == 503">
281
  was <span data-bind="text: firewallAction" style="color: #F00;"></span> at
282
  </span>
283
 
lib/menu_blockedIPs.php CHANGED
@@ -12,12 +12,16 @@
12
  <a href="#" onclick="WFAD.clearAllBlocked('blocked'); return false;">Clear all blocked IP addresses</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href="#" onclick="WFAD.clearAllBlocked('locked'); return false;">Clear all locked out IP addresses</a><br />
13
  You can manually (and permanently) block an IP by entering the address here: <input type="text" id="wfManualBlock" size="20" maxlength="40" value="" onkeydown="if(event.keyCode == 13){ WFAD.blockIPTwo(jQuery('#wfManualBlock').val(), 'Manual block by administrator', true); return false; }" />&nbsp;<input type="button" name="but1" value="Manually block IP" onclick="WFAD.blockIPTwo(jQuery('#wfManualBlock').val(), 'Manual block by administrator', true); return false;" />
14
  </div>
15
- <div class="wordfenceWrap">
 
 
 
 
16
  <div>
17
  <div id="wfTabs">
18
  <a href="#" class="wfTab1 wfTabSwitch selected" onclick="wordfenceAdmin.switchTab(this, 'wfTab1', 'wfDataPanel', 'wfActivity_blockedIPs', function(){ WFAD.staticTabChanged(); }); return false;">IPs that are blocked from accessing the site</a>
19
  <a href="#" class="wfTab1 wfTabSwitch" onclick="wordfenceAdmin.switchTab(this, 'wfTab1', 'wfDataPanel', 'wfActivity_lockedOutIPs', function(){ WFAD.staticTabChanged(); }); return false;">IPs that are Locked Out from Login</a>
20
- <a href="#" class="wfTab1 wfTabSwitch" onclick="wordfenceAdmin.switchTab(this, 'wfTab1', 'wfDataPanel', 'wfActivity_throttledIPs', function(){ WFAD.staticTabChanged(); }); return false;">IPs who were recently throttled for accessing the site too frequently</a>
21
  </div>
22
  <div class="wfTabsContainer">
23
  <div id="wfActivity_blockedIPs" class="wfDataPanel"><div class="wfLoadingWhite32"></div></div>
@@ -166,7 +170,7 @@
166
  <script type="text/x-jquery-template" id="wfWelcomeContent4">
167
  <div>
168
  <h3>How to manage Blocked IP addresses</h3>
169
- <strong><p>Block IP's temporarily or permanently</p></strong>
170
  <p>
171
  When you block an IP address, it will appear here with some additional information.
172
  You will be able to see the geographic location of the IP, how many hits occured before
12
  <a href="#" onclick="WFAD.clearAllBlocked('blocked'); return false;">Clear all blocked IP addresses</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href="#" onclick="WFAD.clearAllBlocked('locked'); return false;">Clear all locked out IP addresses</a><br />
13
  You can manually (and permanently) block an IP by entering the address here: <input type="text" id="wfManualBlock" size="20" maxlength="40" value="" onkeydown="if(event.keyCode == 13){ WFAD.blockIPTwo(jQuery('#wfManualBlock').val(), 'Manual block by administrator', true); return false; }" />&nbsp;<input type="button" name="but1" value="Manually block IP" onclick="WFAD.blockIPTwo(jQuery('#wfManualBlock').val(), 'Manual block by administrator', true); return false;" />
14
  </div>
15
+ <div class="wordfenceWrap<?php if (!wfConfig::get('isPaid')) { echo " wordfence-community"; }?>">
16
+ <?php
17
+ $rightRail = new wfView('marketing/rightrail', array('additionalClasses' => 'wordfenceRightRailBlockedIPs'));
18
+ echo $rightRail;
19
+ ?>
20
  <div>
21
  <div id="wfTabs">
22
  <a href="#" class="wfTab1 wfTabSwitch selected" onclick="wordfenceAdmin.switchTab(this, 'wfTab1', 'wfDataPanel', 'wfActivity_blockedIPs', function(){ WFAD.staticTabChanged(); }); return false;">IPs that are blocked from accessing the site</a>
23
  <a href="#" class="wfTab1 wfTabSwitch" onclick="wordfenceAdmin.switchTab(this, 'wfTab1', 'wfDataPanel', 'wfActivity_lockedOutIPs', function(){ WFAD.staticTabChanged(); }); return false;">IPs that are Locked Out from Login</a>
24
+ <a href="#" class="wfTab1 wfTabSwitch" onclick="wordfenceAdmin.switchTab(this, 'wfTab1', 'wfDataPanel', 'wfActivity_throttledIPs', function(){ WFAD.staticTabChanged(); }); return false;">IPs who were throttled for accessing the site too frequently</a>
25
  </div>
26
  <div class="wfTabsContainer">
27
  <div id="wfActivity_blockedIPs" class="wfDataPanel"><div class="wfLoadingWhite32"></div></div>
170
  <script type="text/x-jquery-template" id="wfWelcomeContent4">
171
  <div>
172
  <h3>How to manage Blocked IP addresses</h3>
173
+ <strong><p>Block IPs temporarily or permanently</p></strong>
174
  <p>
175
  When you block an IP address, it will appear here with some additional information.
176
  You will be able to see the geographic location of the IP, how many hits occured before
lib/menu_countryBlocking.php CHANGED
@@ -8,21 +8,25 @@ WFAD.countryMap = <?php echo json_encode($wfBulkCountries); ?>;
8
  <div class="wrap" id="paidWrap">
9
  <?php require('menuHeader.php'); ?>
10
  <?php $pageTitle = "Block Selected Countries from Accessing your Site"; $helpLink="http://docs.wordfence.com/en/Country_blocking"; $helpLabel="Learn more about Country Blocking"; include('pageTitle.php'); ?>
 
 
 
 
11
  <?php if(! wfConfig::get('isPaid')){ ?>
12
  <div class="wf-premium-callout" style="margin: 20px">
13
  <h3>Country Blocking is only available to Premium Members</h3>
14
  <p>Country blocking is a premium feature that lets you block attacks or malicious activity that originates in a specific country</p>
15
 
16
- <p>Upgrade to Premium today for just $8.25 per month:</p>
17
  <ul>
18
  <li>Receive real-time Firewall and Scan engine rule updates for protection as threats emerge</li>
19
  <li>Other advanced features like IP reputation monitoring, an advanced comment spam filter, advanced scanning options and cell phone sign-in give you the best protection available</li>
20
  <li>Access to Premium Support</li>
21
- <li>Discounts of up to 75% available for multiyear and multi-license purchases</li>
22
  </ul>
23
 
24
  <p class="center"><a class="button button-primary"
25
- href="https://www.wordfence.com/gnl1countryBlock1/wordfence-signup/">Get Premium</a></p>
26
  </div>
27
  <?php } ?>
28
  <?php if(wfConfig::get('cacheType') == 'falcon'){ ?>
@@ -37,7 +41,7 @@ WFAD.countryMap = <?php echo json_encode($wfBulkCountries); ?>;
37
  </div>
38
  <?php } ?>
39
 
40
- <div class="wordfenceWrap" style="margin: 20px 20px 20px 30px;">
41
  <table class="wfConfigForm">
42
  <tr><td colspan="2"><h2>Country Blocking Options</h2></td></tr>
43
  <?php if(! wfConfig::get('firewallEnabled')){ ?><tr><td colspan="2"><div style="color: #F00; font-weight: bold;">Rate limiting rules and advanced blocking are disabled. You can enable it on the <a href="admin.php?page=WordfenceSecOpt">Wordfence Options page</a> at the top.</div></td></tr><?php } ?>
8
  <div class="wrap" id="paidWrap">
9
  <?php require('menuHeader.php'); ?>
10
  <?php $pageTitle = "Block Selected Countries from Accessing your Site"; $helpLink="http://docs.wordfence.com/en/Country_blocking"; $helpLabel="Learn more about Country Blocking"; include('pageTitle.php'); ?>
11
+ <?php
12
+ $rightRail = new wfView('marketing/rightrail', array('additionalClasses' => 'wordfenceRightRailCountryBlocking'));
13
+ echo $rightRail;
14
+ ?>
15
  <?php if(! wfConfig::get('isPaid')){ ?>
16
  <div class="wf-premium-callout" style="margin: 20px">
17
  <h3>Country Blocking is only available to Premium Members</h3>
18
  <p>Country blocking is a premium feature that lets you block attacks or malicious activity that originates in a specific country</p>
19
 
20
+ <p>Upgrade today:</p>
21
  <ul>
22
  <li>Receive real-time Firewall and Scan engine rule updates for protection as threats emerge</li>
23
  <li>Other advanced features like IP reputation monitoring, an advanced comment spam filter, advanced scanning options and cell phone sign-in give you the best protection available</li>
24
  <li>Access to Premium Support</li>
25
+ <li>Discounts of up to 90% available for multiyear and multi-license purchases</li>
26
  </ul>
27
 
28
  <p class="center"><a class="button button-primary"
29
+ href="https://www.wordfence.com/gnl1countryBlock1/wordfence-signup/" target="_blank">Get Premium</a></p>
30
  </div>
31
  <?php } ?>
32
  <?php if(wfConfig::get('cacheType') == 'falcon'){ ?>
41
  </div>
42
  <?php } ?>
43
 
44
+ <div class="wordfenceWrap" style="margin: 20px 20px 20px 30px; max-width: 900px;">
45
  <table class="wfConfigForm">
46
  <tr><td colspan="2"><h2>Country Blocking Options</h2></td></tr>
47
  <?php if(! wfConfig::get('firewallEnabled')){ ?><tr><td colspan="2"><div style="color: #F00; font-weight: bold;">Rate limiting rules and advanced blocking are disabled. You can enable it on the <a href="admin.php?page=WordfenceSecOpt">Wordfence Options page</a> at the top.</div></td></tr><?php } ?>
lib/menu_diagnostic.php CHANGED
@@ -17,6 +17,11 @@ $w = new wfConfig();
17
  Diagnostics
18
  </h2>
19
  <br clear="both"/>
 
 
 
 
 
20
 
21
  <form id="wfConfigForm">
22
  <table class="wf-table"<?php echo !empty($inEmail) ? ' border=1' : '' ?>>
17
  Diagnostics
18
  </h2>
19
  <br clear="both"/>
20
+
21
+ <?php
22
+ $rightRail = new wfView('marketing/rightrail', array('additionalClasses' => 'wordfenceRightRailDiagnostics'));
23
+ echo $rightRail;
24
+ ?>
25
 
26
  <form id="wfConfigForm">
27
  <table class="wf-table"<?php echo !empty($inEmail) ? ' border=1' : '' ?>>
lib/menu_options.php CHANGED
@@ -16,7 +16,10 @@ $w = new wfConfig();
16
  </tr>
17
  </table>
18
  </div>
19
-
 
 
 
20
  <form id="wfConfigForm">
21
  <table class="wfConfigForm">
22
  <tr>
@@ -55,17 +58,17 @@ $w = new wfConfig();
55
  </table>
56
  <?php else: ?>
57
  <div class="wf-premium-callout">
58
- <h3>Upgrade to Wordfence Premium today for just $8.25 per month:</h3>
59
  <ul>
60
  <li>Receive real-time Firewall and Scan engine rule updates for protection as threats emerge</li>
61
  <li>Advanced features like IP reputation monitoring, country blocking, an advanced comment spam filter and cell phone sign-in give you the best protection available</li>
62
  <li>Remote, frequent and scheduled scans</li>
63
  <li>Access to Premium Support</li>
64
- <li>Discounts of up to 75% for multiyear and multi-license purchases</li>
65
  </ul>
66
  <p class="center">
67
  <a class="button button-primary"
68
- href="https://www.wordfence.com/gnl1optCallout1/wordfence-signup/">
69
  Get Premium</a></p>
70
  </div>
71
  <?php endif ?>
@@ -574,6 +577,14 @@ $w = new wfConfig();
574
  name="scansEnabled_highSense" value="1" <?php $w->cb( 'scansEnabled_highSense' ); ?> />
575
  </td>
576
  </tr>
 
 
 
 
 
 
 
 
577
  <tr>
578
  <th>Exclude files from scan that match these wildcard patterns. (One per line).<a
579
  href="http://docs.wordfence.com/en/Wordfence_options#Exclude_files_from_scan_that_match_these_wildcard_patterns."
@@ -909,7 +920,7 @@ $w = new wfConfig();
909
  value="1" <?php $w->cb( 'other_hideWPVersion' ); ?> /></td>
910
  </tr>
911
  <tr>
912
- <th>Block IP's who send POST requests with blank User-Agent and Referer<a
913
  href="http://docs.wordfence.com/en/Wordfence_options#Block_IP.27s_who_send_POST_requests_with_blank_User-Agent_and_Referer" target="_blank"
914
  class="wfhelp"></a></th>
915
  <td><input type="checkbox" id="other_blockBadPOST" class="wfConfigElem" name="other_blockBadPOST"
16
  </tr>
17
  </table>
18
  </div>
19
+ <?php
20
+ $rightRail = new wfView('marketing/rightrail', array('additionalClasses' => 'wordfenceRightRailOptions'));
21
+ echo $rightRail;
22
+ ?>
23
  <form id="wfConfigForm">
24
  <table class="wfConfigForm">
25
  <tr>
58
  </table>
59
  <?php else: ?>
60
  <div class="wf-premium-callout">
61
+ <h3>Upgrade today:</h3>
62
  <ul>
63
  <li>Receive real-time Firewall and Scan engine rule updates for protection as threats emerge</li>
64
  <li>Advanced features like IP reputation monitoring, country blocking, an advanced comment spam filter and cell phone sign-in give you the best protection available</li>
65
  <li>Remote, frequent and scheduled scans</li>
66
  <li>Access to Premium Support</li>
67
+ <li>Discounts of up to 90% for multiyear and multi-license purchases</li>
68
  </ul>
69
  <p class="center">
70
  <a class="button button-primary"
71
+ href="https://www.wordfence.com/gnl1optCallout1/wordfence-signup/" target="_blank">
72
  Get Premium</a></p>
73
  </div>
74
  <?php endif ?>
577
  name="scansEnabled_highSense" value="1" <?php $w->cb( 'scansEnabled_highSense' ); ?> />
578
  </td>
579
  </tr>
580
+ <tr>
581
+ <th>Use low resource scanning. Reduces server load by lengthening the scan duration.<a
582
+ href="http://docs.wordfence.com/en/Wordfence_options#Use_low_resource_scanning"
583
+ target="_blank" class="wfhelp"></a></th>
584
+ <td><input type="checkbox" id="lowResourceScansEnabled" class="wfConfigElem"
585
+ name="lowResourceScansEnabled" value="1" <?php $w->cb( 'lowResourceScansEnabled' ); ?> />
586
+ </td>
587
+ </tr>
588
  <tr>
589
  <th>Exclude files from scan that match these wildcard patterns. (One per line).<a
590
  href="http://docs.wordfence.com/en/Wordfence_options#Exclude_files_from_scan_that_match_these_wildcard_patterns."
920
  value="1" <?php $w->cb( 'other_hideWPVersion' ); ?> /></td>
921
  </tr>
922
  <tr>
923
+ <th>Block IPs who send POST requests with blank User-Agent and Referer<a
924
  href="http://docs.wordfence.com/en/Wordfence_options#Block_IP.27s_who_send_POST_requests_with_blank_User-Agent_and_Referer" target="_blank"
925
  class="wfhelp"></a></th>
926
  <td><input type="checkbox" id="other_blockBadPOST" class="wfConfigElem" name="other_blockBadPOST"
lib/menu_passwd.php CHANGED
@@ -5,19 +5,30 @@
5
  $helpLink = "http://docs.wordfence.com/en/Wordfence_Password_Auditing";
6
  $helpLabel = "Learn more about Password Auditing";
7
  include('pageTitle.php'); ?>
 
 
 
 
 
 
 
 
 
 
 
8
  <?php if (!wfConfig::get('isPaid')) { ?>
9
  <div class="wf-premium-callout" style="margin: 20px 0 20px 20px; width: 700px;">
10
  <h3>Password Auditing is only available to Premium Members</h3>
11
  <p>Wordfence Password Auditing uses our high performance password auditing cluster to test the strength of your admin and user passwords. We securely simulate a high-performance password cracking attack on your password database and will alert you to weak passwords. We then provide a way to change weak passwords or alert members that they need to improve their password strength.</p>
12
 
13
- <p>Upgrade to Premium today for just $8.25 per month:</p>
14
  <ul>
15
  <li>Receive real-time Firewall and Scan engine rule updates for protection as threats emerge</li>
16
  <li>Other advanced features like IP reputation monitoring, an advanced comment spam filter, advanced scanning options, cell phone sign-in and country blocking give you the best protection available</li>
17
  <li>Access to Premium Support</li>
18
- <li>Discounts of up to 75% available for multiyear and multi-license purchases</li>
19
  </ul>
20
- <p class="center"><a class="button button-primary" href="https://www.wordfence.com/gnl1pwAuditUp1/wordfence-signup/">Get Premium</a></p>
21
  </div>
22
  <?php } ?>
23
 
5
  $helpLink = "http://docs.wordfence.com/en/Wordfence_Password_Auditing";
6
  $helpLabel = "Learn more about Password Auditing";
7
  include('pageTitle.php'); ?>
8
+ <?php if (!wfConfig::get('isPaid')) { ?>
9
+ <div class="wordfenceRightRail">
10
+ <ul>
11
+ <li><a href="https://www.wordfence.com/gnl1rightRailGetPremium/wordfence-signup/" target="_blank"><img src="<?php echo wfUtils::getBaseURL() . 'images/rr_premium.png'; ?>" alt="Upgrade your protection - Get Wordfence Premium"></a></li>
12
+ <li><a href="https://www.wordfence.com/gnl1rightRailSiteCleaning/wordfence-site-cleanings/" target="_blank"><img src="<?php echo wfUtils::getBaseURL() . 'images/rr_sitecleaning.jpg'; ?>" alt="Have you been hacked? Get help from Wordfence"></a></li>
13
+ <li>
14
+ <p class="center"><strong>Would you like to remove these ads?</strong><br><a href="https://www.wordfence.com/gnl1rightRailBottomUpgrade/wordfence-signup/" target="_blank">Get Premium</a></p>
15
+ </li>
16
+ </ul>
17
+ </div>
18
+ <?php } ?>
19
  <?php if (!wfConfig::get('isPaid')) { ?>
20
  <div class="wf-premium-callout" style="margin: 20px 0 20px 20px; width: 700px;">
21
  <h3>Password Auditing is only available to Premium Members</h3>
22
  <p>Wordfence Password Auditing uses our high performance password auditing cluster to test the strength of your admin and user passwords. We securely simulate a high-performance password cracking attack on your password database and will alert you to weak passwords. We then provide a way to change weak passwords or alert members that they need to improve their password strength.</p>
23
 
24
+ <p>Upgrade today:</p>
25
  <ul>
26
  <li>Receive real-time Firewall and Scan engine rule updates for protection as threats emerge</li>
27
  <li>Other advanced features like IP reputation monitoring, an advanced comment spam filter, advanced scanning options, cell phone sign-in and country blocking give you the best protection available</li>
28
  <li>Access to Premium Support</li>
29
+ <li>Discounts of up to 90% available for multiyear and multi-license purchases</li>
30
  </ul>
31
+ <p class="center"><a class="button button-primary" href="https://www.wordfence.com/gnl1pwAuditUp1/wordfence-signup/" target="_blank">Get Premium</a></p>
32
  </div>
33
  <?php } ?>
34
 
lib/menu_rangeBlocking.php CHANGED
@@ -2,7 +2,11 @@
2
  <div class="wrap" id="paidWrap">
3
  <?php require('menuHeader.php'); ?>
4
  <?php $helpLink="http://docs.wordfence.com/en/Advanced_Blocking"; $helpLabel="Learn more about Advanced Blocking"; $pageTitle = "Advanced Blocking"; include('pageTitle.php'); ?>
5
- <div class="wordfenceWrap" style="margin: 20px 20px 20px 30px;">
 
 
 
 
6
  <p>
7
  <?php if(! wfConfig::get('firewallEnabled')){ ?><div style="color: #F00; font-weight: bold;">Rate limiting rules and advanced blocking are disabled. You can enable it on the <a href="admin.php?page=WordfenceSecOpt">Wordfence Options page</a> at the top.</div><br /><?php } ?>
8
  <table class="wfConfigForm">
2
  <div class="wrap" id="paidWrap">
3
  <?php require('menuHeader.php'); ?>
4
  <?php $helpLink="http://docs.wordfence.com/en/Advanced_Blocking"; $helpLabel="Learn more about Advanced Blocking"; $pageTitle = "Advanced Blocking"; include('pageTitle.php'); ?>
5
+ <?php
6
+ $rightRail = new wfView('marketing/rightrail');
7
+ echo $rightRail;
8
+ ?>
9
+ <div class="wordfenceWrap<?php if (!wfConfig::get('isPaid')) { echo " wordfence-community"; }?>" style="margin: 20px 20px 20px 30px; max-width: 800px;">
10
  <p>
11
  <?php if(! wfConfig::get('firewallEnabled')){ ?><div style="color: #F00; font-weight: bold;">Rate limiting rules and advanced blocking are disabled. You can enable it on the <a href="admin.php?page=WordfenceSecOpt">Wordfence Options page</a> at the top.</div><br /><?php } ?>
12
  <table class="wfConfigForm">
lib/menu_scan.php CHANGED
@@ -29,6 +29,21 @@ $sigUpdateTime = wfConfig::get('signatureUpdateTime');
29
  <?php require('menuHeader.php'); ?>
30
  <?php $pageTitle = "Wordfence Scan"; $helpLink="http://docs.wordfence.com/en/Wordfence_scanning"; $helpLabel="Learn more about scanning"; include('pageTitle.php'); ?>
31
  <div class="wordfenceWrap">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
  <div class="wordfenceScanButton">
33
  <table border="0" cellpadding="0" cellspacing="0" style="width: 800px;">
34
  <tr>
@@ -63,7 +78,7 @@ $sigUpdateTime = wfConfig::get('signatureUpdateTime');
63
  <?php if (wfConfig::get('scansEnabled_fileContents')): ?>
64
  <div style="width: 800px; ">
65
  <p class="wf-success">You are running the Premium version of the Threat Defense Feed which is
66
- updated in real-time as new threats emerge.</p>
67
  </div>
68
  <?php else: ?>
69
  <div class="wfSecure">Premium scanning enabled</div>
@@ -80,10 +95,9 @@ $sigUpdateTime = wfConfig::get('signatureUpdateTime');
80
 
81
  <p>As new threats emerge, the Threat Defense Feed is updated to detect these new hacks. The Premium
82
  version of the Threat Defense Feed is updated in real-time protecting you immediately. As a free
83
- user <strong>you are receiving the community version</strong> of the feed which is updated 30 days later. Upgrade
84
- now for just $8.25 per month!</p>
85
  <p class="center"><a class="button button-primary"
86
- href="https://www.wordfence.com/gnl1scanUpgrade/wordfence-signup/">
87
  Get Premium</a></p>
88
  </div>
89
 
@@ -137,14 +151,10 @@ $sigUpdateTime = wfConfig::get('signatureUpdateTime');
137
  </div>
138
 
139
  <div class="wf-premium-callout" style="margin: 20px 0 20px 2px;width: 765px;">
140
- <h3>Have you been hacked?</h3>
141
- <p>If your site has been compromised by attackers it is vitally important to restore it to working
142
- order as quickly as possible. But cleaning up a hacked website can be difficult if you've never
143
- done it before, sometimes it takes professional intervention. Let our team of seasoned Security
144
- Analysts resolve it for you quickly and professionally.</p>
145
- <p class="center"><a class="button button-primary"
146
- href="https://www.wordfence.com/gnl1scanGetHelp/wordfence-site-cleanings/">
147
- Get Help</a></p>
148
  </div>
149
 
150
 
@@ -154,7 +164,7 @@ $sigUpdateTime = wfConfig::get('signatureUpdateTime');
154
  <a href="#" id="wfNewIssuesTab" class="wfTab2 wfTabSwitch selected" onclick="wordfenceAdmin.switchIssuesTab(this, 'new'); return false;">New Issues</a>
155
  <a href="#" class="wfTab2 wfTabSwitch" onclick="wordfenceAdmin.switchIssuesTab(this, 'ignored'); return false;">Ignored Issues</a>
156
  </div>
157
- <div class="wfTabsContainer">
158
  <div id="wfIssues_new" class="wfIssuesContainer">
159
  <h2>New Issues</h2>
160
  <?php if (wfConfig::get('scansEnabled_highSense')): ?>
29
  <?php require('menuHeader.php'); ?>
30
  <?php $pageTitle = "Wordfence Scan"; $helpLink="http://docs.wordfence.com/en/Wordfence_scanning"; $helpLabel="Learn more about scanning"; include('pageTitle.php'); ?>
31
  <div class="wordfenceWrap">
32
+ <?php
33
+ $rightRail = new wfView('marketing/rightrail');
34
+ echo $rightRail;
35
+ ?>
36
+ <?php if (!wfConfig::get('isPaid')) { ?>
37
+ <div class="wordfenceRightRail">
38
+ <ul>
39
+ <li><a href="https://www.wordfence.com/gnl1rightRailGetPremium/wordfence-signup/" target="_blank"><img src="<?php echo wfUtils::getBaseURL() . 'images/rr_premium.png'; ?>" alt="Upgrade your protection - Get Wordfence Premium"></a></li>
40
+ <li><a href="https://www.wordfence.com/gnl1rightRailSiteCleaning/wordfence-site-cleanings/" target="_blank"><img src="<?php echo wfUtils::getBaseURL() . 'images/rr_sitecleaning.jpg'; ?>" alt="Have you been hacked? Get help from Wordfence"></a></li>
41
+ <li>
42
+ <p class="center"><strong>Would you like to remove these ads?</strong><br><a href="https://www.wordfence.com/gnl1rightRailBottomUpgrade/wordfence-signup/" target="_blank">Get Premium</a></p>
43
+ </li>
44
+ </ul>
45
+ </div>
46
+ <?php } ?>
47
  <div class="wordfenceScanButton">
48
  <table border="0" cellpadding="0" cellspacing="0" style="width: 800px;">
49
  <tr>
78
  <?php if (wfConfig::get('scansEnabled_fileContents')): ?>
79
  <div style="width: 800px; ">
80
  <p class="wf-success">You are running the Premium version of the Threat Defense Feed which is
81
+ updated in real-time as new threats emerge. <a href="https://www.wordfence.com/zz13/sign-in/" target="_blank">Protect additional sites.</a></p>
82
  </div>
83
  <?php else: ?>
84
  <div class="wfSecure">Premium scanning enabled</div>
95
 
96
  <p>As new threats emerge, the Threat Defense Feed is updated to detect these new hacks. The Premium
97
  version of the Threat Defense Feed is updated in real-time protecting you immediately. As a free
98
+ user <strong>you are receiving the community version</strong> of the feed which is updated 30 days later.</p>
 
99
  <p class="center"><a class="button button-primary"
100
+ href="https://www.wordfence.com/gnl1scanUpgrade/wordfence-signup/" target="_blank">
101
  Get Premium</a></p>
102
  </div>
103
 
151
  </div>
152
 
153
  <div class="wf-premium-callout" style="margin: 20px 0 20px 2px;width: 765px;">
154
+ <h3>Need help with a hacked website?</h3>
155
+ <p>Our team of security experts will clean the infection and remove malicious content. Once your site is restored we will provide a detailed report of our findings. All for an affordable rate.</p>
156
+ <?php if (!wfConfig::get('isPaid')) { ?><p><strong>Includes a 1 year Wordfence Premium license.</strong></p><?php } ?>
157
+ <p class="center"><a class="button button-primary" href="https://www.wordfence.com/gnl1scanGetHelp/wordfence-site-cleanings/" target="_blank">Get Help</a></p>
 
 
 
 
158
  </div>
159
 
160
 
164
  <a href="#" id="wfNewIssuesTab" class="wfTab2 wfTabSwitch selected" onclick="wordfenceAdmin.switchIssuesTab(this, 'new'); return false;">New Issues</a>
165
  <a href="#" class="wfTab2 wfTabSwitch" onclick="wordfenceAdmin.switchIssuesTab(this, 'ignored'); return false;">Ignored Issues</a>
166
  </div>
167
+ <div class="wfTabsContainer wfScanIssuesTabs">
168
  <div id="wfIssues_new" class="wfIssuesContainer">
169
  <h2>New Issues</h2>
170
  <?php if (wfConfig::get('scansEnabled_highSense')): ?>
lib/menu_scanSchedule.php CHANGED
@@ -2,24 +2,28 @@
2
  <div class="wrap" id="paidWrap">
3
  <?php require('menuHeader.php'); ?>
4
  <?php $pageTitle = "Schedule when Wordfence Scans Occur"; $helpLink="http://docs.wordfence.com/en/Wordfence_scan_scheduling"; $helpLabel="Learn more about Scheduling Wordfence Scans"; include('pageTitle.php'); ?>
 
 
 
 
5
  <?php if(! wfConfig::get('isPaid')){ ?>
6
  <div class="wf-premium-callout" style="margin: 20px;">
7
  <h3>Scan Scheduling is only available to Premium Members</h3>
8
  <p>Premium users can increase their WordPress protection by controlling scan frequency up to once per hour. Premium also allows you to control when Wordfence initiates a scan, selecting optimal times that don’t interfere with high-traffic or optimal usage of your site.</p>
9
 
10
- <p>Upgrade to Premium today for just $8.25 per month:</p>
11
  <ul>
12
  <li>Receive real-time Firewall and Scan engine rule updates for protection as threats emerge</li>
13
  <li>Other advanced features like IP reputation monitoring, an advanced comment spam filter, country blocking and cell phone sign-in give you the best protection available</li>
14
  <li>Access to Premium Support</li>
15
- <li>Discounts of up to 75% available for multiyear and multi-license purchases</li>
16
  </ul>
17
  <p class="center"><a class="button button-primary"
18
- href="https://www.wordfence.com/gnl1scanSched1/wordfence-signup/">Get Premium</a></p>
19
  </div>
20
  <?php } ?>
21
 
22
- <div class="wordfenceWrap" style="margin: 20px 20px 20px 30px;">
23
  <p>
24
  <strong>Current time:</strong>&nbsp;<?php echo date('l jS \of F Y H:i:s A', current_time('timestamp')); ?>
25
  <br /><strong>Next scan will start at:</strong>&nbsp;
2
  <div class="wrap" id="paidWrap">
3
  <?php require('menuHeader.php'); ?>
4
  <?php $pageTitle = "Schedule when Wordfence Scans Occur"; $helpLink="http://docs.wordfence.com/en/Wordfence_scan_scheduling"; $helpLabel="Learn more about Scheduling Wordfence Scans"; include('pageTitle.php'); ?>
5
+ <?php
6
+ $rightRail = new wfView('marketing/rightrail', array('additionalClasses' => 'wordfenceRightRailScanSchedule'));
7
+ echo $rightRail;
8
+ ?>
9
  <?php if(! wfConfig::get('isPaid')){ ?>
10
  <div class="wf-premium-callout" style="margin: 20px;">
11
  <h3>Scan Scheduling is only available to Premium Members</h3>
12
  <p>Premium users can increase their WordPress protection by controlling scan frequency up to once per hour. Premium also allows you to control when Wordfence initiates a scan, selecting optimal times that don’t interfere with high-traffic or optimal usage of your site.</p>
13
 
14
+ <p>Upgrade today:</p>
15
  <ul>
16
  <li>Receive real-time Firewall and Scan engine rule updates for protection as threats emerge</li>
17
  <li>Other advanced features like IP reputation monitoring, an advanced comment spam filter, country blocking and cell phone sign-in give you the best protection available</li>
18
  <li>Access to Premium Support</li>
19
+ <li>Discounts of up to 90% available for multiyear and multi-license purchases</li>
20
  </ul>
21
  <p class="center"><a class="button button-primary"
22
+ href="https://www.wordfence.com/gnl1scanSched1/wordfence-signup/" target="_blank">Get Premium</a></p>
23
  </div>
24
  <?php } ?>
25
 
26
+ <div class="wordfenceWrap" style="margin: 20px 20px 20px 30px; max-width: 900px;">
27
  <p>
28
  <strong>Current time:</strong>&nbsp;<?php echo date('l jS \of F Y H:i:s A', current_time('timestamp')); ?>
29
  <br /><strong>Next scan will start at:</strong>&nbsp;
lib/menu_sitePerf.php CHANGED
@@ -5,7 +5,11 @@ $w = new wfConfig();
5
  <div class="wrap">
6
  <?php require('menuHeader.php'); ?>
7
  <?php $pageTitle = "Your Site Performance"; $helpLink="http://docs.wordfence.com/en/Falcon_Cache"; $helpLabel="Learn more about Wordfence Caching"; include('pageTitle.php'); ?>
8
- <div class="wordfenceWrap" style="margin: 20px 20px 20px 30px;">
 
 
 
 
9
  <h2>Caching</h2>
10
  <table border="0">
11
  <tr><td>Disable all performance enhancements:</td><td><input type="radio" name="cacheType" id="cacheType_disable" value="disable" <?php if(! wfConfig::get('cacheType')){ echo 'checked="checked"'; } ?> /></td><td>No performance improvement</td></tr>
@@ -45,7 +49,7 @@ $w = new wfConfig();
45
  <option value="uaeq">User-Agent Exactly Matches</option>
46
  <option value="cc">Cookie Name Contains</option>
47
  </select>
48
- this value then don't cache it:
49
  <input type="text" id="wfPattern" value="" size="20" maxlength="1000" />e.g. /my/dynamic/page/
50
  <input type="button" class="button-primary" value="Add exclusion" onclick="WFAD.addCacheExclusion(jQuery('#wfPatternType').val(), jQuery('#wfPattern').val()); return false;" />
51
  </p>
5
  <div class="wrap">
6
  <?php require('menuHeader.php'); ?>
7
  <?php $pageTitle = "Your Site Performance"; $helpLink="http://docs.wordfence.com/en/Falcon_Cache"; $helpLabel="Learn more about Wordfence Caching"; include('pageTitle.php'); ?>
8
+ <?php
9
+ $rightRail = new wfView('marketing/rightrail');
10
+ echo $rightRail;
11
+ ?>
12
+ <div class="wordfenceWrap" style="margin: 20px 20px 20px 30px; max-width: 800px;">
13
  <h2>Caching</h2>
14
  <table border="0">
15
  <tr><td>Disable all performance enhancements:</td><td><input type="radio" name="cacheType" id="cacheType_disable" value="disable" <?php if(! wfConfig::get('cacheType')){ echo 'checked="checked"'; } ?> /></td><td>No performance improvement</td></tr>
49
  <option value="uaeq">User-Agent Exactly Matches</option>
50
  <option value="cc">Cookie Name Contains</option>
51
  </select>
52
+ this value<br>then don't cache it:
53
  <input type="text" id="wfPattern" value="" size="20" maxlength="1000" />e.g. /my/dynamic/page/
54
  <input type="button" class="button-primary" value="Add exclusion" onclick="WFAD.addCacheExclusion(jQuery('#wfPatternType').val(), jQuery('#wfPattern').val()); return false;" />
55
  </p>
lib/menu_twoFactor.php CHANGED
@@ -2,6 +2,10 @@
2
  <div class="wrap" id="paidWrap">
3
  <?php require('menuHeader.php'); ?>
4
  <?php $pageTitle = "Cellphone Sign-in"; $helpLink="http://docs.wordfence.com/en/Cellphone_sign-in"; $helpLabel="Learn more about Cellphone Sign-in"; include('pageTitle.php'); ?>
 
 
 
 
5
  <?php if(! wfConfig::get('isPaid')){ ?>
6
  <div class="wf-premium-callout" style="margin: 20px 0 20px 20px; width: 700px;">
7
  <h3>Cellphone Sign-in is only available to Premium Members</h3>
@@ -10,18 +14,18 @@
10
  available from Wordfence for your WordPress website. We recommend you enable Cellphone Sign-in for all
11
  Administrator level accounts.</p>
12
 
13
- <p>Upgrade to Premium today for just $8.25 per month:</p>
14
  <ul>
15
  <li>Receive real-time Firewall and Scan engine rule updates for protection as threats emerge</li>
16
  <li>Other advanced features like IP reputation monitoring, an advanced comment spam filter, advanced
17
  scanning options and country blocking give you the best protection available
18
  </li>
19
  <li>Access to Premium Support</li>
20
- <li>Discounts of up to 75% available for multiyear and multi-license purchases</li>
21
  </ul>
22
 
23
  <p class="center"><a class="button button-primary"
24
- href="https://www.wordfence.com/gnl1twoFac1/wordfence-signup/">Get Premium</a></p>
25
  </div>
26
 
27
  <?php } ?>
@@ -34,7 +38,7 @@
34
  <?php
35
  }
36
  ?>
37
- <div class="wordfenceWrap" style="margin: 20px 20px 20px 30px;">
38
  <h2>Enable Cellphone Sign-in</h2>
39
  <p><em>Our Cellphone Sign-in uses a technique called "Two Factor Authentication" which is used by banks, government agencies and military world-wide as one of the most secure forms of remote system authentication. We recommend you enable Cellphone Sign-in for all Administrator level accounts.</em></p>
40
  <table class="wfConfigForm">
@@ -42,7 +46,7 @@
42
  <tr><td class="align-top">Code generation mode:</td><td>
43
  <table class="wfConfigForm">
44
  <tr><td><input type="radio" name="wf2faMode" value="authenticator" checked></td><td>Use authenticator app</td></tr>
45
- <tr><td><input type="radio" name="wf2faMode" value="phone"></td><td>Send code to a phone number: <input type="text" id="wfPhone" value="" size="20" disabled> Format: +1-123-555-5034</td></tr>
46
  </table>
47
  </td></tr>
48
  <tr><td colspan="2"><input type="button" class="button button-primary" value="Enable Cellphone Sign-in" onclick="WFAD.addTwoFactor(jQuery('#wfUsername').val(), jQuery('#wfPhone').val(), jQuery('input[name=wf2faMode]:checked').val());" /></td></tr>
2
  <div class="wrap" id="paidWrap">
3
  <?php require('menuHeader.php'); ?>
4
  <?php $pageTitle = "Cellphone Sign-in"; $helpLink="http://docs.wordfence.com/en/Cellphone_sign-in"; $helpLabel="Learn more about Cellphone Sign-in"; include('pageTitle.php'); ?>
5
+ <?php
6
+ $rightRail = new wfView('marketing/rightrail');
7
+ echo $rightRail;
8
+ ?>
9
  <?php if(! wfConfig::get('isPaid')){ ?>
10
  <div class="wf-premium-callout" style="margin: 20px 0 20px 20px; width: 700px;">
11
  <h3>Cellphone Sign-in is only available to Premium Members</h3>
14
  available from Wordfence for your WordPress website. We recommend you enable Cellphone Sign-in for all
15
  Administrator level accounts.</p>
16
 
17
+ <p>Upgrade today:</p>
18
  <ul>
19
  <li>Receive real-time Firewall and Scan engine rule updates for protection as threats emerge</li>
20
  <li>Other advanced features like IP reputation monitoring, an advanced comment spam filter, advanced
21
  scanning options and country blocking give you the best protection available
22
  </li>
23
  <li>Access to Premium Support</li>
24
+ <li>Discounts of up to 90% available for multiyear and multi-license purchases</li>
25
  </ul>
26
 
27
  <p class="center"><a class="button button-primary"
28
+ href="https://www.wordfence.com/gnl1twoFac1/wordfence-signup/" target="_blank">Get Premium</a></p>
29
  </div>
30
 
31
  <?php } ?>
38
  <?php
39
  }
40
  ?>
41
+ <div class="wordfenceWrap" style="margin: 20px 20px 20px 30px; max-width: 800px;">
42
  <h2>Enable Cellphone Sign-in</h2>
43
  <p><em>Our Cellphone Sign-in uses a technique called "Two Factor Authentication" which is used by banks, government agencies and military world-wide as one of the most secure forms of remote system authentication. We recommend you enable Cellphone Sign-in for all Administrator level accounts.</em></p>
44
  <table class="wfConfigForm">
46
  <tr><td class="align-top">Code generation mode:</td><td>
47
  <table class="wfConfigForm">
48
  <tr><td><input type="radio" name="wf2faMode" value="authenticator" checked></td><td>Use authenticator app</td></tr>
49
+ <tr><td><input type="radio" name="wf2faMode" value="phone"></td><td>Send code to a phone number: <input type="text" id="wfPhone" value="" size="20" disabled><br><em>Format: +1-123-555-5034</em></td></tr>
50
  </table>
51
  </td></tr>
52
  <tr><td colspan="2"><input type="button" class="button button-primary" value="Enable Cellphone Sign-in" onclick="WFAD.addTwoFactor(jQuery('#wfUsername').val(), jQuery('#wfPhone').val(), jQuery('input[name=wf2faMode]:checked').val());" /></td></tr>
lib/menu_waf.php CHANGED
@@ -14,6 +14,11 @@ $wafRemoveURL = network_admin_url('admin.php?page=WordfenceWAF&wafAction=removeA
14
  include('pageTitle.php');
15
  ?>
16
  <div class="wordfenceModeElem" id="wordfenceMode_waf"></div>
 
 
 
 
 
17
 
18
  <?php
19
  if (defined('WFWAF_ENABLED') && !WFWAF_ENABLED) :
@@ -77,21 +82,14 @@ $wafRemoveURL = network_admin_url('admin.php?page=WordfenceWAF&wafAction=removeA
77
  <p>As new threats emerge, the Threat Defense Feed is updated to protect you from new attacks. The
78
  Premium version of the Threat Defense Feed is updated in real-time protecting you immediately. As a
79
  free user <strong>you are receiving the community version</strong> of the feed which is updated 30
80
- days later.
81
- Upgrade now for just $8.25 per month!</p>
82
 
83
  <p class="center"><a class="button button-primary"
84
  href="https://www.wordfence.com/wafOptions1/wordfence-signup/">
85
  Get Premium</a></p>
86
  </div>
87
- <?php } else { ?>
88
- <div class="wf-success">
89
- You are running the Premium version of the Threat Defense Feed which is updated in real-time as new
90
- threats emerge.
91
- </div>
92
  <?php } ?>
93
 
94
-
95
  <?php if (WFWAF_SUBDIRECTORY_INSTALL): ?>
96
  <div class="wf-notice">
97
  You are currently running the Wordfence Web Application Firewall from another WordPress installation.
@@ -101,6 +99,12 @@ $wafRemoveURL = network_admin_url('admin.php?page=WordfenceWAF&wafAction=removeA
101
  </div>
102
  <?php else: ?>
103
  <div class="wordfenceWrap" style="margin: 20px 20px 20px 30px;">
 
 
 
 
 
 
104
  <form action="javascript:void(0)" id="waf-config-form">
105
 
106
  <table class="wfConfigForm">
14
  include('pageTitle.php');
15
  ?>
16
  <div class="wordfenceModeElem" id="wordfenceMode_waf"></div>
17
+
18
+ <?php
19
+ $rightRail = new wfView('marketing/rightrail', array('additionalClasses' => 'wordfenceRightRailWAF'));
20
+ echo $rightRail;
21
+ ?>
22
 
23
  <?php
24
  if (defined('WFWAF_ENABLED') && !WFWAF_ENABLED) :
82
  <p>As new threats emerge, the Threat Defense Feed is updated to protect you from new attacks. The
83
  Premium version of the Threat Defense Feed is updated in real-time protecting you immediately. As a
84
  free user <strong>you are receiving the community version</strong> of the feed which is updated 30
85
+ days later.</p>
 
86
 
87
  <p class="center"><a class="button button-primary"
88
  href="https://www.wordfence.com/wafOptions1/wordfence-signup/">
89
  Get Premium</a></p>
90
  </div>
 
 
 
 
 
91
  <?php } ?>
92
 
 
93
  <?php if (WFWAF_SUBDIRECTORY_INSTALL): ?>
94
  <div class="wf-notice">
95
  You are currently running the Wordfence Web Application Firewall from another WordPress installation.
99
  </div>
100
  <?php else: ?>
101
  <div class="wordfenceWrap" style="margin: 20px 20px 20px 30px;">
102
+ <?php if (wfConfig::get('isPaid')) { ?>
103
+ <div class="wf-success" style="max-width: 881px;">
104
+ You are running the Premium version of the Threat Defense Feed which is updated in real-time as new
105
+ threats emerge. <a href="https://www.wordfence.com/zz14/sign-in/" target="_blank">Protect additional sites.</a>
106
+ </div>
107
+ <?php } ?>
108
  <form action="javascript:void(0)" id="waf-config-form">
109
 
110
  <table class="wfConfigForm">
lib/menu_whois.php CHANGED
@@ -2,14 +2,18 @@
2
  <div class="wrap" id="paidWrap">
3
  <?php require('menuHeader.php'); ?>
4
  <?php $pageTitle = "WHOIS Lookup"; $helpLink="http://docs.wordfence.com/en/Whois_Lookup"; $helpLabel="Learn more about Whois Lookups"; include('pageTitle.php'); ?>
5
- <div class="wordfenceWrap" style="margin: 20px 20px 20px 30px;">
 
 
 
 
6
  <?php
7
  if(! function_exists('fsockopen')){
8
  ?>
9
  <p style="color: #F00; width: 600px;">
10
  Sorry, but your web hosting provider has disabled the 'fsockopen' function on your WordPress server. That means you can't
11
  use WHOIS. Please log a support call with them asking them to enable this function. Explain that you need it to be able to
12
- perform Whois lookups on IP addresses which will allow you to determine who owns the IP's that are attacking your website.
13
  <br /><br />
14
  If you are hosting your own site, edit your php.ini config file and make sure 'fsockopen' does not appear
15
  next to disable_functions in php.ini. You may have to restart your web server for the changes to take effect.
@@ -19,7 +23,7 @@ if(! function_exists('fsockopen')){
19
  ?>
20
  </p>
21
  <p>
22
- <input type="text" name="whois" id="wfwhois" value="" size="40" maxlength="255" onkeydown="if(event.keyCode == 13){ WFAD.whois(jQuery('#wfwhois').val()); }" />&nbsp;<input type="button" name="whoisbutton" id="whoisbutton" class="button-primary" value="Look up IP or Domain" onclick="WFAD.whois(jQuery('#wfwhois').val());" />
23
 
24
  </p>
25
  <?php if( isset( $_GET['wfnetworkblock'] ) && $_GET['wfnetworkblock']){ ?>
2
  <div class="wrap" id="paidWrap">
3
  <?php require('menuHeader.php'); ?>
4
  <?php $pageTitle = "WHOIS Lookup"; $helpLink="http://docs.wordfence.com/en/Whois_Lookup"; $helpLabel="Learn more about Whois Lookups"; include('pageTitle.php'); ?>
5
+ <?php
6
+ $rightRail = new wfView('marketing/rightrail');
7
+ echo $rightRail;
8
+ ?>
9
+ <div class="wordfenceWrap<?php if (!wfConfig::get('isPaid')) { echo " wordfence-community"; }?>" style="margin: 20px 20px 20px 30px; max-width: 800px;">
10
  <?php
11
  if(! function_exists('fsockopen')){
12
  ?>
13
  <p style="color: #F00; width: 600px;">
14
  Sorry, but your web hosting provider has disabled the 'fsockopen' function on your WordPress server. That means you can't
15
  use WHOIS. Please log a support call with them asking them to enable this function. Explain that you need it to be able to
16
+ perform Whois lookups on IP addresses which will allow you to determine who owns the IPs that are attacking your website.
17
  <br /><br />
18
  If you are hosting your own site, edit your php.ini config file and make sure 'fsockopen' does not appear
19
  next to disable_functions in php.ini. You may have to restart your web server for the changes to take effect.
23
  ?>
24
  </p>
25
  <p>
26
+ <input type="text" name="whois" id="wfwhois" value="" size="60" maxlength="255" onkeydown="if(event.keyCode == 13){ WFAD.whois(jQuery('#wfwhois').val()); }" />&nbsp;<input type="button" name="whoisbutton" id="whoisbutton" class="button-primary" value="Look up IP or Domain" onclick="WFAD.whois(jQuery('#wfwhois').val());" />
27
 
28
  </p>
29
  <?php if( isset( $_GET['wfnetworkblock'] ) && $_GET['wfnetworkblock']){ ?>
lib/wfCache.php CHANGED
@@ -449,7 +449,7 @@ class wfCache {
449
  fclose($fh);
450
  return "Could not read from $htaccessPath";
451
  }
452
- $contents = preg_replace('/#WFCACHECODE.*WFCACHECODE[r\s\n\t]*/s', '', $contents);
453
  if($action == 'add'){
454
  $code = self::getHtaccessCode();
455
  $contents = $code . "\n" . $contents;
@@ -606,7 +606,7 @@ EOT;
606
  return "Could not read from $htaccessPath";
607
  }
608
 
609
- $contents = preg_replace('/#WFIPBLOCKS.*WFIPBLOCKS[r\s\n\t]*/s', '', $contents);
610
 
611
  ftruncate($fh, 0);
612
  fflush($fh);
@@ -702,7 +702,7 @@ EOT;
702
  fclose($fh);
703
  return "Could not read from $htaccessPath";
704
  }
705
- $contents = preg_replace('/#WFIPBLOCKS.*WFIPBLOCKS[r\s\n\t]*/s', '', $contents);
706
  $contents = $blockCode . $contents;
707
  ftruncate($fh, 0);
708
  fflush($fh);
449
  fclose($fh);
450
  return "Could not read from $htaccessPath";
451
  }
452
+ $contents = preg_replace('/#WFCACHECODE.*WFCACHECODE[\r\s\n\t]*/s', '', $contents);
453
  if($action == 'add'){
454
  $code = self::getHtaccessCode();
455
  $contents = $code . "\n" . $contents;
606
  return "Could not read from $htaccessPath";
607
  }
608
 
609
+ $contents = preg_replace('/#WFIPBLOCKS.*WFIPBLOCKS[\r\s\n\t]*/s', '', $contents);
610
 
611
  ftruncate($fh, 0);
612
  fflush($fh);
702
  fclose($fh);
703
  return "Could not read from $htaccessPath";
704
  }
705
+ $contents = preg_replace('/#WFIPBLOCKS.*WFIPBLOCKS[\r\s\n\t]*/s', '', $contents);
706
  $contents = $blockCode . $contents;
707
  ftruncate($fh, 0);
708
  fflush($fh);
lib/wfConfig.php CHANGED
@@ -31,6 +31,7 @@ class wfConfig {
31
  "liveTraf_ignorePublishers" => array('value' => true, 'autoload' => self::AUTOLOAD),
32
  //"perfLoggingEnabled" => array('value' => false, 'autoload' => self::AUTOLOAD),
33
  "scheduledScansEnabled" => array('value' => true, 'autoload' => self::AUTOLOAD),
 
34
  "scansEnabled_public" => array('value' => false, 'autoload' => self::AUTOLOAD),
35
  "scansEnabled_heartbleed" => array('value' => true, 'autoload' => self::AUTOLOAD),
36
  "scansEnabled_core" => array('value' => true, 'autoload' => self::AUTOLOAD),
@@ -657,11 +658,15 @@ class wfConfig {
657
  <IfModule mod_php5.c>
658
  php_flag engine 0
659
  </IfModule>
 
 
 
660
 
661
  AddHandler cgi-script .php .phtml .php3 .pl .py .jsp .asp .htm .shtml .sh .cgi
662
  Options -ExecCGI
663
  # END Wordfence code execution protection
664
  ';
 
665
 
666
  private static function _uploadsHtaccessFilePath() {
667
  $upload_dir = wp_upload_dir();
@@ -689,8 +694,25 @@ Options -ExecCGI
689
  if (@file_put_contents($uploads_htaccess_file_path, ($uploads_htaccess_has_content ? "\n\n" : "") . self::$_disable_scripts_htaccess, FILE_APPEND | LOCK_EX) === false) {
690
  throw new wfConfigException("Unable to save the .htaccess file needed to disable script execution in the uploads directory. Please check your permissions on that directory.");
691
  }
 
692
  return true;
693
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
694
 
695
  /**
696
  * Remove script execution protections for our the .htaccess file in the uploads directory.
@@ -704,8 +726,8 @@ Options -ExecCGI
704
  $htaccess_contents = file_get_contents($uploads_htaccess_file_path);
705
 
706
  // Check that it is in the file
707
- if (strpos($htaccess_contents, self::$_disable_scripts_htaccess) !== false) {
708
- $htaccess_contents = str_replace(self::$_disable_scripts_htaccess, '', $htaccess_contents);
709
 
710
  $error_message = "Unable to remove code execution protections applied to the .htaccess file in the uploads directory. Please check your permissions on that file.";
711
  if (strlen(trim($htaccess_contents)) === 0) {
31
  "liveTraf_ignorePublishers" => array('value' => true, 'autoload' => self::AUTOLOAD),
32
  //"perfLoggingEnabled" => array('value' => false, 'autoload' => self::AUTOLOAD),
33
  "scheduledScansEnabled" => array('value' => true, 'autoload' => self::AUTOLOAD),
34
+ "lowResourceScansEnabled" => array('value' => false, 'autoload' => self::AUTOLOAD),
35
  "scansEnabled_public" => array('value' => false, 'autoload' => self::AUTOLOAD),
36
  "scansEnabled_heartbleed" => array('value' => true, 'autoload' => self::AUTOLOAD),
37
  "scansEnabled_core" => array('value' => true, 'autoload' => self::AUTOLOAD),
658
  <IfModule mod_php5.c>
659
  php_flag engine 0
660
  </IfModule>
661
+ <IfModule mod_php7.c>
662
+ php_flag engine 0
663
+ </IfModule>
664
 
665
  AddHandler cgi-script .php .phtml .php3 .pl .py .jsp .asp .htm .shtml .sh .cgi
666
  Options -ExecCGI
667
  # END Wordfence code execution protection
668
  ';
669
+ private static $_disable_scripts_regex = '/# BEGIN Wordfence code execution protection.+?# END Wordfence code execution protection/s';
670
 
671
  private static function _uploadsHtaccessFilePath() {
672
  $upload_dir = wp_upload_dir();
694
  if (@file_put_contents($uploads_htaccess_file_path, ($uploads_htaccess_has_content ? "\n\n" : "") . self::$_disable_scripts_htaccess, FILE_APPEND | LOCK_EX) === false) {
695
  throw new wfConfigException("Unable to save the .htaccess file needed to disable script execution in the uploads directory. Please check your permissions on that directory.");
696
  }
697
+ self::set('disableCodeExecutionUploadsPHP7Migrated', true);
698
  return true;
699
  }
700
+
701
+ public static function migrateCodeExecutionForUploadsPHP7() {
702
+ if (self::get('disableCodeExecutionUploads')) {
703
+ if (!self::get('disableCodeExecutionUploadsPHP7Migrated')) {
704
+ $uploads_htaccess_file_path = self::_uploadsHtaccessFilePath();
705
+ if (file_exists($uploads_htaccess_file_path)) {
706
+ $htaccess_contents = file_get_contents($uploads_htaccess_file_path);
707
+ if (preg_match(self::$_disable_scripts_regex, $htaccess_contents)) {
708
+ $htaccess_contents = preg_replace(self::$_disable_scripts_regex, self::$_disable_scripts_htaccess, $htaccess_contents);
709
+ @file_put_contents($uploads_htaccess_file_path, $htaccess_contents);
710
+ self::set('disableCodeExecutionUploadsPHP7Migrated', true);
711
+ }
712
+ }
713
+ }
714
+ }
715
+ }
716
 
717
  /**
718
  * Remove script execution protections for our the .htaccess file in the uploads directory.
726
  $htaccess_contents = file_get_contents($uploads_htaccess_file_path);
727
 
728
  // Check that it is in the file
729
+ if (preg_match(self::$_disable_scripts_regex, $htaccess_contents)) {
730
+ $htaccess_contents = preg_replace(self::$_disable_scripts_regex, '', $htaccess_contents);
731
 
732
  $error_message = "Unable to remove code execution protections applied to the .htaccess file in the uploads directory. Please check your permissions on that file.";
733
  if (strlen(trim($htaccess_contents)) === 0) {
lib/wfLog.php CHANGED
@@ -989,6 +989,7 @@ class wfLog {
989
  $now = $this->getDB()->querySingle("select unix_timestamp()");
990
  $secsToGo = ($rec['blockedTime'] + wfConfig::get('blockedTime')) - $now;
991
  if(wfConfig::get('other_WFNet') && self::isAuthRequest()){ //It's an auth request and this IP has been blocked
 
992
  wordfence::wfsnReportBlockedAttempt($IP, 'login');
993
  }
994
  $this->do503($secsToGo, $rec['reason']);
@@ -1098,7 +1099,7 @@ class wfLog {
1098
 
1099
  public function do503($secsToGo, $reason){
1100
  $this->initLogRequest();
1101
- $this->currentRequest->statusCode = 403;
1102
  if (!$this->currentRequest->action) {
1103
  $this->currentRequest->action = 'blocked:wordfence';
1104
  }
989
  $now = $this->getDB()->querySingle("select unix_timestamp()");
990
  $secsToGo = ($rec['blockedTime'] + wfConfig::get('blockedTime')) - $now;
991
  if(wfConfig::get('other_WFNet') && self::isAuthRequest()){ //It's an auth request and this IP has been blocked
992
+ $this->getCurrentRequest()->action = 'blocked:wfsnrepeat';
993
  wordfence::wfsnReportBlockedAttempt($IP, 'login');
994
  }
995
  $this->do503($secsToGo, $rec['reason']);
1099
 
1100
  public function do503($secsToGo, $reason){
1101
  $this->initLogRequest();
1102
+ $this->currentRequest->statusCode = 503;
1103
  if (!$this->currentRequest->action) {
1104
  $this->currentRequest->action = 'blocked:wordfence';
1105
  }
lib/wfScan.php CHANGED
@@ -27,7 +27,6 @@ class wfScan {
27
  }
28
  self::status(4, 'info', "Fetching stored cronkey for comparison.");
29
  $currentCronKey = wfConfig::get('currentCronKey', false);
30
- wfConfig::set('currentCronKey', '');
31
  if(! $currentCronKey){
32
  wordfence::status(4, 'error', "Wordfence could not find a saved cron key to start the scan so assuming it started and exiting.");
33
  exit();
@@ -41,6 +40,7 @@ class wfScan {
41
  if($savedKey[1] != $_GET['cronKey']){
42
  self::errorExit("Wordfence could not start a scan because the cron key does not match the saved key. Saved: " . $savedKey[1] . " Sent: " . $_GET['cronKey'] . " Current unexploded: " . $currentCronKey);
43
  }
 
44
  /* --------- end cronkey check ---------- */
45
 
46
  self::status(4, 'info', "Becoming admin for scan");
@@ -56,6 +56,10 @@ class wfScan {
56
  }
57
 
58
  wfConfig::set('wfPeakMemory', 0);
 
 
 
 
59
  }
60
  self::status(4, 'info', "Requesting max memory");
61
  wfUtils::requestMaxMemory();
27
  }
28
  self::status(4, 'info', "Fetching stored cronkey for comparison.");
29
  $currentCronKey = wfConfig::get('currentCronKey', false);
 
30
  if(! $currentCronKey){
31
  wordfence::status(4, 'error', "Wordfence could not find a saved cron key to start the scan so assuming it started and exiting.");
32
  exit();
40
  if($savedKey[1] != $_GET['cronKey']){
41
  self::errorExit("Wordfence could not start a scan because the cron key does not match the saved key. Saved: " . $savedKey[1] . " Sent: " . $_GET['cronKey'] . " Current unexploded: " . $currentCronKey);
42
  }
43
+ wfConfig::set('currentCronKey', '');
44
  /* --------- end cronkey check ---------- */
45
 
46
  self::status(4, 'info', "Becoming admin for scan");
56
  }
57
 
58
  wfConfig::set('wfPeakMemory', 0);
59
+ wfConfig::set('lowResourceScanWaitStep', false);
60
+ if (wfConfig::get('lowResourceScansEnabled')) {
61
+ self::status(1, 'info', "Using low resource scanning");
62
+ }
63
  }
64
  self::status(4, 'info', "Requesting max memory");
65
  wfUtils::requestMaxMemory();
lib/wfScanEngine.php CHANGED
@@ -163,6 +163,15 @@ class wfScanEngine {
163
  }
164
  }
165
  private function doScan(){
 
 
 
 
 
 
 
 
 
166
  while(sizeof($this->jobList) > 0){
167
  self::checkForKill();
168
  $jobName = $this->jobList[0];
@@ -180,7 +189,7 @@ class wfScanEngine {
180
  }
181
  $summary = $this->i->getSummaryItems();
182
  $this->status(1, 'info', '-------------------');
183
- $this->status(1, 'info', "Scan Complete. Scanned " . $summary['totalFiles'] . " files, " . $summary['totalPlugins'] . " plugins, " . $summary['totalThemes'] . " themes, " . ($summary['totalPages'] + $summary['totalPosts']) . " pages, " . $summary['totalComments'] . " comments and " . $summary['totalRows'] . " records in " . (time() - $this->startTime) . " seconds.");
184
  if($this->i->totalIssues > 0){
185
  $this->status(10, 'info', "SUM_FINAL:Scan complete. You have " . $this->i->totalIssues . " new issues to fix. See below.");
186
  } else {
@@ -484,8 +493,6 @@ class wfScanEngine {
484
  $this->i->updateSummaryItem('totalData', wfUtils::formatBytes($this->hasher->totalData));
485
  $this->i->updateSummaryItem('totalFiles', $this->hasher->totalFiles);
486
  $this->i->updateSummaryItem('totalDirs', $this->hasher->totalDirs);
487
- $this->i->updateSummaryItem('linesOfPHP', $this->hasher->linesOfPHP);
488
- $this->i->updateSummaryItem('linesOfJCH', $this->hasher->linesOfJCH);
489
  $this->hasher = false;
490
  }
491
  private function scan_knownFiles_finish(){
@@ -1140,6 +1147,7 @@ class wfScanEngine {
1140
  wfUtils::getScanFileError();
1141
  return "A scan is already running. Use the kill link if you would like to terminate the current scan.";
1142
  }
 
1143
  }
1144
  $timeout = self::getMaxExecutionTime() - 2; //2 seconds shorter than max execution time which ensures that only 2 HTTP processes are ever occupied
1145
  $testURL = admin_url('admin-ajax.php?action=wordfence_testAjax');
163
  }
164
  }
165
  private function doScan(){
166
+ if (wfConfig::get('lowResourceScansEnabled')) {
167
+ $isFork = ($_GET['isFork'] == '1' ? true : false);
168
+ wfConfig::set('lowResourceScanWaitStep', !wfConfig::get('lowResourceScanWaitStep'));
169
+ if ($isFork && wfConfig::get('lowResourceScanWaitStep')) {
170
+ sleep($this->maxExecTime / 2);
171
+ $this->fork(); //exits
172
+ }
173
+ }
174
+
175
  while(sizeof($this->jobList) > 0){
176
  self::checkForKill();
177
  $jobName = $this->jobList[0];
189
  }
190
  $summary = $this->i->getSummaryItems();
191
  $this->status(1, 'info', '-------------------');
192
+ $this->status(1, 'info', "Scan Complete. Scanned " . $summary['totalFiles'] . " files, " . $summary['totalPlugins'] . " plugins, " . $summary['totalThemes'] . " themes, " . ($summary['totalPages'] + $summary['totalPosts']) . " pages, " . $summary['totalComments'] . " comments and " . $summary['totalRows'] . " records in " . wfUtils::makeDuration(time() - $this->startTime, true) . ".");
193
  if($this->i->totalIssues > 0){
194
  $this->status(10, 'info', "SUM_FINAL:Scan complete. You have " . $this->i->totalIssues . " new issues to fix. See below.");
195
  } else {
493
  $this->i->updateSummaryItem('totalData', wfUtils::formatBytes($this->hasher->totalData));
494
  $this->i->updateSummaryItem('totalFiles', $this->hasher->totalFiles);
495
  $this->i->updateSummaryItem('totalDirs', $this->hasher->totalDirs);
 
 
496
  $this->hasher = false;
497
  }
498
  private function scan_knownFiles_finish(){
1147
  wfUtils::getScanFileError();
1148
  return "A scan is already running. Use the kill link if you would like to terminate the current scan.";
1149
  }
1150
+ wfConfig::set('currentCronKey', ''); //Ensure the cron key is cleared
1151
  }
1152
  $timeout = self::getMaxExecutionTime() - 2; //2 seconds shorter than max execution time which ensures that only 2 HTTP processes are ever occupied
1153
  $testURL = admin_url('admin-ajax.php?action=wordfence_testAjax');
lib/wfSchema.php CHANGED
@@ -167,6 +167,16 @@ class wfSchema {
167
  unixday int UNSIGNED NOT NULL,
168
  PRIMARY KEY(IP, unixday)
169
  ) default charset=utf8",
 
 
 
 
 
 
 
 
 
 
170
  /*
171
  'wfPerfLog' => "(
172
  id int UNSIGNED NOT NULL auto_increment PRIMARY KEY,
167
  unixday int UNSIGNED NOT NULL,
168
  PRIMARY KEY(IP, unixday)
169
  ) default charset=utf8",
170
+ 'wfSNIPCache' => "(
171
+ `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
172
+ `IP` varchar(45) NOT NULL DEFAULT '',
173
+ `expiration` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
174
+ `body` varchar(255) NOT NULL DEFAULT '',
175
+ `count` int(10) unsigned NOT NULL DEFAULT '0',
176
+ PRIMARY KEY (`id`),
177
+ KEY `expiration` (`expiration`),
178
+ KEY `IP` (`IP`)
179
+ ) DEFAULT CHARSET=utf8;",
180
  /*
181
  'wfPerfLog' => "(
182
  id int UNSIGNED NOT NULL auto_increment PRIMARY KEY,
lib/wfUtils.php CHANGED
@@ -38,25 +38,40 @@ class wfUtils {
38
  }
39
  }
40
  }
41
- public static function makeDuration($secs) {
42
- $months = floor($secs / (86400 * 30));
43
- $days = floor($secs / 86400);
44
- $hours = floor($secs / 3600);
45
- $minutes = floor($secs / 60);
46
- if($months) {
47
- $days -= $months * 30;
48
- return self::pluralize($months, 'month', $days, 'day');
49
- } else if($days) {
50
- $hours -= $days * 24;
51
- return self::pluralize($days, 'day', $hours, 'hour');
52
- } else if($hours) {
53
- $minutes -= $hours * 60;
54
- return self::pluralize($hours, 'hour', $minutes, 'minute');
55
- } else if($minutes) {
56
- return self::pluralize($minutes, 'minute');
57
- } else {
58
- return self::pluralize($secs, 'second');
 
59
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
  }
61
  public static function pluralize($m1, $t1, $m2 = false, $t2 = false) {
62
  if($m1 != 1) {
@@ -818,6 +833,9 @@ class wfUtils {
818
 
819
  public static function endProcessingFile() {
820
  wfConfig::set('scanFileProcessing', null);
 
 
 
821
  }
822
 
823
  public static function getScanLock(){
38
  }
39
  }
40
  }
41
+ public static function makeDuration($secs, $createExact = false) {
42
+ $components = array();
43
+
44
+ $months = floor($secs / (86400 * 30)); $secs -= $months * 86400 * 30;
45
+ $days = floor($secs / 86400); $secs -= $days * 86400;
46
+ $hours = floor($secs / 3600); $secs -= $hours * 3600;
47
+ $minutes = floor($secs / 60); $secs -= $minutes * 60;
48
+
49
+ if ($months) {
50
+ $components[] = self::pluralize($months, 'month');
51
+ if (!$createExact) {
52
+ $hours = $minutes = $secs = 0;
53
+ }
54
+ }
55
+ if ($days) {
56
+ $components[] = self::pluralize($days, 'day');
57
+ if (!$createExact) {
58
+ $minutes = $secs = 0;
59
+ }
60
  }
61
+ if ($hours) {
62
+ $components[] = self::pluralize($hours, 'hour');
63
+ if (!$createExact) {
64
+ $secs = 0;
65
+ }
66
+ }
67
+ if ($minutes) {
68
+ $components[] = self::pluralize($minutes, 'minute');
69
+ }
70
+ if ($secs) {
71
+ $components[] = self::pluralize($secs, 'second');
72
+ }
73
+
74
+ return implode(' ', $components);
75
  }
76
  public static function pluralize($m1, $t1, $m2 = false, $t2 = false) {
77
  if($m1 != 1) {
833
 
834
  public static function endProcessingFile() {
835
  wfConfig::set('scanFileProcessing', null);
836
+ if (wfConfig::get('lowResourceScansEnabled')) {
837
+ usleep(10000); //10 ms
838
+ }
839
  }
840
 
841
  public static function getScanLock(){
lib/wordfenceClass.php CHANGED
@@ -110,9 +110,10 @@ class wordfence {
110
  public static function hourlyCron(){
111
  global $wpdb; $p = $wpdb->base_prefix;
112
  $api = new wfAPI(wfConfig::get('apiKey'), wfUtils::getWPVersion());
 
 
113
 
114
  if(wfConfig::get('other_WFNet')){
115
- $wfdb = new wfDB();
116
  $q1 = $wfdb->querySelect("select URI from $p"."wfNet404s where ctime > unix_timestamp() - 3600 limit 1000");
117
  $URIs = array();
118
  foreach($q1 as $rec){
@@ -540,6 +541,9 @@ SQL
540
  if (wfConfig::get('email_summary_interval') == 'biweekly') {
541
  wfConfig::set('email_summary_interval', 'weekly');
542
  }
 
 
 
543
 
544
  //Must be the final line
545
  }
@@ -687,6 +691,7 @@ SQL
687
 
688
  if(is_admin()){
689
  add_action('admin_init', 'wordfence::admin_init');
 
690
  if(is_multisite()){
691
  if(wfUtils::isAdminPageMU()){
692
  add_action('network_admin_menu', 'wordfence::admin_menus');
@@ -700,6 +705,7 @@ SQL
700
  add_filter('page_row_actions', 'wordfence::pageRowActions', 0, 2);
701
  add_action('post_submitbox_start', 'wordfence::postSubmitboxStart');
702
  }
 
703
  }
704
 
705
  add_action('request', 'wordfence::preventAuthorNScans');
@@ -721,19 +727,28 @@ SQL
721
  }
722
 
723
  add_action('wordfence_processAttackData', 'wordfence::processAttackData');
724
- if (!empty($_GET['wordfence_syncAttackData']) && get_site_option('wordfence_syncingAttackData') <= time() - 60) {
725
  ignore_user_abort(true);
726
  update_site_option('wordfence_syncingAttackData', time());
727
  header('Content-Type: text/javascript');
728
  add_action('init', 'wordfence::syncAttackData', 10, 0);
729
  add_filter('woocommerce_unforce_ssl_checkout', '__return_false');
730
  }
 
 
 
731
 
732
  if (wfConfig::get('other_hideWPVersion')) {
733
  add_filter('update_feedback', 'wordfence::restoreReadmeForUpgrade');
734
  }
735
 
736
  }
 
 
 
 
 
 
737
  /*
738
  public static function cronAddSchedules($schedules){
739
  $schedules['wfEachMinute'] = array(
@@ -806,7 +821,7 @@ SQL
806
  header("Connection: close");
807
  header("Content-Length: 0");
808
  header("X-Robots-Tag: noindex");
809
- if (!$isCrawler) {
810
  setcookie('wordfence_verifiedHuman', self::getLog()->getVerifiedHumanCookieValue($UA, wfUtils::getIP()), time() + 86400, '/');
811
  }
812
  }
@@ -1028,7 +1043,7 @@ SQL
1028
  header('Location: ' . wp_login_url());
1029
  exit();
1030
  } else if($_GET['func'] == 'unlockAllIPs'){
1031
- wordfence::status(1, 'info', "Request received via unlock email link to unblock all IP's.");
1032
  $wfLog->unblockAllIPs();
1033
  $wfLog->unlockAllIPs();
1034
  delete_transient('wflginfl_' . bin2hex(wfUtils::inet_pton(wfUtils::getIP()))); //Reset login failure counter
@@ -1037,7 +1052,7 @@ SQL
1037
  } else if($_GET['func'] == 'disableRules'){
1038
  wfConfig::set('firewallEnabled', 0);
1039
  wfConfig::set('loginSecurityEnabled', 0);
1040
- wordfence::status(1, 'info', "Request received via unlock email link to unblock all IP's via disabling firewall rules.");
1041
  $wfLog->unblockAllIPs();
1042
  $wfLog->unlockAllIPs();
1043
  delete_transient('wflginfl_' . bin2hex(wfUtils::inet_pton(wfUtils::getIP()))); //Reset login failure counter
@@ -1068,21 +1083,23 @@ SQL
1068
 
1069
  if (empty($_GET['wordfence_syncAttackData'])) {
1070
  $lastAttackMicroseconds = $wpdb->get_var("SELECT MAX(attackLogTime) FROM {$wpdb->base_prefix}wfHits");
1071
- if ($waf->getStorageEngine()->hasNewerAttackData($lastAttackMicroseconds)) {
1072
- if (get_site_option('wordfence_syncingAttackData') <= time() - 60) {
1073
- // Could be the request to itself is not completing, add ajax to the head as a workaround
1074
- $attempts = get_site_option('wordfence_syncAttackDataAttempts', 0);
1075
- if ($attempts > 10) {
1076
- add_action('wp_head', 'wordfence::addSyncAttackDataAjax');
1077
- add_action('login_head', 'wordfence::addSyncAttackDataAjax');
1078
- add_action('admin_head', 'wordfence::addSyncAttackDataAjax');
1079
- } else {
1080
- update_site_option('wordfence_syncAttackDataAttempts', ++$attempts);
1081
- wp_remote_post(add_query_arg('wordfence_syncAttackData', microtime(true), home_url('/')), array(
1082
- 'timeout' => 0.01,
1083
- 'blocking' => false,
1084
- 'sslverify' => apply_filters('https_local_ssl_verify', false)
1085
- ));
 
 
1086
  }
1087
  }
1088
  }
@@ -1598,6 +1615,7 @@ SQL
1598
  if($maxBlockTime = self::wfsnIsBlocked($IP, 'brute')){
1599
  self::getLog()->blockIP($IP, "Blocked by Wordfence Security Network", true, false, $maxBlockTime);
1600
  $secsToGo = wfConfig::get('blockedTime');
 
1601
  self::getLog()->do503($secsToGo, "Blocked by Wordfence Security Network");
1602
  }
1603
 
@@ -1653,20 +1671,139 @@ SQL
1653
  }
1654
  return $authUser;
1655
  }
1656
- public static function wfsnReportBlockedAttempt($IP, $type){
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1657
  try {
1658
- $result = wp_remote_get(WORDFENCE_HACKATTEMPT_URL . 'hackAttempt/?blocked=1&k=' . rawurlencode(wfConfig::get('apiKey')) . '&IP=' . rawurlencode(wfUtils::inet_pton($IP)) . '&t=' . rawurlencode($type), array(
1659
  'timeout' => 1,
1660
  'user-agent' => "Wordfence.com UA " . (defined('WORDFENCE_VERSION') ? WORDFENCE_VERSION : '[Unknown version]'),
 
1661
  ));
1662
- if (is_wp_error($result)) {
1663
- return false;
 
 
 
 
 
1664
  }
1665
- } catch(Exception $err){
1666
- return false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1667
  }
1668
  }
1669
  public static function wfsnIsBlocked($IP, $type){
 
 
 
 
 
 
 
 
 
 
 
 
1670
  try {
1671
  $result = wp_remote_get(WORDFENCE_HACKATTEMPT_URL . 'hackAttempt/?k=' . rawurlencode(wfConfig::get('apiKey')) . '&IP=' . rawurlencode(filter_var($IP, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) ? wfUtils::inet_aton($IP) : wfUtils::inet_pton($IP)) . '&t=' . rawurlencode($type), array(
1672
  'timeout' => 3,
@@ -1675,6 +1812,8 @@ SQL
1675
  if (is_wp_error($result)) {
1676
  return false;
1677
  }
 
 
1678
  if (preg_match('/BLOCKED:(\d+)/', $result['body'], $matches) && (!self::getLog()->isWhitelisted($IP))) {
1679
  return $matches[1];
1680
  }
@@ -2804,7 +2943,7 @@ SQL
2804
  $op = $_POST['op'];
2805
  $wfLog = self::getLog();
2806
  if($op == 'blocked'){
2807
- wordfence::status(1, 'info', "Ajax request received to unblock All IP's including permanent blocks.");
2808
  $wfLog->unblockAllIPs();
2809
  } else if($op == 'locked'){
2810
  $wfLog->unlockAllIPs();
@@ -3223,7 +3362,7 @@ SQL
3223
  }
3224
 
3225
  $htaccess = ABSPATH . '/.htaccess';
3226
- $change = "<IfModule mod_php5.c>\n\tphp_value display_errors 0\n</IfModule>";
3227
  $content = "";
3228
  if (file_exists($htaccess)) {
3229
  $content = file_get_contents($htaccess);
@@ -3286,7 +3425,7 @@ SQL
3286
  if(preg_match('/\.\./', $file)){
3287
  return array('cerrorMsg' => "An invalid file was specified for repair.");
3288
  }
3289
- $localFile = ABSPATH . '/' . preg_replace('/^[\.\/]+/', '', $file);
3290
  if ($wp_filesystem->put_contents($localFile, $result['fileContent'])) {
3291
  $wfIssues->updateIssue($issueID, 'delete');
3292
  return array(
@@ -4256,6 +4395,35 @@ HTML;
4256
  add_submenu_page("Wordfence", "Advanced Blocking", "Advanced Blocking", "activate_plugins", "WordfenceRangeBlocking", 'wordfence::menu_rangeBlocking');
4257
  add_submenu_page("Wordfence", "Options", "Options", "activate_plugins", "WordfenceSecOpt", 'wordfence::menu_options');
4258
  add_submenu_page("Wordfence", "Diagnostics", "Diagnostics", "activate_plugins", "WordfenceDiagnostic", 'wordfence::menu_diagnostic');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4259
  }
4260
  public static function menu_options(){
4261
  require 'menu_options.php';
@@ -6194,6 +6362,7 @@ LIMIT %d", $lastSendTime, $limit));
6194
  }
6195
  update_site_option('wordfence_syncingAttackData', 0);
6196
  update_site_option('wordfence_syncAttackDataAttempts', 0);
 
6197
  if ($exit) {
6198
  exit;
6199
  }
110
  public static function hourlyCron(){
111
  global $wpdb; $p = $wpdb->base_prefix;
112
  $api = new wfAPI(wfConfig::get('apiKey'), wfUtils::getWPVersion());
113
+
114
+ $wfdb = new wfDB();
115
 
116
  if(wfConfig::get('other_WFNet')){
 
117
  $q1 = $wfdb->querySelect("select URI from $p"."wfNet404s where ctime > unix_timestamp() - 3600 limit 1000");
118
  $URIs = array();
119
  foreach($q1 as $rec){
541
  if (wfConfig::get('email_summary_interval') == 'biweekly') {
542
  wfConfig::set('email_summary_interval', 'weekly');
543
  }
544
+
545
+ //6.2.0
546
+ wfConfig::migrateCodeExecutionForUploadsPHP7();
547
 
548
  //Must be the final line
549
  }
691
 
692
  if(is_admin()){
693
  add_action('admin_init', 'wordfence::admin_init');
694
+ add_action('admin_head', 'wordfence::_retargetWordfenceSubmenuCallout');
695
  if(is_multisite()){
696
  if(wfUtils::isAdminPageMU()){
697
  add_action('network_admin_menu', 'wordfence::admin_menus');
705
  add_filter('page_row_actions', 'wordfence::pageRowActions', 0, 2);
706
  add_action('post_submitbox_start', 'wordfence::postSubmitboxStart');
707
  }
708
+ add_filter('plugin_action_links_' . plugin_basename(realpath(dirname(__FILE__) . '/../wordfence.php')), 'wordfence::_pluginPageActionLinks');
709
  }
710
 
711
  add_action('request', 'wordfence::preventAuthorNScans');
727
  }
728
 
729
  add_action('wordfence_processAttackData', 'wordfence::processAttackData');
730
+ if (!empty($_GET['wordfence_syncAttackData']) && get_site_option('wordfence_syncingAttackData') <= time() - 60 && get_site_option('wordfence_lastSyncAttackData', 0) < time() - 4) {
731
  ignore_user_abort(true);
732
  update_site_option('wordfence_syncingAttackData', time());
733
  header('Content-Type: text/javascript');
734
  add_action('init', 'wordfence::syncAttackData', 10, 0);
735
  add_filter('woocommerce_unforce_ssl_checkout', '__return_false');
736
  }
737
+
738
+ add_action('wordfence_batchReportBlockedAttempts', 'wordfence::wfsnBatchReportBlockedAttempts');
739
+ add_action('wordfence_batchReportFailedAttempts', 'wordfence::wfsnBatchReportFailedAttempts');
740
 
741
  if (wfConfig::get('other_hideWPVersion')) {
742
  add_filter('update_feedback', 'wordfence::restoreReadmeForUpgrade');
743
  }
744
 
745
  }
746
+ public static function _pluginPageActionLinks($links) {
747
+ if (!wfConfig::get('isPaid')) {
748
+ $links = array_merge(array('aWordfencePluginCallout' => '<a href="https://www.wordfence.com/zz12/wordfence-signup/" target="_blank"><strong style="color: #FCB214; display: inline;">Upgrade To Premium</strong></a>'), $links);
749
+ }
750
+ return $links;
751
+ }
752
  /*
753
  public static function cronAddSchedules($schedules){
754
  $schedules['wfEachMinute'] = array(
821
  header("Connection: close");
822
  header("Content-Length: 0");
823
  header("X-Robots-Tag: noindex");
824
+ if (!$isCrawler && !wfConfig::get('disableCookies')) {
825
  setcookie('wordfence_verifiedHuman', self::getLog()->getVerifiedHumanCookieValue($UA, wfUtils::getIP()), time() + 86400, '/');
826
  }
827
  }
1043
  header('Location: ' . wp_login_url());
1044
  exit();
1045
  } else if($_GET['func'] == 'unlockAllIPs'){
1046
+ wordfence::status(1, 'info', "Request received via unlock email link to unblock all IPs.");
1047
  $wfLog->unblockAllIPs();
1048
  $wfLog->unlockAllIPs();
1049
  delete_transient('wflginfl_' . bin2hex(wfUtils::inet_pton(wfUtils::getIP()))); //Reset login failure counter
1052
  } else if($_GET['func'] == 'disableRules'){
1053
  wfConfig::set('firewallEnabled', 0);
1054
  wfConfig::set('loginSecurityEnabled', 0);
1055
+ wordfence::status(1, 'info', "Request received via unlock email link to unblock all IPs via disabling firewall rules.");
1056
  $wfLog->unblockAllIPs();
1057
  $wfLog->unlockAllIPs();
1058
  delete_transient('wflginfl_' . bin2hex(wfUtils::inet_pton(wfUtils::getIP()))); //Reset login failure counter
1083
 
1084
  if (empty($_GET['wordfence_syncAttackData'])) {
1085
  $lastAttackMicroseconds = $wpdb->get_var("SELECT MAX(attackLogTime) FROM {$wpdb->base_prefix}wfHits");
1086
+ if (get_site_option('wordfence_lastSyncAttackData', 0) < time() - 4) {
1087
+ if ($waf->getStorageEngine()->hasNewerAttackData($lastAttackMicroseconds)) {
1088
+ if (get_site_option('wordfence_syncingAttackData') <= time() - 60) {
1089
+ // Could be the request to itself is not completing, add ajax to the head as a workaround
1090
+ $attempts = get_site_option('wordfence_syncAttackDataAttempts', 0);
1091
+ if ($attempts > 10) {
1092
+ add_action('wp_head', 'wordfence::addSyncAttackDataAjax');
1093
+ add_action('login_head', 'wordfence::addSyncAttackDataAjax');
1094
+ add_action('admin_head', 'wordfence::addSyncAttackDataAjax');
1095
+ } else {
1096
+ update_site_option('wordfence_syncAttackDataAttempts', ++$attempts);
1097
+ wp_remote_post(add_query_arg('wordfence_syncAttackData', microtime(true), home_url('/')), array(
1098
+ 'timeout' => 0.01,
1099
+ 'blocking' => false,
1100
+ 'sslverify' => apply_filters('https_local_ssl_verify', false)
1101
+ ));
1102
+ }
1103
  }
1104
  }
1105
  }
1615
  if($maxBlockTime = self::wfsnIsBlocked($IP, 'brute')){
1616
  self::getLog()->blockIP($IP, "Blocked by Wordfence Security Network", true, false, $maxBlockTime);
1617
  $secsToGo = wfConfig::get('blockedTime');
1618
+ self::getLog()->getCurrentRequest()->action = 'blocked:wfsnrepeat';
1619
  self::getLog()->do503($secsToGo, "Blocked by Wordfence Security Network");
1620
  }
1621
 
1671
  }
1672
  return $authUser;
1673
  }
1674
+ public static function wfsnBatchReportBlockedAttempts() {
1675
+ $threshold = wfConfig::get('lastBruteForceDataSendTime', 0);;
1676
+
1677
+ $wfdb = new wfDB();
1678
+ global $wpdb;
1679
+ $p = $wpdb->base_prefix;
1680
+ $rawBlocks = $wfdb->querySelect("SELECT SQL_CALC_FOUND_ROWS IP, ctime FROM {$p}wfHits WHERE ctime > %.6f AND action = 'blocked:wfsnrepeat' ORDER BY ctime ASC LIMIT 100", $threshold);
1681
+ $totalRows = $wpdb->get_var('SELECT FOUND_ROWS()');
1682
+ $ipCounts = array();
1683
+ $maxctime = 0;
1684
+ foreach ($rawBlocks as $record) {
1685
+ $maxctime = max($maxctime, $record['ctime']);
1686
+ if (isset($ipCounts[$record['IP']])) {
1687
+ $ipCounts[$record['IP']]++;
1688
+ }
1689
+ else {
1690
+ $ipCounts[$record['IP']] = 1;
1691
+ }
1692
+ }
1693
+
1694
+ $toSend = array();
1695
+ foreach ($ipCounts as $IP => $count) {
1696
+ $toSend[] = array('IP' => base64_encode($IP), 'count' => $count, 'blocked' => 1);
1697
+ }
1698
+
1699
  try {
1700
+ $response = wp_remote_post(WORDFENCE_HACKATTEMPT_URL . 'multipleHackAttempts/?k=' . rawurlencode(wfConfig::get('apiKey')) . '&t=brute', array(
1701
  'timeout' => 1,
1702
  'user-agent' => "Wordfence.com UA " . (defined('WORDFENCE_VERSION') ? WORDFENCE_VERSION : '[Unknown version]'),
1703
+ 'body' => 'IPs=' . rawurlencode(json_encode($toSend)),
1704
  ));
1705
+
1706
+ if (!is_wp_error($response)) {
1707
+ if ($totalRows > 100) {
1708
+ self::wfsnScheduleBatchReportBlockedAttempts();
1709
+ }
1710
+
1711
+ wfConfig::set('lastBruteForceDataSendTime', $maxctime);
1712
  }
1713
+ else {
1714
+ self::wfsnScheduleBatchReportBlockedAttempts();
1715
+ }
1716
+ }
1717
+ catch (Exception $err) {
1718
+ //Do nothing
1719
+ }
1720
+ }
1721
+ private static function wfsnScheduleBatchReportBlockedAttempts($timeToSend = null) {
1722
+ if ($timeToSend === null) {
1723
+ $timeToSend = time() + 30;
1724
+ }
1725
+ $notMainSite = is_multisite() && !is_main_site();
1726
+ if ($notMainSite) {
1727
+ global $current_site;
1728
+ switch_to_blog($current_site->blog_id);
1729
+ }
1730
+ if (!wp_next_scheduled('wordfence_batchReportBlockedAttempts')) {
1731
+ wp_schedule_single_event($timeToSend, 'wordfence_batchReportBlockedAttempts');
1732
+ }
1733
+ if ($notMainSite) {
1734
+ restore_current_blog();
1735
+ }
1736
+ }
1737
+ public static function wfsnReportBlockedAttempt($IP, $type){
1738
+ self::wfsnScheduleBatchReportBlockedAttempts();
1739
+ }
1740
+ public static function wfsnBatchReportFailedAttempts() {
1741
+ $threshold = time();
1742
+
1743
+ $wfdb = new wfDB();
1744
+ global $wpdb;
1745
+ $p = $wpdb->base_prefix;
1746
+ $toSend = $wfdb->querySelect("SELECT id, IP, count, 1 AS failed FROM {$p}wfSNIPCache WHERE count > 0 AND expiration < FROM_UNIXTIME(%d) LIMIT 100", $threshold);
1747
+ $toDelete = array();
1748
+ if (count($toSend)) {
1749
+ foreach ($toSend as &$record) {
1750
+ $toDelete[] = $record['id'];
1751
+ unset($record['id']);
1752
+ $record['IP'] = base64_encode(filter_var($record['IP'], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) ? wfUtils::inet_aton($record['IP']) : wfUtils::inet_pton($record['IP']));
1753
+ }
1754
+ try {
1755
+ $response = wp_remote_post(WORDFENCE_HACKATTEMPT_URL . 'multipleHackAttempts/?k=' . rawurlencode(wfConfig::get('apiKey')) . '&t=brute', array(
1756
+ 'timeout' => 1,
1757
+ 'user-agent' => "Wordfence.com UA " . (defined('WORDFENCE_VERSION') ? WORDFENCE_VERSION : '[Unknown version]'),
1758
+ 'body' => 'IPs=' . rawurlencode(json_encode($toSend)),
1759
+ ));
1760
+
1761
+ if (is_wp_error($response)) {
1762
+ self::wfsnScheduleBatchReportFailedAttempts();
1763
+ return;
1764
+ }
1765
+ }
1766
+ catch (Exception $err) {
1767
+ //Do nothing
1768
+ }
1769
+ }
1770
+ array_unshift($toDelete, $threshold);
1771
+ $wfdb->queryWriteIgnoreError("DELETE FROM {$p}wfSNIPCache WHERE (expiration < FROM_UNIXTIME(%d) AND count = 0)" . (count($toDelete) > 1 ? " OR id IN (" . rtrim(str_repeat('%d, ', count($toDelete) - 1), ', ') . ")" : ""), $toDelete);
1772
+
1773
+ $remainingRows = $wfdb->querySingle("SELECT COUNT(*) FROM {$p}wfSNIPCache");
1774
+ if ($remainingRows > 0) {
1775
+ self::wfsnScheduleBatchReportFailedAttempts();
1776
+ }
1777
+ }
1778
+ private static function wfsnScheduleBatchReportFailedAttempts($timeToSend = null) {
1779
+ if ($timeToSend === null) {
1780
+ $timeToSend = time() + 30;
1781
+ }
1782
+ $notMainSite = is_multisite() && !is_main_site();
1783
+ if ($notMainSite) {
1784
+ global $current_site;
1785
+ switch_to_blog($current_site->blog_id);
1786
+ }
1787
+ if (!wp_next_scheduled('wordfence_batchReportFailedAttempts')) {
1788
+ wp_schedule_single_event($timeToSend, 'wordfence_batchReportFailedAttempts');
1789
+ }
1790
+ if ($notMainSite) {
1791
+ restore_current_blog();
1792
  }
1793
  }
1794
  public static function wfsnIsBlocked($IP, $type){
1795
+ $wfdb = new wfDB();
1796
+ global $wpdb;
1797
+ $p = $wpdb->base_prefix;
1798
+ $cachedRecord = $wfdb->querySingleRec("SELECT id, body FROM {$p}wfSNIPCache WHERE IP = '%s' AND expiration > NOW()", $IP);
1799
+ if (isset($cachedRecord)) {
1800
+ $wfdb->queryWriteIgnoreError("UPDATE {$p}wfSNIPCache SET count = count + 1 WHERE id = %d", $cachedRecord['id']);
1801
+ if (preg_match('/BLOCKED:(\d+)/', $cachedRecord['body'], $matches) && (!self::getLog()->isWhitelisted($IP))) {
1802
+ return $matches[1];
1803
+ }
1804
+ return false;
1805
+ }
1806
+
1807
  try {
1808
  $result = wp_remote_get(WORDFENCE_HACKATTEMPT_URL . 'hackAttempt/?k=' . rawurlencode(wfConfig::get('apiKey')) . '&IP=' . rawurlencode(filter_var($IP, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) ? wfUtils::inet_aton($IP) : wfUtils::inet_pton($IP)) . '&t=' . rawurlencode($type), array(
1809
  'timeout' => 3,
1812
  if (is_wp_error($result)) {
1813
  return false;
1814
  }
1815
+ $wfdb->queryWriteIgnoreError("INSERT INTO {$p}wfSNIPCache (IP, expiration, body) VALUES ('%s', DATE_ADD(NOW(), INTERVAL %d SECOND), '%s')", $IP, 30, $result['body']);
1816
+ self::wfsnScheduleBatchReportFailedAttempts();
1817
  if (preg_match('/BLOCKED:(\d+)/', $result['body'], $matches) && (!self::getLog()->isWhitelisted($IP))) {
1818
  return $matches[1];
1819
  }
2943
  $op = $_POST['op'];
2944
  $wfLog = self::getLog();
2945
  if($op == 'blocked'){
2946
+ wordfence::status(1, 'info', "Ajax request received to unblock All IPs including permanent blocks.");
2947
  $wfLog->unblockAllIPs();
2948
  } else if($op == 'locked'){
2949
  $wfLog->unlockAllIPs();
3362
  }
3363
 
3364
  $htaccess = ABSPATH . '/.htaccess';
3365
+ $change = "<IfModule mod_php5.c>\n\tphp_value display_errors 0\n</IfModule>\n<IfModule mod_php7.c>\n\tphp_value display_errors 0\n</IfModule>";
3366
  $content = "";
3367
  if (file_exists($htaccess)) {
3368
  $content = file_get_contents($htaccess);
3425
  if(preg_match('/\.\./', $file)){
3426
  return array('cerrorMsg' => "An invalid file was specified for repair.");
3427
  }
3428
+ $localFile = rtrim(ABSPATH, '/') . '/' . preg_replace('/^[\.\/]+/', '', $file);
3429
  if ($wp_filesystem->put_contents($localFile, $result['fileContent'])) {
3430
  $wfIssues->updateIssue($issueID, 'delete');
3431
  return array(
4395
  add_submenu_page("Wordfence", "Advanced Blocking", "Advanced Blocking", "activate_plugins", "WordfenceRangeBlocking", 'wordfence::menu_rangeBlocking');
4396
  add_submenu_page("Wordfence", "Options", "Options", "activate_plugins", "WordfenceSecOpt", 'wordfence::menu_options');
4397
  add_submenu_page("Wordfence", "Diagnostics", "Diagnostics", "activate_plugins", "WordfenceDiagnostic", 'wordfence::menu_diagnostic');
4398
+
4399
+ if (wfConfig::get('isPaid')) {
4400
+ add_submenu_page("Wordfence", "Protect More Sites", "<strong id=\"wfMenuCallout\" style=\"color: #FCB214;\">Protect More Sites</strong>", "activate_plugins", "WordfenceProtectMoreSites", 'wordfence::menu_diagnostic');
4401
+ }
4402
+ else {
4403
+ add_submenu_page("Wordfence", "Upgrade To Premium", "<strong id=\"wfMenuCallout\" style=\"color: #FCB214;\">Upgrade To Premium</strong>", "activate_plugins", "WordfenceUpgradeToPremium", 'wordfence::menu_diagnostic');
4404
+ }
4405
+ add_filter('clean_url', 'wordfence::_patchWordfenceSubmenuCallout', 10, 3);
4406
+ }
4407
+ public static function _patchWordfenceSubmenuCallout($url, $original_url, $_context){
4408
+ if (preg_match('/(?:WordfenceUpgradeToPremium)$/i', $url)) {
4409
+ remove_filter('clean_url', 'wordfence::_patchWordfenceSubmenuCallout', 10);
4410
+ return 'https://www.wordfence.com/zz11/wordfence-signup/';
4411
+ }
4412
+ else if (preg_match('/(?:WordfenceProtectMoreSites)$/i', $url)) {
4413
+ remove_filter('clean_url', 'wordfence::_patchWordfenceSubmenuCallout', 10);
4414
+ return 'https://www.wordfence.com/zz10/sign-in/';
4415
+ }
4416
+ return $url;
4417
+ }
4418
+ public static function _retargetWordfenceSubmenuCallout() {
4419
+ echo <<<JQUERY
4420
+ <script type="text/javascript">
4421
+ jQuery(document).ready(function($) {
4422
+ $('#wfMenuCallout').closest('a').attr('target', '_blank');
4423
+ });
4424
+ </script>
4425
+ JQUERY;
4426
+
4427
  }
4428
  public static function menu_options(){
4429
  require 'menu_options.php';
6362
  }
6363
  update_site_option('wordfence_syncingAttackData', 0);
6364
  update_site_option('wordfence_syncAttackDataAttempts', 0);
6365
+ update_site_option('wordfence_lastSyncAttackData', time());
6366
  if ($exit) {
6367
  exit;
6368
  }
lib/wordfenceConstants.php CHANGED
@@ -4,7 +4,7 @@ define('WORDFENCE_API_URL_SEC', 'https://noc1.wordfence.com/');
4
  define('WORDFENCE_API_URL_NONSEC', 'http://noc1.wordfence.com/');
5
  define('WORDFENCE_API_URL_BASE_SEC', WORDFENCE_API_URL_SEC . 'v' . WORDFENCE_API_VERSION . '/');
6
  define('WORDFENCE_API_URL_BASE_NONSEC', WORDFENCE_API_URL_NONSEC . 'v' . WORDFENCE_API_VERSION . '/');
7
- define('WORDFENCE_HACKATTEMPT_URL', 'http://noc3.wordfence.com:9050/');
8
  define('WORDFENCE_MAX_SCAN_TIME', 86400); //Increased this from 10 mins to 1 day because very big scans run for a long time. Users can use kill.
9
  define('WORDFENCE_TRANSIENTS_TIMEOUT', 3600); //how long are items cached in seconds e.g. files downloaded for diffing
10
  define('WORDFENCE_MAX_IPLOC_AGE', 86400); //1 day
4
  define('WORDFENCE_API_URL_NONSEC', 'http://noc1.wordfence.com/');
5
  define('WORDFENCE_API_URL_BASE_SEC', WORDFENCE_API_URL_SEC . 'v' . WORDFENCE_API_VERSION . '/');
6
  define('WORDFENCE_API_URL_BASE_NONSEC', WORDFENCE_API_URL_NONSEC . 'v' . WORDFENCE_API_VERSION . '/');
7
+ define('WORDFENCE_HACKATTEMPT_URL', 'http://noc3.wordfence.com/');
8
  define('WORDFENCE_MAX_SCAN_TIME', 86400); //Increased this from 10 mins to 1 day because very big scans run for a long time. Users can use kill.
9
  define('WORDFENCE_TRANSIENTS_TIMEOUT', 3600); //how long are items cached in seconds e.g. files downloaded for diffing
10
  define('WORDFENCE_MAX_IPLOC_AGE', 86400); //1 day
lib/wordfenceHash.php CHANGED
@@ -10,8 +10,6 @@ class wordfenceHash {
10
  public $totalFiles = 0;
11
  public $totalDirs = 0;
12
  public $totalData = 0; //To do a sanity check, don't use 'du' because it gets sparse files wrong and reports blocks used on disk. Use : find . -type f -ls | awk '{total += $7} END {print total}'
13
- public $linesOfPHP = 0;
14
- public $linesOfJCH = 0; //lines of HTML, CSS and javascript
15
  public $stoppedOnFile = false;
16
  private $coreEnabled = false;
17
  private $pluginsEnabled = false;
@@ -27,6 +25,7 @@ class wordfenceHash {
27
  private $only = false;
28
  private $totalForks = 0;
29
  private $alertedOnUnknownWordPressVersion = false;
 
30
 
31
  /**
32
  * @param string $striplen
@@ -113,7 +112,7 @@ class wordfenceHash {
113
  if($this->coreUnknownEnabled){ $this->status['coreUnknown'] = wordfence::statusStart("Scanning for unknown files in wp-admin and wp-includes"); } else { wordfence::statusDisabled("Skipping unknown core file scan"); }
114
  }
115
  public function __sleep(){
116
- return array('striplen', 'totalFiles', 'totalDirs', 'totalData', 'linesOfPHP', 'linesOfJCH', 'stoppedOnFile', 'coreEnabled', 'pluginsEnabled', 'themesEnabled', 'malwareEnabled', 'coreUnknownEnabled', 'knownFiles', 'malwareData', 'haveIssues', 'status', 'possibleMalware', 'path', 'only', 'totalForks', 'alertedOnUnknownWordPressVersion');
117
  }
118
  public function __wakeup(){
119
  $this->db = new wfDB();
@@ -178,6 +177,8 @@ class wordfenceHash {
178
  return;
179
  }
180
  if(! is_readable($path)){ return; } //Applies to files and dirs
 
 
181
  if(is_dir($path)){
182
  $this->totalDirs++;
183
  if($path[strlen($path) - 1] != '/'){
@@ -188,38 +189,59 @@ class wordfenceHash {
188
  if($cont[$i] == '.' || $cont[$i] == '..'){ continue; }
189
  $file = $path . $cont[$i];
190
  if(is_file($file)){
 
191
  $this->processFile($file);
192
  } else if(is_dir($file)) {
193
  $this->_dirHash($file);
194
  }
195
  }
 
 
 
196
  } else {
197
  if(is_file($path)){
198
  $this->processFile($path);
199
  }
200
  }
201
  }
202
- private function processFile($realFile){
203
- $file = substr($realFile, $this->striplen);
204
- if( (! $this->stoppedOnFile) && microtime(true) - $this->startTime > $this->engine->maxExecTime){ //max X seconds but don't allow fork if we're looking for the file we stopped on. Search mode is VERY fast.
205
  $this->stoppedOnFile = $file;
206
  wordfence::status(4, 'info', "Calling fork() from wordfenceHash::processFile with maxExecTime: " . $this->engine->maxExecTime);
207
  $this->engine->fork();
208
  //exits
209
  }
210
-
211
- $exclude = wordfenceScanner::getExcludeFilePattern(wordfenceScanner::EXCLUSION_PATTERNS_USER);
212
- if ($exclude && preg_match($exclude, $realFile)) {
213
- return;
214
- }
215
-
216
  //Put this after the fork, that way we will at least scan one more file after we fork if it takes us more than 10 seconds to search for the stoppedOnFile
217
- if($this->stoppedOnFile && $file != $this->stoppedOnFile){
218
  return;
219
- } else if($this->stoppedOnFile && $file == $this->stoppedOnFile){
 
220
  $this->stoppedOnFile = false; //Continue scanning
221
  }
222
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
223
  if(wfUtils::fileTooBig($realFile)){
224
  wordfence::status(4, 'info', "Skipping file larger than max size: $realFile");
225
  return;
@@ -229,6 +251,7 @@ class wordfenceHash {
229
  } else {
230
  wordfence::status(4, 'info', "Scanning: $realFile");
231
  }
 
232
  wfUtils::beginProcessingFile($file);
233
  $wfHash = self::wfHash($realFile);
234
  if($wfHash){
@@ -402,12 +425,6 @@ class wordfenceHash {
402
  // But because we want to scan files who's sig we don't recognize, regardless of known path or not, we only need one "knownFile" field.
403
  $this->db->queryWrite("insert into " . $this->db->prefix() . "wfFileMods (filename, filenameMD5, knownFile, oldMD5, newMD5) values ('%s', unhex(md5('%s')), %d, '', unhex('%s')) ON DUPLICATE KEY UPDATE newMD5=unhex('%s'), knownFile=%d", $file, $file, $knownFile, $md5, $md5, $knownFile);
404
 
405
- //Now that we know we can open the file, lets update stats
406
- if(preg_match('/\.(?:js|html|htm|css)$/i', $realFile)){
407
- $this->linesOfJCH += sizeof(file($realFile));
408
- } else if(preg_match('/\.php$/i', $realFile)){
409
- $this->linesOfPHP += sizeof(file($realFile));
410
- }
411
  $this->totalFiles++;
412
  $this->totalData += filesize($realFile); //We already checked if file overflows int in the fileTooBig routine above
413
  if($this->totalFiles % 100 === 0){
@@ -419,22 +436,85 @@ class wordfenceHash {
419
  wfUtils::endProcessingFile();
420
  }
421
  public static function wfHash($file){
422
- wfUtils::errorsOff();
423
- $md5 = @md5_file($file, false);
424
- wfUtils::errorsOn();
425
-
426
- if(! $md5){ return false; }
427
  $fp = @fopen($file, "rb");
428
- if(! $fp){
429
  return false;
430
  }
431
- $ctx = hash_init('sha256');
 
432
  while (!feof($fp)) {
433
- hash_update($ctx, str_replace( array("\n","\r","\t"," ") ,"",fread($fp, 65536)));
 
 
 
 
 
434
  }
435
- $shac = hash_final($ctx, false);
 
436
  return array($md5, $shac);
437
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
438
  private function isMalwarePrefix($hexMD5){
439
  $binPrefix = pack("H*", substr($hexMD5, 0, 8));
440
  if(isset($this->malwareData[$binPrefix])){
10
  public $totalFiles = 0;
11
  public $totalDirs = 0;
12
  public $totalData = 0; //To do a sanity check, don't use 'du' because it gets sparse files wrong and reports blocks used on disk. Use : find . -type f -ls | awk '{total += $7} END {print total}'
 
 
13
  public $stoppedOnFile = false;
14
  private $coreEnabled = false;
15
  private $pluginsEnabled = false;
25
  private $only = false;
26
  private $totalForks = 0;
27
  private $alertedOnUnknownWordPressVersion = false;
28
+ private $foldersProcessed = array();
29
 
30
  /**
31
  * @param string $striplen
112
  if($this->coreUnknownEnabled){ $this->status['coreUnknown'] = wordfence::statusStart("Scanning for unknown files in wp-admin and wp-includes"); } else { wordfence::statusDisabled("Skipping unknown core file scan"); }
113
  }
114
  public function __sleep(){
115
+ return array('striplen', 'totalFiles', 'totalDirs', 'totalData', 'stoppedOnFile', 'coreEnabled', 'pluginsEnabled', 'themesEnabled', 'malwareEnabled', 'coreUnknownEnabled', 'knownFiles', 'malwareData', 'haveIssues', 'status', 'possibleMalware', 'path', 'only', 'totalForks', 'alertedOnUnknownWordPressVersion', 'foldersProcessed');
116
  }
117
  public function __wakeup(){
118
  $this->db = new wfDB();
177
  return;
178
  }
179
  if(! is_readable($path)){ return; } //Applies to files and dirs
180
+ if (!$this->_shouldProcessPath($path)) { return; }
181
+ $this->_checkForTimeout($path);
182
  if(is_dir($path)){
183
  $this->totalDirs++;
184
  if($path[strlen($path) - 1] != '/'){
189
  if($cont[$i] == '.' || $cont[$i] == '..'){ continue; }
190
  $file = $path . $cont[$i];
191
  if(is_file($file)){
192
+ $this->_checkForTimeout($file);
193
  $this->processFile($file);
194
  } else if(is_dir($file)) {
195
  $this->_dirHash($file);
196
  }
197
  }
198
+
199
+ $realPath = realpath($path);
200
+ $this->foldersProcessed[$realPath] = 1;
201
  } else {
202
  if(is_file($path)){
203
  $this->processFile($path);
204
  }
205
  }
206
  }
207
+ private function _checkForTimeout($path) {
208
+ $file = substr($path, $this->striplen);
209
+ if ((!$this->stoppedOnFile) && microtime(true) - $this->startTime > $this->engine->maxExecTime) { //max X seconds but don't allow fork if we're looking for the file we stopped on. Search mode is VERY fast.
210
  $this->stoppedOnFile = $file;
211
  wordfence::status(4, 'info', "Calling fork() from wordfenceHash::processFile with maxExecTime: " . $this->engine->maxExecTime);
212
  $this->engine->fork();
213
  //exits
214
  }
215
+
 
 
 
 
 
216
  //Put this after the fork, that way we will at least scan one more file after we fork if it takes us more than 10 seconds to search for the stoppedOnFile
217
+ if ($this->stoppedOnFile && $file != $this->stoppedOnFile) {
218
  return;
219
+ }
220
+ else if ($this->stoppedOnFile && $file == $this->stoppedOnFile) {
221
  $this->stoppedOnFile = false; //Continue scanning
222
  }
223
+ }
224
+ private function _shouldProcessPath($path) {
225
+ $file = substr($path, $this->striplen);
226
+ $exclude = wordfenceScanner::getExcludeFilePattern(wordfenceScanner::EXCLUSION_PATTERNS_USER);
227
+ if ($exclude && preg_match($exclude, $file)) {
228
+ return false;
229
+ }
230
+
231
+ $realPath = realpath($path);
232
+ if (isset($this->foldersProcessed[$realPath])) {
233
+ return false;
234
+ }
235
+
236
+ return true;
237
+ }
238
+ private function processFile($realFile){
239
+ $file = substr($realFile, $this->striplen);
240
+ if (!$this->_shouldHashFile($realFile)) {
241
+ wordfence::status(4, 'info', "Skipping unneeded hash: {$realFile}");
242
+ return;
243
+ }
244
+
245
  if(wfUtils::fileTooBig($realFile)){
246
  wordfence::status(4, 'info', "Skipping file larger than max size: $realFile");
247
  return;
251
  } else {
252
  wordfence::status(4, 'info', "Scanning: $realFile");
253
  }
254
+
255
  wfUtils::beginProcessingFile($file);
256
  $wfHash = self::wfHash($realFile);
257
  if($wfHash){
425
  // But because we want to scan files who's sig we don't recognize, regardless of known path or not, we only need one "knownFile" field.
426
  $this->db->queryWrite("insert into " . $this->db->prefix() . "wfFileMods (filename, filenameMD5, knownFile, oldMD5, newMD5) values ('%s', unhex(md5('%s')), %d, '', unhex('%s')) ON DUPLICATE KEY UPDATE newMD5=unhex('%s'), knownFile=%d", $file, $file, $knownFile, $md5, $md5, $knownFile);
427
 
 
 
 
 
 
 
428
  $this->totalFiles++;
429
  $this->totalData += filesize($realFile); //We already checked if file overflows int in the fileTooBig routine above
430
  if($this->totalFiles % 100 === 0){
436
  wfUtils::endProcessingFile();
437
  }
438
  public static function wfHash($file){
 
 
 
 
 
439
  $fp = @fopen($file, "rb");
440
+ if (!$fp) {
441
  return false;
442
  }
443
+ $md5Context = hash_init('md5');
444
+ $sha256Context = hash_init('sha256');
445
  while (!feof($fp)) {
446
+ $data = fread($fp, 65536);
447
+ if ($data === false) {
448
+ return false;
449
+ }
450
+ hash_update($md5Context, $data);
451
+ hash_update($sha256Context, str_replace(array("\n","\r","\t"," "),"", $data));
452
  }
453
+ $md5 = hash_final($md5Context, false);
454
+ $shac = hash_final($sha256Context, false);
455
  return array($md5, $shac);
456
  }
457
+ private function _shouldHashFile($fullPath) {
458
+ $file = substr($fullPath, $this->striplen);
459
+
460
+ //Core File, return true
461
+ if ((isset($this->knownFiles['core']) && isset($this->knownFiles['core'][$file])) ||
462
+ (isset($this->knownFiles['plugins']) && isset($this->knownFiles['plugins'][$file])) ||
463
+ (isset($this->knownFiles['themes']) && isset($this->knownFiles['themes'][$file]))) {
464
+ return true;
465
+ }
466
+
467
+ //Excluded file, return false
468
+ $excludePattern = wordfenceScanner::getExcludeFilePattern(wordfenceScanner::EXCLUSION_PATTERNS_USER & wordfenceScanner::EXCLUSION_PATTERNS_MALWARE);
469
+ if ($excludePattern && preg_match($excludePattern, $file)) {
470
+ return false;
471
+ }
472
+
473
+ //Determine treatment
474
+ $fileExt = '';
475
+ if (preg_match('/\.([a-zA-Z\d\-]{1,7})$/', $file, $matches)) {
476
+ $fileExt = strtolower($matches[1]);
477
+ }
478
+ $isPHP = false;
479
+ if (preg_match('/\.(?:php(?:\d+)?|phtml)(\.|$)/i', $file)) {
480
+ $isPHP = true;
481
+ }
482
+ $isHTML = false;
483
+ if (preg_match('/\.(?:html?)(\.|$)/i', $file)) {
484
+ $isHTML = true;
485
+ }
486
+ $isJS = false;
487
+ if (preg_match('/\.(?:js)(\.|$)/i', $file)) {
488
+ $isJS = true;
489
+ }
490
+
491
+ //If scan images is disabled, only allow .js through
492
+ if (!$isPHP && preg_match('/^(?:jpg|jpeg|mp3|avi|m4v|mov|mp4|gif|png|tiff?|svg|sql|js|tbz2?|bz2?|xz|zip|tgz|gz|tar|log|err\d+)$/', $fileExt)) {
493
+ if (!wfConfig::get('scansEnabled_scanImages') && !$isJS) {
494
+ return false;
495
+ }
496
+ }
497
+
498
+ //If high sensitivity is disabled, don't allow .sql
499
+ if (strtolower($fileExt) == 'sql') {
500
+ if (!wfConfig::get('scansEnabled_highSense')) {
501
+ return false;
502
+ }
503
+ }
504
+
505
+ //Treating as binary, return true
506
+ $treatAsBinary = ($isPHP || $isHTML || wfConfig::get('scansEnabled_scanImages'));
507
+ if ($treatAsBinary) {
508
+ return true;
509
+ }
510
+
511
+ //Will be malware scanned, return true
512
+ if (strpos($file, 'lib/wordfenceScanner.php') === false && ($fileExt == 'js')) {
513
+ return true;
514
+ }
515
+
516
+ return false;
517
+ }
518
  private function isMalwarePrefix($hexMD5){
519
  $binPrefix = pack("H*", substr($hexMD5, 0, 8));
520
  if(isset($this->malwareData[$binPrefix])){
lib/wordfenceScanner.php CHANGED
@@ -75,7 +75,9 @@ class wordfenceScanner {
75
  throw new Exception("Wordfence could not get the attack signature patterns from the scanning server.");
76
  }
77
 
78
- try { wfWAF::getInstance()->setMalwareSignatures(array()); } catch (Exception $e) { /* Ignore */ }
 
 
79
 
80
  if (is_array($sigData['rules'])) {
81
  $wafPatterns = array();
@@ -91,7 +93,9 @@ class wordfenceScanner {
91
  }
92
  }
93
 
94
- try { wfWAF::getInstance()->setMalwareSignatures($wafPatterns); } catch (Exception $e) { /* Ignore */ }
 
 
95
  }
96
 
97
  $extra = wfConfig::get('scan_include_extra');
@@ -192,10 +196,7 @@ class wordfenceScanner {
192
  continue;
193
  }
194
  $fileSum = $rec1['newMD5'];
195
-
196
- if(! file_exists($this->path . $file)){
197
- continue;
198
- }
199
  $fileExt = '';
200
  if(preg_match('/\.([a-zA-Z\d\-]{1,7})$/', $file, $matches)){
201
  $fileExt = strtolower($matches[1]);
@@ -318,7 +319,7 @@ class wordfenceScanner {
318
  'ignoreP' => $this->path . $file,
319
  'ignoreC' => $fileSum,
320
  'shortMsg' => "File appears to be malicious: " . esc_html($file),
321
- 'longMsg' => "This file appears to be installed 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;\">\"" . esc_html((strlen($matchString) > 200 ? substr($matchString, 0, 200) . '...' : $matchString)) . "\"</strong>. The infection type is: <strong>" . esc_html($rule[3]) . '</strong>' . $extraMsg,
322
  'data' => array_merge(array(
323
  'file' => $file,
324
  ), $dataForFile),
75
  throw new Exception("Wordfence could not get the attack signature patterns from the scanning server.");
76
  }
77
 
78
+ if (wfWAF::getInstance() && method_exists(wfWAF::getInstance(), 'setMalwareSignatures')) {
79
+ try { wfWAF::getInstance()->setMalwareSignatures(array()); } catch (Exception $e) { /* Ignore */ }
80
+ }
81
 
82
  if (is_array($sigData['rules'])) {
83
  $wafPatterns = array();
93
  }
94
  }
95
 
96
+ if (wfWAF::getInstance() && method_exists(wfWAF::getInstance(), 'setMalwareSignatures')) {
97
+ try { wfWAF::getInstance()->setMalwareSignatures($wafPatterns); } catch (Exception $e) { /* Ignore */ }
98
+ }
99
  }
100
 
101
  $extra = wfConfig::get('scan_include_extra');
196
  continue;
197
  }
198
  $fileSum = $rec1['newMD5'];
199
+
 
 
 
200
  $fileExt = '';
201
  if(preg_match('/\.([a-zA-Z\d\-]{1,7})$/', $file, $matches)){
202
  $fileExt = strtolower($matches[1]);
319
  'ignoreP' => $this->path . $file,
320
  'ignoreC' => $fileSum,
321
  'shortMsg' => "File appears to be malicious: " . esc_html($file),
322
+ 'longMsg' => "This file appears to be installed 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;\">\"" . esc_html((strlen($matchString) > 200 ? substr($matchString, 0, 200) . '...' : $matchString)) . "\"</strong>. The infection type is: <strong>" . esc_html($rule[3]) . '</strong>.' . $extraMsg,
323
  'data' => array_merge(array(
324
  'file' => $file,
325
  ), $dataForFile),
readme.txt CHANGED
@@ -3,9 +3,9 @@ Contributors: mmaunder
3
  Tags: security, secure, security plugin, wordpress security, login security, firewall, malware, antivirus, web application firewall, block hackers, country blocking, block hackers
4
  Requires at least: 3.9
5
  Tested up to: 4.6.1
6
- Stable tag: 6.1.17
7
 
8
- Secure your website with the Wordfence security plugin for WordPress. Wordfence provides free enterprise-class WordPress security, protecting your website from hacks and malware.
9
 
10
  == Description ==
11
  = THE MOST DOWNLOADED WORDPRESS SECURITY PLUGIN =
@@ -52,9 +52,6 @@ Wordfence Security is now Multi-Site compatible and includes Cellphone Sign-in w
52
  * Continuously scans for malware and phishing URL's including all URL's on the Google Safe Browsing List in all your comments, posts and files that are security threats.
53
  * Scans for heuristics of backdoors, trojans, suspicious code and other security issues.
54
 
55
- = WordPress Firewall =
56
- * Includes a firewall to block common security threats like fake Googlebots, malicious scans from hackers and botnets.
57
-
58
  = Monitoring Features =
59
  * See all your traffic in real-time, including robots, humans, 404 errors, logins and logouts and who is consuming most of your content. Enhances your situational awareness of which security threats your site is facing.
60
  * A real-time view of all traffic including automated bots that often constitute security threats that Javascript analytics packages never show you.
@@ -200,6 +197,20 @@ Secure your website with Wordfence.
200
 
201
  == Changelog ==
202
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
203
  = 6.1.17 =
204
  * Fix: Replaced calls to json_decode with our own implentation for hosts without the JSON extension enabled.
205
 
3
  Tags: security, secure, security plugin, wordpress security, login security, firewall, malware, antivirus, web application firewall, block hackers, country blocking, block hackers
4
  Requires at least: 3.9
5
  Tested up to: 4.6.1
6
+ Stable tag: 6.2.0
7
 
8
+ Secure your website with the most comprehensive WordPress security plugin. Firewall, malware scanner, blocking, live traffic, login security & more.
9
 
10
  == Description ==
11
  = THE MOST DOWNLOADED WORDPRESS SECURITY PLUGIN =
52
  * Continuously scans for malware and phishing URL's including all URL's on the Google Safe Browsing List in all your comments, posts and files that are security threats.
53
  * Scans for heuristics of backdoors, trojans, suspicious code and other security issues.
54
 
 
 
 
55
  = Monitoring Features =
56
  * See all your traffic in real-time, including robots, humans, 404 errors, logins and logouts and who is consuming most of your content. Enhances your situational awareness of which security threats your site is facing.
57
  * A real-time view of all traffic including automated bots that often constitute security threats that Javascript analytics packages never show you.
197
 
198
  == Changelog ==
199
 
200
+ = 6.2.0 =
201
+ * Improvement: Massive performance boost in file system scan.
202
+ * Improvement: Added low resource usage scan option for shared hosts.
203
+ * Improvement: Aggregated login attempts when checking the Wordfence Security Network for brute force attackers to reduce total requests.
204
+ * Improvement: Now displaying scan time in a more readable format rather than total seconds.
205
+ * Improvement: Added PHP7 compatible .htaccess directives to disable code execution within uploads directory.
206
+ * Fix: Added throttling to sync the WAF attack data.
207
+ * Fix: Removed unnecessary single quote in copy containing "IP's".
208
+ * Fix: Fixed rare, edge case where cron key does not match the key in the database.
209
+ * Fix: Fixed bug with regex matching carriage returns in the .htaccess based IP block list.
210
+ * Fix: Fixed scans failing in subdirectory sites when updating malware signatures.
211
+ * Fix: Fixed infinite loop in scan caused by symlinks.
212
+ * Fix: Remove extra slash from "File restored OK" message in scan results.
213
+
214
  = 6.1.17 =
215
  * Fix: Replaced calls to json_decode with our own implentation for hosts without the JSON extension enabled.
216
 
views/marketing/rightrail.php ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php if (!wfConfig::get('isPaid')) { ?>
2
+ <div class="wordfenceRightRail<?php if (isset($additionalClasses)) { echo " {$additionalClasses}"; } ?>">
3
+ <ul>
4
+ <li><a href="https://www.wordfence.com/gnl1rightRailGetPremium/wordfence-signup/" target="_blank"><img src="<?php echo wfUtils::getBaseURL() . 'images/rr_premium.png'; ?>" alt="Upgrade your protection - Get Wordfence Premium"></a></li>
5
+ <li><a href="https://www.wordfence.com/gnl1rightRailSiteCleaning/wordfence-site-cleanings/" target="_blank"><img src="<?php echo wfUtils::getBaseURL() . 'images/rr_sitecleaning.jpg'; ?>" alt="Have you been hacked? Get help from Wordfence"></a></li>
6
+ <li>
7
+ <p class="center"><strong>Would you like to remove these ads?</strong><br><a href="https://www.wordfence.com/gnl1rightRailBottomUpgrade/wordfence-signup/" target="_blank">Get Premium</a></p>
8
+ </li>
9
+ </ul>
10
+ </div>
11
+ <?php } ?>
views/reports/activity-report-email-inline.php CHANGED
@@ -126,7 +126,7 @@ h6 a:visited { color: purple !important; }
126
  </p>
127
 
128
  <h2 style="font-size: 20px; vertical-align: baseline; clear: both; color: #222 !important; margin: 20px 0 4px; padding: 0; border: 0;">
129
- Top 10 IP's Blocked
130
  </h2>
131
 
132
  <?php wfHelperString::cycle(); ?>
126
  </p>
127
 
128
  <h2 style="font-size: 20px; vertical-align: baseline; clear: both; color: #222 !important; margin: 20px 0 4px; padding: 0; border: 0;">
129
+ Top 10 IPs Blocked
130
  </h2>
131
 
132
  <?php wfHelperString::cycle(); ?>
views/reports/activity-report-email.php CHANGED
@@ -297,7 +297,7 @@ $title = 'Wordfence Activity for the week of ' . date_i18n(get_option('date_form
297
  </div>
298
  <a href="http://www.wordfence.com/zz7/"><img src="<?php echo wfUtils::getBaseURL(); ?>images/logo.png" alt=""/></a>
299
 
300
- <h2>Top 10 IP's Blocked</h2>
301
 
302
  <?php wfHelperString::cycle(); ?>
303
 
297
  </div>
298
  <a href="http://www.wordfence.com/zz7/"><img src="<?php echo wfUtils::getBaseURL(); ?>images/logo.png" alt=""/></a>
299
 
300
+ <h2>Top 10 IPs Blocked</h2>
301
 
302
  <?php wfHelperString::cycle(); ?>
303
 
views/reports/activity-report.php CHANGED
@@ -5,7 +5,7 @@
5
  ?>
6
  <a class="wf-logo" href="//www.wordfence.com/zz8/"><img src="<?php echo wfUtils::getBaseURL(); ?>images/logo.png" alt=""/></a>
7
 
8
- <h2>Top <?php echo (int) $limit; ?> IP's Blocked</h2>
9
 
10
  <?php wfHelperString::cycle(); ?>
11
 
5
  ?>
6
  <a class="wf-logo" href="//www.wordfence.com/zz8/"><img src="<?php echo wfUtils::getBaseURL(); ?>images/logo.png" alt=""/></a>
7
 
8
+ <h2>Top <?php echo (int) $limit; ?> IPs Blocked</h2>
9
 
10
  <?php wfHelperString::cycle(); ?>
11
 
wordfence.php CHANGED
@@ -4,14 +4,14 @@ Plugin Name: Wordfence Security
4
  Plugin URI: http://www.wordfence.com/
5
  Description: Wordfence Security - Anti-virus, Firewall and High Speed Cache
6
  Author: Wordfence
7
- Version: 6.1.17
8
  Author URI: http://www.wordfence.com/
9
  Network: true
10
  */
11
  if(defined('WP_INSTALLING') && WP_INSTALLING){
12
  return;
13
  }
14
- define('WORDFENCE_VERSION', '6.1.17');
15
  define('WORDFENCE_BASENAME', function_exists('plugin_basename') ? plugin_basename(__FILE__) :
16
  basename(dirname(__FILE__)) . '/' . basename(__FILE__));
17
 
4
  Plugin URI: http://www.wordfence.com/
5
  Description: Wordfence Security - Anti-virus, Firewall and High Speed Cache
6
  Author: Wordfence
7
+ Version: 6.2.0
8
  Author URI: http://www.wordfence.com/
9
  Network: true
10
  */
11
  if(defined('WP_INSTALLING') && WP_INSTALLING){
12
  return;
13
  }
14
+ define('WORDFENCE_VERSION', '6.2.0');
15
  define('WORDFENCE_BASENAME', function_exists('plugin_basename') ? plugin_basename(__FILE__) :
16
  basename(dirname(__FILE__)) . '/' . basename(__FILE__));
17