Version Description
- Improved scanning for specific attacks being used in the PHP-CGI vulnerability ( CVE-2012-1823)
- API keys no longer required. WF fetches a temporary anonymous API key for you on activation.
- Added real-time activity log on scan page.
- Added real-time summary updates on scan page.
- Fixed ability to view files that have symlinks in path.
- Added message to configure alert email address for multi-site and single site installs on activation.
- Disabled firewall rules by default because most sites don't need them.
- Disabled blocking of fake googlebots except for high security levels to prevent users who like to pretend they're googlebot from blocking themselves.
- Geshi the syntax highlighter now asks for more memory before running.
- Fixed bug that caused scan to hang on very large files.
- Added an index to wfStatus to make it faster for summary statuses
- Removed multisite pre-activation check to make activation more reliable on multisite installs.
- Better problem reporting if you trashed your Wordfence schema but the plugin is still installed.
Download this release
Release Info
Developer | mmaunder |
Plugin | Wordfence Security – Firewall & Malware Scan |
Version | 2.0.1 |
Comparing to | |
See all releases |
Code changes from version 1.5.6 to 2.0.1
- css/main.css +59 -15
- images/icons/ajaxScan.gif +0 -0
- js/admin.js +164 -31
- lib/menu_scan.php +41 -88
- lib/wfAPI.php +1 -4
- lib/wfConfig.php +4 -4
- lib/wfDB.php +19 -0
- lib/wfIssues.php +5 -4
- lib/wfLog.php +24 -3
- lib/wfScanEngine.php +125 -36
- lib/wfSchema.php +2 -1
- lib/wfUtils.php +32 -0
- lib/wfViewResult.php +1 -0
- lib/wordfenceClass.php +85 -32
- lib/wordfenceConstants.php +2 -1
- lib/wordfenceHash.php +9 -5
- lib/wordfenceScanner.php +10 -7
- readme.txt +16 -1
- wfscan.php +6 -9
- wordfence.php +1 -1
css/main.css
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
.wordfenceWrap {
|
2 |
-
margin:
|
3 |
}
|
4 |
div.wordfenceLive {
|
5 |
height: 29px;
|
@@ -89,7 +89,7 @@ div.wordfenceScanButton input.button-wf-grey {
|
|
89 |
.wfTabsContainer {
|
90 |
overflow: hidden;
|
91 |
border: 1px solid #CCC;
|
92 |
-
max-width:
|
93 |
padding: 15px;
|
94 |
min-height: 200px;
|
95 |
-webkit-font-smoothing: antialiased;
|
@@ -187,24 +187,18 @@ table th.wfConfigEnable { font-weight: bold; }
|
|
187 |
table th.wfSubheading { font-weight: bold; padding-top: 10px; }
|
188 |
.wfALogTime { color: #999; }
|
189 |
.wfALogEntry { }
|
190 |
-
.wfALogMailLink
|
191 |
display: block;
|
192 |
position: absolute;
|
193 |
-
|
194 |
-
height: 16px;
|
195 |
-
padding: 0;
|
196 |
margin: 0;
|
197 |
-
|
198 |
-
|
199 |
-
right: 20px;
|
200 |
-
top: 2px;
|
201 |
background-image: url(../images/icons/email_go.png);
|
|
|
|
|
202 |
}
|
203 |
-
|
204 |
-
right: 42px;
|
205 |
-
top: 2px;
|
206 |
-
background-image: url(../images/icons/arrow_refresh.png);
|
207 |
-
}
|
208 |
#wfActivity { position: relative; }
|
209 |
h3.wfConfigHeading {
|
210 |
font-size: 22px;
|
@@ -218,3 +212,53 @@ h3.wfConfigHeading {
|
|
218 |
font-family: Georgia;
|
219 |
font-style: italic;
|
220 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
.wordfenceWrap {
|
2 |
+
margin: 20px 0 0 20px;
|
3 |
}
|
4 |
div.wordfenceLive {
|
5 |
height: 29px;
|
89 |
.wfTabsContainer {
|
90 |
overflow: hidden;
|
91 |
border: 1px solid #CCC;
|
92 |
+
max-width: 870px;
|
93 |
padding: 15px;
|
94 |
min-height: 200px;
|
95 |
-webkit-font-smoothing: antialiased;
|
187 |
table th.wfSubheading { font-weight: bold; padding-top: 10px; }
|
188 |
.wfALogTime { color: #999; }
|
189 |
.wfALogEntry { }
|
190 |
+
.wfALogMailLink {
|
191 |
display: block;
|
192 |
position: absolute;
|
193 |
+
padding: 0 0 0 18px;
|
|
|
|
|
194 |
margin: 0;
|
195 |
+
right: 10px;
|
196 |
+
top: 0px;
|
|
|
|
|
197 |
background-image: url(../images/icons/email_go.png);
|
198 |
+
background-repeat: no-repeat;
|
199 |
+
font-weight: normal;
|
200 |
}
|
201 |
+
|
|
|
|
|
|
|
|
|
202 |
#wfActivity { position: relative; }
|
203 |
h3.wfConfigHeading {
|
204 |
font-size: 22px;
|
212 |
font-family: Georgia;
|
213 |
font-style: italic;
|
214 |
}
|
215 |
+
|
216 |
+
.consoleHead {
|
217 |
+
position: relative;
|
218 |
+
padding: 0 0 0 3px;
|
219 |
+
font-weight: bold;
|
220 |
+
width: 800px;
|
221 |
+
}
|
222 |
+
.consoleHeadText {
|
223 |
+
font-size: 18px;
|
224 |
+
font-family: Georgia, serif;
|
225 |
+
font-style: italic;
|
226 |
+
color: #555;
|
227 |
+
font-weight: bold;
|
228 |
+
-webkit-font-smoothing: antialiased;
|
229 |
+
|
230 |
+
}
|
231 |
+
.consoleOuter { width: 800px; margin-bottom: 20px; }
|
232 |
+
.consoleInner { height: 116px; overflow: auto; z-index: 1; }
|
233 |
+
.bevelDiv1 { border: 1px solid #EFEFEF; }
|
234 |
+
.bevelDiv2 { border: 1px solid #AAA; }
|
235 |
+
.bevelDiv3 { border: 1px solid #555;
|
236 |
+
background-color: #FFFFE0; /* #FFFFF0; /* #FFEBCD; #FFFACD; */
|
237 |
+
color: #000; padding: 5px; font-family: Arial; -webkit-font-smoothing: none; }
|
238 |
+
|
239 |
+
.wfBlackCursor{ color: #FFF; }
|
240 |
+
.wfSecure { color: #0A0; font-weight: bold; }
|
241 |
+
.wfActivityLine {
|
242 |
+
}
|
243 |
+
.wfSummaryDate { float: left; margin-left: 3px; }
|
244 |
+
.wfSummaryMsg { float: left; margin-left: 3px; }
|
245 |
+
.wfSummaryResult { float: right; text-align: left; width: 280px; }
|
246 |
+
.wfSummaryLoading { width: 16px; height: 11px; background-image: url('../images/icons/ajaxScan.gif'); }
|
247 |
+
.wfSummaryBad, .wfSummaryErr { color: #A00; }
|
248 |
+
.wfSummaryOK { color: #0A0; }
|
249 |
+
.wfClear {
|
250 |
+
content: ".";
|
251 |
+
display: block;
|
252 |
+
height: 0;
|
253 |
+
width: 0;
|
254 |
+
line-height: 0;
|
255 |
+
clear: both;
|
256 |
+
visibility: hidden;
|
257 |
+
}
|
258 |
+
.wfSummaryFinal {
|
259 |
+
-webkit-font-smoothing: antialiased;
|
260 |
+
font-weight: bold;
|
261 |
+
color: #555;
|
262 |
+
}
|
263 |
+
input.wfStartScanButton { width: 160px; text-align: left; padding-left: 20px; }
|
264 |
+
|
images/icons/ajaxScan.gif
ADDED
Binary file
|
js/admin.js
CHANGED
@@ -1,6 +1,7 @@
|
|
1 |
if(! window['wordfenceAdmin']){
|
2 |
window['wordfenceAdmin'] = {
|
3 |
loading16: '<div class="wfLoading16"></div>',
|
|
|
4 |
dbCheckTables: [],
|
5 |
dbCheckCount_ok: 0,
|
6 |
dbCheckCount_skipped: 0,
|
@@ -11,7 +12,6 @@ window['wordfenceAdmin'] = {
|
|
11 |
scanIDLoaded: 0,
|
12 |
colorboxQueue: [],
|
13 |
colorboxOpen: false,
|
14 |
-
scanPending: false,
|
15 |
mode: '',
|
16 |
visibleIssuesPanel: 'new',
|
17 |
preFirstScanMsgsLoaded: false,
|
@@ -19,33 +19,179 @@ window['wordfenceAdmin'] = {
|
|
19 |
elementGeneratorIter: 1,
|
20 |
reloadConfigPage: false,
|
21 |
nonce: false,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
22 |
init: function(){
|
23 |
this.nonce = WordfenceAdminVars.firstNonce;
|
|
|
24 |
if(jQuery('#wordfenceMode_scan').length > 0){
|
25 |
this.mode = 'scan';
|
|
|
|
|
26 |
this.noScanHTML = jQuery('#wfNoScanYetTmpl').tmpl().html();
|
|
|
|
|
27 |
} else if(jQuery('#wordfenceMode_activity').length > 0){
|
28 |
this.mode = 'activity';
|
29 |
this.activityMode = 'hit';
|
30 |
-
|
31 |
} else if(jQuery('#wordfenceMode_options').length > 0){
|
32 |
this.mode = 'options';
|
33 |
jQuery('.wfConfigElem').change(function(){ jQuery('#securityLevel').val('CUSTOM'); });
|
34 |
this.updateTicker(true);
|
|
|
35 |
} else if(jQuery('#wordfenceMode_blockedIPs').length > 0){
|
36 |
this.mode = 'blocked';
|
37 |
this.staticTabChanged();
|
38 |
this.updateTicker(true);
|
|
|
39 |
} else {
|
40 |
this.mode = false;
|
41 |
}
|
42 |
if(this.mode){ //We are in a Wordfence page
|
43 |
var self = this;
|
44 |
-
|
|
|
|
|
45 |
jQuery(document).bind('cbox_closed', function(){ self.colorboxIsOpen = false; self.colorboxServiceQueue(); });
|
46 |
}
|
47 |
|
48 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
49 |
updateTicker: function(forceUpdate){
|
50 |
if( (! forceUpdate) && this.tickerUpdatePending){
|
51 |
return;
|
@@ -80,27 +226,7 @@ window['wordfenceAdmin'] = {
|
|
80 |
jQuery('#wfLiveStatus').hide().html(newMsg).fadeIn(200);
|
81 |
}
|
82 |
|
83 |
-
if(this.mode == '
|
84 |
-
if(res.running){
|
85 |
-
jQuery('.wfStartScanButton').addClass('button-wf-grey').val("A scan is in progress...").unbind('click').click(function(){ wordfenceAdmin.scanRunningMsg(); }).show();
|
86 |
-
} else {
|
87 |
-
if(! this.scanPending){
|
88 |
-
jQuery('.wfStartScanButton').removeClass('button-wf-grey').val("Start a Wordfence Scan").unbind('click').click(function(){ wordfenceAdmin.startScan(); }).show();
|
89 |
-
}
|
90 |
-
}
|
91 |
-
if(res.currentScanID && res.currentScanID != this.scanIDLoaded){
|
92 |
-
this.scanIDLoaded = res.currentScanID;
|
93 |
-
this.loadIssues();
|
94 |
-
} else if( (! res.currentScanID) && (! this.scanIDLoaded)){
|
95 |
-
//We haven't done our first scan yet.
|
96 |
-
if(! this.preFirstScanMsgsLoaded){
|
97 |
-
this.preFirstScanMsgsLoaded = true;
|
98 |
-
jQuery('#wfSummaryTables').html(this.noScanHTML);
|
99 |
-
this.switchIssuesTab(jQuery('#wfNewIssuesTab'), 'new');
|
100 |
-
jQuery('#wfActivity').html('<p>No events to report yet. Please complete your first scan.</p>');
|
101 |
-
}
|
102 |
-
}
|
103 |
-
} else if(this.mode == 'activity'){
|
104 |
if(res.alsoGet != 'logList_' + this.activityMode){ return; } //user switched panels since ajax request started
|
105 |
if(/^(?:topScanners|topLeechers)$/.test(this.activityMode)){
|
106 |
if(statusMsgChanged){ this.updateTicker(true); } return;
|
@@ -202,12 +328,20 @@ window['wordfenceAdmin'] = {
|
|
202 |
});
|
203 |
},
|
204 |
startScan: function(){
|
205 |
-
var
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
211 |
this.ajax('wordfence_scan', {}, function(res){ } );
|
212 |
},
|
213 |
loadIssues: function(callback){
|
@@ -231,7 +365,6 @@ window['wordfenceAdmin'] = {
|
|
231 |
displayIssues: function(res, callback){
|
232 |
var self = this;
|
233 |
res.summary['lastScanCompleted'] = res['lastScanCompleted'];
|
234 |
-
jQuery('#wfSummaryTables').html( jQuery('#wfScanSummaryTmpl').tmpl(res.summary).html() );
|
235 |
jQuery('.wfIssuesContainer').hide();
|
236 |
for(issueStatus in res.issuesLists){
|
237 |
var containerID = 'wfIssues_dataTable_' + issueStatus;
|
1 |
if(! window['wordfenceAdmin']){
|
2 |
window['wordfenceAdmin'] = {
|
3 |
loading16: '<div class="wfLoading16"></div>',
|
4 |
+
actUpdateInterval: 2000,
|
5 |
dbCheckTables: [],
|
6 |
dbCheckCount_ok: 0,
|
7 |
dbCheckCount_skipped: 0,
|
12 |
scanIDLoaded: 0,
|
13 |
colorboxQueue: [],
|
14 |
colorboxOpen: false,
|
|
|
15 |
mode: '',
|
16 |
visibleIssuesPanel: 'new',
|
17 |
preFirstScanMsgsLoaded: false,
|
19 |
elementGeneratorIter: 1,
|
20 |
reloadConfigPage: false,
|
21 |
nonce: false,
|
22 |
+
tickerUpdatePending: false,
|
23 |
+
activityLogUpdatePending: false,
|
24 |
+
lastALogCtime: 0,
|
25 |
+
activityQueue: [],
|
26 |
+
totalActAdded: 0,
|
27 |
+
maxActivityLogItems: 1000,
|
28 |
+
scanReqAnimation: false,
|
29 |
init: function(){
|
30 |
this.nonce = WordfenceAdminVars.firstNonce;
|
31 |
+
var startTicker = false;
|
32 |
if(jQuery('#wordfenceMode_scan').length > 0){
|
33 |
this.mode = 'scan';
|
34 |
+
jQuery('#consoleActivity').scrollTop(jQuery('#consoleActivity').prop('scrollHeight'));
|
35 |
+
jQuery('#consoleScan').scrollTop(jQuery('#consoleScan').prop('scrollHeight'));
|
36 |
this.noScanHTML = jQuery('#wfNoScanYetTmpl').tmpl().html();
|
37 |
+
this.loadIssues();
|
38 |
+
this.startActivityLogUpdates();
|
39 |
} else if(jQuery('#wordfenceMode_activity').length > 0){
|
40 |
this.mode = 'activity';
|
41 |
this.activityMode = 'hit';
|
42 |
+
startTicker = true;
|
43 |
} else if(jQuery('#wordfenceMode_options').length > 0){
|
44 |
this.mode = 'options';
|
45 |
jQuery('.wfConfigElem').change(function(){ jQuery('#securityLevel').val('CUSTOM'); });
|
46 |
this.updateTicker(true);
|
47 |
+
startTicker = true;
|
48 |
} else if(jQuery('#wordfenceMode_blockedIPs').length > 0){
|
49 |
this.mode = 'blocked';
|
50 |
this.staticTabChanged();
|
51 |
this.updateTicker(true);
|
52 |
+
startTicker = true;
|
53 |
} else {
|
54 |
this.mode = false;
|
55 |
}
|
56 |
if(this.mode){ //We are in a Wordfence page
|
57 |
var self = this;
|
58 |
+
if(startTicker){
|
59 |
+
this.liveInt = setInterval(function(){ self.updateTicker(); }, 2000);
|
60 |
+
}
|
61 |
jQuery(document).bind('cbox_closed', function(){ self.colorboxIsOpen = false; self.colorboxServiceQueue(); });
|
62 |
}
|
63 |
|
64 |
},
|
65 |
+
startActivityLogUpdates: function(){
|
66 |
+
var self = this;
|
67 |
+
setInterval(function(){
|
68 |
+
self.updateActivityLog();
|
69 |
+
}, this.actUpdateInterval);
|
70 |
+
},
|
71 |
+
updateActivityLog: function(){
|
72 |
+
if(this.activityLogUpdatePending){
|
73 |
+
return;
|
74 |
+
}
|
75 |
+
this.activityLogUpdatePending = true;
|
76 |
+
var self = this;
|
77 |
+
this.ajax('wordfence_activityLogUpdate', {
|
78 |
+
lastctime: this.lastALogCtime
|
79 |
+
}, function(res){ self.doneUpdateActivityLog(res); }, function(){ self.activityLogUpdatePending = false; });
|
80 |
+
|
81 |
+
},
|
82 |
+
doneUpdateActivityLog: function(res){
|
83 |
+
this.actNextUpdateAt = (new Date()).getTime() + this.actUpdateInterval;
|
84 |
+
if(res.ok){
|
85 |
+
if(res.items.length > 0){
|
86 |
+
this.activityQueue.push.apply(this.activityQueue, res.items);
|
87 |
+
this.lastALogCtime = res.items[res.items.length - 1].ctime;
|
88 |
+
this.processActQueue(res.currentScanID);
|
89 |
+
}
|
90 |
+
}
|
91 |
+
this.activityLogUpdatePending = false;
|
92 |
+
},
|
93 |
+
processActQueue: function(currentScanID){
|
94 |
+
if(this.activityQueue.length > 0){
|
95 |
+
|
96 |
+
this.addActItem(this.activityQueue.shift());
|
97 |
+
this.totalActAdded++;
|
98 |
+
if(this.totalActAdded > this.maxActivityLogItems){
|
99 |
+
jQuery('#consoleActivity div:first').remove();
|
100 |
+
this.totalActAdded--;
|
101 |
+
}
|
102 |
+
|
103 |
+
var timeTillNextUpdate = this.actNextUpdateAt - (new Date()).getTime();
|
104 |
+
var maxRate = 50 / 1000; //Rate per millisecond
|
105 |
+
var bulkTotal = 0;
|
106 |
+
while(this.activityQueue.length > 0 && this.activityQueue.length / timeTillNextUpdate > maxRate ){
|
107 |
+
var item = this.activityQueue.shift();
|
108 |
+
if(item){
|
109 |
+
bulkTotal++;
|
110 |
+
this.addActItem(item);
|
111 |
+
}
|
112 |
+
}
|
113 |
+
this.totalActAdded += bulkTotal;
|
114 |
+
if(this.totalActAdded > this.maxActivityLogItems){
|
115 |
+
jQuery('#consoleActivity div:lt(' + bulkTotal + ')').remove();
|
116 |
+
this.totalActAdded -= bulkTotal;
|
117 |
+
}
|
118 |
+
var minDelay = 100;
|
119 |
+
var delay = minDelay;
|
120 |
+
if(timeTillNextUpdate < 1){
|
121 |
+
delay = minDelay;
|
122 |
+
} else {
|
123 |
+
delay = Math.round(timeTillNextUpdate / this.activityQueue.length);
|
124 |
+
if(delay < minDelay){ delay = minDelay; }
|
125 |
+
}
|
126 |
+
var self = this;
|
127 |
+
setTimeout(function(){ self.processActQueue(); }, delay);
|
128 |
+
}
|
129 |
+
jQuery('#consoleActivity').scrollTop(jQuery('#consoleActivity').prop('scrollHeight'));
|
130 |
+
},
|
131 |
+
processActArray: function(arr){
|
132 |
+
for(var i = 0; i < arr.length; i++){
|
133 |
+
this.addActItem(arr[i]);
|
134 |
+
}
|
135 |
+
},
|
136 |
+
addActItem: function(item){
|
137 |
+
if(item.msg.indexOf('SUM_') == 0){
|
138 |
+
this.processSummaryLine(item);
|
139 |
+
jQuery('#consoleSummary').scrollTop(jQuery('#consoleSummary').prop('scrollHeight'));
|
140 |
+
jQuery('#wfStartingScan').addClass('wfSummaryOK').html('Done.');
|
141 |
+
} else {
|
142 |
+
jQuery('#consoleActivity').append('<div class="wfActivityLine wf' + item.type + '">[' + item.date + '] ' + item.msg + '</div>');
|
143 |
+
if(/Scan complete\./i.test(item.msg)){
|
144 |
+
this.loadIssues();
|
145 |
+
}
|
146 |
+
}
|
147 |
+
},
|
148 |
+
processSummaryLine: function(item){
|
149 |
+
if(item.msg.indexOf('SUM_START:') != -1){
|
150 |
+
var msg = item.msg.replace('SUM_START:', '');
|
151 |
+
jQuery('#consoleSummary').append('<div class="wfSummaryLine"><div class="wfSummaryDate">[' + item.date + ']</div><div class="wfSummaryMsg">' + msg + '</div><div class="wfSummaryResult"><div class="wfSummaryLoading"></div></div><div class="wfClear"></div>');
|
152 |
+
summaryUpdated = true;
|
153 |
+
} else if(item.msg.indexOf('SUM_ENDBAD') != -1){
|
154 |
+
var msg = item.msg.replace('SUM_ENDBAD:', '');
|
155 |
+
jQuery('div.wfSummaryMsg:contains("' + msg + '")').next().addClass('wfSummaryBad').html('Problems found.');
|
156 |
+
summaryUpdated = true;
|
157 |
+
} else if(item.msg.indexOf('SUM_ENDOK') != -1){
|
158 |
+
var msg = item.msg.replace('SUM_ENDOK:', '');
|
159 |
+
jQuery('div.wfSummaryMsg:contains("' + msg + '")').next().addClass('wfSummaryOK').html('Secure.');
|
160 |
+
summaryUpdated = true;
|
161 |
+
} else if(item.msg.indexOf('SUM_ENDERR') != -1){
|
162 |
+
var msg = item.msg.replace('SUM_ENDERR:', '');
|
163 |
+
jQuery('div.wfSummaryMsg:contains("' + msg + '")').next().addClass('wfSummaryErr').html('An error occured.');
|
164 |
+
summaryUpdated = true;
|
165 |
+
} else if(item.msg.indexOf('SUM_DISABLED:') != -1){
|
166 |
+
var msg = item.msg.replace('SUM_DISABLED:', '');
|
167 |
+
jQuery('#consoleSummary').append('<div class="wfSummaryLine"><div class="wfSummaryDate">[' + item.date + ']</div><div class="wfSummaryMsg">' + msg + '</div><div class="wfSummaryResult">Disabled</div><div class="wfClear"></div>');
|
168 |
+
summaryUpdated = true;
|
169 |
+
} else if(item.msg.indexOf('SUM_PAIDONLY:') != -1){
|
170 |
+
var msg = item.msg.replace('SUM_PAIDONLY:', '');
|
171 |
+
jQuery('#consoleSummary').append('<div class="wfSummaryLine"><div class="wfSummaryDate">[' + item.date + ']</div><div class="wfSummaryMsg">' + msg + '</div><div class="wfSummaryResult"><a href="http://www.wordfence.com/" target="_blank">Paid Members Only</a></div><div class="wfClear"></div>');
|
172 |
+
summaryUpdated = true;
|
173 |
+
} else if(item.msg.indexOf('SUM_FINAL:') != -1){
|
174 |
+
var msg = item.msg.replace('SUM_FINAL:', '');
|
175 |
+
jQuery('#consoleSummary').append('<div class="wfSummaryLine"><div class="wfSummaryDate">[' + item.date + ']</div><div class="wfSummaryMsg wfSummaryFinal">' + msg + '</div><div class="wfSummaryResult wfSummaryOK">Scan Complete.</div><div class="wfClear"></div>');
|
176 |
+
} else if(item.msg.indexOf('SUM_PREP:') != -1){
|
177 |
+
var msg = item.msg.replace('SUM_PREP:', '');
|
178 |
+
jQuery('#consoleSummary').empty().html('<div class="wfSummaryLine"><div class="wfSummaryDate">[' + item.date + ']</div><div class="wfSummaryMsg">' + msg + '</div><div class="wfSummaryResult" id="wfStartingScan"><div class="wfSummaryLoading"></div></div><div class="wfClear"></div>');
|
179 |
+
}
|
180 |
+
},
|
181 |
+
processActQueueItem: function(){
|
182 |
+
var item = this.activityQueue.shift();
|
183 |
+
if(item){
|
184 |
+
jQuery('#consoleActivity').append('<div class="wfActivityLine wf' + item.type + '">[' + item.date + '] ' + item.msg + '</div>');
|
185 |
+
this.totalActAdded++;
|
186 |
+
if(this.totalActAdded > this.maxActivityLogItems){
|
187 |
+
jQuery('#consoleActivity div:first').remove();
|
188 |
+
this.totalActAdded--;
|
189 |
+
}
|
190 |
+
if(item.msg == 'Scan complete.'){
|
191 |
+
this.loadIssues();
|
192 |
+
}
|
193 |
+
}
|
194 |
+
},
|
195 |
updateTicker: function(forceUpdate){
|
196 |
if( (! forceUpdate) && this.tickerUpdatePending){
|
197 |
return;
|
226 |
jQuery('#wfLiveStatus').hide().html(newMsg).fadeIn(200);
|
227 |
}
|
228 |
|
229 |
+
if(this.mode == 'activity'){
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
230 |
if(res.alsoGet != 'logList_' + this.activityMode){ return; } //user switched panels since ajax request started
|
231 |
if(/^(?:topScanners|topLeechers)$/.test(this.activityMode)){
|
232 |
if(statusMsgChanged){ this.updateTicker(true); } return;
|
328 |
});
|
329 |
},
|
330 |
startScan: function(){
|
331 |
+
var scanReqAnimation = setInterval(function(){
|
332 |
+
var str = jQuery('#wfStartScanButton1').prop('value');
|
333 |
+
ch = str.charAt(str.length - 1);
|
334 |
+
if(ch == '/'){ ch = '-'; }
|
335 |
+
else if(ch == '-'){ ch = '\\'; }
|
336 |
+
else if(ch == '\\'){ ch = '|'; }
|
337 |
+
else if(ch == '|'){ ch = '/'; }
|
338 |
+
else {ch = '/'; }
|
339 |
+
jQuery('#wfStartScanButton1,#wfStartScanButton2').prop('value', "Requesting a New Scan " + ch);
|
340 |
+
}, 100);
|
341 |
+
setTimeout(function(res){
|
342 |
+
clearInterval(scanReqAnimation);
|
343 |
+
jQuery('#wfStartScanButton1,#wfStartScanButton2').prop('value', "Start a Wordfence Scan");
|
344 |
+
}, 2000);
|
345 |
this.ajax('wordfence_scan', {}, function(res){ } );
|
346 |
},
|
347 |
loadIssues: function(callback){
|
365 |
displayIssues: function(res, callback){
|
366 |
var self = this;
|
367 |
res.summary['lastScanCompleted'] = res['lastScanCompleted'];
|
|
|
368 |
jQuery('.wfIssuesContainer').hide();
|
369 |
for(issueStatus in res.issuesLists){
|
370 |
var containerID = 'wfIssues_dataTable_' + issueStatus;
|
lib/menu_scan.php
CHANGED
@@ -1,27 +1,49 @@
|
|
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="wordfenceLive">
|
5 |
-
<table border="0" cellpadding="0" cellspacing="0">
|
6 |
-
<tr><td><h2>Wordfence Activity Log:</h2></td><td id="wfLiveStatus"></td></tr>
|
7 |
-
</table>
|
8 |
-
</div>
|
9 |
<div class="wordfenceWrap">
|
|
|
|
|
|
|
10 |
<div>
|
11 |
-
<div
|
12 |
-
<
|
13 |
-
<a href="#" class="wfTab1 wfTabSwitch" onclick="wordfenceAdmin.switchToLiveTab(this); return false;">Activity Log</a>
|
14 |
</div>
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
<div
|
21 |
-
|
22 |
-
|
23 |
</div>
|
|
|
|
|
|
|
|
|
|
|
24 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
25 |
</div>
|
26 |
<div style="margin-top: 20px;">
|
27 |
<div id="wfTabs">
|
@@ -36,7 +58,8 @@
|
|
36 |
If you have fixed all the issues below, you can <a href="#" onclick="WFAD.updateAllIssues('deleteNew'); return false;">click here to mark all new issues as fixed</a>.
|
37 |
You can also <a href="#" onclick="WFAD.updateAllIssues('ignoreAllNew'); return false;">ignore all new issues</a> which will exclude all issues listed below from future scans.
|
38 |
</p>
|
39 |
-
<div id="wfIssues_dataTable_new"
|
|
|
40 |
</div>
|
41 |
<div id="wfIssues_ignored" class="wfIssuesContainer">
|
42 |
<h2>Ignored Issues</h2>
|
@@ -395,7 +418,7 @@
|
|
395 |
where you can post your comments or questions. We would love to hear from you.
|
396 |
</td></tr>
|
397 |
<tr><td>
|
398 |
-
<div class="wordfenceScanButton"><input type="button" value="Start a Wordfence Scan" class="wfStartScanButton button-primary" /></div>
|
399 |
</td></tr>
|
400 |
</table>
|
401 |
</td>
|
@@ -403,74 +426,4 @@
|
|
403 |
</div>
|
404 |
</script>
|
405 |
|
406 |
-
<script type="text/x-jquery-template" id="wfScanSummaryTmpl">
|
407 |
-
<div>
|
408 |
-
<table class="wfSummaryParent" cellpadding="0" cellspacing="0">
|
409 |
-
<tr><th class="wfHead">Activity Summary:</th><th class="wfHead" colspan="3">Wordfence is Protecting:</th></tr>
|
410 |
-
<tr><td>
|
411 |
-
<table class="wfSC1" cellpadding="0" cellspacing="0">
|
412 |
-
<tr><td>
|
413 |
-
The most recent scan completed ${scanTimeAgo} ago.
|
414 |
-
</td></tr>
|
415 |
-
<tr><td>
|
416 |
-
{{if scanRunning == '1'}}
|
417 |
-
There is currently a scan running
|
418 |
-
{{else}}
|
419 |
-
A scan is not running at this time
|
420 |
-
{{/if}}
|
421 |
-
{{if scheduledScansEnabled}}
|
422 |
-
and the next scan is scheduled to run approximately ${nextRun}.
|
423 |
-
{{else}}
|
424 |
-
and scheduled scans are disabled.
|
425 |
-
{{/if}}
|
426 |
-
</td></tr>
|
427 |
-
<tr><td>
|
428 |
-
{{if totalCritical > 0 || totalWarning > 0}}
|
429 |
-
There are currently
|
430 |
-
{{if totalCritical > 0 && totalWarning > 0}}
|
431 |
-
${totalCritical} critical issues and ${totalWarning} warning issues
|
432 |
-
{{else totalCritical > 0}}
|
433 |
-
${totalCritical} critical issues
|
434 |
-
{{else totalWarning > 0}}
|
435 |
-
${totalWarning} warning issues
|
436 |
-
{{/if}}
|
437 |
-
you need to investigate. See below for full details.
|
438 |
-
{{else lastScanCompleted == 'ok'}}
|
439 |
-
Congratulations, you have no security issues that need investigating.
|
440 |
-
{{else lastScanCompleted}}
|
441 |
-
<span style="color: #A00;">Latest scan failed: ${lastScanCompleted}</span>
|
442 |
-
{{/if}}
|
443 |
-
</td></tr>
|
444 |
-
<tr><td>
|
445 |
-
<div class="wordfenceScanButton"><input type="button" value="Start a Wordfence Scan" class="wfStartScanButton button-primary" onclick="wordfenceAdmin.startScan();" /></div>
|
446 |
-
<a href="http://www.wordfence.com/forums/" target="_blank">Visit the Wordfence forums for help.</a>
|
447 |
-
</td></tr>
|
448 |
-
</table>
|
449 |
-
</td>
|
450 |
-
<td>
|
451 |
-
<table class="wfSummaryChild wfSC2" cellpadding="0" cellspacing="0">
|
452 |
-
<tr><th>${wordfenceAdmin.commify(totalFiles)}</th><td>Files</td></tr>
|
453 |
-
<tr><th>${wordfenceAdmin.commify(totalDirs)}</th><td>Directories</td></tr>
|
454 |
-
<tr><th>${wordfenceAdmin.commify(totalUsers)}</th><td>Users</td></tr>
|
455 |
-
<tr><th>${wordfenceAdmin.commify(totalPlugins)}</th><td>Plugins</td></tr>
|
456 |
-
<tr><th>${wordfenceAdmin.commify(totalThemes)}</th><td>Themes</td></tr>
|
457 |
-
<tr><th>${wordfenceAdmin.commify(totalPages)}</th><td>Pages</td></tr>
|
458 |
-
<tr><th>${wordfenceAdmin.commify(totalPosts)}</th><td>Posts</td></tr>
|
459 |
-
</table>
|
460 |
-
</td>
|
461 |
-
<td> </td>
|
462 |
-
<td>
|
463 |
-
<table class="wfSummaryChild wfSC3" cellpadding="0" cellspacing="0">
|
464 |
-
<tr><th>${wordfenceAdmin.commify(totalComments)}</th><td>Comments</td></tr>
|
465 |
-
<tr><th>${wordfenceAdmin.commify(totalCategories)}</th><td>Categories</td></tr>
|
466 |
-
<tr><th>${wordfenceAdmin.commify(linesOfPHP)}</th><td>Lines of PHP code</td></tr>
|
467 |
-
<tr><th>${wordfenceAdmin.commify(linesOfJCH)}</th><td>Lines of JS, HTML and CSS code</td></tr>
|
468 |
-
<tr><th>${wordfenceAdmin.commify(totalData)}</th><td>of data in ${wordfenceAdmin.commify(totalFiles)} files</td></tr>
|
469 |
-
<tr><th>${wordfenceAdmin.commify(totalTables)}</th><td>Database Tables</td><tr>
|
470 |
-
<tr><th>${wordfenceAdmin.commify(totalRows)}</th><td>Database Rows</td></tr>
|
471 |
-
</table>
|
472 |
-
</td>
|
473 |
-
</tr></table>
|
474 |
-
</div>
|
475 |
-
</script>
|
476 |
|
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 |
+
</div>
|
8 |
<div>
|
9 |
+
<div class="consoleHead">
|
10 |
+
<span class="consoleHeadText">Scan Summary</span>
|
|
|
11 |
</div>
|
12 |
+
<?php
|
13 |
+
$events = wordfence::getLog()->getStatusEvents(0);
|
14 |
+
?>
|
15 |
+
<div class="bevelDiv1 consoleOuter"><div class="bevelDiv2"><div class="bevelDiv3 consoleInner" id="consoleSummary">
|
16 |
+
<?php if(sizeof($events) < 1){ ?>
|
17 |
+
<div style="width: 500px;">
|
18 |
+
Welcome to Wordfence!<br /><br />
|
19 |
+
To get started, simply click the blue button at the top of this page to start your first scan.
|
20 |
</div>
|
21 |
+
<?php } ?>
|
22 |
+
</div></div></div>
|
23 |
+
<div class="consoleHead">
|
24 |
+
<span class="consoleHeadText">Scan Detailed Activity</span>
|
25 |
+
<a href="#" class="wfALogMailLink" onclick="WFAD.emailActivityLog(); return false;">Email Activity Log</a>
|
26 |
</div>
|
27 |
+
<div class="bevelDiv1 consoleOuter"><div class="bevelDiv2"><div class="bevelDiv3 consoleInner" id="consoleActivity">
|
28 |
+
<?php
|
29 |
+
if(sizeof($events) > 0){
|
30 |
+
$newestItem = 0;
|
31 |
+
$sumEvents = array();
|
32 |
+
foreach($events as $e){
|
33 |
+
if(strpos($e['msg'], 'SUM_') !== 0){
|
34 |
+
echo '<div class="wfActivityLine wf' . $e['type'] . '">[' . date('M d H:i:s', $e['ctime']) . '] ' . $e['msg'] . '</div>';
|
35 |
+
}
|
36 |
+
$newestItem = $e['ctime'];
|
37 |
+
}
|
38 |
+
|
39 |
+
echo '<script type="text/javascript">WFAD.lastALogCtime = ' . $newestItem . '; WFAD.processActArray(' . json_encode(wordfence::getLog()->getSummaryEvents()) . ');</script>';
|
40 |
+
} else { ?>
|
41 |
+
A live stream of what Wordfence is busy with right now will appear in this box.
|
42 |
+
|
43 |
+
<?php
|
44 |
+
}
|
45 |
+
?>
|
46 |
+
</div></div></div>
|
47 |
</div>
|
48 |
<div style="margin-top: 20px;">
|
49 |
<div id="wfTabs">
|
58 |
If you have fixed all the issues below, you can <a href="#" onclick="WFAD.updateAllIssues('deleteNew'); return false;">click here to mark all new issues as fixed</a>.
|
59 |
You can also <a href="#" onclick="WFAD.updateAllIssues('ignoreAllNew'); return false;">ignore all new issues</a> which will exclude all issues listed below from future scans.
|
60 |
</p>
|
61 |
+
<div id="wfIssues_dataTable_new">
|
62 |
+
</div>
|
63 |
</div>
|
64 |
<div id="wfIssues_ignored" class="wfIssuesContainer">
|
65 |
<h2>Ignored Issues</h2>
|
418 |
where you can post your comments or questions. We would love to hear from you.
|
419 |
</td></tr>
|
420 |
<tr><td>
|
421 |
+
<div class="wordfenceScanButton"><input type="button" value="Start a Wordfence Scan" id="wfStartScanButton2" class="wfStartScanButton button-primary" /></div>
|
422 |
</td></tr>
|
423 |
</table>
|
424 |
</td>
|
426 |
</div>
|
427 |
</script>
|
428 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
429 |
|
lib/wfAPI.php
CHANGED
@@ -15,7 +15,6 @@ class wfAPI {
|
|
15 |
$this->wordpressVersion = $wordpressVersion;
|
16 |
}
|
17 |
public function call($action, $getParams = array(), $postParams = array()){
|
18 |
-
wordfence::status(3, 'info', "Starting API call: $action");
|
19 |
$this->errorMsg = false;
|
20 |
$json = $this->getURL(WORDFENCE_API_URL . '/v' . WORDFENCE_VERSION . '/?' . $this->makeAPIQueryString() . '&' . http_build_query(
|
21 |
array_merge(
|
@@ -42,7 +41,7 @@ class wfAPI {
|
|
42 |
if($this->errorMsg){
|
43 |
wordfence::status(3, 'error', "API Error: " . $this->errorMsg);
|
44 |
} else {
|
45 |
-
wordfence::status(3, 'info', "Completed API call: $action");
|
46 |
}
|
47 |
return $dat;
|
48 |
}
|
@@ -94,7 +93,6 @@ class wfAPI {
|
|
94 |
|
95 |
}
|
96 |
public function binCall($func, $postData){
|
97 |
-
wordfence::status(3, 'info', "Starting binary API call: $func");
|
98 |
$this->errorMsg = false;
|
99 |
$url = WORDFENCE_API_URL . '/v' . WORDFENCE_VERSION . '/?' . $this->makeAPIQueryString() . '&action=' . $func;
|
100 |
$curl = curl_init($url);
|
@@ -120,7 +118,6 @@ class wfAPI {
|
|
120 |
return false;
|
121 |
}
|
122 |
}
|
123 |
-
wordfence::status(3, 'info', "Completed binary API call $func with code: $httpStatus");
|
124 |
return array('code' => $httpStatus, 'data' => $data);
|
125 |
}
|
126 |
public function makeAPIQueryString(){
|
15 |
$this->wordpressVersion = $wordpressVersion;
|
16 |
}
|
17 |
public function call($action, $getParams = array(), $postParams = array()){
|
|
|
18 |
$this->errorMsg = false;
|
19 |
$json = $this->getURL(WORDFENCE_API_URL . '/v' . WORDFENCE_VERSION . '/?' . $this->makeAPIQueryString() . '&' . http_build_query(
|
20 |
array_merge(
|
41 |
if($this->errorMsg){
|
42 |
wordfence::status(3, 'error', "API Error: " . $this->errorMsg);
|
43 |
} else {
|
44 |
+
//wordfence::status(3, 'info', "Completed API call: $action");
|
45 |
}
|
46 |
return $dat;
|
47 |
}
|
93 |
|
94 |
}
|
95 |
public function binCall($func, $postData){
|
|
|
96 |
$this->errorMsg = false;
|
97 |
$url = WORDFENCE_API_URL . '/v' . WORDFENCE_VERSION . '/?' . $this->makeAPIQueryString() . '&action=' . $func;
|
98 |
$curl = curl_init($url);
|
118 |
return false;
|
119 |
}
|
120 |
}
|
|
|
121 |
return array('code' => $httpStatus, 'data' => $data);
|
122 |
}
|
123 |
public function makeAPIQueryString(){
|
lib/wfConfig.php
CHANGED
@@ -89,7 +89,7 @@ class wfConfig {
|
|
89 |
"scansEnabled_diskSpace" => true,
|
90 |
"scansEnabled_dns" => true,
|
91 |
"scansEnabled_oldVersions" => true,
|
92 |
-
"firewallEnabled" =>
|
93 |
"blockFakeBots" => false,
|
94 |
"autoBlockScanners" => true,
|
95 |
"loginSecurityEnabled" => true,
|
@@ -150,8 +150,8 @@ class wfConfig {
|
|
150 |
"scansEnabled_diskSpace" => true,
|
151 |
"scansEnabled_dns" => true,
|
152 |
"scansEnabled_oldVersions" => true,
|
153 |
-
"firewallEnabled" =>
|
154 |
-
"blockFakeBots" =>
|
155 |
"autoBlockScanners" => true,
|
156 |
"loginSecurityEnabled" => true,
|
157 |
"loginSec_lockInvalidUsers" => false,
|
@@ -212,7 +212,7 @@ class wfConfig {
|
|
212 |
"scansEnabled_dns" => true,
|
213 |
"scansEnabled_oldVersions" => true,
|
214 |
"firewallEnabled" => true,
|
215 |
-
"blockFakeBots" =>
|
216 |
"autoBlockScanners" => true,
|
217 |
"loginSecurityEnabled" => true,
|
218 |
"loginSec_lockInvalidUsers" => false,
|
89 |
"scansEnabled_diskSpace" => true,
|
90 |
"scansEnabled_dns" => true,
|
91 |
"scansEnabled_oldVersions" => true,
|
92 |
+
"firewallEnabled" => false,
|
93 |
"blockFakeBots" => false,
|
94 |
"autoBlockScanners" => true,
|
95 |
"loginSecurityEnabled" => true,
|
150 |
"scansEnabled_diskSpace" => true,
|
151 |
"scansEnabled_dns" => true,
|
152 |
"scansEnabled_oldVersions" => true,
|
153 |
+
"firewallEnabled" => false,
|
154 |
+
"blockFakeBots" => false,
|
155 |
"autoBlockScanners" => true,
|
156 |
"loginSecurityEnabled" => true,
|
157 |
"loginSec_lockInvalidUsers" => false,
|
212 |
"scansEnabled_dns" => true,
|
213 |
"scansEnabled_oldVersions" => true,
|
214 |
"firewallEnabled" => true,
|
215 |
+
"blockFakeBots" => false,
|
216 |
"autoBlockScanners" => true,
|
217 |
"loginSecurityEnabled" => true,
|
218 |
"loginSec_lockInvalidUsers" => false,
|
lib/wfDB.php
CHANGED
@@ -117,6 +117,25 @@ class wfDB {
|
|
117 |
error_log($msg);
|
118 |
exit(1);
|
119 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
120 |
}
|
121 |
|
122 |
?>
|
117 |
error_log($msg);
|
118 |
exit(1);
|
119 |
}
|
120 |
+
public function createKeyIfNotExists($table, $col, $keyName){
|
121 |
+
global $wpdb; $prefix = $wpdb->prefix;
|
122 |
+
$table = $prefix . $table;
|
123 |
+
$exists = $this->querySingle("show tables like '$table'");
|
124 |
+
$keyFound = false;
|
125 |
+
if($exists){
|
126 |
+
$q = $this->query("show keys from $table");
|
127 |
+
if($q){
|
128 |
+
while($row = mysql_fetch_assoc($q)){
|
129 |
+
if($row['Key_name'] == $keyName){
|
130 |
+
$keyFound = true;
|
131 |
+
}
|
132 |
+
}
|
133 |
+
}
|
134 |
+
}
|
135 |
+
if(! $keyFound){
|
136 |
+
$this->query("alter table $table add KEY $keyName($col)");
|
137 |
+
}
|
138 |
+
}
|
139 |
}
|
140 |
|
141 |
?>
|
lib/wfIssues.php
CHANGED
@@ -25,9 +25,9 @@ class wfIssues {
|
|
25 |
$ignoreC = md5($ignoreC);
|
26 |
$rec = $this->getDB()->querySingleRec("select status, ignoreP, ignoreC from " . $this->issuesTable . " where (ignoreP='%s' OR ignoreC='%s')", $ignoreP, $ignoreC);
|
27 |
if($rec){
|
28 |
-
if($rec['status'] == 'new' && ($rec['ignoreC'] == $ignoreC || $rec['ignoreP'] == $ignoreP)){ return; }
|
29 |
-
if($rec['status'] == 'ignoreC' && $rec['ignoreC'] == $ignoreC){ return; }
|
30 |
-
if($rec['status'] == 'ignoreP' && $rec['ignoreP'] == $ignoreP){ return; }
|
31 |
}
|
32 |
|
33 |
$this->totalIssues++;
|
@@ -56,6 +56,7 @@ class wfIssues {
|
|
56 |
$longMsg,
|
57 |
serialize($templateData)
|
58 |
);
|
|
|
59 |
}
|
60 |
public function deleteIgnored(){
|
61 |
$this->getDB()->query("delete from " . $this->issuesTable . " where status='ignoreP' or status='ignoreC'");
|
@@ -190,7 +191,7 @@ class wfIssues {
|
|
190 |
$this->updateSummaryItems();
|
191 |
}
|
192 |
$arr = wfConfig::get_ser('wf_summaryItems', array());
|
193 |
-
|
194 |
$arr['scanRunning'] = wfConfig::get('wf_scanRunning') ? '1' : '0';
|
195 |
$arr['scheduledScansEnabled'] = wfConfig::get('scheduledScansEnabled');
|
196 |
$secsToGo = wp_next_scheduled('wordfence_scheduled_scan') - time();
|
25 |
$ignoreC = md5($ignoreC);
|
26 |
$rec = $this->getDB()->querySingleRec("select status, ignoreP, ignoreC from " . $this->issuesTable . " where (ignoreP='%s' OR ignoreC='%s')", $ignoreP, $ignoreC);
|
27 |
if($rec){
|
28 |
+
if($rec['status'] == 'new' && ($rec['ignoreC'] == $ignoreC || $rec['ignoreP'] == $ignoreP)){ return false; }
|
29 |
+
if($rec['status'] == 'ignoreC' && $rec['ignoreC'] == $ignoreC){ return false; }
|
30 |
+
if($rec['status'] == 'ignoreP' && $rec['ignoreP'] == $ignoreP){ return false; }
|
31 |
}
|
32 |
|
33 |
$this->totalIssues++;
|
56 |
$longMsg,
|
57 |
serialize($templateData)
|
58 |
);
|
59 |
+
return true;
|
60 |
}
|
61 |
public function deleteIgnored(){
|
62 |
$this->getDB()->query("delete from " . $this->issuesTable . " where status='ignoreP' or status='ignoreC'");
|
191 |
$this->updateSummaryItems();
|
192 |
}
|
193 |
$arr = wfConfig::get_ser('wf_summaryItems', array());
|
194 |
+
//$arr['scanTimeAgo'] = wfUtils::makeTimeAgo(sprintf('%.0f', time() - $arr['scanTime']));
|
195 |
$arr['scanRunning'] = wfConfig::get('wf_scanRunning') ? '1' : '0';
|
196 |
$arr['scheduledScansEnabled'] = wfConfig::get('scheduledScansEnabled');
|
197 |
$secsToGo = wp_next_scheduled('wordfence_scheduled_scan') - time();
|
lib/wfLog.php
CHANGED
@@ -575,16 +575,37 @@ class wfLog {
|
|
575 |
//$msg = '[' . sprintf('%.2f', memory_get_usage(true) / (1024 * 1024)) . '] ' . $msg;
|
576 |
$this->getDB()->query("insert into " . $this->statusTable . " (ctime, level, type, msg) values (%s, %d, '%s', '%s')", microtime(true), $level, $type, $msg);
|
577 |
}
|
578 |
-
public function getStatusEvents(){
|
579 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
580 |
$results = array();
|
581 |
$lastTime = false;
|
582 |
while($rec = mysql_fetch_assoc($res)){
|
583 |
-
|
|
|
584 |
array_push($results, $rec);
|
585 |
}
|
586 |
return $results;
|
587 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
588 |
}
|
589 |
|
590 |
?>
|
575 |
//$msg = '[' . sprintf('%.2f', memory_get_usage(true) / (1024 * 1024)) . '] ' . $msg;
|
576 |
$this->getDB()->query("insert into " . $this->statusTable . " (ctime, level, type, msg) values (%s, %d, '%s', '%s')", microtime(true), $level, $type, $msg);
|
577 |
}
|
578 |
+
public function getStatusEvents($lastCtime){
|
579 |
+
if($lastCtime < 1){
|
580 |
+
$lastCtime = $this->getDB()->querySingle("select ctime from " . $this->statusTable . " order by ctime desc limit 1000,1");
|
581 |
+
if(! $lastCtime){
|
582 |
+
$lastCtime = 0;
|
583 |
+
}
|
584 |
+
}
|
585 |
+
$res = $this->getDB()->query("select ctime, level, type, msg from " . $this->statusTable . " where ctime > %f order by ctime asc", $lastCtime);
|
586 |
$results = array();
|
587 |
$lastTime = false;
|
588 |
while($rec = mysql_fetch_assoc($res)){
|
589 |
+
//$rec['timeAgo'] = wfUtils::makeTimeAgo(time() - $rec['ctime']);
|
590 |
+
$rec['date'] = date('M d H:i:s', $rec['ctime']);
|
591 |
array_push($results, $rec);
|
592 |
}
|
593 |
return $results;
|
594 |
}
|
595 |
+
public function getSummaryEvents(){
|
596 |
+
$res = $this->getDB()->query("select ctime, level, type, msg from " . $this->statusTable . " where level = 10 order by ctime desc limit 100", $lastCtime);
|
597 |
+
$results = array();
|
598 |
+
$lastTime = false;
|
599 |
+
while($rec = mysql_fetch_assoc($res)){
|
600 |
+
$rec['date'] = date('M d H:i:s', $rec['ctime']);
|
601 |
+
array_push($results, $rec);
|
602 |
+
if(strpos($rec['msg'], 'SUM_PREP:') === 0){
|
603 |
+
break;
|
604 |
+
}
|
605 |
+
}
|
606 |
+
return array_reverse($results);
|
607 |
+
}
|
608 |
+
|
609 |
}
|
610 |
|
611 |
?>
|
lib/wfScanEngine.php
CHANGED
@@ -14,7 +14,9 @@ class wfScanEngine {
|
|
14 |
private $apiKey = false;
|
15 |
private $errorStopped = false;
|
16 |
private $dictWords = array();
|
|
|
17 |
public function __construct(){
|
|
|
18 |
$this->i = new wfIssues();
|
19 |
$this->wp_version = wfUtils::getWPVersion();
|
20 |
$this->apiKey = wfConfig::get('apiKey');
|
@@ -86,40 +88,58 @@ class wfScanEngine {
|
|
86 |
$this->scanOldVersions();
|
87 |
if($this->errorStopped){ return; }
|
88 |
}
|
89 |
-
$this->
|
|
|
|
|
|
|
|
|
|
|
|
|
90 |
return;
|
91 |
}
|
92 |
private function scanKnownFiles(){
|
93 |
$malwareScanEnabled = $coreScanEnabled = $pluginScanEnabled = $themeScanEnabled = false;
|
|
|
|
|
|
|
|
|
|
|
|
|
94 |
if(wfConfig::get('scansEnabled_core')){
|
95 |
$coreScanEnabled = true;
|
|
|
96 |
} else {
|
97 |
-
|
98 |
}
|
99 |
if(wfConfig::get('scansEnabled_plugins')){
|
100 |
$pluginScanEnabled = true;
|
|
|
101 |
} else {
|
|
|
102 |
$this->status(2, 'info', "Skipping plugin scan because it's disabled.");
|
103 |
}
|
104 |
if(wfConfig::get('scansEnabled_themes')){
|
105 |
$themeScanEnabled = true;
|
|
|
106 |
} else {
|
|
|
107 |
$this->status(2, 'info', "Skipping themes scan because it's disabled.");
|
108 |
}
|
109 |
|
110 |
if(wfConfig::get('scansEnabled_malware')){
|
|
|
111 |
$malwareScanEnabled = true;
|
112 |
} else {
|
|
|
113 |
$this->status(2, 'info', "Skipping malware scan because it's disabled.");
|
114 |
}
|
115 |
$summaryUpdateRequired = $this->i->summaryUpdateRequired();
|
116 |
if((! $summaryUpdateRequired) && (! ($coreScanEnabled || $pluginScanEnabled || $themeScanEnabled || $malwareScanEnabled))){
|
117 |
-
$this->status(2, 'info', "
|
118 |
return array();
|
119 |
}
|
120 |
|
121 |
//CORE SCAN
|
122 |
-
$this->status(2, 'info', "Examining files in WordPress base directory.");
|
123 |
$hasher = new wordfenceHash(strlen(ABSPATH));
|
124 |
$baseWPStuff = array( '.htaccess', 'index.php', 'license.txt', 'readme.html', 'wp-activate.php', 'wp-admin', 'wp-app.php', 'wp-blog-header.php', 'wp-comments-post.php', 'wp-config-sample.php', 'wp-content', 'wp-cron.php', 'wp-includes', 'wp-links-opml.php', 'wp-load.php', 'wp-login.php', 'wp-mail.php', 'wp-pass.php', 'wp-register.php', 'wp-settings.php', 'wp-signup.php', 'wp-trackback.php', 'xmlrpc.php');
|
125 |
$baseContents = scandir(ABSPATH);
|
@@ -186,28 +206,44 @@ class wfScanEngine {
|
|
186 |
$result1 = $this->api->call('main_scan', array(), array(
|
187 |
'data' => json_encode($scanData)
|
188 |
));
|
189 |
-
$this->status(2, 'info', "Done API call to Wordfence servers and got a result.");
|
190 |
if($this->api->errorMsg){
|
191 |
$this->errorStop($this->api->errorMsg);
|
|
|
192 |
return;
|
193 |
}
|
194 |
if(empty($result1['errorMsg']) === false){
|
195 |
$this->errorStop($result['errorMsg']);
|
|
|
196 |
return;
|
197 |
}
|
198 |
if(! $result1){
|
199 |
$this->errorStop("We received an empty response from the Wordfence server when scanning core, plugin and theme files.");
|
|
|
200 |
return;
|
201 |
}
|
202 |
$this->status(2, 'info', "Processing scan results");
|
|
|
|
|
|
|
|
|
|
|
|
|
203 |
foreach($result1['results'] as $issue){
|
204 |
$this->status(2, 'info', "Adding issue: " . $issue['shortMsg']);
|
205 |
-
$this->addIssue($issue['type'], $issue['severity'], $issue['ignoreP'], $issue['ignoreC'], $issue['shortMsg'], $issue['longMsg'], $issue['data'])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
206 |
}
|
207 |
return $result1['unknownFiles'];
|
208 |
}
|
209 |
private function scanFileContents($unknownFiles){
|
210 |
-
$
|
|
|
211 |
if(! is_array($unknownFiles)){
|
212 |
$unknownFiles = array();
|
213 |
}
|
@@ -219,13 +255,23 @@ class wfScanEngine {
|
|
219 |
if($scanner->errorMsg){
|
220 |
$this->errorStop($scanner->errorMsg);
|
221 |
}
|
|
|
|
|
222 |
foreach($result2 as $issue){
|
223 |
$this->status(2, 'info', "Adding issue: " . $issue['shortMsg']);
|
224 |
-
$this->addIssue($issue['type'], $issue['severity'], $issue['ignoreP'], $issue['ignoreC'], $issue['shortMsg'], $issue['longMsg'], $issue['data'])
|
|
|
|
|
|
|
|
|
|
|
|
|
225 |
}
|
|
|
|
|
226 |
}
|
227 |
private function scanPosts(){
|
228 |
-
$
|
229 |
global $wpdb;
|
230 |
$wfdb = new wfDB();
|
231 |
//NOTE: There must be no other DB activity by wfDB between here and free_result below because we're doing an unbuffered query. THAT INCLUDES calls to status() which updates the DB
|
@@ -248,8 +294,11 @@ class wfScanEngine {
|
|
248 |
$this->status(2, 'info', "Done examining URls");
|
249 |
if($h->errorMsg){
|
250 |
$this->errorStop($h->errorMsg);
|
|
|
251 |
return;
|
|
|
252 |
}
|
|
|
253 |
foreach($hooverResults as $id => $hresults){
|
254 |
$uctype = ucfirst($postDat[$id]['type']);
|
255 |
$type = $postDat[$id]['type'];
|
@@ -265,7 +314,7 @@ class wfScanEngine {
|
|
265 |
continue;
|
266 |
}
|
267 |
$this->status(2, 'info', "Adding issue: $shortMsg");
|
268 |
-
$this->addIssue('postBadURL', 1, $id, $id . $postDat[$id]['contentMD5'], $shortMsg, $longMsg, array(
|
269 |
'postID' => $id,
|
270 |
'badURL' => $result['URL'],
|
271 |
'postTitle' => $postDat[$id]['title'],
|
@@ -274,9 +323,12 @@ class wfScanEngine {
|
|
274 |
'permalink' => get_permalink($id),
|
275 |
'editPostLink' => get_edit_post_link($id),
|
276 |
'postDate' => $postDat[$id]['postDate']
|
277 |
-
))
|
|
|
|
|
278 |
}
|
279 |
}
|
|
|
280 |
}
|
281 |
public function isBadComment($author, $email, $url, $IP, $content){
|
282 |
$content = $author . ' ' . $email . ' ' . $url . ' ' . $IP . ' ' . $content;
|
@@ -315,11 +367,13 @@ class wfScanEngine {
|
|
315 |
return false;
|
316 |
}
|
317 |
private function scanComments(){
|
|
|
318 |
global $wpdb;
|
319 |
$wfdb = new wfDB();
|
320 |
//NOTE: There must be no other DB activity by wfDB between here and free_result below because we're doing an unbuffered query. THAT INCLUDES calls to status() which updates the DB
|
321 |
$q1 = $wfdb->uQuery("select comment_ID, comment_date, comment_type, comment_author, comment_author_url, comment_content from $wpdb->comments where comment_approved=1");
|
322 |
if( ! $q1){
|
|
|
323 |
return;
|
324 |
}
|
325 |
$h = new wordfenceURLHoover($this->apiKey, $this->wp_version);
|
@@ -336,12 +390,17 @@ class wfScanEngine {
|
|
336 |
);
|
337 |
}
|
338 |
mysql_free_result($q1);
|
339 |
-
if(! $gotRow){
|
|
|
|
|
|
|
340 |
$hooverResults = $h->getBaddies();
|
341 |
if($h->errorMsg){
|
342 |
$this->errorStop($h->errorMsg);
|
|
|
343 |
return;
|
344 |
}
|
|
|
345 |
foreach($hooverResults as $id => $hresults){
|
346 |
$uctype = ucfirst($commentDat[$id]['type']);
|
347 |
$type = $commentDat[$id]['type'];
|
@@ -356,7 +415,7 @@ class wfScanEngine {
|
|
356 |
//A list type that may be new and the plugin has not been upgraded yet.
|
357 |
continue;
|
358 |
}
|
359 |
-
$this->addIssue('commentBadURL', 1, $id, $id . $commentDat[$id]['contentMD5'], $shortMsg, $longMsg, array(
|
360 |
'commentID' => $id,
|
361 |
'badURL' => $result['URL'],
|
362 |
'author' => $commentDat[$id]['author'],
|
@@ -364,9 +423,12 @@ class wfScanEngine {
|
|
364 |
'uctype' => $uctype,
|
365 |
'editCommentLink' => get_edit_comment_link($id),
|
366 |
'commentDate' => $commentDat[$id]['date']
|
367 |
-
))
|
|
|
|
|
368 |
}
|
369 |
}
|
|
|
370 |
}
|
371 |
private function highestCap($caps){
|
372 |
foreach(array('administrator', 'editor', 'author', 'contributor', 'subscriber') as $cap){
|
@@ -385,12 +447,16 @@ class wfScanEngine {
|
|
385 |
return false;
|
386 |
}
|
387 |
private function scanAllPasswords(){
|
|
|
388 |
global $wpdb;
|
389 |
$ws = $wpdb->get_results("SELECT ID, user_login FROM $wpdb->users");
|
|
|
390 |
foreach($ws as $user){
|
391 |
$this->status(2, 'info', "Checking password strength for: " . $user->user_login);
|
392 |
-
$this->scanUserPassword($user->ID);
|
|
|
393 |
}
|
|
|
394 |
}
|
395 |
public function scanUserPassword($userID){
|
396 |
require_once( ABSPATH . 'wp-includes/class-phpass.php');
|
@@ -412,28 +478,33 @@ class wfScanEngine {
|
|
412 |
$level = 2;
|
413 |
$words = array($userDat->user_login);
|
414 |
}
|
|
|
415 |
for($i = 0; $i < sizeof($words); $i++){
|
416 |
if($hasher->CheckPassword($words[$i], $userDat->user_pass)){
|
417 |
$this->status(2, 'info', "Adding issue " . $shortMsg);
|
418 |
-
$this->addIssue('easyPassword', $level, $userDat->ID, $userDat->ID . '-' . $userDat->user_pass, $shortMsg, $longMsg, array(
|
419 |
'ID' => $userDat->ID,
|
420 |
'user_login' => $userDat->user_login,
|
421 |
'user_email' => $userDat->user_email,
|
422 |
'first_name' => $userDat->first_name,
|
423 |
'last_name' => $userDat->last_name,
|
424 |
'editUserLink' => wfUtils::editUserLink($userDat->ID)
|
425 |
-
))
|
|
|
|
|
426 |
break;
|
427 |
}
|
428 |
}
|
429 |
$this->status(2, 'info', "Completed checking password strength of user '" . $userDat->user_login . "'");
|
|
|
430 |
}
|
431 |
private function scanDiskSpace(){
|
432 |
-
$
|
433 |
$total = disk_total_space('.');
|
434 |
$free = disk_free_space('.');
|
435 |
$this->status(2, 'info', "Total space: $total Free space: $free");
|
436 |
if( (! $total) || (! $free )){ //If we get zeros it's probably not reading right. If free is zero then we're out of space and already in trouble.
|
|
|
437 |
return;
|
438 |
}
|
439 |
$level = false;
|
@@ -444,20 +515,23 @@ class wfScanEngine {
|
|
444 |
} else if($spaceLeft < 5){
|
445 |
$level = 2;
|
446 |
} else {
|
|
|
447 |
return;
|
448 |
}
|
449 |
-
$this->
|
450 |
-
|
451 |
-
|
452 |
-
|
453 |
-
|
|
|
454 |
}
|
455 |
private function scanDNSChanges(){
|
456 |
if(! function_exists('dns_get_record')){
|
457 |
$this->status(1, 'info', "Skipping DNS scan because this system does not support dns_get_record()");
|
458 |
return;
|
459 |
}
|
460 |
-
$
|
|
|
461 |
$home = get_home_url();
|
462 |
if(preg_match('/https?:\/\/([^\/]+)/i', $home, $matches)){
|
463 |
$host = strtolower($matches[1]);
|
@@ -480,12 +554,14 @@ class wfScanEngine {
|
|
480 |
$loggedCNAME = wfConfig::get('wf_dnsCNAME');
|
481 |
$dnsLogged = wfConfig::get('wf_dnsLogged', false);
|
482 |
if($dnsLogged && $loggedCNAME != $currentCNAME){
|
483 |
-
$this->addIssue('dnsChange', 2, 'dnsChanges', 'dnsChanges', "Your DNS records have changed", "We have detected a change in the CNAME records of your DNS configuration for the domain $host. A CNAME record is an alias that is used to point a domain name to another domain name. For example foo.example.com can point to bar.example.com which then points to an IP address of 10.1.1.1. $msg", array(
|
484 |
'type' => 'CNAME',
|
485 |
'host' => $host,
|
486 |
'oldDNS' => $loggedCNAME,
|
487 |
'newDNS' => $currentCNAME
|
488 |
-
))
|
|
|
|
|
489 |
}
|
490 |
wfConfig::set('wf_dnsCNAME', $currentCNAME);
|
491 |
|
@@ -505,12 +581,14 @@ class wfScanEngine {
|
|
505 |
$dnsLogged = wfConfig::get('wf_dnsLogged', false);
|
506 |
$msg = "A change in your DNS records may indicate that a hacker has hacked into your DNS administration system and has pointed your email or website to their own server for malicious purposes. It could also indicate that your domain has expired. If you made this change yourself you can mark it 'resolved' and safely ignore it.";
|
507 |
if($dnsLogged && $loggedA != $currentA){
|
508 |
-
$this->addIssue('dnsChange', 2, 'dnsChanges', 'dnsChanges', "Your DNS records have changed", "We have detected a change in the A records of your DNS configuration that may affect the domain $host. An A record is a record in DNS that points a domain name to an IP address. $msg", array(
|
509 |
'type' => 'A',
|
510 |
'host' => $host,
|
511 |
'oldDNS' => $loggedA,
|
512 |
'newDNS' => $currentA
|
513 |
-
))
|
|
|
|
|
514 |
}
|
515 |
wfConfig::set('wf_dnsA', $currentA);
|
516 |
|
@@ -530,29 +608,36 @@ class wfScanEngine {
|
|
530 |
$currentMX = implode(', ', $mxArr);
|
531 |
$loggedMX = wfConfig::get('wf_dnsMX');
|
532 |
if($dnsLogged && $loggedMX != $currentMX){
|
533 |
-
$this->addIssue('dnsChange', 2, 'dnsChanges', 'dnsChanges', "Your DNS records have changed", "We have detected a change in the email server (MX) records of your DNS configuration for the domain $host. $msg", array(
|
534 |
'type' => 'MX',
|
535 |
'host' => $host,
|
536 |
'oldDNS' => $loggedMX,
|
537 |
'newDNS' => $currentMX
|
538 |
-
))
|
|
|
|
|
539 |
|
540 |
}
|
541 |
wfConfig::set('wf_dnsMX', $currentMX);
|
542 |
|
543 |
wfConfig::set('wf_dnsLogged', 1);
|
544 |
}
|
|
|
545 |
}
|
546 |
private function scanOldVersions(){
|
|
|
547 |
if(! function_exists( 'get_preferred_from_update_core')){
|
548 |
require_once(ABSPATH . 'wp-admin/includes/update.php');
|
549 |
}
|
550 |
$cur = get_preferred_from_update_core();
|
|
|
551 |
if(isset( $cur->response ) && $cur->response == 'upgrade'){
|
552 |
-
$this->addIssue('wfUpgrade', 1, 'wfUpgrade' . $cur->current, 'wfUpgrade' . $cur->current, "Your WordPress version is out of date", "WordPress version " . $cur->current . " is now available. Please upgrade immediately to get the latest security updates from WordPress.", array(
|
553 |
'currentVersion' => $this->wp_version,
|
554 |
'newVersion' => $cur->current
|
555 |
-
))
|
|
|
|
|
556 |
}
|
557 |
$update_plugins = get_site_transient( 'update_plugins' );
|
558 |
if(isset($update_plugins) && (! empty($update_plugins->response))){
|
@@ -565,7 +650,9 @@ class wfScanEngine {
|
|
565 |
$data = get_plugin_data($pluginFile);
|
566 |
$data['newVersion'] = $vals->new_version;
|
567 |
$key = 'wfPluginUpgrade' . ' ' . $plugin . ' ' . $data['newVersion'] . ' ' . $data['Version'];
|
568 |
-
$this->addIssue('wfPluginUpgrade', 1, $key, $key, "The Plugin \"" . $data['Name'] . "\" needs an upgrade.", "You need to upgrade \"" . $data['Name'] . "\" to the newest version to ensure you have any security fixes the developer has released.", $data)
|
|
|
|
|
569 |
}
|
570 |
}
|
571 |
}
|
@@ -586,13 +673,15 @@ class wfScanEngine {
|
|
586 |
'version' => $themeData['Version']
|
587 |
);
|
588 |
$key = 'wfThemeUpgrade' . ' ' . $theme . ' ' . $tData['version'] . ' ' . $tData['newVersion'];
|
589 |
-
$this->addIssue('wfThemeUpgrade', 1, $key, $key, "The Theme \"" . $themeData['Name'] . "\" needs an upgrade.", "You need to upgrade \"" . $themeData['Name'] . "\" to the newest version to ensure you have any security fixes the developer has released.", $tData)
|
|
|
|
|
590 |
}
|
591 |
}
|
592 |
|
593 |
}
|
594 |
}
|
595 |
-
|
596 |
}
|
597 |
private function errorStop($msg){
|
598 |
$this->errorStopped = true;
|
@@ -603,7 +692,7 @@ class wfScanEngine {
|
|
603 |
wordfence::status($level, $type, $msg);
|
604 |
}
|
605 |
private function addIssue($type, $severity, $ignoreP, $ignoreC, $shortMsg, $longMsg, $templateData){
|
606 |
-
$this->i->addIssue($type, $severity, $ignoreP, $ignoreC, $shortMsg, $longMsg, $templateData);
|
607 |
}
|
608 |
}
|
609 |
|
14 |
private $apiKey = false;
|
15 |
private $errorStopped = false;
|
16 |
private $dictWords = array();
|
17 |
+
private $startTime = 0;
|
18 |
public function __construct(){
|
19 |
+
$this->startTime = time();
|
20 |
$this->i = new wfIssues();
|
21 |
$this->wp_version = wfUtils::getWPVersion();
|
22 |
$this->apiKey = wfConfig::get('apiKey');
|
88 |
$this->scanOldVersions();
|
89 |
if($this->errorStopped){ return; }
|
90 |
}
|
91 |
+
$summary = $this->i->getSummaryItems();
|
92 |
+
$this->status(1, 'info', "Scan Complete. Scanned " . $summary['totalFiles'] . " files, " . $summary['totalPlugins'] . " plugins, " . $summary['totalThemes'] . " themes, " . ($summary['totalPages'] + $summary['totalPosts']) . " pages, " . $summary['totalComments'] . " comments and " . $summary['totalRows'] . " records in " . (time() - $this->startTime) . " seconds.");
|
93 |
+
if($this->i->totalIssues > 0){
|
94 |
+
$this->status(10, 'info', "SUM_FINAL:Scan complete. You have " . $this->i->totalIssues . " new issues to fix. See below for details.");
|
95 |
+
} else {
|
96 |
+
$this->status(10, 'info', "SUM_FINAL:Scan complete. Congratulations, there were no problems found.");
|
97 |
+
}
|
98 |
return;
|
99 |
}
|
100 |
private function scanKnownFiles(){
|
101 |
$malwareScanEnabled = $coreScanEnabled = $pluginScanEnabled = $themeScanEnabled = false;
|
102 |
+
$statusIDX = array(
|
103 |
+
'core' => false,
|
104 |
+
'plugin' => false,
|
105 |
+
'theme' => false,
|
106 |
+
'unknown' => false
|
107 |
+
);
|
108 |
if(wfConfig::get('scansEnabled_core')){
|
109 |
$coreScanEnabled = true;
|
110 |
+
$statusIDX['core'] = wordfence::statusStart("Comparing core WordPress files against originals in repository");
|
111 |
} else {
|
112 |
+
wordfence::statusDisabled("Skipping core scan");
|
113 |
}
|
114 |
if(wfConfig::get('scansEnabled_plugins')){
|
115 |
$pluginScanEnabled = true;
|
116 |
+
$statusIDX['plugin'] = wordfence::statusStart("Comparing plugin files against originals in repository");
|
117 |
} else {
|
118 |
+
wordfence::statusDisabled("Skipping plugin scan");
|
119 |
$this->status(2, 'info', "Skipping plugin scan because it's disabled.");
|
120 |
}
|
121 |
if(wfConfig::get('scansEnabled_themes')){
|
122 |
$themeScanEnabled = true;
|
123 |
+
$statusIDX['theme'] = wordfence::statusStart("Comparing theme files against originals in repository");
|
124 |
} else {
|
125 |
+
wordfence::statusDisabled("Skipping theme scan");
|
126 |
$this->status(2, 'info', "Skipping themes scan because it's disabled.");
|
127 |
}
|
128 |
|
129 |
if(wfConfig::get('scansEnabled_malware')){
|
130 |
+
$statusIDX['unknown'] = wordfence::statusStart("Scanning for known malware files");
|
131 |
$malwareScanEnabled = true;
|
132 |
} else {
|
133 |
+
wordfence::statusDisabled("Skipping malware scan");
|
134 |
$this->status(2, 'info', "Skipping malware scan because it's disabled.");
|
135 |
}
|
136 |
$summaryUpdateRequired = $this->i->summaryUpdateRequired();
|
137 |
if((! $summaryUpdateRequired) && (! ($coreScanEnabled || $pluginScanEnabled || $themeScanEnabled || $malwareScanEnabled))){
|
138 |
+
$this->status(2, 'info', "Finishing this stage because we don't have to do a summary update and we don't need to do a core, plugin, theme or malware scan.");
|
139 |
return array();
|
140 |
}
|
141 |
|
142 |
//CORE SCAN
|
|
|
143 |
$hasher = new wordfenceHash(strlen(ABSPATH));
|
144 |
$baseWPStuff = array( '.htaccess', 'index.php', 'license.txt', 'readme.html', 'wp-activate.php', 'wp-admin', 'wp-app.php', 'wp-blog-header.php', 'wp-comments-post.php', 'wp-config-sample.php', 'wp-content', 'wp-cron.php', 'wp-includes', 'wp-links-opml.php', 'wp-load.php', 'wp-login.php', 'wp-mail.php', 'wp-pass.php', 'wp-register.php', 'wp-settings.php', 'wp-signup.php', 'wp-trackback.php', 'xmlrpc.php');
|
145 |
$baseContents = scandir(ABSPATH);
|
206 |
$result1 = $this->api->call('main_scan', array(), array(
|
207 |
'data' => json_encode($scanData)
|
208 |
));
|
|
|
209 |
if($this->api->errorMsg){
|
210 |
$this->errorStop($this->api->errorMsg);
|
211 |
+
wordfence::statusEndErr();
|
212 |
return;
|
213 |
}
|
214 |
if(empty($result1['errorMsg']) === false){
|
215 |
$this->errorStop($result['errorMsg']);
|
216 |
+
wordfence::statusEndErr();
|
217 |
return;
|
218 |
}
|
219 |
if(! $result1){
|
220 |
$this->errorStop("We received an empty response from the Wordfence server when scanning core, plugin and theme files.");
|
221 |
+
wordfence::statusEndErr();
|
222 |
return;
|
223 |
}
|
224 |
$this->status(2, 'info', "Processing scan results");
|
225 |
+
$haveIssues = array(
|
226 |
+
'core' => false,
|
227 |
+
'plugin' => false,
|
228 |
+
'theme' => false,
|
229 |
+
'unknown' => false
|
230 |
+
);
|
231 |
foreach($result1['results'] as $issue){
|
232 |
$this->status(2, 'info', "Adding issue: " . $issue['shortMsg']);
|
233 |
+
if($this->addIssue($issue['type'], $issue['severity'], $issue['ignoreP'], $issue['ignoreC'], $issue['shortMsg'], $issue['longMsg'], $issue['data'])){
|
234 |
+
$haveIssues[$issue['data']['cType']] = true;
|
235 |
+
}
|
236 |
+
}
|
237 |
+
foreach($haveIssues as $type => $have){
|
238 |
+
if($statusIDX[$type] !== false){
|
239 |
+
wordfence::statusEnd($statusIDX[$type], $have);
|
240 |
+
}
|
241 |
}
|
242 |
return $result1['unknownFiles'];
|
243 |
}
|
244 |
private function scanFileContents($unknownFiles){
|
245 |
+
$statusIDX = wordfence::statusStart('Scanning file contents for infections and vulnerabilities');
|
246 |
+
$statusIDX2 = wordfence::statusStart('Scanning files for URLs in Google\'s Safe Browsing List');
|
247 |
if(! is_array($unknownFiles)){
|
248 |
$unknownFiles = array();
|
249 |
}
|
255 |
if($scanner->errorMsg){
|
256 |
$this->errorStop($scanner->errorMsg);
|
257 |
}
|
258 |
+
$haveIssues = false;
|
259 |
+
$haveIssuesGSB = false;
|
260 |
foreach($result2 as $issue){
|
261 |
$this->status(2, 'info', "Adding issue: " . $issue['shortMsg']);
|
262 |
+
if($this->addIssue($issue['type'], $issue['severity'], $issue['ignoreP'], $issue['ignoreC'], $issue['shortMsg'], $issue['longMsg'], $issue['data'])){
|
263 |
+
if(empty($issue['data']['gsb']) === false){
|
264 |
+
$haveIssuesGSB = true;
|
265 |
+
} else {
|
266 |
+
$haveIssues = true;
|
267 |
+
}
|
268 |
+
}
|
269 |
}
|
270 |
+
wordfence::statusEnd($statusIDX, $haveIssues);
|
271 |
+
wordfence::statusEnd($statusIDX2, $haveIssuesGSB);
|
272 |
}
|
273 |
private function scanPosts(){
|
274 |
+
$statusIDX = wordfence::statusStart('Scanning posts for URL\'s in Google\'s Safe Browsing List');
|
275 |
global $wpdb;
|
276 |
$wfdb = new wfDB();
|
277 |
//NOTE: There must be no other DB activity by wfDB between here and free_result below because we're doing an unbuffered query. THAT INCLUDES calls to status() which updates the DB
|
294 |
$this->status(2, 'info', "Done examining URls");
|
295 |
if($h->errorMsg){
|
296 |
$this->errorStop($h->errorMsg);
|
297 |
+
wordfence::statusEndErr();
|
298 |
return;
|
299 |
+
|
300 |
}
|
301 |
+
$haveIssues = false;
|
302 |
foreach($hooverResults as $id => $hresults){
|
303 |
$uctype = ucfirst($postDat[$id]['type']);
|
304 |
$type = $postDat[$id]['type'];
|
314 |
continue;
|
315 |
}
|
316 |
$this->status(2, 'info', "Adding issue: $shortMsg");
|
317 |
+
if($this->addIssue('postBadURL', 1, $id, $id . $postDat[$id]['contentMD5'], $shortMsg, $longMsg, array(
|
318 |
'postID' => $id,
|
319 |
'badURL' => $result['URL'],
|
320 |
'postTitle' => $postDat[$id]['title'],
|
323 |
'permalink' => get_permalink($id),
|
324 |
'editPostLink' => get_edit_post_link($id),
|
325 |
'postDate' => $postDat[$id]['postDate']
|
326 |
+
))){
|
327 |
+
$haveIssues = true;
|
328 |
+
}
|
329 |
}
|
330 |
}
|
331 |
+
wordfence::statusEnd($statusIDX, $haveIssues);
|
332 |
}
|
333 |
public function isBadComment($author, $email, $url, $IP, $content){
|
334 |
$content = $author . ' ' . $email . ' ' . $url . ' ' . $IP . ' ' . $content;
|
367 |
return false;
|
368 |
}
|
369 |
private function scanComments(){
|
370 |
+
$statusIDX = wordfence::statusStart('Scanning comments for URL\'s in Google\'s Safe Browsing List');
|
371 |
global $wpdb;
|
372 |
$wfdb = new wfDB();
|
373 |
//NOTE: There must be no other DB activity by wfDB between here and free_result below because we're doing an unbuffered query. THAT INCLUDES calls to status() which updates the DB
|
374 |
$q1 = $wfdb->uQuery("select comment_ID, comment_date, comment_type, comment_author, comment_author_url, comment_content from $wpdb->comments where comment_approved=1");
|
375 |
if( ! $q1){
|
376 |
+
wordfence::statusEndErr();
|
377 |
return;
|
378 |
}
|
379 |
$h = new wordfenceURLHoover($this->apiKey, $this->wp_version);
|
390 |
);
|
391 |
}
|
392 |
mysql_free_result($q1);
|
393 |
+
if(! $gotRow){
|
394 |
+
wordfence::statusEnd($statusIDX, false);
|
395 |
+
return;
|
396 |
+
}
|
397 |
$hooverResults = $h->getBaddies();
|
398 |
if($h->errorMsg){
|
399 |
$this->errorStop($h->errorMsg);
|
400 |
+
wordfence::statusEndErr();
|
401 |
return;
|
402 |
}
|
403 |
+
$haveIssues = false;
|
404 |
foreach($hooverResults as $id => $hresults){
|
405 |
$uctype = ucfirst($commentDat[$id]['type']);
|
406 |
$type = $commentDat[$id]['type'];
|
415 |
//A list type that may be new and the plugin has not been upgraded yet.
|
416 |
continue;
|
417 |
}
|
418 |
+
if($this->addIssue('commentBadURL', 1, $id, $id . $commentDat[$id]['contentMD5'], $shortMsg, $longMsg, array(
|
419 |
'commentID' => $id,
|
420 |
'badURL' => $result['URL'],
|
421 |
'author' => $commentDat[$id]['author'],
|
423 |
'uctype' => $uctype,
|
424 |
'editCommentLink' => get_edit_comment_link($id),
|
425 |
'commentDate' => $commentDat[$id]['date']
|
426 |
+
))){
|
427 |
+
$haveIssues = true;
|
428 |
+
}
|
429 |
}
|
430 |
}
|
431 |
+
wordfence::statusEnd($statusIDX, $haveIssues);
|
432 |
}
|
433 |
private function highestCap($caps){
|
434 |
foreach(array('administrator', 'editor', 'author', 'contributor', 'subscriber') as $cap){
|
447 |
return false;
|
448 |
}
|
449 |
private function scanAllPasswords(){
|
450 |
+
$statusIDX = wordfence::statusStart('Scanning for weak passwords');
|
451 |
global $wpdb;
|
452 |
$ws = $wpdb->get_results("SELECT ID, user_login FROM $wpdb->users");
|
453 |
+
$haveIssues = false;
|
454 |
foreach($ws as $user){
|
455 |
$this->status(2, 'info', "Checking password strength for: " . $user->user_login);
|
456 |
+
$isWeak = $this->scanUserPassword($user->ID);
|
457 |
+
if($isWeak){ $haveIssues = true; }
|
458 |
}
|
459 |
+
wordfence::statusEnd($statusIDX, $haveIssues);
|
460 |
}
|
461 |
public function scanUserPassword($userID){
|
462 |
require_once( ABSPATH . 'wp-includes/class-phpass.php');
|
478 |
$level = 2;
|
479 |
$words = array($userDat->user_login);
|
480 |
}
|
481 |
+
$haveIssue = false;
|
482 |
for($i = 0; $i < sizeof($words); $i++){
|
483 |
if($hasher->CheckPassword($words[$i], $userDat->user_pass)){
|
484 |
$this->status(2, 'info', "Adding issue " . $shortMsg);
|
485 |
+
if($this->addIssue('easyPassword', $level, $userDat->ID, $userDat->ID . '-' . $userDat->user_pass, $shortMsg, $longMsg, array(
|
486 |
'ID' => $userDat->ID,
|
487 |
'user_login' => $userDat->user_login,
|
488 |
'user_email' => $userDat->user_email,
|
489 |
'first_name' => $userDat->first_name,
|
490 |
'last_name' => $userDat->last_name,
|
491 |
'editUserLink' => wfUtils::editUserLink($userDat->ID)
|
492 |
+
))){
|
493 |
+
$haveIssue = true;
|
494 |
+
}
|
495 |
break;
|
496 |
}
|
497 |
}
|
498 |
$this->status(2, 'info', "Completed checking password strength of user '" . $userDat->user_login . "'");
|
499 |
+
return $haveIssue;
|
500 |
}
|
501 |
private function scanDiskSpace(){
|
502 |
+
$statusIDX = wordfence::statusStart("Scanning to check available disk space");
|
503 |
$total = disk_total_space('.');
|
504 |
$free = disk_free_space('.');
|
505 |
$this->status(2, 'info', "Total space: $total Free space: $free");
|
506 |
if( (! $total) || (! $free )){ //If we get zeros it's probably not reading right. If free is zero then we're out of space and already in trouble.
|
507 |
+
wordfence::statusEnd($statusIDX, false);
|
508 |
return;
|
509 |
}
|
510 |
$level = false;
|
515 |
} else if($spaceLeft < 5){
|
516 |
$level = 2;
|
517 |
} else {
|
518 |
+
wordfence::statusEnd($statusIDX, false);
|
519 |
return;
|
520 |
}
|
521 |
+
if($this->addIssue('diskSpace', $level, 'diskSpace' . $level, 'diskSpace' . $level, "You have $spaceLeft" . "% disk space remaining", "You only have $spaceLeft" . "% of your disk space remaining. Please free up disk space or your website may stop serving requests.", array(
|
522 |
+
'spaceLeft' => $spaceLeft ))){
|
523 |
+
wordfence::statusEnd($statusIDX, true);
|
524 |
+
} else {
|
525 |
+
wordfence::statusEnd($statusIDX, true);
|
526 |
+
}
|
527 |
}
|
528 |
private function scanDNSChanges(){
|
529 |
if(! function_exists('dns_get_record')){
|
530 |
$this->status(1, 'info', "Skipping DNS scan because this system does not support dns_get_record()");
|
531 |
return;
|
532 |
}
|
533 |
+
$statusIDX = wordfence::statusStart("Scanning DNS for unauthorized changes");
|
534 |
+
$haveIssues = false;
|
535 |
$home = get_home_url();
|
536 |
if(preg_match('/https?:\/\/([^\/]+)/i', $home, $matches)){
|
537 |
$host = strtolower($matches[1]);
|
554 |
$loggedCNAME = wfConfig::get('wf_dnsCNAME');
|
555 |
$dnsLogged = wfConfig::get('wf_dnsLogged', false);
|
556 |
if($dnsLogged && $loggedCNAME != $currentCNAME){
|
557 |
+
if($this->addIssue('dnsChange', 2, 'dnsChanges', 'dnsChanges', "Your DNS records have changed", "We have detected a change in the CNAME records of your DNS configuration for the domain $host. A CNAME record is an alias that is used to point a domain name to another domain name. For example foo.example.com can point to bar.example.com which then points to an IP address of 10.1.1.1. $msg", array(
|
558 |
'type' => 'CNAME',
|
559 |
'host' => $host,
|
560 |
'oldDNS' => $loggedCNAME,
|
561 |
'newDNS' => $currentCNAME
|
562 |
+
))){
|
563 |
+
$haveIssues = true;
|
564 |
+
}
|
565 |
}
|
566 |
wfConfig::set('wf_dnsCNAME', $currentCNAME);
|
567 |
|
581 |
$dnsLogged = wfConfig::get('wf_dnsLogged', false);
|
582 |
$msg = "A change in your DNS records may indicate that a hacker has hacked into your DNS administration system and has pointed your email or website to their own server for malicious purposes. It could also indicate that your domain has expired. If you made this change yourself you can mark it 'resolved' and safely ignore it.";
|
583 |
if($dnsLogged && $loggedA != $currentA){
|
584 |
+
if($this->addIssue('dnsChange', 2, 'dnsChanges', 'dnsChanges', "Your DNS records have changed", "We have detected a change in the A records of your DNS configuration that may affect the domain $host. An A record is a record in DNS that points a domain name to an IP address. $msg", array(
|
585 |
'type' => 'A',
|
586 |
'host' => $host,
|
587 |
'oldDNS' => $loggedA,
|
588 |
'newDNS' => $currentA
|
589 |
+
))){
|
590 |
+
$haveIssues = true;
|
591 |
+
}
|
592 |
}
|
593 |
wfConfig::set('wf_dnsA', $currentA);
|
594 |
|
608 |
$currentMX = implode(', ', $mxArr);
|
609 |
$loggedMX = wfConfig::get('wf_dnsMX');
|
610 |
if($dnsLogged && $loggedMX != $currentMX){
|
611 |
+
if($this->addIssue('dnsChange', 2, 'dnsChanges', 'dnsChanges', "Your DNS records have changed", "We have detected a change in the email server (MX) records of your DNS configuration for the domain $host. $msg", array(
|
612 |
'type' => 'MX',
|
613 |
'host' => $host,
|
614 |
'oldDNS' => $loggedMX,
|
615 |
'newDNS' => $currentMX
|
616 |
+
))){
|
617 |
+
$haveIssues = true;
|
618 |
+
}
|
619 |
|
620 |
}
|
621 |
wfConfig::set('wf_dnsMX', $currentMX);
|
622 |
|
623 |
wfConfig::set('wf_dnsLogged', 1);
|
624 |
}
|
625 |
+
wordfence::statusEnd($statusIDX, $haveIssues);
|
626 |
}
|
627 |
private function scanOldVersions(){
|
628 |
+
$statusIDX = wordfence::statusStart("Scanning for old themes, plugins and core files");
|
629 |
if(! function_exists( 'get_preferred_from_update_core')){
|
630 |
require_once(ABSPATH . 'wp-admin/includes/update.php');
|
631 |
}
|
632 |
$cur = get_preferred_from_update_core();
|
633 |
+
$haveIssues = false;
|
634 |
if(isset( $cur->response ) && $cur->response == 'upgrade'){
|
635 |
+
if($this->addIssue('wfUpgrade', 1, 'wfUpgrade' . $cur->current, 'wfUpgrade' . $cur->current, "Your WordPress version is out of date", "WordPress version " . $cur->current . " is now available. Please upgrade immediately to get the latest security updates from WordPress.", array(
|
636 |
'currentVersion' => $this->wp_version,
|
637 |
'newVersion' => $cur->current
|
638 |
+
))){
|
639 |
+
$haveIssues = true;
|
640 |
+
}
|
641 |
}
|
642 |
$update_plugins = get_site_transient( 'update_plugins' );
|
643 |
if(isset($update_plugins) && (! empty($update_plugins->response))){
|
650 |
$data = get_plugin_data($pluginFile);
|
651 |
$data['newVersion'] = $vals->new_version;
|
652 |
$key = 'wfPluginUpgrade' . ' ' . $plugin . ' ' . $data['newVersion'] . ' ' . $data['Version'];
|
653 |
+
if($this->addIssue('wfPluginUpgrade', 1, $key, $key, "The Plugin \"" . $data['Name'] . "\" needs an upgrade.", "You need to upgrade \"" . $data['Name'] . "\" to the newest version to ensure you have any security fixes the developer has released.", $data)){
|
654 |
+
$haveIssues = true;
|
655 |
+
}
|
656 |
}
|
657 |
}
|
658 |
}
|
673 |
'version' => $themeData['Version']
|
674 |
);
|
675 |
$key = 'wfThemeUpgrade' . ' ' . $theme . ' ' . $tData['version'] . ' ' . $tData['newVersion'];
|
676 |
+
if($this->addIssue('wfThemeUpgrade', 1, $key, $key, "The Theme \"" . $themeData['Name'] . "\" needs an upgrade.", "You need to upgrade \"" . $themeData['Name'] . "\" to the newest version to ensure you have any security fixes the developer has released.", $tData)){
|
677 |
+
$haveIssues = true;
|
678 |
+
}
|
679 |
}
|
680 |
}
|
681 |
|
682 |
}
|
683 |
}
|
684 |
+
wordfence::statusEnd($statusIDX, $haveIssues);
|
685 |
}
|
686 |
private function errorStop($msg){
|
687 |
$this->errorStopped = true;
|
692 |
wordfence::status($level, $type, $msg);
|
693 |
}
|
694 |
private function addIssue($type, $severity, $ignoreP, $ignoreC, $shortMsg, $longMsg, $templateData){
|
695 |
+
return $this->i->addIssue($type, $severity, $ignoreP, $ignoreC, $shortMsg, $longMsg, $templateData);
|
696 |
}
|
697 |
}
|
698 |
|
lib/wfSchema.php
CHANGED
@@ -126,7 +126,8 @@ class wfSchema {
|
|
126 |
level tinyint UNSIGNED NOT NULL,
|
127 |
type char(5) NOT NULL,
|
128 |
msg varchar(255) NOT NULL,
|
129 |
-
KEY k1(ctime)
|
|
|
130 |
) default charset=utf8",
|
131 |
'wfNet404s' => "(
|
132 |
sig binary(16) NOT NULL PRIMARY KEY,
|
126 |
level tinyint UNSIGNED NOT NULL,
|
127 |
type char(5) NOT NULL,
|
128 |
msg varchar(255) NOT NULL,
|
129 |
+
KEY k1(ctime),
|
130 |
+
KEY k2(type)
|
131 |
) default charset=utf8",
|
132 |
'wfNet404s' => "(
|
133 |
sig binary(16) NOT NULL PRIMARY KEY,
|
lib/wfUtils.php
CHANGED
@@ -165,6 +165,38 @@ class wfUtils {
|
|
165 |
}
|
166 |
return 'unknown';
|
167 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
168 |
}
|
169 |
|
170 |
|
165 |
}
|
166 |
return 'unknown';
|
167 |
}
|
168 |
+
public static function longestLine($data){
|
169 |
+
$lines = preg_split('/[\r\n]+/', $data);
|
170 |
+
$max = 0;
|
171 |
+
foreach($lines as $line){
|
172 |
+
$len = strlen($line);
|
173 |
+
if($len > $max){
|
174 |
+
$max = $len;
|
175 |
+
}
|
176 |
+
}
|
177 |
+
return $max;
|
178 |
+
}
|
179 |
+
public static function longestNospace($data){
|
180 |
+
$lines = preg_split('/[\r\n\s\t]+/', $data);
|
181 |
+
$max = 0;
|
182 |
+
foreach($lines as $line){
|
183 |
+
$len = strlen($line);
|
184 |
+
if($len > $max){
|
185 |
+
$max = $len;
|
186 |
+
}
|
187 |
+
}
|
188 |
+
return $max;
|
189 |
+
}
|
190 |
+
public static function requestMaxMemory(){
|
191 |
+
if(wfConfig::get('maxMem', false) && (int) wfConfig::get('maxMem') > 0){
|
192 |
+
$maxMem = (int) wfConfig::get('maxMem');
|
193 |
+
} else {
|
194 |
+
$maxMem = 256;
|
195 |
+
}
|
196 |
+
if( function_exists('memory_get_usage') && ( (int) @ini_get('memory_limit') < $maxMem ) ){
|
197 |
+
@ini_set('memory_limit', $maxMem . 'M');
|
198 |
+
}
|
199 |
+
}
|
200 |
}
|
201 |
|
202 |
|
lib/wfViewResult.php
CHANGED
@@ -15,6 +15,7 @@
|
|
15 |
if($isEmpty){
|
16 |
echo "File is empty.";
|
17 |
} else {
|
|
|
18 |
echo $geshi->parse_code();
|
19 |
}
|
20 |
?>
|
15 |
if($isEmpty){
|
16 |
echo "File is empty.";
|
17 |
} else {
|
18 |
+
wfUtils::requestMaxMemory();
|
19 |
echo $geshi->parse_code();
|
20 |
}
|
21 |
?>
|
lib/wordfenceClass.php
CHANGED
@@ -22,13 +22,24 @@ class wordfence {
|
|
22 |
public static $newVisit = false;
|
23 |
private static $wfLog = false;
|
24 |
private static $hitID = 0;
|
|
|
25 |
public static function installPlugin(){
|
26 |
-
if(is_multisite() && @$_GET['networkwide'] != 1){
|
27 |
-
die("Sorry but you can't activate Wordfence on an individual site when WordPress MultiSite is enabled. Only the Network Admin can enable Wordfence and only they have access to administer Wordfence.");
|
28 |
-
}
|
29 |
$schema = new wfSchema();
|
30 |
$schema->createAll(); //if not exists
|
31 |
wfConfig::setDefaults(); //If not set
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
32 |
if( !wp_next_scheduled( 'wordfence_daily_cron' )){
|
33 |
wp_schedule_event(time(), 'daily', 'wordfence_daily_cron');
|
34 |
}
|
@@ -36,6 +47,10 @@ class wordfence {
|
|
36 |
wp_schedule_event(time(), 'hourly', 'wordfence_daily_cron');
|
37 |
}
|
38 |
update_option('wordfenceActivated', 1);
|
|
|
|
|
|
|
|
|
39 |
}
|
40 |
public static function uninstallPlugin(){
|
41 |
update_option('wordfenceActivated', 0);
|
@@ -136,8 +151,12 @@ class wordfence {
|
|
136 |
$wfdb->query("delete from $p"."wfThrottleLog order by endTime asc limit %d", ($count3 - $maxRows));
|
137 |
}
|
138 |
$count4 = $wfdb->querySingle("select count(*) as cnt from $p"."wfStatus");
|
139 |
-
if($count4 >
|
140 |
-
$wfdb->query("delete from $p"."wfStatus order by ctime asc limit %d", ($count4 -
|
|
|
|
|
|
|
|
|
141 |
}
|
142 |
|
143 |
}
|
@@ -651,8 +670,7 @@ class wordfence {
|
|
651 |
$issues = new wfIssues();
|
652 |
$jsonData = array(
|
653 |
'serverTime' => $serverTime,
|
654 |
-
'msg' => $wfdb->querySingle("select msg from $p"."wfStatus where level < 3 order by ctime desc limit 1")
|
655 |
-
'currentScanID' => $issues->getScanTime()
|
656 |
);
|
657 |
$events = array();
|
658 |
$alsoGet = $_POST['alsoGet'];
|
@@ -667,16 +685,14 @@ class wordfence {
|
|
667 |
}
|
668 |
$jsonData['events'] = $events;
|
669 |
$jsonData['alsoGet'] = $alsoGet; //send it back so we don't load data if panel has changed
|
670 |
-
if(wfConfig::get('wf_scanRunning') && time() - wfConfig::get('wf_scanRunning') < WORDFENCE_MAX_SCAN_TIME){
|
671 |
-
$jsonData['running'] = '1';
|
672 |
-
} else {
|
673 |
-
$jsonData['running'] = '';
|
674 |
-
}
|
675 |
return $jsonData;
|
676 |
}
|
677 |
-
public static function
|
|
|
678 |
return array(
|
679 |
-
'
|
|
|
|
|
680 |
);
|
681 |
}
|
682 |
public static function ajax_deleteFile_callback(){
|
@@ -943,10 +959,10 @@ class wordfence {
|
|
943 |
return ($a['ctime'] < $b['ctime']) ? -1 : 1;
|
944 |
}
|
945 |
public static function wfFunc_view(){
|
946 |
-
$localFile =
|
947 |
-
if(strpos($localFile,
|
948 |
-
echo "
|
949 |
-
exit(
|
950 |
}
|
951 |
$lang = false;
|
952 |
$cont = @file_get_contents($localFile);
|
@@ -1048,7 +1064,7 @@ class wordfence {
|
|
1048 |
public static function admin_init(){
|
1049 |
if(! self::isAdmin()){ return; }
|
1050 |
|
1051 |
-
foreach(array('activate', 'scan', 'sendActivityLog', 'restoreFile', 'deleteFile', 'removeExclusion', '
|
1052 |
add_action('wp_ajax_wordfence_' . $func, 'wordfence::ajaxReceiver');
|
1053 |
}
|
1054 |
wp_enqueue_style('wordfence-main-style', WP_PLUGIN_URL . '/wordfence/css/main.css');
|
@@ -1069,23 +1085,26 @@ class wordfence {
|
|
1069 |
|
1070 |
}
|
1071 |
public static function configure_warning(){
|
1072 |
-
|
|
|
|
|
1073 |
}
|
1074 |
public static function admin_menus(){
|
1075 |
if(! self::isAdmin()){ return; }
|
1076 |
-
if(wfConfig::get('
|
1077 |
-
|
1078 |
-
|
1079 |
-
|
1080 |
-
|
1081 |
}
|
1082 |
-
|
1083 |
-
|
1084 |
-
|
1085 |
-
|
1086 |
-
add_submenu_page("Wordfence", "
|
1087 |
-
|
1088 |
-
|
|
|
1089 |
}
|
1090 |
public static function menu_options(){
|
1091 |
require 'menu_options.php';
|
@@ -1201,5 +1220,39 @@ class wordfence {
|
|
1201 |
}
|
1202 |
return self::$wfLog;
|
1203 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1204 |
}
|
1205 |
?>
|
22 |
public static $newVisit = false;
|
23 |
private static $wfLog = false;
|
24 |
private static $hitID = 0;
|
25 |
+
private static $statusStartMsgs = array();
|
26 |
public static function installPlugin(){
|
|
|
|
|
|
|
27 |
$schema = new wfSchema();
|
28 |
$schema->createAll(); //if not exists
|
29 |
wfConfig::setDefaults(); //If not set
|
30 |
+
|
31 |
+
$api = new wfAPI('', wfUtils::getWPVersion());
|
32 |
+
$keyData = $api->call('get_anon_api_key');
|
33 |
+
if($api->errorMsg){
|
34 |
+
die("Error fetching free API key from Wordfence: " . $api->errorMsg);
|
35 |
+
}
|
36 |
+
if($keyData['ok'] && $keyData['apiKey']){
|
37 |
+
wfConfig::set('apiKey', $keyData['apiKey']);
|
38 |
+
} else {
|
39 |
+
die("Could not understand the response we received from the Wordfence servers when applying for a free API key.");
|
40 |
+
}
|
41 |
+
|
42 |
+
|
43 |
if( !wp_next_scheduled( 'wordfence_daily_cron' )){
|
44 |
wp_schedule_event(time(), 'daily', 'wordfence_daily_cron');
|
45 |
}
|
47 |
wp_schedule_event(time(), 'hourly', 'wordfence_daily_cron');
|
48 |
}
|
49 |
update_option('wordfenceActivated', 1);
|
50 |
+
$db = new wfDB();
|
51 |
+
|
52 |
+
//Upgrading from 1.5.6 or earlier needs:
|
53 |
+
$db->createKeyIfNotExists($prefix . 'wfStatus', 'level', 'k2');
|
54 |
}
|
55 |
public static function uninstallPlugin(){
|
56 |
update_option('wordfenceActivated', 0);
|
151 |
$wfdb->query("delete from $p"."wfThrottleLog order by endTime asc limit %d", ($count3 - $maxRows));
|
152 |
}
|
153 |
$count4 = $wfdb->querySingle("select count(*) as cnt from $p"."wfStatus");
|
154 |
+
if($count4 > 100000){ //max status events we keep. This determines how much gets emailed to us when users sends us a debug report.
|
155 |
+
$wfdb->query("delete from $p"."wfStatus where level != 10 order by ctime asc limit %d", ($count4 - 100000));
|
156 |
+
$count5 = $wfdb->querySingle("select count(*) as cnt from $p"."wfStatus where level=10");
|
157 |
+
if($count5 > 100){
|
158 |
+
$wfdb->query("delete from $p"."wfStatus where level = 10 order by ctime asc limit %d", ($count5 - 100) );
|
159 |
+
}
|
160 |
}
|
161 |
|
162 |
}
|
670 |
$issues = new wfIssues();
|
671 |
$jsonData = array(
|
672 |
'serverTime' => $serverTime,
|
673 |
+
'msg' => $wfdb->querySingle("select msg from $p"."wfStatus where level < 3 order by ctime desc limit 1")
|
|
|
674 |
);
|
675 |
$events = array();
|
676 |
$alsoGet = $_POST['alsoGet'];
|
685 |
}
|
686 |
$jsonData['events'] = $events;
|
687 |
$jsonData['alsoGet'] = $alsoGet; //send it back so we don't load data if panel has changed
|
|
|
|
|
|
|
|
|
|
|
688 |
return $jsonData;
|
689 |
}
|
690 |
+
public static function ajax_activityLogUpdate_callback(){
|
691 |
+
$issues = new wfIssues();
|
692 |
return array(
|
693 |
+
'ok' => 1,
|
694 |
+
'items' => self::getLog()->getStatusEvents($_POST['lastctime']),
|
695 |
+
'currentScanID' => $issues->getScanTime()
|
696 |
);
|
697 |
}
|
698 |
public static function ajax_deleteFile_callback(){
|
959 |
return ($a['ctime'] < $b['ctime']) ? -1 : 1;
|
960 |
}
|
961 |
public static function wfFunc_view(){
|
962 |
+
$localFile = ABSPATH . '/' . preg_replace('/^[\.\/]+/', '', $_GET['file']);
|
963 |
+
if(strpos($localFile, '..') !== false){
|
964 |
+
echo "Invalid file requested. (Relative paths not allowed)";
|
965 |
+
exit();
|
966 |
}
|
967 |
$lang = false;
|
968 |
$cont = @file_get_contents($localFile);
|
1064 |
public static function admin_init(){
|
1065 |
if(! self::isAdmin()){ return; }
|
1066 |
|
1067 |
+
foreach(array('activate', 'scan', 'sendActivityLog', 'restoreFile', 'deleteFile', 'removeExclusion', 'activityLogUpdate', 'ticker', 'loadIssues', 'updateIssueStatus', 'deleteIssue', 'updateAllIssues', 'reverseLookup', 'unlockOutIP', 'unblockIP', 'blockIP', 'loadStaticPanel', 'saveConfig', 'clearAllBlocked') as $func){
|
1068 |
add_action('wp_ajax_wordfence_' . $func, 'wordfence::ajaxReceiver');
|
1069 |
}
|
1070 |
wp_enqueue_style('wordfence-main-style', WP_PLUGIN_URL . '/wordfence/css/main.css');
|
1085 |
|
1086 |
}
|
1087 |
public static function configure_warning(){
|
1088 |
+
if(! preg_match('/WordfenceSecOpt/', $_SERVER['REQUEST_URI'])){
|
1089 |
+
echo '<div id="wordfenceConfigWarning" class="updated fade"><p><strong>Please set up an email address to receive Wordfence security alerts. </strong> You can do this on the <a href="admin.php?page=WordfenceSecOpt">Wordfence Options Page</a>.</p></div>';
|
1090 |
+
}
|
1091 |
}
|
1092 |
public static function admin_menus(){
|
1093 |
if(! self::isAdmin()){ return; }
|
1094 |
+
if(! wfConfig::get('alertEmails')){
|
1095 |
+
if(wfUtils::isAdminPageMU()){
|
1096 |
+
add_action('network_admin_notices', 'wordfence::configure_warning');
|
1097 |
+
} else {
|
1098 |
+
add_action('admin_notices', 'wordfence::configure_warning');
|
1099 |
}
|
1100 |
+
}
|
1101 |
+
add_submenu_page("Wordfence", "Scan", "Scan", "activate_plugins", "Wordfence", 'wordfence::menu_scan');
|
1102 |
+
add_menu_page('Wordfence', 'Wordfence', 'activate_plugins', 'Wordfence', 'wordfence::menu_scan', WP_PLUGIN_URL . '/wordfence/images/wordfence-logo-16x16.png', 'div');
|
1103 |
+
if(wfConfig::get('liveTrafficEnabled')){
|
1104 |
+
add_submenu_page("Wordfence", "Live Traffic", "Live Traffic", "activate_plugins", "WordfenceActivity", 'wordfence::menu_activity');
|
1105 |
+
}
|
1106 |
+
add_submenu_page('Wordfence', 'Blocked IPs', 'Blocked IPs', 'activate_plugins', 'WordfenceBlockedIPs', 'wordfence::menu_blockedIPs');
|
1107 |
+
add_submenu_page("Wordfence", "Options", "Options", "activate_plugins", "WordfenceSecOpt", 'wordfence::menu_options');
|
1108 |
}
|
1109 |
public static function menu_options(){
|
1110 |
require 'menu_options.php';
|
1220 |
}
|
1221 |
return self::$wfLog;
|
1222 |
}
|
1223 |
+
public static function statusStart($msg){
|
1224 |
+
self::$statusStartMsgs[] = $msg;
|
1225 |
+
self::status(10, 'info', 'SUM_START:' . $msg);
|
1226 |
+
return sizeof(self::$statusStartMsgs) - 1;
|
1227 |
+
}
|
1228 |
+
public static function statusEnd($idx, $haveIssues){
|
1229 |
+
if($haveIssues){
|
1230 |
+
self::status(10, 'info', 'SUM_ENDBAD:' . self::$statusStartMsgs[$idx]);
|
1231 |
+
} else {
|
1232 |
+
self::status(10, 'info', 'SUM_ENDOK:' . self::$statusStartMsgs[$idx]);
|
1233 |
+
}
|
1234 |
+
self::$statusStartMsgs[$idx] = '';
|
1235 |
+
}
|
1236 |
+
public static function statusEndErr(){
|
1237 |
+
for($i = 0; $i < sizeof(self::$statusStartMsgs); $i++){
|
1238 |
+
if(empty(self::$statusStartMsgs[$i]) === false){
|
1239 |
+
self::status(10, 'info', 'SUM_ENDERR:' . self::$statusStartMsgs[$i]);
|
1240 |
+
self::$statusStartMsgs[$i] = '';
|
1241 |
+
}
|
1242 |
+
}
|
1243 |
+
}
|
1244 |
+
public static function statusDisabled($msg){
|
1245 |
+
if(wfConfig::get('isPaid') == 'free'){
|
1246 |
+
self::status(10, 'info', "SUM_PAIDONLY:" . $msg);
|
1247 |
+
} else {
|
1248 |
+
self::status(10, 'info', "SUM_DISABLED:" . $msg);
|
1249 |
+
}
|
1250 |
+
}
|
1251 |
+
public static function wfSchemaExists(){
|
1252 |
+
$db = new wfDB();
|
1253 |
+
global $wpdb; $prefix = $wpdb->prefix;
|
1254 |
+
$exists = $db->querySingle("show tables like '$prefix"."wfConfig'");
|
1255 |
+
return $exists ? true : false;
|
1256 |
+
}
|
1257 |
}
|
1258 |
?>
|
lib/wordfenceConstants.php
CHANGED
@@ -1,9 +1,10 @@
|
|
1 |
<?php
|
2 |
-
define('WORDFENCE_VERSION', 1.
|
3 |
define('WORDFENCE_API_URL', 'https://noc1.wordfence.com/');
|
4 |
define('WORDFENCE_MAX_SCAN_TIME', 600);
|
5 |
define('WORDFENCE_TRANSIENTS_TIMEOUT', 3600); //how long are items cached in seconds e.g. files downloaded for diffing
|
6 |
define('WORDFENCE_MAX_IPLOC_AGE', 604800); //1 week
|
7 |
define('WORDFENCE_CRAWLER_VERIFY_CACHE_TIME', 604800);
|
8 |
define('WORDFENCE_REVERSE_LOOKUP_CACHE_TIME', 86400);
|
|
|
9 |
?>
|
1 |
<?php
|
2 |
+
define('WORDFENCE_VERSION', 1.3);
|
3 |
define('WORDFENCE_API_URL', 'https://noc1.wordfence.com/');
|
4 |
define('WORDFENCE_MAX_SCAN_TIME', 600);
|
5 |
define('WORDFENCE_TRANSIENTS_TIMEOUT', 3600); //how long are items cached in seconds e.g. files downloaded for diffing
|
6 |
define('WORDFENCE_MAX_IPLOC_AGE', 604800); //1 week
|
7 |
define('WORDFENCE_CRAWLER_VERIFY_CACHE_TIME', 604800);
|
8 |
define('WORDFENCE_REVERSE_LOOKUP_CACHE_TIME', 86400);
|
9 |
+
define('WORDFENCE_MAX_FILE_SIZE_TO_PROCESS', 52428800); //50 megs
|
10 |
?>
|
lib/wordfenceHash.php
CHANGED
@@ -58,13 +58,17 @@ class wordfenceHash {
|
|
58 |
}
|
59 |
}
|
60 |
private function processFile($file){
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
61 |
$wfHash = $this->wfHash($file, true);
|
62 |
if($wfHash){
|
63 |
-
if(function_exists('memory_get_usage')){
|
64 |
-
wordfence::status(2, 'info', "Examined file: $file (Mem:" . sprintf('%.1f', memory_get_usage(true) / (1024 * 1024)) . "M)");
|
65 |
-
} else {
|
66 |
-
wordfence::status(2, 'info', "Examined file: $file");
|
67 |
-
}
|
68 |
$this->hashes[substr($file, $this->striplen)] = $wfHash;
|
69 |
//Now that we know we can open the file, lets update stats
|
70 |
if(preg_match('/\.(?:js|html|htm|css)$/i', $file)){
|
58 |
}
|
59 |
}
|
60 |
private function processFile($file){
|
61 |
+
if(@filesize($file) > WORDFENCE_MAX_FILE_SIZE_TO_PROCESS){
|
62 |
+
wordfence::status(2, 'info', "Skipping file larger than 50 megs: $file");
|
63 |
+
return;
|
64 |
+
}
|
65 |
+
if(function_exists('memory_get_usage')){
|
66 |
+
wordfence::status(2, 'info', "Scanning: $file (Mem:" . sprintf('%.1f', memory_get_usage(true) / (1024 * 1024)) . "M)");
|
67 |
+
} else {
|
68 |
+
wordfence::status(2, 'info', "Scanning: $file");
|
69 |
+
}
|
70 |
$wfHash = $this->wfHash($file, true);
|
71 |
if($wfHash){
|
|
|
|
|
|
|
|
|
|
|
72 |
$this->hashes[substr($file, $this->striplen)] = $wfHash;
|
73 |
//Now that we know we can open the file, lets update stats
|
74 |
if(preg_match('/\.(?:js|html|htm|css)$/i', $file)){
|
lib/wordfenceScanner.php
CHANGED
@@ -49,9 +49,9 @@ class wordfenceScanner {
|
|
49 |
$fsize = $fsize . "B";
|
50 |
}
|
51 |
if(function_exists('memory_get_usage')){
|
52 |
-
wordfence::status(2, 'info', "
|
53 |
} else {
|
54 |
-
wordfence::status(2, 'info', "
|
55 |
}
|
56 |
$stime = microtime(true);
|
57 |
$fileSum = @md5_file($this->path . $file);
|
@@ -88,14 +88,15 @@ class wordfenceScanner {
|
|
88 |
));
|
89 |
break;
|
90 |
}
|
91 |
-
|
|
|
92 |
$this->addResult(array(
|
93 |
'type' => 'file',
|
94 |
'severity' => 1,
|
95 |
'ignoreP' => $this->path . $file,
|
96 |
'ignoreC' => $fileSum,
|
97 |
-
'shortMsg' => "This file may contain
|
98 |
-
'longMsg' => "This file is a PHP executable file and contains
|
99 |
'data' => array(
|
100 |
'file' => $file,
|
101 |
'canDiff' => false,
|
@@ -143,7 +144,8 @@ class wordfenceScanner {
|
|
143 |
'file' => $file,
|
144 |
'canDiff' => false,
|
145 |
'canFix' => false,
|
146 |
-
'canDelete' => true
|
|
|
147 |
)
|
148 |
));
|
149 |
} else if($result['badList'] == 'googpub-phish-shavar'){
|
@@ -158,7 +160,8 @@ class wordfenceScanner {
|
|
158 |
'file' => $file,
|
159 |
'canDiff' => false,
|
160 |
'canFix' => false,
|
161 |
-
'canDelete' => true
|
|
|
162 |
)
|
163 |
));
|
164 |
}
|
49 |
$fsize = $fsize . "B";
|
50 |
}
|
51 |
if(function_exists('memory_get_usage')){
|
52 |
+
wordfence::status(2, 'info', "Scanning contents: $file (Size:$fsize Mem:" . sprintf('%.1f', memory_get_usage(true) / (1024 * 1024)) . "M)");
|
53 |
} else {
|
54 |
+
wordfence::status(2, 'info', "Scanning contents: $file (Size: $fsize)");
|
55 |
}
|
56 |
$stime = microtime(true);
|
57 |
$fileSum = @md5_file($this->path . $file);
|
88 |
));
|
89 |
break;
|
90 |
}
|
91 |
+
$longestNospace = wfUtils::longestNospace($data);
|
92 |
+
if($longestNospace > 1000 && (strpos($data, 'eval') !== false || preg_match('/preg_replace\([^\(]+\/[a-z]*e/', $data)) ){
|
93 |
$this->addResult(array(
|
94 |
'type' => 'file',
|
95 |
'severity' => 1,
|
96 |
'ignoreP' => $this->path . $file,
|
97 |
'ignoreC' => $fileSum,
|
98 |
+
'shortMsg' => "This file may contain malicious executable code",
|
99 |
+
'longMsg' => "This file is a PHP executable file and contains a line $longestNospace characters long without spaces that may be encoded data along with functions that may be used to execute that code. If you know about this file you can choose to ignore it to exclude it from future scans.",
|
100 |
'data' => array(
|
101 |
'file' => $file,
|
102 |
'canDiff' => false,
|
144 |
'file' => $file,
|
145 |
'canDiff' => false,
|
146 |
'canFix' => false,
|
147 |
+
'canDelete' => true,
|
148 |
+
'gsb' => 'goog-malware-shavar'
|
149 |
)
|
150 |
));
|
151 |
} else if($result['badList'] == 'googpub-phish-shavar'){
|
160 |
'file' => $file,
|
161 |
'canDiff' => false,
|
162 |
'canFix' => false,
|
163 |
+
'canDelete' => true,
|
164 |
+
'gsb' => 'googpub-phish-shavar'
|
165 |
)
|
166 |
));
|
167 |
}
|
readme.txt
CHANGED
@@ -3,7 +3,7 @@ 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.3.2
|
6 |
-
Stable tag:
|
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 |
|
@@ -152,6 +152,21 @@ 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 |
= 1.5.6 =
|
156 |
* Removed use of nonces and purely using 30 minute key for unlocking emails.
|
157 |
* Fixed bug that caused admin emails to not get emailed when requesting unlocking email.
|
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.3.2
|
6 |
+
Stable tag: 2.0.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 |
|
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 |
+
= 2.0.1 =
|
156 |
+
* Improved scanning for specific attacks being used in the PHP-CGI vulnerability ( CVE-2012-1823)
|
157 |
+
* API keys no longer required. WF fetches a temporary anonymous API key for you on activation.
|
158 |
+
* Added real-time activity log on scan page.
|
159 |
+
* Added real-time summary updates on scan page.
|
160 |
+
* Fixed ability to view files that have symlinks in path.
|
161 |
+
* Added message to configure alert email address for multi-site and single site installs on activation.
|
162 |
+
* Disabled firewall rules by default because most sites don't need them.
|
163 |
+
* Disabled blocking of fake googlebots except for high security levels to prevent users who like to pretend they're googlebot from blocking themselves.
|
164 |
+
* Geshi the syntax highlighter now asks for more memory before running.
|
165 |
+
* Fixed bug that caused scan to hang on very large files.
|
166 |
+
* Added an index to wfStatus to make it faster for summary statuses
|
167 |
+
* Removed multisite pre-activation check to make activation more reliable on multisite installs.
|
168 |
+
* Better problem reporting if you trashed your Wordfence schema but the plugin is still installed.
|
169 |
+
|
170 |
= 1.5.6 =
|
171 |
* Removed use of nonces and purely using 30 minute key for unlocking emails.
|
172 |
* Fixed bug that caused admin emails to not get emailed when requesting unlocking email.
|
wfscan.php
CHANGED
@@ -20,6 +20,9 @@ require_once('lib/wfScanEngine.php');
|
|
20 |
|
21 |
class wfScan {
|
22 |
public static function wfScanMain(){
|
|
|
|
|
|
|
23 |
if(! $_SERVER['HTTP_X_WORDFENCE_CRONKEY']){
|
24 |
self::errorExit("The Wordfence scanner did not receive the x_wordfence_cronkey secure header.");
|
25 |
}
|
@@ -43,15 +46,8 @@ class wfScan {
|
|
43 |
if($scanRunning && time() - $scanRunning < WORDFENCE_MAX_SCAN_TIME){
|
44 |
self::errorExit("There is already a scan running.");
|
45 |
}
|
46 |
-
|
47 |
-
|
48 |
-
} else {
|
49 |
-
$maxMem = 256;
|
50 |
-
}
|
51 |
-
if( function_exists('memory_get_usage') && ( (int) @ini_get('memory_limit') < $maxMem ) ){
|
52 |
-
wordfence::status(1, 'info', "Requesting a maximum memory limit of $maxMem megabytes from PHP.");
|
53 |
-
@ini_set('memory_limit', $maxMem . 'M');
|
54 |
-
}
|
55 |
|
56 |
set_error_handler('wfScan::error_handler', E_ALL);
|
57 |
register_shutdown_function('wfScan::shutdown');
|
@@ -62,6 +58,7 @@ class wfScan {
|
|
62 |
wfConfig::set('wf_scanRunning', time());
|
63 |
$scan = new wfScanEngine();
|
64 |
$scan->go();
|
|
|
65 |
wfConfig::set('wf_scanRunning', '');
|
66 |
}
|
67 |
public static function obHandler($buf){
|
20 |
|
21 |
class wfScan {
|
22 |
public static function wfScanMain(){
|
23 |
+
if(! wordfence::wfSchemaExists()){
|
24 |
+
self::errorExit("Looks like the Wordfence database tables have been deleted. You can fix this by de-activating and re-activating the Wordfence plugin from your Plugins menu.");
|
25 |
+
}
|
26 |
if(! $_SERVER['HTTP_X_WORDFENCE_CRONKEY']){
|
27 |
self::errorExit("The Wordfence scanner did not receive the x_wordfence_cronkey secure header.");
|
28 |
}
|
46 |
if($scanRunning && time() - $scanRunning < WORDFENCE_MAX_SCAN_TIME){
|
47 |
self::errorExit("There is already a scan running.");
|
48 |
}
|
49 |
+
wordfence::status(10, 'info', "SUM_PREP:Preparing a new scan.");
|
50 |
+
wfUtils::requestMaxMemory();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
51 |
|
52 |
set_error_handler('wfScan::error_handler', E_ALL);
|
53 |
register_shutdown_function('wfScan::shutdown');
|
58 |
wfConfig::set('wf_scanRunning', time());
|
59 |
$scan = new wfScanEngine();
|
60 |
$scan->go();
|
61 |
+
|
62 |
wfConfig::set('wf_scanRunning', '');
|
63 |
}
|
64 |
public static function obHandler($buf){
|
wordfence.php
CHANGED
@@ -4,7 +4,7 @@ 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:
|
8 |
Author URI: http://wordfence.com/
|
9 |
*/
|
10 |
require_once('lib/wordfenceConstants.php');
|
4 |
Plugin URI: http://wordfence.com/
|
5 |
Description: Wordfence Security - Anti-virus and Firewall security plugin for WordPress
|
6 |
Author: Mark Maunder
|
7 |
+
Version: 2.0.1
|
8 |
Author URI: http://wordfence.com/
|
9 |
*/
|
10 |
require_once('lib/wordfenceConstants.php');
|