Wordfence Security – Firewall & Malware Scan - Version 3.2.1

Version Description

  • Theme and plugin scanning is now free. Woohoo!
  • Added introductory tour for Wordfence.
  • Upgraded to Wordfence scanning API version 2.0 to allow free theme and plugin scanning.
  • Fixed two issue with scheduled scanning for premium users that would cause scans to not run or run at wrong times under certain conditions.
  • Added feature to view unknown files on system to help clean badly infected systems. See on scanning page in "Tools" under yellow box.
  • Fixed blocked countries overflowing their container in the user interface.
  • Fixed case where if user is using MySQL >
Download this release

Release Info

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

Code changes from version 3.1.6 to 3.2.1

css/main.css CHANGED
@@ -85,6 +85,7 @@ div.wordfenceScanButton input.button-wf-grey {
85
  background: #EFEFEF url(../images/button-grad-grey.png) repeat-x scroll left top;
86
  border-color: #EFEFEF;
87
  }
 
88
 
89
  .wfTabsContainer {
90
  overflow: hidden;
@@ -300,3 +301,8 @@ input.wfStartScanButton { width: 160px; text-align: left; padding-left: 20px; }
300
  text-align: center;
301
  -webkit-font-smoothing: antialiased;
302
  }
 
 
 
 
 
85
  background: #EFEFEF url(../images/button-grad-grey.png) repeat-x scroll left top;
86
  border-color: #EFEFEF;
87
  }
88
+ .wordfenceScanButton table td { vertical-align: top; }
89
 
90
  .wfTabsContainer {
91
  overflow: hidden;
301
  text-align: center;
302
  -webkit-font-smoothing: antialiased;
303
  }
304
+ .wfMarker {
305
+ height: 1px;
306
+ width: 1px;
307
+ }
308
+
js/admin.js CHANGED
@@ -30,9 +30,11 @@ window['wordfenceAdmin'] = {
30
  blockedCountriesPending: [],
31
  ownCountry: "",
32
  schedStartHour: false,
 
33
  init: function(){
34
  this.nonce = WordfenceAdminVars.firstNonce;
35
  this.debugOn = WordfenceAdminVars.debugOn == '1' ? true : false;
 
36
  var startTicker = false;
37
  if(jQuery('#wordfenceMode_scan').length > 0){
38
  this.mode = 'scan';
@@ -42,28 +44,61 @@ window['wordfenceAdmin'] = {
42
  this.noScanHTML = jQuery('#wfNoScanYetTmpl').tmpl().html();
43
  this.loadIssues();
44
  this.startActivityLogUpdates();
 
 
 
45
  } else if(jQuery('#wordfenceMode_activity').length > 0){
46
  this.mode = 'activity';
47
  this.activityMode = 'hit';
48
  startTicker = true;
 
 
 
 
49
  } else if(jQuery('#wordfenceMode_options').length > 0){
50
  this.mode = 'options';
51
  jQuery('.wfConfigElem').change(function(){ jQuery('#securityLevel').val('CUSTOM'); });
52
  this.updateTicker(true);
53
  startTicker = true;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
  } else if(jQuery('#wordfenceMode_blockedIPs').length > 0){
55
  this.mode = 'blocked';
56
  this.staticTabChanged();
57
  this.updateTicker(true);
58
  startTicker = true;
 
 
 
 
59
  } else if(jQuery('#wordfenceMode_countryBlocking').length > 0){
60
  this.mode = 'countryBlocking';
61
  startTicker = false;
62
  this.drawBlockedCountries();
 
 
 
 
63
  } else if(jQuery('#wordfenceMode_scanScheduling').length > 0){
64
  this.mode = 'scanScheduling';
65
  startTicker = false;
66
  this.sched_modeChange();
 
 
 
 
67
  } else {
68
  this.mode = false;
69
  }
@@ -75,6 +110,58 @@ window['wordfenceAdmin'] = {
75
  jQuery(document).bind('cbox_closed', function(){ self.colorboxIsOpen = false; self.colorboxServiceQueue(); });
76
  }
77
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
  showLoading: function(){
79
  this.removeLoading();
80
  jQuery('<div id="wordfenceWorking">Wordfence is working...</div>').appendTo('body');
@@ -1024,6 +1111,7 @@ window['wordfenceAdmin'] = {
1024
  schedMode: schedMode,
1025
  schedTxt: scheduleTxt
1026
  }, function(res){
 
1027
  jQuery('.wfAjax24').hide();
1028
  self.pulse('.wfSaveMsg');
1029
  });
30
  blockedCountriesPending: [],
31
  ownCountry: "",
32
  schedStartHour: false,
33
+ currentPointer: false,
34
  init: function(){
35
  this.nonce = WordfenceAdminVars.firstNonce;
36
  this.debugOn = WordfenceAdminVars.debugOn == '1' ? true : false;
37
+ this.tourClosed = WordfenceAdminVars.tourClosed == '1' ? true : false;
38
  var startTicker = false;
39
  if(jQuery('#wordfenceMode_scan').length > 0){
40
  this.mode = 'scan';
44
  this.noScanHTML = jQuery('#wfNoScanYetTmpl').tmpl().html();
45
  this.loadIssues();
46
  this.startActivityLogUpdates();
47
+ if(! this.tourClosed){
48
+ this.scanTourStart();
49
+ }
50
  } else if(jQuery('#wordfenceMode_activity').length > 0){
51
  this.mode = 'activity';
52
  this.activityMode = 'hit';
53
  startTicker = true;
54
+ if(! this.tourClosed){
55
+ var self = this;
56
+ this.tour('wfWelcomeContent3', 'wfHeading', 'top', 'left', "Learn about IP Blocking", function(){ self.tourRedir('WordfenceBlockedIPs'); });
57
+ }
58
  } else if(jQuery('#wordfenceMode_options').length > 0){
59
  this.mode = 'options';
60
  jQuery('.wfConfigElem').change(function(){ jQuery('#securityLevel').val('CUSTOM'); });
61
  this.updateTicker(true);
62
  startTicker = true;
63
+ if(! this.tourClosed){
64
+ var self = this;
65
+ this.tour('wfContentBasicOptions', 'wfMarkerBasicOptions', 'top', 'left', "Learn about Live Traffic Options", function(){
66
+ self.tour('wfContentLiveTrafficOptions', 'wfMarkerLiveTrafficOptions', 'bottom', 'left', "Learn about Scanning Options", function(){
67
+ self.tour('wfContentScansToInclude', 'wfMarkerScansToInclude', 'bottom', 'left', "Learn about Firewall Rules", function(){
68
+ self.tour('wfContentFirewallRules', 'wfMarkerFirewallRules', 'bottom', 'left', "Learn about Login Security", function(){
69
+ self.tour('wfContentLoginSecurity', 'wfMarkerLoginSecurity', 'bottom', 'left', "Learn about Other Options", function(){
70
+ self.tour('wfContentOtherOptions', 'wfMarkerOtherOptions', 'bottom', 'left', false, false);
71
+ });
72
+ });
73
+ });
74
+ });
75
+ });
76
+ }
77
  } else if(jQuery('#wordfenceMode_blockedIPs').length > 0){
78
  this.mode = 'blocked';
79
  this.staticTabChanged();
80
  this.updateTicker(true);
81
  startTicker = true;
82
+ if(! this.tourClosed){
83
+ var self = this;
84
+ this.tour('wfWelcomeContent4', 'wfHeading', 'top', 'left', "Learn how to Block Countries", function(){ self.tourRedir('WordfenceCountryBlocking'); });
85
+ }
86
  } else if(jQuery('#wordfenceMode_countryBlocking').length > 0){
87
  this.mode = 'countryBlocking';
88
  startTicker = false;
89
  this.drawBlockedCountries();
90
+ if(! this.tourClosed){
91
+ var self = this;
92
+ this.tour('wfWelcomeContentCntBlk', 'wfHeading', 'top', 'left', "Learn how to Schedule Scans", function(){ self.tourRedir('WordfenceScanSchedule'); });
93
+ }
94
  } else if(jQuery('#wordfenceMode_scanScheduling').length > 0){
95
  this.mode = 'scanScheduling';
96
  startTicker = false;
97
  this.sched_modeChange();
98
+ if(! this.tourClosed){
99
+ var self = this;
100
+ this.tour('wfWelcomeContentScanSched', 'wfHeading', 'top', 'left', "Learn how to Customize Wordfence", function(){ self.tourRedir('WordfenceSecOpt'); });
101
+ }
102
  } else {
103
  this.mode = false;
104
  }
110
  jQuery(document).bind('cbox_closed', function(){ self.colorboxIsOpen = false; self.colorboxServiceQueue(); });
111
  }
112
  },
113
+ scanTourStart: function(){
114
+ var self = this;
115
+ this.tour('wfWelcomeContent1', 'wfHeading', 'top', 'left', "Continue the Tour", function(){
116
+ self.tour('wfWelcomeContent2', 'wfHeading', 'top', 'left', "Learn how to use Wordfence", function(){
117
+ self.tour('wfWelcomeContent3', 'wfHeading', 'top', 'left', "Learn about Live Traffic", function(){ self.tourRedir('WordfenceActivity'); });
118
+ });
119
+ });
120
+ },
121
+ tourRedir: function(menuItem){
122
+ window.location.href = 'admin.php?page=' + menuItem;
123
+ },
124
+ tourFinish: function(){
125
+ this.ajax('wordfence_tourClosed', {}, function(res){});
126
+ },
127
+ tour: function(contentID, elemID, edge, align, buttonLabel, buttonCallback){
128
+ var self = this;
129
+ if(this.currentPointer){
130
+ this.currentPointer.pointer('destroy');
131
+ this.currentPointer = false;
132
+ }
133
+ var options = {
134
+ buttons: function(event, t){
135
+ var buttonElem = jQuery('<div id="wfTourButCont"><a id="pointer-close" style="margin-left:5px" class="button-secondary">End the Tour</a></div><div><a id="wfRateLink" href="http://wordpress.org/extend/plugins/wordfence/" target="_blank" style="font-size: 10px; font-family: Verdana;">Help spread the word by rating us 5&#9733; on WordPress.org</a></div>');
136
+ buttonElem.find('#pointer-close').bind('click.pointer', function (evtObj) {
137
+ if(evtObj.srcElement.id == 'wfRateLink'){
138
+ return true;
139
+ }
140
+ self.tourFinish();
141
+ t.element.pointer('close');
142
+ return false;
143
+ });
144
+ return buttonElem;
145
+ },
146
+ close: function(){},
147
+ content: jQuery('#' + contentID).tmpl().html(),
148
+ pointerWidth: 400,
149
+ position: {
150
+ edge: edge,
151
+ align: align,
152
+ }
153
+ };
154
+ this.currentPointer = jQuery('#' + elemID).pointer(options).pointer('open');
155
+ if(buttonLabel && buttonCallback){
156
+ jQuery('#pointer-close').after('<a id="pointer-primary" class="button-primary">' + buttonLabel + '</a>');
157
+ jQuery('#pointer-primary').click(buttonCallback);
158
+ }
159
+ },
160
+ startTourAgain: function(){
161
+ this.ajax('wordfence_startTourAgain', {}, function(res){});
162
+ this.tourClosed = false;
163
+ this.scanTourStart();
164
+ },
165
  showLoading: function(){
166
  this.removeLoading();
167
  jQuery('<div id="wordfenceWorking">Wordfence is working...</div>').appendTo('body');
1111
  schedMode: schedMode,
1112
  schedTxt: scheduleTxt
1113
  }, function(res){
1114
+ jQuery('#wfScanStartTime').html(res.nextStart);
1115
  jQuery('.wfAjax24').hide();
1116
  self.pulse('.wfSaveMsg');
1117
  });
js/tourTip.js ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ jQuery(function(){
2
+ if(WordfenceAdminVars.tourClosed != '1'){
3
+ jQuery('#toplevel_page_Wordfence').pointer({
4
+ close: function(){},
5
+ content: "<h3>Congratulations!</h3><p>You've just installed Wordfence! Click \"Start Tour\" to get a quick introduction to how Wordfence protects your site, keeps you off Google's SEO black-list and can even help clean a hacked site.</p>",
6
+ pointerWidth: 300,
7
+ position: { edge: 'top', align: 'left' },
8
+ buttons: function(event, t){
9
+ buttonElem = jQuery('<a id="pointer-close" style="margin-left:5px" class="button-secondary">Close</a>');
10
+ buttonElem.bind('click.pointer', function(){ t.element.pointer('close');
11
+ var ajaxData = {
12
+ action: 'wordfence_tourClosed',
13
+ nonce: WordfenceAdminVars.firstNonce
14
+ };
15
+ jQuery.ajax({
16
+ type: 'POST',
17
+ url: WordfenceAdminVars.ajaxURL,
18
+ dataType: "json",
19
+ data: ajaxData,
20
+ success: function(json){},
21
+ error: function(){}
22
+ });
23
+ });
24
+ return buttonElem;
25
+ }
26
+ }).pointer('open');
27
+ jQuery('#pointer-close').after('<a id="pointer-primary" class="button-primary">Start Tour</a>');
28
+ jQuery('#pointer-primary').click(function(){ window.location.href = 'admin.php?page=Wordfence'; });
29
+ }
30
+ });
lib/menu_activity.php CHANGED
@@ -1,6 +1,6 @@
1
  <div class="wordfenceModeElem" id="wordfenceMode_activity"></div>
2
  <div class="wrap wordfence">
3
- <div class="wordfence-lock-icon wordfence-icon32"><br /></div><h2>Live Site Activity</h2>
4
  <div class="wordfenceLive">
5
  <table border="0" cellpadding="0" cellspacing="0">
6
  <tr><td><h2>Wordfence Live Activity:</h2></td><td id="wfLiveStatus"></td></tr>
@@ -162,3 +162,40 @@
162
  </div>
163
  </div>
164
  </script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  <div class="wordfenceModeElem" id="wordfenceMode_activity"></div>
2
  <div class="wrap wordfence">
3
+ <div class="wordfence-lock-icon wordfence-icon32"><br /></div><h2 id="wfHeading">Live Site Activity</h2>
4
  <div class="wordfenceLive">
5
  <table border="0" cellpadding="0" cellspacing="0">
6
  <tr><td><h2>Wordfence Live Activity:</h2></td><td id="wfLiveStatus"></td></tr>
162
  </div>
163
  </div>
164
  </script>
165
+ <script type="text/x-jquery-template" id="wfWelcomeContent3">
166
+ <div>
167
+ <h3>Welcome to ALL Your Site Visits, Live!</h3>
168
+ <strong><p>Traffic you've never seen before</p></strong>
169
+ <p>
170
+ Google Analytics and other Javascript analytics packages can't show you crawlers, RSS feed readers, hack attempts and other non-human traffic that hits your site.
171
+ Wordfence runs on your server and shows you, in real-time, all the traffic that is hitting your server right now, including those non-human crawlers, feed readers and hackers that Analytics can't track.
172
+ </p>
173
+ <strong><p>Separated into the important categories</p></strong>
174
+ <p>
175
+ You'll notice we have divided your traffic into tabs. These include an "All Hits" tab to simply view everything that is hitting your server right now.
176
+ We then sub-divide that into Human traffic, your site members, crawlers - which we further break down into Google crawlers.
177
+ </p>
178
+ <p>
179
+ <strong>How to use this page when your site is being attacked</strong>
180
+ </p>
181
+ <p>
182
+ Start by looking at "All Hits" because you may notice that a single IP address is generating most of your traffic.
183
+ This could be a denial of service attack, someone stealing your content or a hacker probing for weaknesses.
184
+ If you see a suspicious pattern, simply block that IP address.
185
+ </p>
186
+ <p>
187
+ If you don't see any clear patterns of attack, take a look at "Top 404s" which will show you IP addresses that are generating excessive page not found errors.
188
+ It's common for an attacker probing for weaknesses to generate a lot of page not found errors. If you see one IP
189
+ address that is generating many of these requests, and it's not Google or another trusted crawler, then you should consider
190
+ blocking them.
191
+ </p>
192
+ <p>
193
+ Next look at "Logins and Logouts". If you see a large number of failed logins from an IP address, block them if you don't recognize who they are.
194
+ </p>
195
+ <p>
196
+ Finally, take a look at "Top Consumers". These are the top IP addresses who are "consuming" or accessing most of your content.
197
+ If you're trying to protect yourself against a content thief, this is the first place to look.
198
+ </p>
199
+
200
+ </div>
201
+ </script>
lib/menu_blockedIPs.php CHANGED
@@ -1,6 +1,6 @@
1
  <div class="wordfenceModeElem" id="wordfenceMode_blockedIPs"></div>
2
  <div class="wrap">
3
- <div class="wordfence-lock-icon wordfence-icon32"><br /></div><h2>Wordfence Blocked IP Addresses</h2>
4
  <div class="wordfenceLive">
5
  <table border="0" cellpadding="0" cellspacing="0">
6
  <tr><td><h2>Wordfence Live Activity:</h2></td><td id="wfLiveStatus"></td></tr>
@@ -158,3 +158,23 @@
158
  </div>
159
  </script>
160
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  <div class="wordfenceModeElem" id="wordfenceMode_blockedIPs"></div>
2
  <div class="wrap">
3
+ <div class="wordfence-lock-icon wordfence-icon32"><br /></div><h2 id="wfHeading">Wordfence Blocked IP Addresses</h2>
4
  <div class="wordfenceLive">
5
  <table border="0" cellpadding="0" cellspacing="0">
6
  <tr><td><h2>Wordfence Live Activity:</h2></td><td id="wfLiveStatus"></td></tr>
158
  </div>
159
  </script>
160
 
161
+ <script type="text/x-jquery-template" id="wfWelcomeContent4">
162
+ <div>
163
+ <h3>How to manage Blocked IP addresses</h3>
164
+ <strong><p>Block IP's temporarily or permanently</p></strong>
165
+ <p>
166
+ When you block an IP address, it will appear here with some additional information.
167
+ You will be able to see the geographic location of the IP, how many hits occured before
168
+ it was blocked and how many attempts it has made on your site since it was blocked.
169
+ </p>
170
+ <p>
171
+ You can also see how long until a blocked IP will be automatically unblocked.
172
+ You can also manually add IP addresses on this page to be blocked.
173
+ </p>
174
+ <p>
175
+ You also have the option to see IP addresses who have been locked out from the login system for too many login attempts.
176
+ And finally, when the firewall "throttles" someone's access for accessing the site too quickly, you can
177
+ see which IP addresses have been throttled.
178
+ </p>
179
+ </div>
180
+ </script>
lib/menu_countryBlocking.php CHANGED
@@ -1,6 +1,6 @@
1
  <div class="wordfenceModeElem" id="wordfenceMode_countryBlocking"></div>
2
  <div class="wrap" id="paidWrap">
3
- <div class="wordfence-lock-icon wordfence-icon32"><br /></div><h2>Block specific countries from accessing your site</h2>
4
  <div class="wordfenceWrap" style="margin: 20px 20px 20px 30px;">
5
  <table class="wfConfigForm">
6
  <tr><td colspan="2"><h2>Country Blocking Options</h2></td></tr>
@@ -20,7 +20,7 @@
20
  <?php require('wfCountrySelect.php'); ?>
21
  </select><input type="button" name="but3" class="button-primary" value="Add Country" onclick="var cVal = jQuery('#wfBlockedCountry').val(); WFAD.addBlockedCountry(cVal, jQuery('#wfBlockedCountry option[value=\'' + cVal + '\']').text());" /></td></tr>
22
  <tr><td colspan="2">
23
- <div id="wfCountryList" style="width: 350px; height: 200px; border: 1px solid #999; padding: 5px; margin: 5px;">
24
  </div>
25
  <b>Changes to the country list will only take effect once you hit the save button below.</b>
26
  </td></tr>
@@ -43,9 +43,34 @@ WFAD.loadBlockedCountries('<?php echo wfConfig::get('cbl_countries'); ?>');
43
  }
44
  ?>
45
  <?php
46
- if(! wfConfig::get('isPaid')){
47
  echo 'WFAD.paidUsersOnly("Country blocking is only available to paid members because we have licensed a commercial geolocation database to provide this feature.");';
48
  }
49
  ?>
50
  </script>
51
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  <div class="wordfenceModeElem" id="wordfenceMode_countryBlocking"></div>
2
  <div class="wrap" id="paidWrap">
3
+ <div class="wordfence-lock-icon wordfence-icon32"><br /></div><h2 id="wfHeading">Block specific countries from accessing your site</h2>
4
  <div class="wordfenceWrap" style="margin: 20px 20px 20px 30px;">
5
  <table class="wfConfigForm">
6
  <tr><td colspan="2"><h2>Country Blocking Options</h2></td></tr>
20
  <?php require('wfCountrySelect.php'); ?>
21
  </select><input type="button" name="but3" class="button-primary" value="Add Country" onclick="var cVal = jQuery('#wfBlockedCountry').val(); WFAD.addBlockedCountry(cVal, jQuery('#wfBlockedCountry option[value=\'' + cVal + '\']').text());" /></td></tr>
22
  <tr><td colspan="2">
23
+ <div id="wfCountryList" style="width: 350px; height: 200px; border: 1px solid #999; padding: 5px; margin: 5px; overflow: auto;">
24
  </div>
25
  <b>Changes to the country list will only take effect once you hit the save button below.</b>
26
  </td></tr>
43
  }
44
  ?>
45
  <?php
46
+ if( (! wfConfig::get('isPaid')) && (wfConfig::get('tourClosed', 0) == '1') ){
47
  echo 'WFAD.paidUsersOnly("Country blocking is only available to paid members because we have licensed a commercial geolocation database to provide this feature.");';
48
  }
49
  ?>
50
  </script>
51
+ <script type="text/x-jquery-template" id="wfWelcomeContentCntBlk">
52
+ <div>
53
+ <h3>Premium Feature: Block or redirect countries</h3>
54
+ <strong><p>Being targeted by hackers in a specific country?</p></strong>
55
+ <p>
56
+ The premium version of Wordfence offers country blocking.
57
+ This uses a commercial geolocation database to block hackers, spammers
58
+ or other malicious traffic by country with a 99.5% accuracy rate.
59
+ </p>
60
+ <p>
61
+ <?php
62
+ if(wfConfig::get('isPaid')){
63
+ ?>
64
+ You have upgraded to the premium version of Wordfence and have full access
65
+ to this feature along with our other premium features and priority support.
66
+ <?php
67
+ } else {
68
+ ?>
69
+ If you would like access to this premium feature, please
70
+ <a href="https://www.wordfence.com/choose-a-wordfence-membership-type/?s2-ssl=yes" target="_blank">upgrade to our premium version</a>.
71
+ </p>
72
+ <?php
73
+ }
74
+ ?>
75
+ </div>
76
+ </script>
lib/menu_options.php CHANGED
@@ -6,7 +6,7 @@ var WFSLevels = <?php echo json_encode(wfConfig::$securityLevels); ?>;
6
  </script>
7
  <div class="wordfenceModeElem" id="wordfenceMode_options"></div>
8
  <div class="wrap">
9
- <div class="wordfence-lock-icon wordfence-icon32"><br /></div><h2>Wordfence Options</h2>
10
  <div class="wordfenceLive">
11
  <table border="0" cellpadding="0" cellspacing="0">
12
  <tr><td><h2>Wordfence Live Activity:</h2></td><td id="wfLiveStatus"></td></tr>
@@ -39,6 +39,7 @@ var WFSLevels = <?php echo json_encode(wfConfig::$securityLevels); ?>;
39
 
40
  </table>
41
  <p><table border="0" cellpadding="0" cellspacing="0"><tr><td><input type="button" id="button1" name="button1" class="button-primary" value="Save Changes" onclick="WFAD.saveConfig();" /></td><td style="height: 24px;"><div class="wfAjax24"></div><span class="wfSavedMsg">&nbsp;Your changes have been saved!</span></td></tr></table></p>
 
42
  <div style="margin-top: 25px;">
43
  <h2>Advanced Options:</h2>
44
  <p style="width: 600px;">
@@ -56,27 +57,23 @@ var WFSLevels = <?php echo json_encode(wfConfig::$securityLevels); ?>;
56
  <tr><th>Alert when the "lost password" form is used for a valid user</th><td><input type="checkbox" id="alertOn_lostPasswdForm" class="wfConfigElem" name="alertOn_lostPasswdForm" value="1" <?php $w->cb('alertOn_lostPasswdForm'); ?>/></td></tr>
57
  <tr><th>Alert me when someone with administrator access signs in</th><td><input type="checkbox" id="alertOn_adminLogin" class="wfConfigElem" name="alertOn_adminLogin" value="1" <?php $w->cb('alertOn_adminLogin'); ?>/></td></tr>
58
  <tr><th>Alert me when a non-admin user signs in</th><td><input type="checkbox" id="alertOn_nonAdminLogin" class="wfConfigElem" name="alertOn_nonAdminLogin" value="1" <?php $w->cb('alertOn_nonAdminLogin'); ?>/></td></tr>
59
- <tr><td colspan="2"><h3 class="wfConfigHeading">Live Traffic View</h3></td></tr>
 
 
 
60
  <tr><th class="wfConfigEnable">Enable Live Traffic View</th><td><input type="checkbox" id="liveTrafficEnabled" class="wfConfigElem" name="liveTrafficEnabled" value="1" <?php $w->cb('liveTrafficEnabled'); ?> onclick="WFAD.reloadConfigPage = true; return true;" /></td></tr>
61
  <tr><th>Don't log signed-in users with publishing access:</th><td><input type="checkbox" id="liveTraf_ignorePublishers" name="liveTraf_ignorePublishers" value="1" <?php $w->cb('liveTraf_ignorePublishers'); ?> /></td></tr>
62
  <tr><th>List of comma separated usernames to ignore:</th><td><input type="text" name="liveTraf_ignoreUsers" id="liveTraf_ignoreUsers" value="<?php echo $w->getHTML('liveTraf_ignoreUsers'); ?>" /></td></tr>
63
  <tr><th>List of comma separated IP addresses to ignore:</th><td><input type="text" name="liveTraf_ignoreIPs" id="liveTraf_ignoreIPs" value="<?php echo $w->getHTML('liveTraf_ignoreIPs'); ?>" /></td></tr>
64
  <tr><th>Browser user-agent to ignore:</th><td><input type="text" name="liveTraf_ignoreUA" id="liveTraf_ignoreUA" value="<?php echo $w->getHTML('liveTraf_ignoreUA'); ?>" /></td></tr>
65
- <tr><td colspan="2"><h3 class="wfConfigHeading">Scans to include</h3></td></tr>
 
 
66
  <tr><th class="wfConfigEnable">Enable automatic scheduled scans</th><td><input type="checkbox" id="scheduledScansEnabled" class="wfConfigElem" name="scheduledScansEnabled" value="1" <?php $w->cb('scheduledScansEnabled'); ?> /></td></tr>
67
  <tr><th>Scan core files against repository versions for changes</th><td><input type="checkbox" id="scansEnabled_core" class="wfConfigElem" name="scansEnabled_core" value="1" <?php $w->cb('scansEnabled_core'); ?>/></td></tr>
68
 
69
- <?php if(wfConfig::get('isPaid')){ ?>
70
- <tr><th style="color: #0A0; padding-top: 10px; font-weight: bold;" colspan="2">Premium Scanning:</th><td></td></tr>
71
- <tr><th style="font-weight: bold;">Scan theme files against repository versions for changes</th><td><input type="checkbox" id="scansEnabled_themes" class="wfConfigElem" name="scansEnabled_themes" value="1" <?php $w->cb('scansEnabled_themes'); ?>/></td></tr>
72
- <tr><th style="font-weight: bold;">Scan plugin files against repository versions for changes</th><td><input type="checkbox" id="scansEnabled_plugins" class="wfConfigElem" name="scansEnabled_plugins" value="1" <?php $w->cb('scansEnabled_plugins'); ?>/></td></tr>
73
- <tr><td colspan="2">&nbsp;</td></tr>
74
- <?php } else { ?>
75
- <tr><th style="color: #F00; padding-top: 10px;" colspan="2">Only available to Premium Members: <a href="https://www.wordfence.com/choose-a-wordfence-membership-type/" target="_blank">[click to upgrade]</a></th><td></td></tr>
76
- <tr><th style="color: #999;">Scan theme files against repository versions for changes</th><td><input type="checkbox" id="scansEnabled_themes" class="wfConfigElem" name="scansEnabled_themes" value="1" DISABLED /></td></tr>
77
- <tr><th style="color: #999;">Scan plugin files against repository versions for changes</th><td><input type="checkbox" id="scansEnabled_plugins" class="wfConfigElem" name="scansEnabled_plugins" value="1" DISABLED /></td></tr>
78
- <tr><td colspan="2">&nbsp;</td></tr>
79
- <?php } ?>
80
  <tr><th>Scan for signatures of known malicious files</th><td><input type="checkbox" id="scansEnabled_malware" class="wfConfigElem" name="scansEnabled_malware" value="1" <?php $w->cb('scansEnabled_malware'); ?>/></td></tr>
81
  <tr><th>Scan file contents for backdoors, trojans and suspicious code</th><td><input type="checkbox" id="scansEnabled_fileContents" class="wfConfigElem" name="scansEnabled_fileContents" value="1" <?php $w->cb('scansEnabled_fileContents'); ?>/></td></tr>
82
  <tr><th>Scan posts for known dangerous URLs and suspicious content</th><td><input type="checkbox" id="scansEnabled_posts" class="wfConfigElem" name="scansEnabled_posts" value="1" <?php $w->cb('scansEnabled_posts'); ?>/></td></tr>
@@ -87,6 +84,7 @@ var WFSLevels = <?php echo json_encode(wfConfig::$securityLevels); ?>;
87
  <tr><th>Scan for unauthorized DNS changes</th><td><input type="checkbox" id="scansEnabled_dns" class="wfConfigElem" name="scansEnabled_dns" value="1" <?php $w->cb('scansEnabled_dns'); ?>/></td></tr>
88
  <tr><th>Scan files outside your WordPress installation</th><td><input type="checkbox" id="other_scanOutside" class="wfConfigElem" name="other_scanOutside" value="1" <?php $w->cb('other_scanOutside'); ?> /></td></tr>
89
  <tr><td colspan="2">
 
90
  <h3 class="wfConfigHeading">Firewall Rules</h3>
91
  </td></tr>
92
 
@@ -120,7 +118,10 @@ var WFSLevels = <?php echo json_encode(wfConfig::$securityLevels); ?>;
120
  <option value="2592000"<?php $w->sel('blockedTime', '2592000'); ?>>1 month</option>
121
  </select></td></tr>
122
 
123
- <tr><td colspan="2"><h3 class="wfConfigHeading">Login Security Options</h3></td></tr>
 
 
 
124
  <tr><th class="wfConfigEnable">Enable login security</th><td><input type="checkbox" id="loginSecurityEnabled" class="wfConfigElem" name="loginSecurityEnabled" value="1" <?php $w->cb('loginSecurityEnabled'); ?> /></td></tr>
125
  <tr><th>Lock out after how many login failures</th><td>
126
  <select id="loginSec_maxFailures" class="wfConfigElem" name="loginSec_maxFailures">
@@ -196,7 +197,10 @@ var WFSLevels = <?php echo json_encode(wfConfig::$securityLevels); ?>;
196
  </td></tr>
197
  <tr><th>Immediately lock out invalid usernames</th><td><input type="checkbox" id="loginSec_lockInvalidUsers" class="wfConfigElem" name="loginSec_lockInvalidUsers" <?php $w->cb('loginSec_lockInvalidUsers'); ?> /></td></tr>
198
  <tr><th>Don't let WordPress reveal valid users in login errors</th><td><input type="checkbox" id="loginSec_maskLoginErrors" class="wfConfigElem" name="loginSec_maskLoginErrors" <?php $w->cb('loginSec_maskLoginErrors'); ?> /></td></tr>
199
- <tr><td colspan="2"><h3 class="wfConfigHeading">Other Options</h3></td></tr>
 
 
 
200
  <tr><th>Whitelisted IP addresses that bypass all rules:</th><td><input type="text" name="whitelisted" id="whitelisted" value="<?php echo $w->getHTML('whitelisted'); ?>" size="40" /></td></tr>
201
  <tr><th colspan="2" style="color: #999;">Whitelisted IP's must be separated by commas. You can specify ranges using the following format: 123.23.34.[1-50]<br />Wordfence automatically whitelists <a href="http://en.wikipedia.org/wiki/Private_network" target="_blank">private networks</a> because these are not routable on the public Internet.<br /><br /></th></tr>
202
  <tr><th>Hide WordPress version</th><td><input type="checkbox" id="other_hideWPVersion" class="wfConfigElem" name="other_hideWPVersion" value="1" <?php $w->cb('other_hideWPVersion'); ?> /></td></tr>
@@ -214,3 +218,98 @@ var WFSLevels = <?php echo json_encode(wfConfig::$securityLevels); ?>;
214
  </div>
215
  </form>
216
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
  </script>
7
  <div class="wordfenceModeElem" id="wordfenceMode_options"></div>
8
  <div class="wrap">
9
+ <div class="wordfence-lock-icon wordfence-icon32"><br /></div><h2 id="wfHeading">Wordfence Options</h2>
10
  <div class="wordfenceLive">
11
  <table border="0" cellpadding="0" cellspacing="0">
12
  <tr><td><h2>Wordfence Live Activity:</h2></td><td id="wfLiveStatus"></td></tr>
39
 
40
  </table>
41
  <p><table border="0" cellpadding="0" cellspacing="0"><tr><td><input type="button" id="button1" name="button1" class="button-primary" value="Save Changes" onclick="WFAD.saveConfig();" /></td><td style="height: 24px;"><div class="wfAjax24"></div><span class="wfSavedMsg">&nbsp;Your changes have been saved!</span></td></tr></table></p>
42
+ <div class="wfMarker" id="wfMarkerBasicOptions"></div>
43
  <div style="margin-top: 25px;">
44
  <h2>Advanced Options:</h2>
45
  <p style="width: 600px;">
57
  <tr><th>Alert when the "lost password" form is used for a valid user</th><td><input type="checkbox" id="alertOn_lostPasswdForm" class="wfConfigElem" name="alertOn_lostPasswdForm" value="1" <?php $w->cb('alertOn_lostPasswdForm'); ?>/></td></tr>
58
  <tr><th>Alert me when someone with administrator access signs in</th><td><input type="checkbox" id="alertOn_adminLogin" class="wfConfigElem" name="alertOn_adminLogin" value="1" <?php $w->cb('alertOn_adminLogin'); ?>/></td></tr>
59
  <tr><th>Alert me when a non-admin user signs in</th><td><input type="checkbox" id="alertOn_nonAdminLogin" class="wfConfigElem" name="alertOn_nonAdminLogin" value="1" <?php $w->cb('alertOn_nonAdminLogin'); ?>/></td></tr>
60
+ <tr><td colspan="2">
61
+ <div class="wfMarker" id="wfMarkerLiveTrafficOptions"></div>
62
+ <h3 class="wfConfigHeading">Live Traffic View</h3>
63
+ </td></tr>
64
  <tr><th class="wfConfigEnable">Enable Live Traffic View</th><td><input type="checkbox" id="liveTrafficEnabled" class="wfConfigElem" name="liveTrafficEnabled" value="1" <?php $w->cb('liveTrafficEnabled'); ?> onclick="WFAD.reloadConfigPage = true; return true;" /></td></tr>
65
  <tr><th>Don't log signed-in users with publishing access:</th><td><input type="checkbox" id="liveTraf_ignorePublishers" name="liveTraf_ignorePublishers" value="1" <?php $w->cb('liveTraf_ignorePublishers'); ?> /></td></tr>
66
  <tr><th>List of comma separated usernames to ignore:</th><td><input type="text" name="liveTraf_ignoreUsers" id="liveTraf_ignoreUsers" value="<?php echo $w->getHTML('liveTraf_ignoreUsers'); ?>" /></td></tr>
67
  <tr><th>List of comma separated IP addresses to ignore:</th><td><input type="text" name="liveTraf_ignoreIPs" id="liveTraf_ignoreIPs" value="<?php echo $w->getHTML('liveTraf_ignoreIPs'); ?>" /></td></tr>
68
  <tr><th>Browser user-agent to ignore:</th><td><input type="text" name="liveTraf_ignoreUA" id="liveTraf_ignoreUA" value="<?php echo $w->getHTML('liveTraf_ignoreUA'); ?>" /></td></tr>
69
+ <tr><td colspan="2">
70
+ <div class="wfMarker" id="wfMarkerScansToInclude"></div>
71
+ <h3 class="wfConfigHeading">Scans to include</h3></td></tr>
72
  <tr><th class="wfConfigEnable">Enable automatic scheduled scans</th><td><input type="checkbox" id="scheduledScansEnabled" class="wfConfigElem" name="scheduledScansEnabled" value="1" <?php $w->cb('scheduledScansEnabled'); ?> /></td></tr>
73
  <tr><th>Scan core files against repository versions for changes</th><td><input type="checkbox" id="scansEnabled_core" class="wfConfigElem" name="scansEnabled_core" value="1" <?php $w->cb('scansEnabled_core'); ?>/></td></tr>
74
 
75
+ <tr><th>Scan theme files against repository versions for changes</th><td><input type="checkbox" id="scansEnabled_themes" class="wfConfigElem" name="scansEnabled_themes" value="1" <?php $w->cb('scansEnabled_themes'); ?>/></td></tr>
76
+ <tr><th>Scan plugin files against repository versions for changes</th><td><input type="checkbox" id="scansEnabled_plugins" class="wfConfigElem" name="scansEnabled_plugins" value="1" <?php $w->cb('scansEnabled_plugins'); ?>/></td></tr>
 
 
 
 
 
 
 
 
 
77
  <tr><th>Scan for signatures of known malicious files</th><td><input type="checkbox" id="scansEnabled_malware" class="wfConfigElem" name="scansEnabled_malware" value="1" <?php $w->cb('scansEnabled_malware'); ?>/></td></tr>
78
  <tr><th>Scan file contents for backdoors, trojans and suspicious code</th><td><input type="checkbox" id="scansEnabled_fileContents" class="wfConfigElem" name="scansEnabled_fileContents" value="1" <?php $w->cb('scansEnabled_fileContents'); ?>/></td></tr>
79
  <tr><th>Scan posts for known dangerous URLs and suspicious content</th><td><input type="checkbox" id="scansEnabled_posts" class="wfConfigElem" name="scansEnabled_posts" value="1" <?php $w->cb('scansEnabled_posts'); ?>/></td></tr>
84
  <tr><th>Scan for unauthorized DNS changes</th><td><input type="checkbox" id="scansEnabled_dns" class="wfConfigElem" name="scansEnabled_dns" value="1" <?php $w->cb('scansEnabled_dns'); ?>/></td></tr>
85
  <tr><th>Scan files outside your WordPress installation</th><td><input type="checkbox" id="other_scanOutside" class="wfConfigElem" name="other_scanOutside" value="1" <?php $w->cb('other_scanOutside'); ?> /></td></tr>
86
  <tr><td colspan="2">
87
+ <div class="wfMarker" id="wfMarkerFirewallRules"></div>
88
  <h3 class="wfConfigHeading">Firewall Rules</h3>
89
  </td></tr>
90
 
118
  <option value="2592000"<?php $w->sel('blockedTime', '2592000'); ?>>1 month</option>
119
  </select></td></tr>
120
 
121
+ <tr><td colspan="2">
122
+ <div class="wfMarker" id="wfMarkerLoginSecurity"></div>
123
+ <h3 class="wfConfigHeading">Login Security Options</h3>
124
+ </td></tr>
125
  <tr><th class="wfConfigEnable">Enable login security</th><td><input type="checkbox" id="loginSecurityEnabled" class="wfConfigElem" name="loginSecurityEnabled" value="1" <?php $w->cb('loginSecurityEnabled'); ?> /></td></tr>
126
  <tr><th>Lock out after how many login failures</th><td>
127
  <select id="loginSec_maxFailures" class="wfConfigElem" name="loginSec_maxFailures">
197
  </td></tr>
198
  <tr><th>Immediately lock out invalid usernames</th><td><input type="checkbox" id="loginSec_lockInvalidUsers" class="wfConfigElem" name="loginSec_lockInvalidUsers" <?php $w->cb('loginSec_lockInvalidUsers'); ?> /></td></tr>
199
  <tr><th>Don't let WordPress reveal valid users in login errors</th><td><input type="checkbox" id="loginSec_maskLoginErrors" class="wfConfigElem" name="loginSec_maskLoginErrors" <?php $w->cb('loginSec_maskLoginErrors'); ?> /></td></tr>
200
+ <tr><td colspan="2">
201
+ <div class="wfMarker" id="wfMarkerOtherOptions"></div>
202
+ <h3 class="wfConfigHeading">Other Options</h3>
203
+ </td></tr>
204
  <tr><th>Whitelisted IP addresses that bypass all rules:</th><td><input type="text" name="whitelisted" id="whitelisted" value="<?php echo $w->getHTML('whitelisted'); ?>" size="40" /></td></tr>
205
  <tr><th colspan="2" style="color: #999;">Whitelisted IP's must be separated by commas. You can specify ranges using the following format: 123.23.34.[1-50]<br />Wordfence automatically whitelists <a href="http://en.wikipedia.org/wiki/Private_network" target="_blank">private networks</a> because these are not routable on the public Internet.<br /><br /></th></tr>
206
  <tr><th>Hide WordPress version</th><td><input type="checkbox" id="other_hideWPVersion" class="wfConfigElem" name="other_hideWPVersion" value="1" <?php $w->cb('other_hideWPVersion'); ?> /></td></tr>
218
  </div>
219
  </form>
220
  </div>
221
+ <script type="text/x-jquery-template" id="wfContentBasicOptions">
222
+ <div>
223
+ <h3>Basic Options</h3>
224
+ <p>
225
+ Using Wordfence is simple. Install Wordfence, enter an email address on this page to send alerts to, and then do your first scan and work through the security alerts we provide.
226
+ We give you a few basic security levels to choose from, depending on your needs. Remember to hit the "Save" button to save any changes you make.
227
+ </p>
228
+ <p>
229
+ If you use the free edition of Wordfence, you don't need to worry about entering an API key in the "API Key" field above. One is automatically created for you. If you choose to <a href="https://www.wordfence.com/choose-a-wordfence-membership-type/?s2-ssl=yes" target="_blank">upgrade to Wordfence premium edition</a>, you will receive an API key. You will need to copy and paste that key into the "API Key"
230
+ field above and hit "Save" to activate your key.
231
+ </p>
232
+ </div>
233
+ </script>
234
+ <script type="text/x-jquery-template" id="wfContentLiveTrafficOptions">
235
+ <div>
236
+ <h3>Live Traffic Options</h3>
237
+ <p>
238
+ These options let you ignore certain types of visitors, based on their level of access, usernames, IP address or browser type.
239
+ If you run a very high traffic website where it is not feasible to see your visitors in real-time, simply un-check the live traffic option and nothing will be written to the Wordfence tracking tables.
240
+ </p>
241
+ </div>
242
+ </script>
243
+ <script type="text/x-jquery-template" id="wfContentScansToInclude">
244
+ <div>
245
+ <h3>Scans to Include</h3>
246
+ <p>
247
+ This section gives you the ability to fine-tune what we scan.
248
+ If you use many themes or plugins from the public WordPress directory we recommend you
249
+ enable theme and plugin scanning. This will verify the integrity of all these themes and plugins and alert you of any changes.
250
+ <p>
251
+ <p>
252
+ The option to "scan files outside your WordPress installation" will cause Wordfence to do a much wider security scan
253
+ that is not limited to your base WordPress directory and known WordPress subdirectories. This scan may take longer
254
+ but can be very useful if you have other infected files outside this WordPress installation that you would like us to look for.
255
+ </p>
256
+ </div>
257
+ </script>
258
+ <script type="text/x-jquery-template" id="wfContentFirewallRules">
259
+ <div>
260
+ <h3>Firewall Rules</h3>
261
+ <p>
262
+ <strong>NOTE:</strong> Before modifying these rules, make sure you have access to the email address associated with this site's administrator account. If you accidentally lock yourself out, you will be given the option
263
+ to enter that email address and receive an "unlock email" which will allow you to regain access.
264
+ </p>
265
+ <p>
266
+ <strong>Tips:</strong>
267
+ <p>&#8226; If you choose to limit the rate at which your site can be accessed, you need to customize the settings for your site.</p>
268
+ <p>&#8226; If your users usually skip quickly between pages, you should set the values for human visitors to be high.</p>
269
+ <p>&#8226; If you are aggressively crawled by non-Google crawlers like Baidu, you should set the page view limit for crawlers to a high value.</p>
270
+ <p>&#8226; If you are currently under attack and want to aggressively protect your site or your content, you can set low values for most options.</p>
271
+ <p>&#8226; In general we recommend you don't block fake Google crawlers unless you have a specific problem with someone stealing your content.</p>
272
+ </p>
273
+ <p>
274
+ Remember that as long as you have your administrator email set correctly in this site's user administration, and you are able to receive email at that address,
275
+ you will be able to regain access if you are accidentally locked out because your rules are too strict.
276
+ </p>
277
+ </div>
278
+ </script>
279
+ <script type="text/x-jquery-template" id="wfContentLoginSecurity">
280
+ <div>
281
+ <h3>Login Security</h3>
282
+ <p>
283
+ We have found that real brute force login attacks make hundreds or thousands of requests trying to guess passwords or user login names.
284
+ So in general you can leave the number of failed logins before a user is locked out as a fairly high number.
285
+ We have found that blocking after 20 failed attempts is sufficient for most sites and it allows your real site users enough
286
+ attempts to guess their forgotten passwords without getting locked out.
287
+ </p>
288
+ </div>
289
+ </script>
290
+ <script type="text/x-jquery-template" id="wfContentOtherOptions">
291
+ <div>
292
+ <h3>Other Options</h3>
293
+ <p>
294
+ We have worked hard to make Wordfence memory efficient and much of the heavy lifting is done for your site by our cloud scanning servers in our Seattle data center.
295
+ On most sites Wordfence will only use about 8 megabytes of additional memory when doing a scan, even if you have large files or a large number of files.
296
+ You should not have to adjust the maximum memory that Wordfence can use, but we have provided the option. Remember that this does not affect the actual memory usage of Wordfence, simply the maximum Wordfence can use if it needs to.
297
+ </p>
298
+ <p>
299
+ You may find debugging mode helpful if Wordfence is not able to start a scan on your site or
300
+ if you are experiencing some other problem. Enable debugging by checking the box, save your options
301
+ and then try to do a scan. You will notice a lot more output on the "Scan" page.
302
+ </p>
303
+ <p>
304
+ If you decide to permanently remove Wordfence, you can choose the option to delete all data on deactivation.
305
+ We also provide helpful links at the bottom of this page which lets you see your systems configuration and test how
306
+ much memory your host really allows you to use.
307
+ </p>
308
+ <p>
309
+ Thanks for completing this tour and I'm very happy to have you as our newest Wordfence customer. Don't forget to <a href="http://wordpress.org/extend/plugins/wordfence/" target="_blank">rate us 5 stars if you love Wordfence</a>.<br />
310
+ <br />
311
+ <strong>Mark Maunder</strong> - Wordfence Creator.
312
+ </p>
313
+ </div>
314
+ </script>
315
+
lib/menu_scan.php CHANGED
@@ -1,11 +1,21 @@
1
  <div class="wordfenceModeElem" id="wordfenceMode_scan"></div>
2
  <div class="wrap wordfence">
3
- <div class="wordfence-lock-icon wordfence-icon32"><br /></div><h2>Wordfence Scan</h2>
4
  <div class="wordfenceWrap">
5
- <div class="wordfenceScanButton"><input type="button" value="Start a Wordfence Scan" id="wfStartScanButton1" class="wfStartScanButton button-primary" onclick="wordfenceAdmin.startScan();" />
6
- <a target="_blank" href="http://www.wordfence.com/forums/">You can always get help on our support forum.</a>
7
- <br />
8
- &nbsp;&nbsp;&nbsp;&nbsp;<a href="#" onclick="WFAD.killScan(); return false;" style="font-size: 10px; color: #AAA;">Click here to kill a running scan.</a>
 
 
 
 
 
 
 
 
 
 
9
  </div>
10
  <div>
11
  <div class="consoleHead">
@@ -28,7 +38,7 @@
28
  </div>
29
  <?php } else { ?>
30
  <div style="margin: 0 0 20px 5px; width: 795px;">
31
- <strong>How to upgrade:</strong> <a href="https://www.wordfence.com/choose-a-wordfence-membership-type/?s2-ssl=yes" target="_blank">Visit www.wordfence.com</a> and sign up for a paid option. Then go to the Wordfence options page on this site and replace your free API key with your new premium key. You will then be able to activate the premium scanning options on the Wordfence options page.
32
  </div>
33
 
34
  <?php } ?>
@@ -67,6 +77,12 @@
67
  &nbsp;
68
  <a href="#" target="_blank" class="wfALogViewLink" id="wfALogViewLink">View activity log</a>
69
  </div>
 
 
 
 
 
 
70
  </div>
71
  <div style="margin-top: 20px;">
72
  <div id="wfTabs">
@@ -509,3 +525,67 @@
509
  </script>
510
 
511
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  <div class="wordfenceModeElem" id="wordfenceMode_scan"></div>
2
  <div class="wrap wordfence">
3
+ <div class="wordfence-lock-icon wordfence-icon32"><br /></div><h2 id="wfHeading">Wordfence Scan</h2>
4
  <div class="wordfenceWrap">
5
+ <div class="wordfenceScanButton">
6
+ <table border="0" cellpadding="0" cellspacing="0" style="width: 800px;">
7
+ <tr>
8
+ <td style="width: 250px; padding-top: 10px;">
9
+ <input type="button" value="Start a Wordfence Scan" id="wfStartScanButton1" class="wfStartScanButton button-primary" onclick="wordfenceAdmin.startScan();" /><br />
10
+ &nbsp;&nbsp;&nbsp;&nbsp;<a href="#" onclick="WFAD.killScan(); return false;" style="font-size: 10px; color: #AAA;">Click here to kill a running scan.</a>
11
+ </td>
12
+ <td>
13
+ <div style="border: 1px solid #CCC; padding: 4px;">
14
+ You can <a href="#" onclick="WFAD.startTourAgain(); return false;">start the tour again</a> or <a target="_blank" href="http://www.wordfence.com/forums/">visit our support forums for help.</a> Love Wordfence? You can help by doing two simple things: <a href="http://wordpress.org/extend/plugins/wordfence/" target="_blank">Go to WordPress.org now and give this plugin a 5&#9733; rating</a>. Blog about Wordfence and link to the <a href="http://wordpress.org/extend/plugins/wordfence/" target="_blank">plugin page</a>. Spreading the word helps us keep the best features free.
15
+ </div>
16
+ </td>
17
+ </tr>
18
+ </table>
19
  </div>
20
  <div>
21
  <div class="consoleHead">
38
  </div>
39
  <?php } else { ?>
40
  <div style="margin: 0 0 20px 5px; width: 795px;">
41
+ <strong>How to upgrade:</strong> If you would like to control how often your site is checked for security vulnerabilities and infections, and you would like to be able to block countries, <a href="https://www.wordfence.com/choose-a-wordfence-membership-type/?s2-ssl=yes" target="_blank">visit www.wordfence.com</a> and sign up for our paid option. Then go to the Wordfence options page on this site and replace your free API key with your new premium key. You will then be able to activate the premium scanning options on the Wordfence options page.
42
  </div>
43
 
44
  <?php } ?>
77
  &nbsp;
78
  <a href="#" target="_blank" class="wfALogViewLink" id="wfALogViewLink">View activity log</a>
79
  </div>
80
+ <div style="margin: 0 0 20px 5px; width: 795px;">
81
+ <strong>Docs:</strong> Our <a href="http://www.wordfence.com/docs/" target="_blank">Wordfence Documentation</a> has tips on <a href="http://www.wordfence.com/docs/using-wordfence-to-analyze-changes-in-wordpress-files/" target="_blank">dealing with changed files</a>, <a href="http://www.wordfence.com/docs/how-to-clean-a-hacked-wordpress-site-using-wordfence/" target="_blank">how to clean a hacked site</a> and our <a href="http://www.wordfence.com/docs/frequently-asked-questions/" target="_blank">FAQ</a>.
82
+ <?php $unknownFilesLink = wfUtils::siteURLRelative() . '?_wfsf=unknownFiles&nonce=' . wp_create_nonce('wp-ajax'); ?>
83
+ <br /><strong>Tools:</strong> Cleaning a hacked system? See a <a href="<?php echo $unknownFilesLink ?>&sort=3&dir=rev" target="_blank">list of files that are not in the WordPress core, plugin or theme repositories</a> after your first scan.
84
+ </div>
85
+
86
  </div>
87
  <div style="margin-top: 20px;">
88
  <div id="wfTabs">
525
  </script>
526
 
527
 
528
+ <script type="text/x-jquery-template" id="wfWelcomeContent1">
529
+ <div>
530
+ <h3>Welcome to Wordfence</h3>
531
+ <p>
532
+ Wordfence is a robust and complete security system for WordPress. It protects your WordPress site
533
+ from security threats and keeps you off Google's SEO black-list by providing a firewall, brute force protection, continuous scanning and many other security enhancements.
534
+ </p>
535
+ <p>
536
+ Wordfence also detects if there are any security problems on
537
+ your site or if there has been an intrusion and will alert you via email.
538
+ Wordfence can also help repair hacked sites, even if you don't have a backup of your site.
539
+ </p>
540
+ </div>
541
+ </script>
542
+ <script type="text/x-jquery-template" id="wfWelcomeContent2">
543
+ <div>
544
+ <h3>How Wordfence is different</h3>
545
+ <p><strong>Powered by our Cloud Servers</strong></p>
546
+ <p>
547
+ Wordfence is not just a standalone plugin for WordPress. It is part of Feedjit Inc. and is powered by our cloud scanning servers based at our
548
+ data center in Seattle, Washington in the USA. On these servers we keep an updated mirror of every version of WordPress ever released
549
+ and every version of every plugin and theme ever released into the WordPress repository. That allows us to
550
+ do an integrity check on your core files, plugins and themes. It also means that when we detect they have changed, we can show you the
551
+ changes and we can give you the option to repair any corrupt files. Even if you don't have a backup of that file.
552
+ </p>
553
+ <p><strong>Keeping you off Google's SEO Black-List</strong></p>
554
+ <p>
555
+ We also maintain a real-time copy of the Google Safe Browsing list (the GSB) and use it to scan all your files, posts, pages and comments for dangerous URL's.
556
+ If you accidentally link to a URL on the GSB, your site is often black-listed by Google and removed from search results.
557
+ The GSB is constantly changing, so constant scanning of all your content is needed to keep you safe and off Google's SEO black-list.
558
+ </p>
559
+ <p><strong>Scans for back-doors, malware, viruses and other threats</strong></p>
560
+ <p>
561
+ Wordfence also maintains an updated threat and malware signature database which we use to scan your site for intrusions, malware, backdoors and more.
562
+ </p>
563
+ </div>
564
+ </script>
565
+ <script type="text/x-jquery-template" id="wfWelcomeContent3">
566
+ <div>
567
+ <h3>How to use Wordfence</h3>
568
+ <strong><p>Start with a Scan</p></strong>
569
+ <p>
570
+ Using Wordfence is simple. Start by doing a scan. One is probably already running if you just installed Wordfence.
571
+ Once the scan is complete, a list of issues will appear at the bottom of this page. Work through each issue one at a time. If you know an
572
+ issue is not a security problem, simply choose to ignore it. When you click "ignore" it will be moved to the list of ignored issues.
573
+ </p>
574
+ <strong><p>Use the tools we provide</p></strong>
575
+ <p>
576
+ You'll notice that with each issue we provide tools to help you repair problems you may find. For example, if a core file has been modified
577
+ you can view how it has been changed, view the whole file or repair the file. If we find a back-door a hacker has left behind, we give
578
+ you the option to delete the file. Using these tools is an essential part of the diagnostic and cleaning process if you have been hacked.
579
+ </p>
580
+ <p>
581
+ Repair each security problem that you find. You may have to fix a weak password that we detected, upgrade a theme or plugin, delete a comment that
582
+ contains an unsafe URL and so on. Once you're done, start another scan and your site should come back with no security issues.
583
+ </p>
584
+ <strong><p>Regular scheduled scans keep your site safe</p></strong>
585
+ <p>
586
+ Once you've done your initial scan and cleanup, Wordfence will automatically scan your site once a day.
587
+ If you would like to scan your site more frequently or control when Wordfence does a scan, upgrade to the
588
+ paid version of Wordfence which includes other features like country blocking.
589
+ </p>
590
+ </div>
591
+ </script>
lib/menu_scanSchedule.php CHANGED
@@ -1,9 +1,18 @@
1
  <div class="wordfenceModeElem" id="wordfenceMode_scanScheduling"></div>
2
  <div class="wrap" id="paidWrap">
3
- <div class="wordfence-lock-icon wordfence-icon32"><br /></div><h2>Schedule Wordfence Scanning</h2>
4
  <div class="wordfenceWrap" style="margin: 20px 20px 20px 30px;">
5
  <p>
6
- <strong>Current time: <?php echo date('l jS \of F Y H:i:s A', current_time('timestamp')); ?></strong>
 
 
 
 
 
 
 
 
 
7
  </p>
8
  <p style="width: 600px;">
9
  Wordfence provides continuous real-time security for your site. Occasionally we run a full scan of all files, posts, pages, comments, user password and other site components.
@@ -60,9 +69,40 @@
60
 
61
  <script type="text/javascript">
62
  <?php
63
- if(! wfConfig::get('isPaid')){
64
  echo 'WFAD.paidUsersOnly("Scan scheduling is only available to paid members because it puts significant additional load on our cloud scanning servers. As a free customer, Wordfence will automatically schedule scans to run approximately once daily.");';
65
  }
66
  ?>
67
 
68
  </script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  <div class="wordfenceModeElem" id="wordfenceMode_scanScheduling"></div>
2
  <div class="wrap" id="paidWrap">
3
+ <div class="wordfence-lock-icon wordfence-icon32"><br /></div><h2 id="wfHeading">Schedule Wordfence Scanning</h2>
4
  <div class="wordfenceWrap" style="margin: 20px 20px 20px 30px;">
5
  <p>
6
+ <strong>Current time:</strong>&nbsp;<?php echo date('l jS \of F Y H:i:s A', current_time('timestamp')); ?>
7
+ <br /><strong>Next scan will start at:</strong>&nbsp;
8
+ <span id="wfScanStartTime">
9
+ <?php
10
+ $nextTime = wordfence::getNextScanStartTime();
11
+ if($nextTime){
12
+ echo $nextTime;
13
+ }
14
+ ?>
15
+ </span>
16
  </p>
17
  <p style="width: 600px;">
18
  Wordfence provides continuous real-time security for your site. Occasionally we run a full scan of all files, posts, pages, comments, user password and other site components.
69
 
70
  <script type="text/javascript">
71
  <?php
72
+ if( (! wfConfig::get('isPaid')) && (wfConfig::get('tourClosed', 0) == '1') ){
73
  echo 'WFAD.paidUsersOnly("Scan scheduling is only available to paid members because it puts significant additional load on our cloud scanning servers. As a free customer, Wordfence will automatically schedule scans to run approximately once daily.");';
74
  }
75
  ?>
76
 
77
  </script>
78
+ <script type="text/x-jquery-template" id="wfWelcomeContentScanSched">
79
+ <div>
80
+ <h3>Premium Feature: Scan Scheduling</h3>
81
+ <strong><p>Want full control over when your scans run?</p></strong>
82
+ <p>
83
+ If you upgrade to our premium version you will have access to our scan scheduling feature.
84
+ This gives you full control over when and how frequently your site is scanned
85
+ for security vulnerabilities and intrusions.
86
+ </p>
87
+ <p>
88
+ If your site gets a surge of traffic in the mornings, you may choose to run
89
+ two scans in the late afternoon and at midnight, for example. Or if you
90
+ are experiencing an unusually high number of attacks, you might choose
91
+ to run scans once every two to four hours to be extra vigilant during the attack.
92
+ <p>
93
+ <?php
94
+ if(wfConfig::get('isPaid')){
95
+ ?>
96
+ You have upgraded to the premium version of Wordfence and have full access
97
+ to this feature along with our other premium features and priority support.
98
+ <?php
99
+ } else {
100
+ ?>
101
+ If you would like access to this premium feature, please
102
+ <a href="https://www.wordfence.com/choose-a-wordfence-membership-type/?s2-ssl=yes" target="_blank">upgrade to our premium version</a>.
103
+ </p>
104
+ <?php
105
+ }
106
+ ?>
107
+ </div>
108
+ </script>
lib/unknownFiles.php ADDED
@@ -0,0 +1,149 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php if(! wfUtils::isAdmin()){ exit(); } ?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2
+ <html xmlns="http://www.w3.org/1999/xhtml" dir="ltr" lang="en-US">
3
+ <head>
4
+ <title>Files found that don't belong to WordPress Core or known Themes and Plugins</title>
5
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
6
+ <link rel='stylesheet' id='wordfence-main-style-css' href='<?php echo wfUtils::getBaseURL(); ?>/css/diff.css?ver=<?php echo WORDFENCE_VERSION; ?>' type='text/css' media='all' />
7
+ <body>
8
+ <h1>Wordfence: Files found that don't belong to WordPress Core or known Themes and Plugins.</h1>
9
+ <?php
10
+ $path = ABSPATH;
11
+ $fileList = wfConfig::get('lastUnknownFileList');
12
+ if($fileList){
13
+ ?>
14
+ <p style="width: 700px; margin-top: 20px;">
15
+ <b>Please note:</b> To use this utility, you must enable scanning of Core, Theme and Plugin files on the Wordfence options page.
16
+ <?php if(! wfConfig::get('scansEnabled_themes')){ echo '<span style="color: #F00;">Theme scanning is currently disabled.</span> '; } ?>
17
+ <?php if(! wfConfig::get('scansEnabled_plugins')){ echo '<span style="color: #F00;">Plugin scanning is currently disabled.</span> '; } ?>
18
+ <?php if( (!wfConfig::get('scansEnabled_plugins')) || (!wfConfig::get('scansEnabled_themes')) ){ echo 'You can visit the Wordfence "options" page to enable theme or plugin scanning.'; } ?>
19
+
20
+ If you don't have core, theme and plugin scanning enabled, then the list below will not be very useful because Wordfence won't recognize known core, theme and plugin files.
21
+ If you have the option enabled to "Scan files outside your WordPress installation" enabled, then you may find that this list is very long because it will include files in all your directories.
22
+ <br /><br />
23
+ <b>What is in this list:</b>
24
+ When Wordfence does a scan, it separates files on your system into two lists. The first list is files that belong to WordPress Core or a known theme or plugin. The second list is all other files.
25
+ <br /><br />
26
+ If a <b>file belongs to WordPress Core or a known theme or plugin</b>, we do an integrity check and let you know if it has been modified.
27
+ The integrity check we do on known Core, theme and plugin files is a very reliable way to detect compromised files. It is impossible as far as we know for a hacker to fool this scan
28
+ because we are comparing your files to known originals on our secure scanning servers. If the file is modified, we let you know with a warning or critical alert in the scan results.
29
+ <br /><br />
30
+ If the file <b>does not belong to WordPress Core or a known theme or plugin</b>, we scan it for security problems.
31
+ We have a pretty good detection rate for this second scan, but for very advanced or sneaky attacks our admin's sometimes prefer to examine these files by hand.
32
+ If you would like to look at these non-integrity checked files, we provide you with the list below. You can click on any file to view the contents and see if it has been hacked.
33
+ <br /><br />
34
+ <b>Files that you will find in this list are:</b>
35
+ <ul>
36
+ <li>Files belonging to commercial themes that are not in the open source WordPress theme repository</li>
37
+ <li>Files belonging to commercial plugins that are not in the open source WordPress repository</li>
38
+ <li>Files created by themes or plugins</li>
39
+ <li>Files created by you on your WordPress installation by uploading them through WordPress or a utility like FTP or SFTP</li>
40
+ <li>Files that a hacker put on your system to create a back-door, distribute spam or for another nefarious purpose.</li>
41
+ </ul>
42
+ <b>How to use this list to clean your system if it is infected:</b>
43
+ <ul>
44
+ <li>First sort by most recently modified files by clicking the "Last Modified" column. You may have to click it twice.</li>
45
+ <li>Examine recently modified files by clicking them to view the file and check if it is infected. This is often the most reliable way to find an infection.</li>
46
+ <li>Then sort by "Full File Path" and look at files that aren't one of your custom themes or plugins.</li>
47
+ <li>Note that custom themes and plugins live in the /wp-content/themes/ and /wp-content/plugins directories.</li>
48
+ <li>Then start going through your themes and plugins to see if they are infected.</li>
49
+ </ul>
50
+ </p>
51
+ <h2 style="margin-top: 30px;">Files that don't belong to WordPress Core, or to a theme or plugin in the WordPress Repository:</h2>
52
+
53
+
54
+ <?php
55
+ $files = array();
56
+ while(strlen($fileList) > 0){
57
+ $filenameLen = unpack('n', substr($fileList, 0, 2));
58
+ $filenameLen = $filenameLen[1];
59
+ if($filenameLen > 1000 || $filenameLen < 1){
60
+ continue;
61
+ }
62
+ $file = substr($fileList, 2, $filenameLen);
63
+ $fileList = substr($fileList, 2 + $filenameLen);
64
+ $fullFile = $path . $file;
65
+ if(! file_exists($fullFile)){
66
+ continue;
67
+ }
68
+ $fileExt = '';
69
+ if(preg_match('/\.([a-zA-Z\d\-]{1,7})$/', $file, $matches)){
70
+ $fileExt = strtolower($matches[1]);
71
+ }
72
+ $isPHP = false;
73
+ if(preg_match('/^(?:php|phtml|php\d+)$/', $fileExt)){
74
+ $isPHP = true;
75
+ }
76
+ // http://test3.com/?_wfsf=view&nonce=c1ad72bcbd&file=wp-content%2Fplugins%2Fwordfence%2Flib%2Fmenu_options.php
77
+ $viewLink = wfUtils::siteURLRelative() . '?_wfsf=view&nonce=' . wp_create_nonce('wp-ajax') . '&file=' . urlencode($file);
78
+ $stat = stat($fullFile);
79
+ $owner = posix_getpwuid($stat['uid']);
80
+ $owner = $owner['name'];
81
+ $group = posix_getgrgid($stat['gid']);
82
+ $group = $group['name'];
83
+ $perms = substr(sprintf('%o', fileperms($fullFile)), -4);
84
+ $files[] = array($file, $fullFile, $stat['size'], $stat['mtime'], $viewLink, $owner, $group, $perms);
85
+ }
86
+ function wfUKFcmp($a, $b){
87
+ $idx = $_GET['sort'] ? $_GET['sort'] : 2;
88
+ if($_GET['dir'] == 'rev'){
89
+ $tmp = $a;
90
+ $a = $b;
91
+ $b = $tmp;
92
+ }
93
+ $type = 'num';
94
+ if($idx == 1 || $idx == 5 || $idx == 6 || $idx == 7){
95
+ $type = 'str';
96
+ }
97
+
98
+ if($a[$idx] == $b[$idx]){
99
+ return 0;
100
+ }
101
+ if($type == 'num'){
102
+ return ($a[$idx] < $b[$idx]) ? -1 : 1;
103
+ } else {
104
+ return strcmp($a[$idx], $b[$idx]);
105
+ }
106
+ }
107
+ usort($files, 'wfUKFcmp');
108
+
109
+ $sortLink = wfUtils::siteURLRelative() . '?_wfsf=unknownFiles&nonce=' . wp_create_nonce('wp-ajax') . '&sort=';
110
+ $sortIDX = $_GET['sort'];
111
+ if(! $sortIDX){
112
+ $sortIDX = 2;
113
+ }
114
+ $sortDir = $_GET['dir'];
115
+ if(! $sortDir){
116
+ $sortDir = 'fwd';
117
+ }
118
+ ?>
119
+ <p>
120
+ All columns are sortable. Click the heading to sort a column. Click again to sort in reverse direction.<br />
121
+ If you are cleaning a hacked site, start by sorting files by most recently modified and view those files first.
122
+ </p>
123
+ <table border="1" cellpadding="2" cellspacing="0">
124
+ <tr>
125
+ <th><a href="<?php echo $sortLink; ?>2&dir=<?php echo ($sortIDX == 2 && $sortDir == 'fwd') ? 'rev' : 'fwd'; ?>">File Size in Bytes</a></th>
126
+ <th><a href="<?php echo $sortLink; ?>3&dir=<?php echo ($sortIDX == 3 && $sortDir == 'fwd') ? 'rev' : 'fwd'; ?>">Last modified</a></th>
127
+ <th><a href="<?php echo $sortLink; ?>5&dir=<?php echo ($sortIDX == 5 && $sortDir == 'fwd') ? 'rev' : 'fwd'; ?>">Owner<a></th>
128
+ <th><a href="<?php echo $sortLink; ?>6&dir=<?php echo ($sortIDX == 6 && $sortDir == 'fwd') ? 'rev' : 'fwd'; ?>">Group</a></th>
129
+ <th><a href="<?php echo $sortLink; ?>7&dir=<?php echo ($sortIDX == 7 && $sortDir == 'fwd') ? 'rev' : 'fwd'; ?>">Permissions</a></th>
130
+ <th><a href="<?php echo $sortLink; ?>1&dir=<?php echo ($sortIDX == 1 && $sortDir == 'fwd') ? 'rev' : 'fwd'; ?>">Full file path</a></th>
131
+ </tr>
132
+ <?php
133
+ for($i = 0; $i < sizeof($files); $i++){
134
+ echo '<tr><td>' . wfUtils::formatBytes($files[$i][2]) . '</td><td>' . wfUtils::makeTimeAgo(time() - $files[$i][3]) . ' ago.</td><td>' . $files[$i][5] . '</td><td>' . $files[$i][6] . '</td><td>' . $files[$i][7] . '</td><td><a href="' . $files[$i][4] . '" target="_blank">' . $files[$i][1] . '</a></td></tr>';
135
+ }
136
+ echo "</table>";
137
+ } else {
138
+ ?>
139
+ <p style="margin: 40px; font-size: 20px;">
140
+ You either have not completed a scan recently, or there were no files found on your system that are not in the WordPress official repository for Core files, themes and plugins.
141
+ </p>
142
+ <?php
143
+ }
144
+
145
+ ?>
146
+
147
+ <div class="diffFooter">&copy;&nbsp;2011 Wordfence &mdash; Visit <a href="http://wordfence.com/">Wordfence.com</a> for help, security updates and more.</a>
148
+ </body>
149
+ </html>
lib/wfDB.php CHANGED
@@ -68,7 +68,7 @@ class wfDB {
68
  }
69
  }
70
  public function reconnect(){
71
- if(! mysql_ping($this->dbh)){
72
  $this->connectHandle();
73
  }
74
  }
@@ -224,6 +224,10 @@ class wfDB {
224
  public function getAffectedRows(){
225
  return mysql_affected_rows($this->dbh);
226
  }
 
 
 
 
227
  }
228
 
229
  ?>
68
  }
69
  }
70
  public function reconnect(){
71
+ if((! $this->dbh) || (! mysql_ping($this->dbh)) ){
72
  $this->connectHandle();
73
  }
74
  }
224
  public function getAffectedRows(){
225
  return mysql_affected_rows($this->dbh);
226
  }
227
+ public function truncate($table){ //Ensures everything is deleted if user is using MySQL >= 5.1.16 and does not have "drop" privileges
228
+ $this->query("truncate table $table");
229
+ $this->query("delete from $table");
230
+ }
231
  }
232
 
233
  ?>
lib/wfScanEngine.php CHANGED
@@ -136,27 +136,23 @@ class wfScanEngine {
136
  } else {
137
  wordfence::statusDisabled("Skipping core scan");
138
  }
139
- if(wfConfig::get('isPaid')){
140
- if(wfConfig::get('scansEnabled_plugins')){
141
- $this->pluginScanEnabled = true;
142
- $this->statusIDX['plugin'] = wordfence::statusStart("Premium: Comparing plugin files against originals in repository");
143
- } else {
144
- wordfence::statusDisabled("Skipping comparing plugin files against originals in repository");
145
- }
146
  } else {
147
- wordfence::statusPaidOnly("Skipping comparing plugin files against originals in repository");
148
  }
149
- if(wfConfig::get('isPaid')){
150
- if(wfConfig::get('scansEnabled_themes')){
151
- $this->themeScanEnabled = true;
152
- $this->statusIDX['theme'] = wordfence::statusStart("Premium: Comparing theme files against originals in repository");
153
- } else {
154
- wordfence::statusDisabled("Skipping comparing theme files against originals in repository");
155
- }
156
  } else {
157
- wordfence::statusPaidOnly("Skipping comparing theme files against originals in repository");
158
  }
159
-
 
160
  if(wfConfig::get('scansEnabled_malware')){
161
  $this->statusIDX['unknown'] = wordfence::statusStart("Scanning for known malware files");
162
  $this->malwareScanEnabled = true;
@@ -259,6 +255,7 @@ class wfScanEngine {
259
  $totalUStrLen = unpack('N', substr($dataArr['data'], 0, 4));
260
  $totalUStrLen = $totalUStrLen[1];
261
  $this->unknownFiles = substr($dataArr['data'], 4, ($totalUStrLen - 4)); //subtruct the first 4 bytes which is an INT that is the total length of unknown string including the 4 bytes
 
262
  $resultArr = json_decode(substr($dataArr['data'], $totalUStrLen), true);
263
  if(! (is_array($resultArr) && isset($resultArr['results'])) ){
264
  wordfence::statusEndErr();
136
  } else {
137
  wordfence::statusDisabled("Skipping core scan");
138
  }
139
+
140
+ //These are both now available to free customers
141
+ if(wfConfig::get('scansEnabled_plugins')){
142
+ $this->pluginScanEnabled = true;
143
+ $this->statusIDX['plugin'] = wordfence::statusStart("Comparing open source plugins against WordPress.org originals");
 
 
144
  } else {
145
+ wordfence::statusDisabled("Skipping comparing plugin files against originals in repository");
146
  }
147
+
148
+ if(wfConfig::get('scansEnabled_themes')){
149
+ $this->themeScanEnabled = true;
150
+ $this->statusIDX['theme'] = wordfence::statusStart("Comparing open source themes against WordPress.org originals");
 
 
 
151
  } else {
152
+ wordfence::statusDisabled("Skipping comparing theme files against originals in repository");
153
  }
154
+ //End new section available to free customers
155
+
156
  if(wfConfig::get('scansEnabled_malware')){
157
  $this->statusIDX['unknown'] = wordfence::statusStart("Scanning for known malware files");
158
  $this->malwareScanEnabled = true;
255
  $totalUStrLen = unpack('N', substr($dataArr['data'], 0, 4));
256
  $totalUStrLen = $totalUStrLen[1];
257
  $this->unknownFiles = substr($dataArr['data'], 4, ($totalUStrLen - 4)); //subtruct the first 4 bytes which is an INT that is the total length of unknown string including the 4 bytes
258
+ wfConfig::set('lastUnknownFileList', $this->unknownFiles);
259
  $resultArr = json_decode(substr($dataArr['data'], $totalUStrLen), true);
260
  if(! (is_array($resultArr) && isset($resultArr['results'])) ){
261
  wordfence::statusEndErr();
lib/wordfenceClass.php CHANGED
@@ -39,7 +39,7 @@ class wordfence {
39
  wp_clear_scheduled_hook('wordfence_scheduled_scan');
40
 
41
  //Remove all scheduled scans.
42
- wp_clear_scheduled_hook('wordfence_start_scheduled_scan'); //Clear all scheduled scans.
43
 
44
  if(wfConfig::get('deleteTablesOnDeact')){
45
  $schema = new wfSchema();
@@ -61,7 +61,7 @@ class wordfence {
61
  while($rec = mysql_fetch_assoc($q1)){
62
  array_push($URIs, $rec['URI']);
63
  }
64
- $wfdb->query("truncate table $p"."wfNet404s");
65
  if(sizeof($URIs) > 0){
66
  try {
67
  $api->call('send_net_404s', array(), array( 'URIs' => json_encode($URIs) ));
@@ -75,7 +75,7 @@ class wordfence {
75
  while($rec = mysql_fetch_assoc($q2)){
76
  $scanCont .= pack('N', ip2long($rec['IP']));
77
  }
78
- $wfdb->query("truncate table $p"."wfVulnScanners");
79
 
80
  $q3 = $wfdb->query("select INET_NTOA(IP) as IP from $p"."wfLockedOut where blockedTime > unix_timestamp() - 3600");
81
  $lockCont = "";
@@ -120,7 +120,7 @@ class wordfence {
120
  }
121
 
122
  $wfdb->query("delete from $p"."wfLocs where ctime < unix_timestamp() - %d", WORDFENCE_MAX_IPLOC_AGE);
123
- $wfdb->query("truncate table $p"."wfBadLeechers"); //only uses date that's less than 1 minute old
124
  $wfdb->query("delete from $p"."wfBlocks where (blockedTime + %s < unix_timestamp()) and permanent=0", wfConfig::get('blockedTime'));
125
  $wfdb->query("delete from $p"."wfCrawlers where lastUpdate < unix_timestamp() - (86400 * 7)");
126
 
@@ -136,20 +136,20 @@ class wordfence {
136
  $wfdb->query("delete from $p"."wfLockedOut where blockedTime + %s < unix_timestamp()", wfConfig::get('loginSec_lockoutMins') * 60);
137
  $count2 = $wfdb->querySingle("select count(*) as cnt from $p"."wfLogins");
138
  if($count2 > 20000){
139
- $wfdb->query("truncate table $p"."wfLogins"); //in case of Dos
140
  } else if($count2 > $maxRows){
141
  $wfdb->query("delete from $p"."wfLogins order by ctime asc limit %d", ($count2 - $maxRows));
142
  }
143
  $wfdb->query("delete from $p"."wfReverseCache where unix_timestamp() - lastUpdate > 86400");
144
  $count3 = $wfdb->querySingle("select count(*) as cnt from $p"."wfThrottleLog");
145
  if($count3 > 20000){
146
- $wfdb->query("truncate table $p"."wfThrottleLog"); //in case of DoS
147
  } else if($count3 > $maxRows){
148
  $wfdb->query("delete from $p"."wfThrottleLog order by endTime asc limit %d", ($count3 - $maxRows));
149
  }
150
  $count4 = $wfdb->querySingle("select count(*) as cnt from $p"."wfStatus");
151
  if($count4 > 100000){
152
- $wfdb->query("truncate table $p"."wfStatus");
153
  } else if($count4 > 1000){ //max status events we keep. This determines how much gets emailed to us when users sends us a debug report.
154
  $wfdb->query("delete from $p"."wfStatus where level != 10 order by ctime asc limit %d", ($count4 - 1000));
155
  $count5 = $wfdb->querySingle("select count(*) as cnt from $p"."wfStatus where level=10");
@@ -535,7 +535,22 @@ class wordfence {
535
  wfConfig::set_ser('scanSched', $schedule);
536
  wfConfig::set('schedMode', $schedMode);
537
  wordfence::scheduleScans();
538
- return array('ok' => 1);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
539
  }
540
  public static function wordfenceStartScheduledScan(){
541
  //This prevents scheduled scans from piling up on low traffic blogs and all being run at once.
@@ -555,7 +570,7 @@ class wordfence {
555
  wfScanEngine::startScan();
556
  }
557
  public static function scheduleScans(){ //Idempotent. Deschedules everything and schedules the following week.
558
- wp_clear_scheduled_hook('wordfence_start_scheduled_scan'); //Clear all scheduled scans.
559
  $sched = wfConfig::get_ser('scanSched', array());
560
  $mode = wfConfig::get('schedMode');
561
  if($mode == 'manual' && is_array($sched) && is_array($sched[0]) ){
@@ -582,21 +597,38 @@ class wordfence {
582
  $wpTime = current_time('timestamp');
583
  $currentDayOfWeek = date('w', $wpTime);
584
  $daysInFuture = $scheduledDay - $currentDayOfWeek; //It's monday and scheduledDay is Wed (3) then result is 2 days in future. It's Wed and sched day is monday, then result is 3 - 1 = -2
585
- if($daysInFuture < 0){ $daysInFuture -= 7; } //Turns -2 into 5 days in future
586
  $currentHour = date('G', $wpTime);
587
  $secsOffset = ($scheduledHour - $currentHour) * 3600; //Offset from current hour, can be negative
588
  $secondsInFuture = ($daysInFuture * 86400) + $secsOffset; //Can be negative, so we schedule those 1 week ahead
589
  if($secondsInFuture < 1){
590
  $secondsInFuture += (86400 * 7); //Add a week
591
  }
592
- $wpTimeRoundDownHour = strtotime(date("D, d M y H:00:00 O", $wpTime));
593
- $futureTime = $wpTimeRoundDownHour + $secondsInFuture;
594
  wordfence::status(4, 'info', "Scheduled time for day $scheduledDay hour $scheduledHour is: " . date('l jS \of F Y h:i:s A', $futureTime));
595
- wp_schedule_single_event($futureTime, 'wordfence_start_scheduled_scan');
596
  }
597
  }
598
  }
599
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
600
  public static function ajax_saveCountryBlocking_callback(){
601
  if(! wfConfig::get('isPaid')){
602
  return array('errorMsg' => "Sorry but this feature is only available for paid customers.");
@@ -632,6 +664,14 @@ class wordfence {
632
  wp_mail($_POST['email'], "Wordfence Activity Log", $content);
633
  return array('ok' => 1);
634
  }
 
 
 
 
 
 
 
 
635
  public static function ajax_saveConfig_callback(){
636
  $opts = wfConfig::parseOptions();
637
  $emails = array();
@@ -1027,7 +1067,7 @@ class wordfence {
1027
  }
1028
  }
1029
 
1030
- if(! ($wfFunc == 'diff' || $wfFunc == 'view' || $wfFunc == 'sysinfo' || $wfFunc == 'IPTraf' || $wfFunc == 'viewActivityLog' || $wfFunc == 'testmem' || $wfFunc == 'testtime')){
1031
  return;
1032
  }
1033
  if(! wfUtils::isAdmin()){
@@ -1036,7 +1076,7 @@ class wordfence {
1036
 
1037
  $nonce = $_GET['nonce'];
1038
  if(! wp_verify_nonce($nonce, 'wp-ajax')){
1039
- echo "Bad security token. Please sign out and sign-in again.";
1040
  exit(0);
1041
  }
1042
  if($wfFunc == 'diff'){
@@ -1045,6 +1085,8 @@ class wordfence {
1045
  self::wfFunc_view();
1046
  } else if($wfFunc == 'sysinfo'){
1047
  require('sysinfo.php');
 
 
1048
  } else if($wfFunc == 'IPTraf'){
1049
  self::wfFunc_IPTraf();
1050
  } else if($wfFunc == 'viewActivityLog'){
@@ -1153,7 +1195,7 @@ class wordfence {
1153
  return ($a['ctime'] < $b['ctime']) ? -1 : 1;
1154
  }
1155
  public static function wfFunc_view(){
1156
- $localFile = ABSPATH . '/' . preg_replace('/^[\.\/]+/', '', $_GET['file']);
1157
  if(strpos($localFile, '..') !== false){
1158
  echo "Invalid file requested. (Relative paths not allowed)";
1159
  exit();
@@ -1226,12 +1268,13 @@ class wordfence {
1226
  }
1227
  public static function admin_init(){
1228
  if(! wfUtils::isAdmin()){ return; }
1229
- foreach(array('activate', 'scan', 'sendActivityLog', 'restoreFile', 'deleteFile', 'removeExclusion', 'activityLogUpdate', 'ticker', 'loadIssues', 'updateIssueStatus', 'deleteIssue', 'updateAllIssues', 'reverseLookup', 'unlockOutIP', 'unblockIP', 'blockIP', 'permBlockIP', 'loadStaticPanel', 'saveConfig', 'clearAllBlocked', 'killScan', 'saveCountryBlocking', 'saveScanSchedule') as $func){
1230
  add_action('wp_ajax_wordfence_' . $func, 'wordfence::ajaxReceiver');
1231
  }
1232
 
1233
  if(preg_match('/^Wordfence/', @$_GET['page'])){
1234
-
 
1235
  wp_enqueue_style('wordfence-main-style', wfUtils::getBaseURL() . 'css/main.css', '', WORDFENCE_VERSION);
1236
  wp_enqueue_style('wordfence-colorbox-style', wfUtils::getBaseURL() . 'css/colorbox.css', '', WORDFENCE_VERSION);
1237
  wp_enqueue_style('wordfence-dttable-style', wfUtils::getBaseURL() . 'css/dt_table.css', '', WORDFENCE_VERSION);
@@ -1242,15 +1285,24 @@ class wordfence {
1242
  wp_enqueue_script('jquery.dataTables', wfUtils::getBaseURL() . 'js/jquery.dataTables.min.js', array('jquery'), WORDFENCE_VERSION);
1243
  //wp_enqueue_script('jquery.tools', wfUtils::getBaseURL() . 'js/jquery.tools.min.js', array('jquery'));
1244
  wp_enqueue_script('wordfenceAdminjs', wfUtils::getBaseURL() . 'js/admin.js', array('jquery'), WORDFENCE_VERSION);
1245
- wp_localize_script('wordfenceAdminjs', 'WordfenceAdminVars', array(
1246
- 'ajaxURL' => admin_url('admin-ajax.php'),
1247
- 'firstNonce' => wp_create_nonce('wp-ajax'),
1248
- 'siteBaseURL' => wfUtils::getSiteBaseURL(),
1249
- 'debugOn' => wfConfig::get('debugOn', 0)
1250
- ));
1251
  }
1252
 
1253
  }
 
 
 
 
 
 
 
 
 
1254
  public static function configure_warning(){
1255
  if(! preg_match('/WordfenceSecOpt/', $_SERVER['REQUEST_URI'])){
1256
  $numRun = wfConfig::get('alertEmailMsgCount', 0);
@@ -1266,6 +1318,7 @@ class wordfence {
1266
  }
1267
  public static function admin_menus(){
1268
  if(! wfUtils::isAdmin()){ return; }
 
1269
  if(! wfConfig::get('alertEmails')){
1270
  if(wfUtils::isAdminPageMU()){
1271
  add_action('network_admin_notices', 'wordfence::configure_warning');
@@ -1273,6 +1326,7 @@ class wordfence {
1273
  add_action('admin_notices', 'wordfence::configure_warning');
1274
  }
1275
  }
 
1276
  if(! wfConfig::get('apiKey')){
1277
  if(wfUtils::isAdminPageMU()){
1278
  add_action('network_admin_notices', 'wordfence::noKeyError');
39
  wp_clear_scheduled_hook('wordfence_scheduled_scan');
40
 
41
  //Remove all scheduled scans.
42
+ self::unscheduleAllScans();
43
 
44
  if(wfConfig::get('deleteTablesOnDeact')){
45
  $schema = new wfSchema();
61
  while($rec = mysql_fetch_assoc($q1)){
62
  array_push($URIs, $rec['URI']);
63
  }
64
+ $wfdb->truncate($p . "wfNet404s");
65
  if(sizeof($URIs) > 0){
66
  try {
67
  $api->call('send_net_404s', array(), array( 'URIs' => json_encode($URIs) ));
75
  while($rec = mysql_fetch_assoc($q2)){
76
  $scanCont .= pack('N', ip2long($rec['IP']));
77
  }
78
+ $wfdb->truncate($p . "wfVulnScanners");
79
 
80
  $q3 = $wfdb->query("select INET_NTOA(IP) as IP from $p"."wfLockedOut where blockedTime > unix_timestamp() - 3600");
81
  $lockCont = "";
120
  }
121
 
122
  $wfdb->query("delete from $p"."wfLocs where ctime < unix_timestamp() - %d", WORDFENCE_MAX_IPLOC_AGE);
123
+ $wfdb->truncate($p . "wfBadLeechers"); //only uses date that's less than 1 minute old
124
  $wfdb->query("delete from $p"."wfBlocks where (blockedTime + %s < unix_timestamp()) and permanent=0", wfConfig::get('blockedTime'));
125
  $wfdb->query("delete from $p"."wfCrawlers where lastUpdate < unix_timestamp() - (86400 * 7)");
126
 
136
  $wfdb->query("delete from $p"."wfLockedOut where blockedTime + %s < unix_timestamp()", wfConfig::get('loginSec_lockoutMins') * 60);
137
  $count2 = $wfdb->querySingle("select count(*) as cnt from $p"."wfLogins");
138
  if($count2 > 20000){
139
+ $wfdb->truncate($p . "wfLogins"); //in case of Dos
140
  } else if($count2 > $maxRows){
141
  $wfdb->query("delete from $p"."wfLogins order by ctime asc limit %d", ($count2 - $maxRows));
142
  }
143
  $wfdb->query("delete from $p"."wfReverseCache where unix_timestamp() - lastUpdate > 86400");
144
  $count3 = $wfdb->querySingle("select count(*) as cnt from $p"."wfThrottleLog");
145
  if($count3 > 20000){
146
+ $wfdb->truncate($p . "wfThrottleLog"); //in case of DoS
147
  } else if($count3 > $maxRows){
148
  $wfdb->query("delete from $p"."wfThrottleLog order by endTime asc limit %d", ($count3 - $maxRows));
149
  }
150
  $count4 = $wfdb->querySingle("select count(*) as cnt from $p"."wfStatus");
151
  if($count4 > 100000){
152
+ $wfdb->truncate($p . "wfStatus");
153
  } else if($count4 > 1000){ //max status events we keep. This determines how much gets emailed to us when users sends us a debug report.
154
  $wfdb->query("delete from $p"."wfStatus where level != 10 order by ctime asc limit %d", ($count4 - 1000));
155
  $count5 = $wfdb->querySingle("select count(*) as cnt from $p"."wfStatus where level=10");
535
  wfConfig::set_ser('scanSched', $schedule);
536
  wfConfig::set('schedMode', $schedMode);
537
  wordfence::scheduleScans();
538
+ $nextTime = self::getNextScanStartTime();
539
+ return array(
540
+ 'ok' => 1,
541
+ 'nextStart' => ($nextTime ? $nextTime : '')
542
+ );
543
+ }
544
+ public static function getNextScanStartTime(){
545
+ $nextTime = false;
546
+ $cron = _get_cron_array();
547
+ foreach($cron as $key => $val){
548
+ if(isset($val['wordfence_start_scheduled_scan'])){
549
+ $nextTime = $key;
550
+ break;
551
+ }
552
+ }
553
+ return ($nextTime ? date('l jS \of F Y H:i:s A', $nextTime + (3600 * get_option('gmt_offset'))) : '');
554
  }
555
  public static function wordfenceStartScheduledScan(){
556
  //This prevents scheduled scans from piling up on low traffic blogs and all being run at once.
570
  wfScanEngine::startScan();
571
  }
572
  public static function scheduleScans(){ //Idempotent. Deschedules everything and schedules the following week.
573
+ self::unscheduleAllScans();
574
  $sched = wfConfig::get_ser('scanSched', array());
575
  $mode = wfConfig::get('schedMode');
576
  if($mode == 'manual' && is_array($sched) && is_array($sched[0]) ){
597
  $wpTime = current_time('timestamp');
598
  $currentDayOfWeek = date('w', $wpTime);
599
  $daysInFuture = $scheduledDay - $currentDayOfWeek; //It's monday and scheduledDay is Wed (3) then result is 2 days in future. It's Wed and sched day is monday, then result is 3 - 1 = -2
600
+ if($daysInFuture < 0){ $daysInFuture += 7; } //Turns -2 into 5 days in future
601
  $currentHour = date('G', $wpTime);
602
  $secsOffset = ($scheduledHour - $currentHour) * 3600; //Offset from current hour, can be negative
603
  $secondsInFuture = ($daysInFuture * 86400) + $secsOffset; //Can be negative, so we schedule those 1 week ahead
604
  if($secondsInFuture < 1){
605
  $secondsInFuture += (86400 * 7); //Add a week
606
  }
607
+ $futureTime = time() - (time() % 3600) + $secondsInFuture; //Modulo rounds down to top of the hour
 
608
  wordfence::status(4, 'info', "Scheduled time for day $scheduledDay hour $scheduledHour is: " . date('l jS \of F Y h:i:s A', $futureTime));
609
+ self::scheduleSingleScan($futureTime);
610
  }
611
  }
612
  }
613
  }
614
+ private static function scheduleSingleScan($futureTime){
615
+ wp_schedule_single_event($futureTime, 'wordfence_start_scheduled_scan', array($futureTime));
616
+ $schedArgs = wfConfig::get_ser('schedScanArgs', array());
617
+ if(! is_array($schedArgs)){ //paranoia
618
+ $schedArgs = array();
619
+ }
620
+ $schedArgs[] = $futureTime;
621
+ wfConfig::set_ser('schedScanArgs', $schedArgs);
622
+ }
623
+ private static function unscheduleAllScans(){
624
+ wp_clear_scheduled_hook('wordfence_start_scheduled_scan'); //Unschedule legacy scans without args
625
+
626
+ $schedArgs = wfConfig::get_ser('schedScanArgs', array());
627
+ foreach($schedArgs as $futureTime){
628
+ wp_clear_scheduled_hook('wordfence_start_scheduled_scan', array($futureTime));
629
+ }
630
+ wfConfig::set_ser('schedScanArgs', array());
631
+ }
632
  public static function ajax_saveCountryBlocking_callback(){
633
  if(! wfConfig::get('isPaid')){
634
  return array('errorMsg' => "Sorry but this feature is only available for paid customers.");
664
  wp_mail($_POST['email'], "Wordfence Activity Log", $content);
665
  return array('ok' => 1);
666
  }
667
+ public static function ajax_startTourAgain_callback(){
668
+ wfConfig::set('tourClosed', 0);
669
+ return array('ok' => 1);
670
+ }
671
+ public static function ajax_tourClosed_callback(){
672
+ wfConfig::set('tourClosed', 1);
673
+ return array('ok' => 1);
674
+ }
675
  public static function ajax_saveConfig_callback(){
676
  $opts = wfConfig::parseOptions();
677
  $emails = array();
1067
  }
1068
  }
1069
 
1070
+ if(! ($wfFunc == 'diff' || $wfFunc == 'view' || $wfFunc == 'sysinfo' || $wfFunc == 'unknownFiles' || $wfFunc == 'IPTraf' || $wfFunc == 'viewActivityLog' || $wfFunc == 'testmem' || $wfFunc == 'testtime')){
1071
  return;
1072
  }
1073
  if(! wfUtils::isAdmin()){
1076
 
1077
  $nonce = $_GET['nonce'];
1078
  if(! wp_verify_nonce($nonce, 'wp-ajax')){
1079
+ echo "Bad security token. It may have been more than 12 hours since you reloaded the page you came from. Try reloading the page you came from. If that doesn't work, please sign out and sign-in again.";
1080
  exit(0);
1081
  }
1082
  if($wfFunc == 'diff'){
1085
  self::wfFunc_view();
1086
  } else if($wfFunc == 'sysinfo'){
1087
  require('sysinfo.php');
1088
+ } else if($wfFunc == 'unknownFiles'){
1089
+ require('unknownFiles.php');
1090
  } else if($wfFunc == 'IPTraf'){
1091
  self::wfFunc_IPTraf();
1092
  } else if($wfFunc == 'viewActivityLog'){
1195
  return ($a['ctime'] < $b['ctime']) ? -1 : 1;
1196
  }
1197
  public static function wfFunc_view(){
1198
+ $localFile = ABSPATH . '/' . preg_replace('/^(?:\.\.|[\/]+)/', '', $_GET['file']);
1199
  if(strpos($localFile, '..') !== false){
1200
  echo "Invalid file requested. (Relative paths not allowed)";
1201
  exit();
1268
  }
1269
  public static function admin_init(){
1270
  if(! wfUtils::isAdmin()){ return; }
1271
+ foreach(array('activate', 'scan', 'sendActivityLog', 'restoreFile', 'deleteFile', 'removeExclusion', 'activityLogUpdate', 'ticker', 'loadIssues', 'updateIssueStatus', 'deleteIssue', 'updateAllIssues', 'reverseLookup', 'unlockOutIP', 'unblockIP', 'blockIP', 'permBlockIP', 'loadStaticPanel', 'saveConfig', 'clearAllBlocked', 'killScan', 'saveCountryBlocking', 'saveScanSchedule', 'tourClosed', 'startTourAgain') as $func){
1272
  add_action('wp_ajax_wordfence_' . $func, 'wordfence::ajaxReceiver');
1273
  }
1274
 
1275
  if(preg_match('/^Wordfence/', @$_GET['page'])){
1276
+ wp_enqueue_style('wp-pointer');
1277
+ wp_enqueue_script('wp-pointer');
1278
  wp_enqueue_style('wordfence-main-style', wfUtils::getBaseURL() . 'css/main.css', '', WORDFENCE_VERSION);
1279
  wp_enqueue_style('wordfence-colorbox-style', wfUtils::getBaseURL() . 'css/colorbox.css', '', WORDFENCE_VERSION);
1280
  wp_enqueue_style('wordfence-dttable-style', wfUtils::getBaseURL() . 'css/dt_table.css', '', WORDFENCE_VERSION);
1285
  wp_enqueue_script('jquery.dataTables', wfUtils::getBaseURL() . 'js/jquery.dataTables.min.js', array('jquery'), WORDFENCE_VERSION);
1286
  //wp_enqueue_script('jquery.tools', wfUtils::getBaseURL() . 'js/jquery.tools.min.js', array('jquery'));
1287
  wp_enqueue_script('wordfenceAdminjs', wfUtils::getBaseURL() . 'js/admin.js', array('jquery'), WORDFENCE_VERSION);
1288
+ self::setupAdminVars();
1289
+ } else {
1290
+ wp_enqueue_style('wp-pointer');
1291
+ wp_enqueue_script('wp-pointer');
1292
+ wp_enqueue_script('wordfenceAdminjs', wfUtils::getBaseURL() . 'js/tourTip.js', array('jquery'), WORDFENCE_VERSION);
1293
+ self::setupAdminVars();
1294
  }
1295
 
1296
  }
1297
+ private static function setupAdminVars(){
1298
+ wp_localize_script('wordfenceAdminjs', 'WordfenceAdminVars', array(
1299
+ 'ajaxURL' => admin_url('admin-ajax.php'),
1300
+ 'firstNonce' => wp_create_nonce('wp-ajax'),
1301
+ 'siteBaseURL' => wfUtils::getSiteBaseURL(),
1302
+ 'debugOn' => wfConfig::get('debugOn', 0),
1303
+ 'tourClosed' => wfConfig::get('tourClosed', 0)
1304
+ ));
1305
+ }
1306
  public static function configure_warning(){
1307
  if(! preg_match('/WordfenceSecOpt/', $_SERVER['REQUEST_URI'])){
1308
  $numRun = wfConfig::get('alertEmailMsgCount', 0);
1318
  }
1319
  public static function admin_menus(){
1320
  if(! wfUtils::isAdmin()){ return; }
1321
+ /* Removed this because we now have the tour.
1322
  if(! wfConfig::get('alertEmails')){
1323
  if(wfUtils::isAdminPageMU()){
1324
  add_action('network_admin_notices', 'wordfence::configure_warning');
1326
  add_action('admin_notices', 'wordfence::configure_warning');
1327
  }
1328
  }
1329
+ */
1330
  if(! wfConfig::get('apiKey')){
1331
  if(wfUtils::isAdminPageMU()){
1332
  add_action('network_admin_notices', 'wordfence::noKeyError');
lib/wordfenceConstants.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
- define('WORDFENCE_API_VERSION', 1.9);
3
- define('WORDFENCE_API_URL_SEC', 'https://69.46.36.8/');
4
- define('WORDFENCE_API_URL_NONSEC', 'http://69.46.36.8/');
5
  define('WORDFENCE_MAX_SCAN_TIME', 600);
6
  define('WORDFENCE_TRANSIENTS_TIMEOUT', 3600); //how long are items cached in seconds e.g. files downloaded for diffing
7
  define('WORDFENCE_MAX_IPLOC_AGE', 604800); //1 week
1
  <?php
2
+ define('WORDFENCE_API_VERSION', '2.0');
3
+ define('WORDFENCE_API_URL_SEC', 'https://noc1.wordfence.com/');
4
+ define('WORDFENCE_API_URL_NONSEC', 'http://noc1.wordfence.com/');
5
  define('WORDFENCE_MAX_SCAN_TIME', 600);
6
  define('WORDFENCE_TRANSIENTS_TIMEOUT', 3600); //how long are items cached in seconds e.g. files downloaded for diffing
7
  define('WORDFENCE_MAX_IPLOC_AGE', 604800); //1 week
lib/wordfenceHash.php CHANGED
@@ -42,7 +42,7 @@ class wordfenceHash {
42
  $this->api = new wfAPI($this->apiKey, $this->wp_version);
43
  }
44
  public function buildFileQueue($path, $only = array()){ //base path and 'only' is a list of files and dirs in the bast that are the only ones that should be processed. Everything else in base is ignored. If only is empty then everything is processed.
45
- $this->db->query("truncate table " . $this->table);
46
  if($path[strlen($path) - 1] != '/'){
47
  $path .= '/';
48
  }
@@ -72,7 +72,11 @@ class wordfenceHash {
72
  $haveMoreInDB = true;
73
  while($haveMoreInDB){
74
  $haveMoreInDB = false;
75
- $res = $this->db->query("select id, filename from " . $this->table . " limit 1000");
 
 
 
 
76
  $ids = array();
77
  while($rec = mysql_fetch_row($res)){
78
  $this->processFile($rec[1]);
@@ -86,7 +90,7 @@ class wordfenceHash {
86
  }
87
  //Will only reach here if we empty file queue. fork may cause exit
88
  $this->sendHashPacket();
89
- $this->db->query("truncate table " . $this->table); //Also resets id autoincrement to 1
90
  $this->writeHashingStatus();
91
  }
92
  private function writeHashingStatus(){
42
  $this->api = new wfAPI($this->apiKey, $this->wp_version);
43
  }
44
  public function buildFileQueue($path, $only = array()){ //base path and 'only' is a list of files and dirs in the bast that are the only ones that should be processed. Everything else in base is ignored. If only is empty then everything is processed.
45
+ $this->db->truncate($this->table);
46
  if($path[strlen($path) - 1] != '/'){
47
  $path .= '/';
48
  }
72
  $haveMoreInDB = true;
73
  while($haveMoreInDB){
74
  $haveMoreInDB = false;
75
+ //This limit used to be 1000, but we changed it to 5 because forkIfNeeded needs to run frequently, but
76
+ // we still want to minimize the number of queries we do.
77
+ // So now we select, process and delete 5 from teh queue and then check forkIfNeeded()
78
+ // So this assumes that processing 5 files won't take longer than wfScanEngine::$maxExecTime (which was 10 at the time of writing, which is 2 secs per file)
79
+ $res = $this->db->query("select id, filename from " . $this->table . " limit 5");
80
  $ids = array();
81
  while($rec = mysql_fetch_row($res)){
82
  $this->processFile($rec[1]);
90
  }
91
  //Will only reach here if we empty file queue. fork may cause exit
92
  $this->sendHashPacket();
93
+ $this->db->truncate($this->table); //Also resets id autoincrement to 1
94
  $this->writeHashingStatus();
95
  }
96
  private function writeHashingStatus(){
lib/wordfenceScanner.php CHANGED
@@ -3,6 +3,8 @@ require_once('wordfenceConstants.php');
3
  require_once('wordfenceClass.php');
4
  require_once('wordfenceURLHoover.php');
5
  class wordfenceScanner {
 
 
6
  //serialized:
7
  protected $path = '';
8
  protected $fileList = array();
@@ -17,6 +19,7 @@ class wordfenceScanner {
17
  return array('path', 'fileList', 'results', 'errorMsg', 'apiKey', 'wordpressVersion', 'urlHoover', 'totalFilesScanned', 'startTime', 'lastStatusTime');
18
  }
19
  public function __wakeup(){
 
20
  }
21
  public function __construct($apiKey, $wordpressVersion, $fileList, $path){
22
  $this->apiKey = $apiKey;
@@ -26,10 +29,86 @@ class wordfenceScanner {
26
  $path .= '/';
27
  }
28
  $this->path = $path;
 
 
29
  $this->results = array();
30
  $this->errorMsg = false;
31
  //First extract hosts or IP's and their URL's into $this->hostsFound and URL's into $this->urlsFound
32
  $this->urlHoover = new wordfenceURLHoover($this->apiKey, $this->wordpressVersion);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  }
34
  public function scan($forkObj){
35
  if(! $this->startTime){
@@ -116,6 +195,23 @@ class wordfenceScanner {
116
  )
117
  ));
118
  break;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
119
  }
120
  $longestNospace = wfUtils::longestNospace($data);
121
  if($longestNospace > 1000 && (strpos($data, 'eval') !== false || preg_match('/preg_replace\([^\(]+\/[a-z]*e/', $data)) ){
3
  require_once('wordfenceClass.php');
4
  require_once('wordfenceURLHoover.php');
5
  class wordfenceScanner {
6
+ protected $sigs = array();
7
+ protected $sigPattern = "";
8
  //serialized:
9
  protected $path = '';
10
  protected $fileList = array();
19
  return array('path', 'fileList', 'results', 'errorMsg', 'apiKey', 'wordpressVersion', 'urlHoover', 'totalFilesScanned', 'startTime', 'lastStatusTime');
20
  }
21
  public function __wakeup(){
22
+ $this->setupSigs();
23
  }
24
  public function __construct($apiKey, $wordpressVersion, $fileList, $path){
25
  $this->apiKey = $apiKey;
29
  $path .= '/';
30
  }
31
  $this->path = $path;
32
+
33
+
34
  $this->results = array();
35
  $this->errorMsg = false;
36
  //First extract hosts or IP's and their URL's into $this->hostsFound and URL's into $this->urlsFound
37
  $this->urlHoover = new wordfenceURLHoover($this->apiKey, $this->wordpressVersion);
38
+ $this->setupSigs();
39
+ }
40
+ private function setupSigs(){
41
+ //Set up sigs
42
+ $this->sigs = array(
43
+ array('\$QBDB51E25BF9A7F3D2475072803D1C36D', "antichat.php, cgi.php and possibly others, this is the var they assign the code to"),
44
+ array('\$login\s*=\s*"c99"|\$pass\s*=\s*"c99"|\$sess_cookie\s*=\s*"c9'.'9shvars"', "several lines of c99 decoded"),
45
+ array('C9'.'9Shell v\.', "c99.php"),
46
+ array('passthru\s*\(\s*getenv\s*\(\s*"HTTP_ACCEPT_LANGUAGE', "accept_language HTTP header backdoor"),
47
+ array('runcommand\s*\([\'"]etcpasswdfile', "Ajax_PHP Command Shell"),
48
+ array('exesysform', "AK-74 Security Team Web Shell"),
49
+ array('\$password\s*=\s*[\'"]antichat', "Antichat shell"),
50
+ array('if\s*\(\s*\$action\s*==\s*["\']phpeval', "Antichat shell"),
51
+ array('Can\'t open file, permission denide', "Antichat spelling error"),
52
+ array('tmp[\'"],\s*["\']phpshell', "Ayyildiz Tim -AYT- Shell v 2.1 Biz"),
53
+ array('\$this_file\?op=phpinfo', "aZRaiLPhp v1.0"),
54
+ array('\.\s*\$server_ip\s*=\s*gethostbyname\s*\(\$SERVER_NAME', "c0derz shell [csh] v. 0.1.1"),
55
+ array('dosyayicek', "c99_locus7s and c99_PSych0"),
56
+ array('c99_sess_put', "c99_locus7s, c99_PSych0, c99_w4cking, RedhatC99 "),
57
+ array('PHP Safe\-Mode Bypass', "c99_w4cking"),
58
+ array('fonksiyonlary_kapat', "CasuS"),
59
+ array('Dim szCMD, szTempFile', "CmdAsp.asp"),
60
+ array('Open base dir: \$hopenbasedir', "Crystal shell"),
61
+ array('find config.inc.php files', "Many c99 variants including NFM, Perl, Predator, CTT, r57, Redhatc99"),
62
+ array('find all .htpasswd files', "Many c99 variants including NFM, Perl, Predator, CTT, r57, Redhatc9"),
63
+ array('function anonim_mail', "Cybershell"),
64
+ array('\$_SESSION\[aupass\]=md5\(\$aupassword', "Cybershell"),
65
+ array('echo\s+htmlspecialchars\(\s*crypt\(\s*fread', "dC3 Security Crew Shell PRiV"),
66
+ array('proc_open\(\s*\$_REQUEST', "Dive Shell"),
67
+ array('file_exists\([\'"]\/usr\/bin\/gcc', "DTool Pro"),
68
+ array('find all \*\.php files with word [\'"]password', "Dx"),
69
+ array('WebShell::Configuration', "Gamma Web Shell (perl)"),
70
+ array('base64_decode\(\$prx', "GFS shell"),
71
+ array('icq, command\-n\-conquer and shell nfm', "Various GFS variants"),
72
+ array('open\(FILEHANDLE,\s*[\'"]cd\s+\$param\{dir\}', "go-shell (perl)"),
73
+ array('document.PostActForm\$', "GRP Webshell"),
74
+ array('\$cmd 1> \/tmp\/cmdtemp 2>\&1\; cat', "h4ntu shell"),
75
+ array('\$Düzenlecols, \$Düzenlerows', "iMHaBiRLiGi PHP FTP"),
76
+ array('get_execution_method\s*\(', "ironshell and many others"),
77
+ array('proc\s*=\s*runtime\.exec\(\s*cmd\s*\)', "JSP Web Shell"),
78
+ array('eval>PHP Eval Code', "KAdot Universal Shell"),
79
+ array('if\(\(\$_POST\[\'exe\'\]\) == "Execute"', "Lamashell"),
80
+ array('cat \/etc\/passwd', "Liz0ziM and many other malicious apps"),
81
+ array('exec\(\$com,\$arr\)', "Loaderz WEB Shell"),
82
+ array('\$SFileName=\$PHP_SELF', "Macker's Private PHPShell"),
83
+ array('if\s*\(isset\s*\(\$_POST\)\)\s*walkArray\(\s*\$_POST', "Macker's and some c99 variantes"),
84
+ array('define\(\s*["\']PHPSHELL_VERSION[\'"]\s*,\s*[\'"]\d+', "Matamu and others"),
85
+ array('If\s*\(\$file_name\)\s*\$header\s*\.=\s*"Content\-Transfer\-Encoding:\s*base64', "Moroccan Spamers Ma-EditioN By GhOsT"),
86
+ array('\$MyShellVersion', "MyShell"),
87
+ array('function viewSchema', "Mysql interface"),
88
+ array('global \$HTTP_GET_VARS, \$HTTP_COOKIE_VARS, \$password', "mysql_tool"),
89
+ array('\$file\s*=\s*[\'"]\/etc\/passwd[\'"];', "mysql.php"),
90
+ array('move_uploaded_file\(\$_FILES\[\'probe\'\]\[\'tmp_name\'\]', "NCC-Shell"),
91
+ array('["\']find all suid files[\'"]', "NetworkFileManager.php and variants"),
92
+ array('["\']find all sgid files[\'"]', "NetworkFileManager.php and variants"),
93
+ array('["\']find all config\.inc\.php files[\'"]', "NetworkFileManager.php and variants"),
94
+ array('["\']find writeable directories and files[\'"]', "NetworkFileManager.php and variants"),
95
+ array('xargs grep \-li password', "NetworkFileManager.php and variants"),
96
+ array('\$filename\s*=\s*[\'"]\/etc\/passwd["\']', 'NFM 1.8, NIX Remote Web Shell and others'),
97
+ array('function mvcp\(\$from', 'NGH, Webcommander'),
98
+ array('find \/ \-type f \-name \.ht', 'NIX Remote Web Shell, nsTView and other variants'),
99
+ array('passthru\(\$comd', 'NShell'),
100
+ array('find \/ \-type f \-perm \-04000', 'nsTView and others'),
101
+ array('bind\(S,sockaddr_in\(\$LISTEN_PORT,INADDR_ANY', 'Perl Web Shell by RST-GHC'),
102
+ array('jmp_buf jmp;', 'PHANTASMA'),
103
+ array('\b(?:system|exec|passthru|shell_exec|proc_open)[\r\n\s\t]*\([\r\n\s\t]*\$_(?:POST|GET|REQUEST|SERVER)', 'PHP Backdoor, many malicious apps and any badly written app')
104
+
105
+
106
+ ); //End sigs
107
+ $sigArr = array();
108
+ foreach($this->sigs as $elem){
109
+ $sigArr[] = $elem[0];
110
+ }
111
+ $this->sigPattern = '/(' . implode('|', $sigArr) . ')/i';
112
  }
113
  public function scan($forkObj){
114
  if(! $this->startTime){
195
  )
196
  ));
197
  break;
198
+ } else if(strpos($file, 'lib/wordfenceScanner.php') === false && preg_match($this->sigPattern, $data, $matches)){
199
+ $this->addResult(array(
200
+ 'type' => 'file',
201
+ 'severity' => 1,
202
+ 'ignoreP' => $this->path . $file,
203
+ 'ignoreC' => $fileSum,
204
+ 'shortMsg' => "This file appears to be an attack shell",
205
+ 'longMsg' => "This file appears to be an executable shell that allows hackers entry to your site via a backdoor. 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;\">\"" . $matches[1] . "\"</strong>.",
206
+ 'data' => array(
207
+ 'file' => $file,
208
+ 'canDiff' => false,
209
+ 'canFix' => false,
210
+ 'canDelete' => true
211
+ )
212
+ ));
213
+ break;
214
+
215
  }
216
  $longestNospace = wfUtils::longestNospace($data);
217
  if($longestNospace > 1000 && (strpos($data, 'eval') !== false || preg_match('/preg_replace\([^\(]+\/[a-z]*e/', $data)) ){
lib/wordfenceURLHoover.php CHANGED
@@ -39,7 +39,7 @@ class wordfenceURLHoover {
39
  } else {
40
  $this->table = 'wp_wfHoover';
41
  }
42
- $this->db->query("truncate table $this->table");
43
  }
44
  public function hoover($id, $data){
45
  if(strpos($data, '.') === false){
39
  } else {
40
  $this->table = 'wp_wfHoover';
41
  }
42
+ $this->db->truncate($this->table);
43
  }
44
  public function hoover($id, $data){
45
  if(strpos($data, '.') === false){
readme.txt CHANGED
@@ -3,29 +3,30 @@ Contributors: mmaunder
3
  Tags: wordpress, security, wordpress security, security plugin, secure, anti-virus, malware, firewall, antivirus, virus, google safe browsing, phishing, scrapers, hacking, wordfence, securty, secrity, secure
4
  Requires at least: 3.3.1
5
  Tested up to: 3.4.1
6
- Stable tag: 3.1.6
7
 
8
  Wordfence Security is a free enterprise class security plugin that includes a firewall, virus scanning, real-time traffic with geolocation and more.
9
 
10
  == Description ==
11
 
12
- Wordfence Security is a free enterprise class security plugin that includes a firewall and anti-virus scanning for WordPress websites.
13
 
14
- Wordfence is now Multi-Site compatible. Support for Multi-Site is currently in Beta. Please visit our forums to report any issues.
15
 
16
  [Remember to visit our support forums if you have questions or comments.](http://wordfence.com/forums/)
17
 
18
- Wordfence is 100% free. We also offer a Premium API key that adds additional scanning capabilities.
19
 
20
  Wordfence:
21
 
22
- * Scans core files against repository versions to check their integrity.
23
- * WordPress Multi-Site (or WordPress MU in the older parlance) compatible (beta).
24
  * Wordfence Security for multi-site also scans all posts and comments across all blogs from one admin panel.
25
- * Premium API key also scans themes and plugins against repository versions.
26
  * See how files have changed. Optionally repair changed files that are security threats.
27
  * Scans for signatures of over 44,000 known malware variants that are known security threats.
28
- * Continuously scans for malware and phishing URL's in all your comments, posts and files that are security threats.
 
29
  * Scans for heuristics of backdoors, trojans, suspicious code and other security issues.
30
  * Checks the strength of all user and admin passwords to enhance login security.
31
  * Monitor your DNS security for unauthorized DNS changes.
@@ -152,8 +153,34 @@ or a theme, because often these have been updated to fix a security hole.
152
  5. If you're technically minded, this is the under-the-hood view of Wordfence options where you can fine-tune your security settings.
153
 
154
  == Changelog ==
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
155
  = 3.1.6 =
156
- * Changed noc1.wordfence.com to IP address.
157
 
158
  = 3.1.4 =
159
  * Fixed SQL error in code that checks if IP blockedTime has expired. Changed column type to signed.
3
  Tags: wordpress, security, wordpress security, security plugin, secure, anti-virus, malware, firewall, antivirus, virus, google safe browsing, phishing, scrapers, hacking, wordfence, securty, secrity, secure
4
  Requires at least: 3.3.1
5
  Tested up to: 3.4.1
6
+ Stable tag: 3.2.1
7
 
8
  Wordfence Security is a free enterprise class security plugin that includes a firewall, virus scanning, real-time traffic with geolocation and more.
9
 
10
  == Description ==
11
 
12
+ Wordfence Security is a free enterprise class security plugin that includes a firewall, anti-virus scanning, malicious URL scanning and live traffic including crawlers. Wordfence is the only WordPress security plugin that can verify and repair your core, theme and plugin files, even if you don't have backups.
13
 
14
+ Wordfence is now Multi-Site compatible.
15
 
16
  [Remember to visit our support forums if you have questions or comments.](http://wordfence.com/forums/)
17
 
18
+ Wordfence is 100% free. We also offer a Premium API key that lets you block countries and schedule scans for specific times.
19
 
20
  Wordfence:
21
 
22
+ * Scans core files, themes and plugins against WordPress.org repository versions to check their integrity.
23
+ * WordPress Multi-Site (or WordPress MU in the older parlance) compatible.
24
  * Wordfence Security for multi-site also scans all posts and comments across all blogs from one admin panel.
25
+ * Premium users can also block countries and schedule scans for specific times and a higher frequency.
26
  * See how files have changed. Optionally repair changed files that are security threats.
27
  * Scans for signatures of over 44,000 known malware variants that are known security threats.
28
+ * Scans for many known backdoors including C99, R57, RootShell, Crystal Shell, Matamu, Cybershell, W4cking, Sniper, Predator, Jackal, Phantasma, GFS, Dive, Dx and many many more.
29
+ * 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.
30
  * Scans for heuristics of backdoors, trojans, suspicious code and other security issues.
31
  * Checks the strength of all user and admin passwords to enhance login security.
32
  * Monitor your DNS security for unauthorized DNS changes.
153
  5. If you're technically minded, this is the under-the-hood view of Wordfence options where you can fine-tune your security settings.
154
 
155
  == Changelog ==
156
+ = 3.2.1 =
157
+ * Theme and plugin scanning is now free. Woohoo!
158
+ * Added introductory tour for Wordfence.
159
+ * Upgraded to Wordfence scanning API version 2.0 to allow free theme and plugin scanning.
160
+ * Fixed two issue with scheduled scanning for premium users that would cause scans to not run or run at wrong times under certain conditions.
161
+ * Added feature to view unknown files on system to help clean badly infected systems. See on scanning page in "Tools" under yellow box.
162
+ * Fixed blocked countries overflowing their container in the user interface.
163
+ * Fixed case where if user is using MySQL >= 5.1.16 and doesn't have the "drop" privilege, they can't truncate the wfFileQueue table and it could grow uncontrollably.
164
+ * Updated to the new Libyan flag.
165
+ * Fixed mysql_ping() reconnection to DB generating warnings.
166
+ * Fixed issue that caused scans to hang. Wordfence now processes smaller batches of files before checking if it needs to fork.
167
+ * Security scan for backdoors: "s72 Shell", "r57 kartal", "r57shell", "rootshell", "r57", "r57 Mohajer22", "r57 iFX", "php backdoor", "phpRemoteView"
168
+ * Security scan for backdoors: "nstview", "nshell", "mysql tool", "nsTView", "matamu", "mysql shell", "load shell", "ironshell", "lamashell", "hiddens shell"
169
+ * Security scan for backdoors: "h4ntu shell", "go shell", "dC3 Shell", "gfs sh", "cybershell", "c99 w4cking", "ctt sh"
170
+ * Security scan for backdoors: "c99 madnet", "c99 locus7s", "c99 PSych0", "c99", "c0derz shell", "accept language", "Web shell"
171
+ * Security scan for backdoors: "aZRaiLPhp", "SnIpEr SA Shell", "Safe0ver Shell"
172
+ * Security scan for backdoors: "SimShell", "Rootshell", "Predator", "PhpSpy", "PHPJackal", "PHANTASMA", "PHP Shell"
173
+ * Security scan for backdoors: "NTDaddy", "NetworkFileManagerPHP", "NIX REMOTE WEB SHELL", "NGH"
174
+ * Security scan for backdoors: "NFM", "Mysql interface", "NCC Shell", "MySQL Web Interface", "MyShell", "Macker PHPShell"
175
+ * Security scan for backdoors: "Loaderz WEB Shell", "KA uShell", "KAdot Universal Shell", "Liz0ziM"
176
+ * Security scan for backdoors: "Gamma Web Shell", "JspWebshell", "GRP WebShell", "GFS web shell"
177
+ * Security scan for backdoors: "GFS Web Shell", "Dx", "DxShell, "Dive Shell", "DTool Pro"
178
+ * Security scan for backdoors: "Ajax PHP Command Shell", "Antichat Shell", "Ayyildiz Shell"
179
+ * Security scan for backdoors: "C99 Shell", "C99 madShell", "CTT Shell", "CasuS", "CmdAsp", "Crystal Shell", "Cyber Shell"
180
+ * DNS fix from previous release backed out because it's no longer needed. (We temporarily hardcoded an IP)
181
+
182
  = 3.1.6 =
183
+ * Emergency release to deal with DNS issue.
184
 
185
  = 3.1.4 =
186
  * Fixed SQL error in code that checks if IP blockedTime has expired. Changed column type to signed.
wordfence.php CHANGED
@@ -4,10 +4,10 @@ Plugin Name: Wordfence Security
4
  Plugin URI: http://wordfence.com/
5
  Description: Wordfence Security - Anti-virus and Firewall security plugin for WordPress
6
  Author: Mark Maunder
7
- Version: 3.1.6
8
  Author URI: http://wordfence.com/
9
  */
10
- define('WORDFENCE_VERSION', '3.1.6');
11
  if(! defined('WORDFENCE_VERSIONONLY_MODE')){
12
  if((int) @ini_get('memory_limit') < 64){
13
  @ini_set('memory_limit', '64M'); //Some hosts have ini set at as little as 32 megs. 64 is the min sane amount of memory.
4
  Plugin URI: http://wordfence.com/
5
  Description: Wordfence Security - Anti-virus and Firewall security plugin for WordPress
6
  Author: Mark Maunder
7
+ Version: 3.2.1
8
  Author URI: http://wordfence.com/
9
  */
10
+ define('WORDFENCE_VERSION', '3.2.1');
11
  if(! defined('WORDFENCE_VERSIONONLY_MODE')){
12
  if((int) @ini_get('memory_limit') < 64){
13
  @ini_set('memory_limit', '64M'); //Some hosts have ini set at as little as 32 megs. 64 is the min sane amount of memory.