Wordfence Security – Firewall & Malware Scan - Version 6.2.1

Version Description

  • Improvement: Now performing scanning for PHP code in all uploaded files in real-time.
  • Improvement: Improved handling of bad characters and IPv6 ranges in Advanced Blocking.
  • Improvement: Live traffic and scanning activity now display a paused notice when real-time updates are suspended while in the background.
  • Improvement: The file system scan alerts for files flagged by antivirus software with a '.suspected' extension.
  • Improvement: New alert option to get notified only when logins are from a new location/device.
  • Change: First phase for removing the Falcon cache in place, which will add a notice of its pending removal.
  • Fix: Included country flags for Kosovo and Curaao.
  • Fix: Fixed the .htaccess directives used to hide files found by the scanner.
  • Fix: Dashboard widget shows correct status for failed logins by deleted users.
  • Fix: Removed duplicate issues for modified files in the scan results.
  • Fix: Suppressed warning from reverse lookup on IPv6 addresses without valid DNS records.
  • Fix: Fixed file inclusion error with themes lacking a 404 page.
  • Fix: CSS fixes for activity report email.
Download this release

Release Info

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

Code changes from version 6.2.0 to 6.2.1

css/main.css CHANGED
@@ -5,6 +5,7 @@
5
margin: 20px 0 0 20px;
6
}
7
div.wordfenceLive {
8
height: 29px;
9
white-space: nowrap;
10
overflow: hidden;
@@ -37,6 +38,118 @@ div.wordfenceLive p {
37
font-weight: normal;
38
display: inline;
39
}
40
.wordfence-icon32 {
41
width: 32px;
42
height: 32px;
5
margin: 20px 0 0 20px;
6
}
7
div.wordfenceLive {
8
+ position: relative;
9
height: 29px;
10
white-space: nowrap;
11
overflow: hidden;
38
font-weight: normal;
39
display: inline;
40
}
41
+ div.wordfenceLive .wordfenceLiveActivity::after {
42
+ position: absolute;
43
+ z-index: 3000;
44
+ top: 0;
45
+ right: 0;
46
+ width: 0;
47
+ height: 0;
48
+ background: rgba(255, 252, 239, 0.9);
49
+ content: '';
50
+ opacity: 0;
51
+ -webkit-transition: opacity 0.5s, width 0.1s, height 0.1s;
52
+ -webkit-transition-delay: 0s, 0.5s, 0.5s;
53
+ -moz-transition: opacity 0.5s, width 0.1s 0.5s, height 0.1s 0.5s;
54
+ -o-transition: opacity 0.5s, width 0.1s 0.5s, height 0.1s 0.5s;
55
+ transition: opacity 0.5s, width 0.1s 0.5s, height 0.1s 0.5s;
56
+ }
57
+ .wordfenceLiveActivityPaused div.wordfenceLive .wordfenceLiveActivity::after {
58
+ width: 100%;
59
+ height: 100%;
60
+ opacity: 1;
61
+ -webkit-transition: opacity 0.5s;
62
+ transition: opacity 0.5s;
63
+ }
64
+ div.wordfenceLive .wordfenceLiveStateMessage {
65
+ display: none;
66
+ position: absolute;
67
+ z-index: 3001;
68
+ top: 0;
69
+ left: 0;
70
+ width: 100%;
71
+ height: 100%;
72
+ text-align: center;
73
+ padding: 3px;
74
+ font-weight: normal;
75
+ line-height: 29px;
76
+ color: #666666;
77
+ opacity: 0;
78
+ -webkit-transition: opacity 0.5s, width 0.1s, height 0.1s;
79
+ -webkit-transition-delay: 0s, 0.5s, 0.5s;
80
+ -moz-transition: opacity 0.5s, width 0.1s 0.5s, height 0.1s 0.5s;
81
+ -o-transition: opacity 0.5s, width 0.1s 0.5s, height 0.1s 0.5s;
82
+ transition: opacity 0.5s, width 0.1s 0.5s, height 0.1s 0.5s;
83
+ }
84
+ div.wordfenceLive .wordfenceLiveStateMessage td {
85
+ padding: 0px;
86
+ }
87
+ .wordfenceLiveActivityPaused div.wordfenceLive .wordfenceLiveStateMessage {
88
+ opacity: 1;
89
+ -webkit-transition: opacity 0.5s;
90
+ transition: opacity 0.5s;
91
+ display: table;
92
+ }
93
+ #wfLiveTrafficOverlayAnchor::after {
94
+ position: absolute;
95
+ z-index: 3002;
96
+ top: 0;
97
+ right: 0;
98
+ width: 0;
99
+ height: 0;
100
+ background: rgba(241, 241, 241, 0.6);
101
+ content: '';
102
+ opacity: 0;
103
+ -webkit-transition: opacity 0.5s, width 0.1s, height 0.1s;
104
+ -webkit-transition-delay: 0s, 0.5s, 0.5s;
105
+ -moz-transition: opacity 0.5s, width 0.1s 0.5s, height 0.1s 0.5s;
106
+ -o-transition: opacity 0.5s, width 0.1s 0.5s, height 0.1s 0.5s;
107
+ transition: opacity 0.5s, width 0.1s 0.5s, height 0.1s 0.5s;
108
+ }
109
+ .wordfenceLiveActivityPaused #wfLiveTrafficOverlayAnchor::after {
110
+ width: 100%;
111
+ height: 100%;
112
+ opacity: 1;
113
+ -webkit-transition: opacity 0.5s;
114
+ transition: opacity 0.5s;
115
+ }
116
+ #wfLiveTrafficDisabledMessage {
117
+ display: none;
118
+ position: fixed;
119
+ z-index: 3003;
120
+ left: 0;
121
+ width: 100%;
122
+ top: 50%;
123
+ transform: translateY(-50%);
124
+ text-align: center;
125
+ color: #666666;
126
+ opacity: 0;
127
+ -webkit-transition: opacity 0.5s, width 0.1s, height 0.1s;
128
+ -webkit-transition-delay: 0s, 0.5s, 0.5s;
129
+ -moz-transition: opacity 0.5s, width 0.1s 0.5s, height 0.1s 0.5s;
130
+ -o-transition: opacity 0.5s, width 0.1s 0.5s, height 0.1s 0.5s;
131
+ transition: opacity 0.5s, width 0.1s 0.5s, height 0.1s 0.5s;
132
+ }
133
+ #wfLiveTrafficDisabledMessage h2 {
134
+ background-color: #FFF;
135
+ overflow: hidden;
136
+ border: 1px solid #CCC;
137
+ max-width: 350px;
138
+ margin: 0 auto;
139
+ padding: 15px;
140
+ font-size: 2.0em;
141
+ }
142
+ #wfLiveTrafficDisabledMessage h2 small {
143
+ font-size: 0.5em;
144
+ font-weight: normal;
145
+ margin-top: 20px;
146
+ }
147
+ .wordfenceLiveActivityPaused #wfLiveTrafficDisabledMessage {
148
+ display: block;
149
+ opacity: 1;
150
+ -webkit-transition: opacity 0.5s;
151
+ transition: opacity 0.5s;
152
+ }
153
.wordfence-icon32 {
154
width: 32px;
155
height: 32px;
images/flags/cw.png ADDED
Binary file
images/flags/xk.png ADDED
Binary file
js/admin.js CHANGED
@@ -399,8 +399,14 @@
399
},
400
updateActivityLog: function() {
401
if (this.activityLogUpdatePending || !this.windowHasFocus()) {
402
return;
403
}
404
this.activityLogUpdatePending = true;
405
var self = this;
406
this.ajax('wordfence_activityLogUpdate', {
@@ -578,8 +584,14 @@
578
},
579
updateTicker: function(forceUpdate) {
580
if ((!forceUpdate) && (this.tickerUpdatePending || !this.windowHasFocus())) {
581
return;
582
}
583
this.tickerUpdatePending = true;
584
var self = this;
585
var alsoGet = '';
@@ -875,7 +887,8 @@
875
"sWidth": '400px',
876
"sType": 'html',
877
fnRender: function(obj) {
878
- var tmplName = 'issueTmpl_' + obj.aData.type;
879
return jQuery('#' + tmplName).tmpl(obj.aData).html();
880
}
881
}
@@ -1543,15 +1556,62 @@
1543
return;
1544
}
1545
range = range.replace(/ /g, '');
1546
- if (range && /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\s*\-\s*\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}#x2F;.test(range)) {
1547
var ips = range.split('-');
1548
- var total = this.inet_aton(ips[1]) - this.inet_aton(ips[0]) + 1;
1549
- if (total < 1) {
1550
jQuery('#wfShowRangeTotal').html("<span style=\"color: #F00;\">Invalid. Starting IP is greater than ending IP.</span>");
1551
return;
1552
}
1553
- jQuery('#wfShowRangeTotal').html("<span style=\"color: #0A0;\">Valid: " + total + " addresses in range.</span>");
1554
- } else {
1555
jQuery('#wfShowRangeTotal').empty();
1556
}
1557
},
@@ -1649,6 +1709,7 @@
1649
return;
1650
}
1651
ipRange = ipRange.replace(/ /g, '').toLowerCase();
1652
if (ipRange) {
1653
var range = ipRange.split('-'),
1654
validRange;
@@ -2255,33 +2316,42 @@
2255
// Return if 4 bytes, otherwise false.
2256
return m.length === 4 ? m : false;
2257
}
2258
- r = /^((?:[\da-f]{1,4}(?::|)){0,8})(::)?((?:[\da-f]{1,4}(?::|)){0,8})#x2F;;
2259
m = a.match(r); // IPv6
2260
if (m) {
2261
- // Translate each hexadecimal value.
2262
- for (j = 1; j < 4; j++) {
2263
- // Indice 2 is :: and if no length, continue.
2264
- if (j === 2 || m[j].length === 0) {
2265
- continue;
2266
- }
2267
- m[j] = m[j].split(':');
2268
- for (i = 0; i < m[j].length; i++) {
2269
- m[j][i] = parseInt(m[j][i], 16);
2270
- // Would be NaN if it was blank, return false.
2271
- if (isNaN(m[j][i])) {
2272
- return false; // Invalid IP.
2273
- }
2274
- m[j][i] = f(m[j][i] >> 8) + f(m[j][i] & 0xFF);
2275
}
2276
- m[j] = m[j].join('');
2277
}
2278
- x = m[1].length + m[3].length;
2279
- if (x === 16) {
2280
- return m[1] + m[3];
2281
- } else if (x < 16 && m[2].length > 0) {
2282
- return m[1] + (new Array(16 - x + 1))
2283
- .join('\x00') + m[3];
2284
}
2285
}
2286
return false; // Invalid IP.
2287
},
@@ -2668,6 +2738,11 @@
2668
}
2669
jQuery(function() {
2670
wordfenceAdmin.init();
2671
});
2672
})(jQuery);
2673
399
},
400
updateActivityLog: function() {
401
if (this.activityLogUpdatePending || !this.windowHasFocus()) {
402
+ if (!jQuery('body').hasClass('wordfenceLiveActivityPaused') && !this.activityLogUpdatePending) {
403
+ jQuery('body').addClass('wordfenceLiveActivityPaused');
404
+ }
405
return;
406
}
407
+ if (jQuery('body').hasClass('wordfenceLiveActivityPaused')) {
408
+ jQuery('body').removeClass('wordfenceLiveActivityPaused');
409
+ }
410
this.activityLogUpdatePending = true;
411
var self = this;
412
this.ajax('wordfence_activityLogUpdate', {
584
},
585
updateTicker: function(forceUpdate) {
586
if ((!forceUpdate) && (this.tickerUpdatePending || !this.windowHasFocus())) {
587
+ if (!jQuery('body').hasClass('wordfenceLiveActivityPaused') && !this.tickerUpdatePending) {
588
+ jQuery('body').addClass('wordfenceLiveActivityPaused');
589
+ }
590
return;
591
}
592
+ if (jQuery('body').hasClass('wordfenceLiveActivityPaused')) {
593
+ jQuery('body').removeClass('wordfenceLiveActivityPaused');
594
+ }
595
this.tickerUpdatePending = true;
596
var self = this;
597
var alsoGet = '';
887
"sWidth": '400px',
888
"sType": 'html',
889
fnRender: function(obj) {
890
+ var issueType = (obj.aData.type == 'knownfile' ? 'file' : obj.aData.type);
891
+ var tmplName = 'issueTmpl_' + issueType;
892
return jQuery('#' + tmplName).tmpl(obj.aData).html();
893
}
894
}
1556
return;
1557
}
1558
range = range.replace(/ /g, '');
1559
+ range = range.replace(/[\u2013-\u2015]/g, '-'); //Non-hyphen dashes to hyphen
1560
+ if (range && /^[^\-]+\-[^\-]+#x2F;.test(range)) {
1561
+ var count = 1;
1562
+ var countOverflow = false;
1563
+ var badRange = false;
1564
+ var badIP = false;
1565
+
1566
var ips = range.split('-');
1567
+ var ip1 = this.inet_pton(ips[0]);
1568
+ var ip2 = this.inet_pton(ips[1]);
1569
+
1570
+ if (ip1 === false || ip2 === false) {
1571
+ badIP = true;
1572
+ }
1573
+ else {
1574
+ //Both to 16-byte binary strings
1575
+ var binStart = ("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff" + ip1).slice(-16);
1576
+ var binEnd = ("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff" + ip2).slice(-16);
1577
+
1578
+ for (var i = 0; i < binStart.length; i++) {
1579
+ var n0 = binStart.charCodeAt(i);
1580
+ var n1 = binEnd.charCodeAt(i);
1581
+
1582
+ if (i < 11 && n1 - n0 > 0) { //Based on Number.MAX_SAFE_INTEGER, which equals 2 ^ 53 - 1. Any of the first 9 bytes and part of the 10th that add to the range will put us over that
1583
+ countOverflow = true;
1584
+ break;
1585
+ }
1586
+ else if (i < 11 && n1 - n0 < 0) {
1587
+ badRange = true;
1588
+ break;
1589
+ }
1590
+
1591
+ count += (n1 - n0) << (8 * (15 - i));
1592
+ if (count < 1) {
1593
+ badRange = true;
1594
+ break;
1595
+ }
1596
+ }
1597
+ }
1598
+
1599
+ if (badIP) {
1600
+ jQuery('#wfShowRangeTotal').html("<span style=\"color: #F00;\">Invalid IP entered.</span>");
1601
+ return;
1602
+ }
1603
+ else if (badRange) {
1604
jQuery('#wfShowRangeTotal').html("<span style=\"color: #F00;\">Invalid. Starting IP is greater than ending IP.</span>");
1605
return;
1606
}
1607
+ else if (countOverflow) {
1608
+ jQuery('#wfShowRangeTotal').html("<span style=\"color: #0A0;\">Valid: &gt;281474976710656 addresses in range.</span>");
1609
+ return;
1610
+ }
1611
+
1612
+ jQuery('#wfShowRangeTotal').html("<span style=\"color: #0A0;\">Valid: " + count + " addresses in range.</span>");
1613
+ }
1614
+ else {
1615
jQuery('#wfShowRangeTotal').empty();
1616
}
1617
},
1709
return;
1710
}
1711
ipRange = ipRange.replace(/ /g, '').toLowerCase();
1712
+ ipRange = ipRange.replace(/[\u2013-\u2015]/g, '-'); //Non-hyphen dashes to hyphen
1713
if (ipRange) {
1714
var range = ipRange.split('-'),
1715
validRange;
2316
// Return if 4 bytes, otherwise false.
2317
return m.length === 4 ? m : false;
2318
}
2319
+ r = /^((?:[\da-f]{1,4}(?::|)){0,8})(::)?((?:[\da-f]{1,4}(?::|)){0,8})#x2F;i;
2320
m = a.match(r); // IPv6
2321
if (m) {
2322
+ if (a == '::') {
2323
+ return "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
2324
+ }
2325
+
2326
+ var colonCount = a.split(':').length - 1;
2327
+ var doubleColonPos = a.indexOf('::');
2328
+ if (doubleColonPos > -1) {
2329
+ var expansionLength = ((doubleColonPos == 0 || doubleColonPos == a.length - 2) ? 9 : 8) - colonCount;
2330
+ var expansion = '';
2331
+ for (i = 0; i < expansionLength; i++) {
2332
+ expansion += ':0000';
2333
}
2334
+ a = a.replace('::', expansion + ':');
2335
+ a = a.replace(/(?:^\:|\:$)/, '', a);
2336
}
2337
+
2338
+ var ipGroups = a.split(':');
2339
+ var ipBin = '';
2340
+ for (i = 0; i < ipGroups.length; i++) {
2341
+ var group = ipGroups[i];
2342
+ if (group.length > 4) {
2343
+ return false;
2344
+ }
2345
+ group = ("0000" + group).slice(-4);
2346
+ var b1 = parseInt(group.slice(0, 2), 16);
2347
+ var b2 = parseInt(group.slice(-2), 16);
2348
+ if (isNaN(b1) || isNaN(b2)) {
2349
+ return false;
2350
+ }
2351
+ ipBin += f(b1) + f(b2);
2352
}
2353
+
2354
+ return ipBin.length == 16 ? ipBin : false;
2355
}
2356
return false; // Invalid IP.
2357
},
2738
}
2739
jQuery(function() {
2740
wordfenceAdmin.init();
2741
+ jQuery(window).on('focus', function() {
2742
+ if (jQuery('body').hasClass('wordfenceLiveActivityPaused')) {
2743
+ jQuery('body').removeClass('wordfenceLiveActivityPaused');
2744
+ }
2745
+ });
2746
});
2747
})(jQuery);
2748
js/tourTip.js CHANGED
@@ -41,6 +41,14 @@ window['wordfenceExt'] = {
41
function(){ jQuery('#wordfenceSuPHPUpdateWarning').fadeOut(); }
42
);
43
},
44
removeFromCache: function(postID){
45
this.ajax('wordfence_removeFromCache', {
46
id: postID
41
function(){ jQuery('#wordfenceSuPHPUpdateWarning').fadeOut(); }
42
);
43
},
44
+ falconDeprecationChoice: function(choice) {
45
+ this.ajax('wordfence_falconDeprecationChoice', {
46
+ choice: choice
47
+ },
48
+ function(res){ jQuery('#wordfenceFalconDeprecationWarning').fadeOut(); },
49
+ function(){ jQuery('#wordfenceFalconDeprecationWarning').fadeOut(); }
50
+ );
51
+ },
52
removeFromCache: function(postID){
53
this.ajax('wordfence_removeFromCache', {
54
id: postID
lib/menu_activity.php CHANGED
@@ -1,3 +1,9 @@
1
<div class="wrap wordfence">
2
<?php require('menuHeader.php'); ?>
3
@@ -23,12 +29,17 @@
23
24
<div class="wordfenceModeElem" id="wordfenceMode_activity"></div>
25
<div class="wordfenceLive">
26
- <table border="0" cellpadding="0" cellspacing="0">
27
<tr>
28
<td><h2>Wordfence Live Activity:</h2></td>
29
<td id="wfLiveStatus"></td>
30
</tr>
31
</table>
32
</div>
33
<div class="wordfenceWrap<?php if (!wfConfig::get('isPaid')) { echo " wordfence-community"; }?>">
34
<?php
1
+ <?php if (wfConfig::liveTrafficEnabled()): ?>
2
+ <div id="wfLiveTrafficOverlayAnchor"></div>
3
+ <div id="wfLiveTrafficDisabledMessage">
4
+ <h2>Live Updates Paused<br /><small>Click inside window to resume</small></h2>
5
+ </div>
6
+ <?php endif ?>
7
<div class="wrap wordfence">
8
<?php require('menuHeader.php'); ?>
9
29
30
<div class="wordfenceModeElem" id="wordfenceMode_activity"></div>
31
<div class="wordfenceLive">
32
+ <table border="0" cellpadding="0" cellspacing="0" class="wordfenceLiveActivity">
33
<tr>
34
<td><h2>Wordfence Live Activity:</h2></td>
35
<td id="wfLiveStatus"></td>
36
</tr>
37
</table>
38
+ <table border="0" cellpadding="0" cellspacing="0" class="wordfenceLiveStateMessage">
39
+ <tr>
40
+ <td>Live Updates Paused &mdash; Click inside window to resume</td>
41
+ </tr>
42
+ </table>
43
</div>
44
<div class="wordfenceWrap<?php if (!wfConfig::get('isPaid')) { echo " wordfence-community"; }?>">
45
<?php
lib/menu_blockedIPs.php CHANGED
@@ -3,8 +3,16 @@
3
<?php require('menuHeader.php'); ?>
4
<?php $helpLink="http://docs.wordfence.com/en/Blocked_IPs"; $helpLabel="Learn more about Blocked IPs"; $pageTitle = "Wordfence Blocked IPs"; include('pageTitle.php'); ?>
5
<div class="wordfenceLive">
6
- <table border="0" cellpadding="0" cellspacing="0">
7
- <tr><td><h2>Wordfence Live Activity:</h2></td><td id="wfLiveStatus"></td></tr>
8
</table>
9
</div>
10
<?php if(! wfConfig::get('firewallEnabled')){ ?><div style="color: #F00; font-weight: bold;">Rate limiting rules and advanced blocking are disabled. You can enable it on the <a href="admin.php?page=WordfenceSecOpt">Wordfence Options page</a> at the top.</div><?php } ?>
3
<?php require('menuHeader.php'); ?>
4
<?php $helpLink="http://docs.wordfence.com/en/Blocked_IPs"; $helpLabel="Learn more about Blocked IPs"; $pageTitle = "Wordfence Blocked IPs"; include('pageTitle.php'); ?>
5
<div class="wordfenceLive">
6
+ <table border="0" cellpadding="0" cellspacing="0" class="wordfenceLiveActivity">
7
+ <tr>
8
+ <td><h2>Wordfence Live Activity:</h2></td>
9
+ <td id="wfLiveStatus"></td>
10
+ </tr>
11
+ </table>
12
+ <table border="0" cellpadding="0" cellspacing="0" class="wordfenceLiveStateMessage">
13
+ <tr>
14
+ <td>Live Updates Paused &mdash; Click inside window to resume</td>
15
+ </tr>
16
</table>
17
</div>
18
<?php if(! wfConfig::get('firewallEnabled')){ ?><div style="color: #F00; font-weight: bold;">Rate limiting rules and advanced blocking are disabled. You can enable it on the <a href="admin.php?page=WordfenceSecOpt">Wordfence Options page</a> at the top.</div><?php } ?>
lib/menu_options.php CHANGED
@@ -9,12 +9,17 @@ $w = new wfConfig();
9
$pageTitle = "Wordfence Options";
10
include( 'pageTitle.php' ); ?>
11
<div class="wordfenceLive">
12
- <table border="0" cellpadding="0" cellspacing="0">
13
<tr>
14
<td><h2>Wordfence Live Activity:</h2></td>
15
<td id="wfLiveStatus"></td>
16
</tr>
17
</table>
18
</div>
19
<?php
20
$rightRail = new wfView('marketing/rightrail', array('additionalClasses' => 'wordfenceRightRailOptions'));
@@ -297,11 +302,21 @@ $w = new wfConfig();
297
<td><input type="checkbox" id="alertOn_adminLogin" class="wfConfigElem" name="alertOn_adminLogin"
298
value="1" <?php $w->cb( 'alertOn_adminLogin' ); ?>/></td>
299
</tr>
300
<tr>
301
<th>Alert me when a non-admin user signs in</th>
302
<td><input type="checkbox" id="alertOn_nonAdminLogin" class="wfConfigElem"
303
name="alertOn_nonAdminLogin" value="1" <?php $w->cb( 'alertOn_nonAdminLogin' ); ?>/></td>
304
</tr>
305
<tr>
306
<th>Alert me when there's a large increase in attacks detected on my site</th>
307
<td><input type="checkbox" id="wafAlertOnAttacks" class="wfConfigElem"
@@ -434,6 +449,15 @@ $w = new wfConfig();
434
name="scansEnabled_checkReadableConfig" value="1" <?php $w->cb( 'scansEnabled_checkReadableConfig' ); ?> />
435
</td>
436
</tr>
437
<!-- <tr>-->
438
<!-- <th>Scan for Full Path Disclosure?<a-->
439
<!-- href="http://docs.wordfence.com/en/Wordfence_options#Scan_for_Full_Path_Disclosure"-->
9
$pageTitle = "Wordfence Options";
10
include( 'pageTitle.php' ); ?>
11
<div class="wordfenceLive">
12
+ <table border="0" cellpadding="0" cellspacing="0" class="wordfenceLiveActivity">
13
<tr>
14
<td><h2>Wordfence Live Activity:</h2></td>
15
<td id="wfLiveStatus"></td>
16
</tr>
17
</table>
18
+ <table border="0" cellpadding="0" cellspacing="0" class="wordfenceLiveStateMessage">
19
+ <tr>
20
+ <td>Live Updates Paused &mdash; Click inside window to resume</td>
21
+ </tr>
22
+ </table>
23
</div>
24
<?php
25
$rightRail = new wfView('marketing/rightrail', array('additionalClasses' => 'wordfenceRightRailOptions'));
302
<td><input type="checkbox" id="alertOn_adminLogin" class="wfConfigElem" name="alertOn_adminLogin"
303
value="1" <?php $w->cb( 'alertOn_adminLogin' ); ?>/></td>
304
</tr>
305
+ <tr>
306
+ <th style="color: #666666;padding-left: 20px;">Only alert me when that administrator signs in from a new device or location</th>
307
+ <td><input type="checkbox" id="alertOn_firstAdminLoginOnly" class="wfConfigElem" name="alertOn_firstAdminLoginOnly"
308
+ value="1" <?php $w->cb( 'alertOn_firstAdminLoginOnly' ); ?>/></td>
309
+ </tr>
310
<tr>
311
<th>Alert me when a non-admin user signs in</th>
312
<td><input type="checkbox" id="alertOn_nonAdminLogin" class="wfConfigElem"
313
name="alertOn_nonAdminLogin" value="1" <?php $w->cb( 'alertOn_nonAdminLogin' ); ?>/></td>
314
</tr>
315
+ <tr>
316
+ <th style="color: #666666;padding-left: 20px;">Only alert me when that user signs in from a new device or location</th>
317
+ <td><input type="checkbox" id="alertOn_firstNonAdminLoginOnly" class="wfConfigElem" name="alertOn_firstNonAdminLoginOnly"
318
+ value="1" <?php $w->cb( 'alertOn_firstNonAdminLoginOnly' ); ?>/></td>
319
+ </tr>
320
<tr>
321
<th>Alert me when there's a large increase in attacks detected on my site</th>
322
<td><input type="checkbox" id="wafAlertOnAttacks" class="wfConfigElem"
449
name="scansEnabled_checkReadableConfig" value="1" <?php $w->cb( 'scansEnabled_checkReadableConfig' ); ?> />
450
</td>
451
</tr>
452
+ <tr>
453
+ <th>Scan for publicly accessible quarantined files<a
454
+ href="http://docs.wordfence.com/en/Wordfence_options#Scan_for_publicly_accessible_quarantined_files"
455
+ target="_blank" class="wfhelp"></a></th>
456
+ <td><input type="checkbox" id="scansEnabled_suspectedFiles" class="wfConfigElem"
457
+ name="scansEnabled_suspectedFiles"
458
+ value="1" <?php $w->cb( 'scansEnabled_suspectedFiles' ); ?>/>
459
+ </td>
460
+ </tr>
461
<!-- <tr>-->
462
<!-- <th>Scan for Full Path Disclosure?<a-->
463
<!-- href="http://docs.wordfence.com/en/Wordfence_options#Scan_for_Full_Path_Disclosure"-->
lib/menu_scan.php CHANGED
@@ -2,6 +2,10 @@
2
$sigUpdateTime = wfConfig::get('signatureUpdateTime');
3
?>
4
<div class="wordfenceModeElem" id="wordfenceMode_scan"></div>
5
<div class="wrap wordfence">
6
7
<?php
@@ -256,6 +260,55 @@ $sigUpdateTime = wfConfig::get('signatureUpdateTime');
256
</div>
257
</div>
258
</script>
259
<script type="text/x-jquery-template" id="issueTmpl_wpscan_fullPathDiscl">
260
<div>
261
<div class="wfIssue">
2
$sigUpdateTime = wfConfig::get('signatureUpdateTime');
3
?>
4
<div class="wordfenceModeElem" id="wordfenceMode_scan"></div>
5
+ <div id="wfLiveTrafficOverlayAnchor"></div>
6
+ <div id="wfLiveTrafficDisabledMessage">
7
+ <h2>Live Updates Paused<br /><small>Click inside window to resume</small></h2>
8
+ </div>
9
<div class="wrap wordfence">
10
11
<?php
260
</div>
261
</div>
262
</script>
263
+ <script type="text/x-jquery-template" id="issueTmpl_publiclyAccessible">
264
+ <div>
265
+ <div class="wfIssue">
266
+ <h2>${shortMsg}</h2>
267
+ <table border="0" class="wfIssue" cellspacing="0" cellpadding="0">
268
+ <tr>
269
+ <th>URL:</th>
270
+ <td><a href="${data.url}" target="_blank">${data.url}</a></td>
271
+ <tr>
272
+ <th>Severity:</th>
273
+ <td>{{if severity == '1'}}Critical{{else}}Warning{{/if}}</td>
274
+ </tr>
275
+ <tr>
276
+ <th>Status</th>
277
+ <td>
278
+ {{if status == 'new' }}New{{/if}}
279
+ {{if status == 'ignoreP' || status == 'ignoreC' }}Ignored{{/if}}
280
+ </td>
281
+ </tr>
282
+ </table>
283
+ <p>
284
+ {{html longMsg}}
285
+ </p>
286
+ <div class="wfIssueOptions">
287
+ <strong>Tools:</strong>
288
+ {{if data.fileExists}}
289
+ <a target="_blank" href="${WFAD.makeViewFileLink(data.file)}">View the file</a>
290
+ {{/if}}
291
+ <a href="#" onclick="WFAD.hideFile('${id}', 'delete'); return false;">Hide this file in <em>.htaccess</em></a>
292
+ {{if data.canDelete}}
293
+ <a href="#" onclick="WFAD.deleteFile('${id}'); return false;">Delete this file (can't be undone).</a>
294
+ <p>
295
+ <label><input type="checkbox" class="wfdelCheckbox" value="${id}" />&nbsp;Select for bulk delete</label>
296
+ </p>
297
+ {{/if}}
298
+ </div>
299
+ <div class="wfIssueOptions">
300
+ {{if status == 'new'}}
301
+ <strong>Resolve:</strong>
302
+ <a href="#" onclick="WFAD.updateIssueStatus('${id}', 'delete'); return false;">I have fixed this issue</a>
303
+ <a href="#" onclick="WFAD.updateIssueStatus('${id}', 'ignoreC'); return false;">Ignore this issue</a>
304
+ {{/if}}
305
+ {{if status == 'ignoreC' || status == 'ignoreP'}}
306
+ <a href="#" onclick="WFAD.updateIssueStatus('${id}', 'delete'); return false;">Stop ignoring this issue</a>
307
+ {{/if}}
308
+ </div>
309
+ </div>
310
+ </div>
311
+ </script>
312
<script type="text/x-jquery-template" id="issueTmpl_wpscan_fullPathDiscl">
313
<div>
314
<div class="wfIssue">
lib/menu_sitePerf.php CHANGED
@@ -10,6 +10,11 @@ $w = new wfConfig();
10
echo $rightRail;
11
?>
12
<div class="wordfenceWrap" style="margin: 20px 20px 20px 30px; max-width: 800px;">
13
<h2>Caching</h2>
14
<table border="0">
15
<tr><td>Disable all performance enhancements:</td><td><input type="radio" name="cacheType" id="cacheType_disable" value="disable" <?php if(! wfConfig::get('cacheType')){ echo 'checked="checked"'; } ?> /></td><td>No performance improvement</td></tr>
10
echo $rightRail;
11
?>
12
<div class="wordfenceWrap" style="margin: 20px 20px 20px 30px; max-width: 800px;">
13
+ <?php if (wfConfig::get('cacheType') == 'php' || wfConfig::get('cacheType') == 'falcon') { ?>
14
+ <div id="wordfenceFalconDeprecationWarning" class="wf-notice"><p><strong>Support for the Falcon and Basic cache will be removed.</strong> This site currently has the <?php echo (wfConfig::get('cacheType') == 'php' ? 'Basic' : 'Falcon'); ?> cache enabled, and it is scheduled to be removed in an upcoming release. Please investigate other caching options and then manually disable it below. It will be disabled automatically when support is removed. <a href="http://docs.wordfence.com/en/Falcon_Cache" target="_blank">More information.</a></p></div>
15
+ <?php } else { ?>
16
+ <div id="wordfenceFalconDeprecationWarning" class="wf-notice"><p><strong>Support for the Falcon and Basic cache will be removed.</strong> It is scheduled to be removed in an upcoming release and should not be enabled. If enabled, it will be disabled automatically when support is removed. <a href="http://docs.wordfence.com/en/Falcon_Cache" target="_blank">More information.</a></p></div>
17
+ <?php } ?>
18
<h2>Caching</h2>
19
<table border="0">
20
<tr><td>Disable all performance enhancements:</td><td><input type="radio" name="cacheType" id="cacheType_disable" value="disable" <?php if(! wfConfig::get('cacheType')){ echo 'checked="checked"'; } ?> /></td><td>No performance improvement</td></tr>
lib/menu_waf.php CHANGED
@@ -51,6 +51,7 @@ $wafRemoveURL = network_admin_url('admin.php?page=WordfenceWAF&wafAction=removeA
51
<?php echo wp_kses($storageExceptionMessage, 'post') ?>
52
</div>
53
<?php elseif (!empty($wafActionContent)): ?>
54
<?php echo $wafActionContent ?>
55
56
<?php if (!empty($_REQUEST['wafAction']) && $_REQUEST['wafAction'] == 'removeAutoPrepend') { ?>
@@ -66,11 +67,11 @@ $wafRemoveURL = network_admin_url('admin.php?page=WordfenceWAF&wafAction=removeA
66
<a target="_blank" href="https://docs.wordfence.com/en/Web_Application_Firewall_Setup">click here for
67
help</a>.</em></p>
68
<?php } ?>
69
-
70
<?php else: ?>
71
72
<?php if (!empty($configExceptionMessage)): ?>
73
- <div style="font-weight: bold; margin: 20px 0px;;">
74
<?php echo wp_kses($configExceptionMessage, 'post') ?>
75
</div>
76
<?php endif ?>
51
<?php echo wp_kses($storageExceptionMessage, 'post') ?>
52
</div>
53
<?php elseif (!empty($wafActionContent)): ?>
54
+ <div style="max-width: 900px;">
55
<?php echo $wafActionContent ?>
56
57
<?php if (!empty($_REQUEST['wafAction']) && $_REQUEST['wafAction'] == 'removeAutoPrepend') { ?>
67
<a target="_blank" href="https://docs.wordfence.com/en/Web_Application_Firewall_Setup">click here for
68
help</a>.</em></p>
69
<?php } ?>
70
+ </div>
71
<?php else: ?>
72
73
<?php if (!empty($configExceptionMessage)): ?>
74
+ <div style="font-weight: bold; margin: 20px 0px; max-width: 700px;">
75
<?php echo wp_kses($configExceptionMessage, 'post') ?>
76
</div>
77
<?php endif ?>
lib/wfActivityReport.php CHANGED
@@ -256,13 +256,14 @@ SQL
256
}
257
258
$results = $this->db->get_results($this->db->prepare(<<<SQL
259
- SELECT *,
260
- sum(fail) as fail_count,
261
- max(userID) as is_valid_user
262
- FROM {$this->db->base_prefix}wfLogins
263
- WHERE fail = 1
264
- AND ctime > $interval
265
- GROUP BY username
266
ORDER BY fail_count DESC
267
LIMIT %d
268
SQL
256
}
257
258
$results = $this->db->get_results($this->db->prepare(<<<SQL
259
+ SELECT wfl.*,
260
+ sum(wfl.fail) as fail_count,
261
+ !ISNULL(wpu.ID) as is_valid_user
262
+ FROM {$this->db->base_prefix}wfLogins wfl
263
+ LEFT JOIN {$this->db->base_prefix}users wpu ON wfl.username = wpu.user_login OR wfl.username = wpu.user_email
264
+ WHERE wfl.fail = 1
265
+ AND wfl.ctime > $interval
266
+ GROUP BY wfl.username
267
ORDER BY fail_count DESC
268
LIMIT %d
269
SQL
lib/wfCache.php CHANGED
@@ -719,10 +719,7 @@ EOT;
719
720
$homePath = get_home_path();
721
$htaccessFile = $homePath.'.htaccess';
722
- if (file_exists($htaccessFile)) {
723
- return $htaccessFile;
724
- }
725
- return false;
726
}
727
public static function doNotCache(){
728
if(! defined('WFDONOTCACHE')){
719
720
$homePath = get_home_path();
721
$htaccessFile = $homePath.'.htaccess';
722
+ return $htaccessFile;
723
}
724
public static function doNotCache(){
725
if(! defined('WFDONOTCACHE')){
lib/wfConfig.php CHANGED
@@ -22,7 +22,9 @@ class wfConfig {
22
"alertOn_loginLockout" => array('value' => true, 'autoload' => self::AUTOLOAD),
23
"alertOn_lostPasswdForm" => array('value' => true, 'autoload' => self::AUTOLOAD),
24
"alertOn_adminLogin" => array('value' => true, 'autoload' => self::AUTOLOAD),
25
"alertOn_nonAdminLogin" => array('value' => false, 'autoload' => self::AUTOLOAD),
26
"liveTrafficEnabled" => array('value' => true, 'autoload' => self::AUTOLOAD),
27
"scansEnabled_checkReadableConfig" => array('value' => true, 'autoload' => self::AUTOLOAD),
28
"advancedCommentScanning" => array('value' => false, 'autoload' => self::AUTOLOAD),
@@ -40,6 +42,7 @@ class wfConfig {
40
"scansEnabled_coreUnknown" => array('value' => true, 'autoload' => self::AUTOLOAD),
41
"scansEnabled_malware" => array('value' => true, 'autoload' => self::AUTOLOAD),
42
"scansEnabled_fileContents" => array('value' => true, 'autoload' => self::AUTOLOAD),
43
"scansEnabled_posts" => array('value' => true, 'autoload' => self::AUTOLOAD),
44
"scansEnabled_comments" => array('value' => true, 'autoload' => self::AUTOLOAD),
45
"scansEnabled_passwds" => array('value' => true, 'autoload' => self::AUTOLOAD),
@@ -61,7 +64,7 @@ class wfConfig {
61
"loginSec_blockAdminReg" => array('value' => true, 'autoload' => self::AUTOLOAD),
62
"loginSec_disableAuthorScan" => array('value' => true, 'autoload' => self::AUTOLOAD),
63
"loginSec_disableOEmbedAuthor" => array('value' => false, 'autoload' => self::AUTOLOAD),
64
- "other_hideWPVersion" => array('value' => true, 'autoload' => self::AUTOLOAD),
65
"other_noAnonMemberComments" => array('value' => true, 'autoload' => self::AUTOLOAD),
66
"other_blockBadPOST" => array('value' => false, 'autoload' => self::AUTOLOAD),
67
"other_scanComments" => array('value' => true, 'autoload' => self::AUTOLOAD),
22
"alertOn_loginLockout" => array('value' => true, 'autoload' => self::AUTOLOAD),
23
"alertOn_lostPasswdForm" => array('value' => true, 'autoload' => self::AUTOLOAD),
24
"alertOn_adminLogin" => array('value' => true, 'autoload' => self::AUTOLOAD),
25
+ "alertOn_firstAdminLoginOnly" => array('value' => false, 'autoload' => self::AUTOLOAD),
26
"alertOn_nonAdminLogin" => array('value' => false, 'autoload' => self::AUTOLOAD),
27
+ "alertOn_firstNonAdminLoginOnly" => array('value' => false, 'autoload' => self::AUTOLOAD),
28
"liveTrafficEnabled" => array('value' => true, 'autoload' => self::AUTOLOAD),
29
"scansEnabled_checkReadableConfig" => array('value' => true, 'autoload' => self::AUTOLOAD),
30
"advancedCommentScanning" => array('value' => false, 'autoload' => self::AUTOLOAD),
42
"scansEnabled_coreUnknown" => array('value' => true, 'autoload' => self::AUTOLOAD),
43
"scansEnabled_malware" => array('value' => true, 'autoload' => self::AUTOLOAD),
44
"scansEnabled_fileContents" => array('value' => true, 'autoload' => self::AUTOLOAD),
45
+ "scansEnabled_suspectedFiles" => array('value' => true, 'autoload' => self::AUTOLOAD),
46
"scansEnabled_posts" => array('value' => true, 'autoload' => self::AUTOLOAD),
47
"scansEnabled_comments" => array('value' => true, 'autoload' => self::AUTOLOAD),
48
"scansEnabled_passwds" => array('value' => true, 'autoload' => self::AUTOLOAD),
64
"loginSec_blockAdminReg" => array('value' => true, 'autoload' => self::AUTOLOAD),
65
"loginSec_disableAuthorScan" => array('value' => true, 'autoload' => self::AUTOLOAD),
66
"loginSec_disableOEmbedAuthor" => array('value' => false, 'autoload' => self::AUTOLOAD),
67
+ "other_hideWPVersion" => array('value' => false, 'autoload' => self::AUTOLOAD),
68
"other_noAnonMemberComments" => array('value' => true, 'autoload' => self::AUTOLOAD),
69
"other_blockBadPOST" => array('value' => false, 'autoload' => self::AUTOLOAD),
70
"other_scanComments" => array('value' => true, 'autoload' => self::AUTOLOAD),
lib/wfLog.php CHANGED
@@ -153,6 +153,15 @@ class wfLog {
153
return;
154
}
155
}
156
// change the action flag here if the user does not exist.
157
if ($action == 'loginFailValidUsername' && $userID == 0) {
158
$action = 'loginFailInvalidUsername';
@@ -1246,9 +1255,11 @@ class wfUserIPRange {
1246
1247
// IPv6 range
1248
} else if (strpos($ip_string, ':') !== false && strpos($ip, ':') !== false) {
1249
- if (preg_match('/\[[a-f0-9]+\-[a-f0-9]+\]/', $ip_string)) {
1250
- $IPparts = explode(':', strtolower(wfUtils::expandIPv6Address($ip)));
1251
- $whiteParts = explode(':', strtolower(self::expandIPv6Range($ip_string)));
1252
$mismatch = false;
1253
for ($i = 0; $i <= 7; $i++) {
1254
if (preg_match('/^\[([a-f0-9]+)\-([a-f0-9]+)\]#x2F;i', $whiteParts[$i], $m)) {
@@ -1416,7 +1427,7 @@ class wfUserIPRange {
1416
* @param string|null $ip_string
1417
*/
1418
public function setIPString($ip_string) {
1419
- $this->ip_string = $ip_string;
1420
}
1421
}
1422
153
return;
154
}
155
}
156
+ else {
157
+ $user = get_user_by('email', $username);
158
+ if ($user) {
159
+ $userID = $user->ID;
160
+ if (!$userID) {
161
+ return;
162
+ }
163
+ }
164
+ }
165
// change the action flag here if the user does not exist.
166
if ($action == 'loginFailValidUsername' && $userID == 0) {
167
$action = 'loginFailInvalidUsername';
1255
1256
// IPv6 range
1257
} else if (strpos($ip_string, ':') !== false && strpos($ip, ':') !== false) {
1258
+ $ip = strtolower(wfUtils::expandIPv6Address($ip));
1259
+ $ip_string = strtolower(self::expandIPv6Range($ip_string));
1260
+ if (preg_match('/\[[a-f0-9]+\-[a-f0-9]+\]/i', $ip_string)) {
1261
+ $IPparts = explode(':', $ip);
1262
+ $whiteParts = explode(':', $ip_string);
1263
$mismatch = false;
1264
for ($i = 0; $i <= 7; $i++) {
1265
if (preg_match('/^\[([a-f0-9]+)\-([a-f0-9]+)\]#x2F;i', $whiteParts[$i], $m)) {
1427
* @param string|null $ip_string
1428
*/
1429
public function setIPString($ip_string) {
1430
+ $this->ip_string = preg_replace('/[\x{2013}-\x{2015}]/u', '-', $ip_string); //Replace em-dash, en-dash, and horizontal bar with a regular dash
1431
}
1432
}
1433
lib/wfMD5BloomFilter.php ADDED
@@ -0,0 +1,134 @@
1
+ <?php
2
+ /*
3
+ Copyright (c) 2012, Da Xue
4
+ All rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions are met:
8
+ 1. Redistributions of source code must retain the above copyright
9
+ notice, this list of conditions and the following disclaimer.
10
+ 2. Redistributions in binary form must reproduce the above copyright
11
+ notice, this list of conditions and the following disclaimer in the
12
+ documentation and/or other materials provided with the distribution.
13
+ 3. The name of the author nor the names of its contributors may be used
14
+ to endorse or promote products derived from this software without
15
+ specific prior written permission.
16
+
17
+ THIS SOFTWARE IS PROVIDED BY DA XUE ''AS IS'' AND ANY
18
+ EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20
+ DISCLAIMED. IN NO EVENT SHALL DA XUE BE LIABLE FOR ANY
21
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
+ */
28
+
29
+ /* https://github.com/dsx724/php-bloom-filter */
30
+
31
+ // Modified for PHP 5.2 compatibility and to support serialization.
32
+
33
+ class wfMD5BloomFilter {
34
+ private static function merge($bf1,$bf2,$bfout,$union = false){
35
+ if ($bf1->m != $bf2->m) throw new Exception('Unable to merge due to vector difference.');
36
+ if ($bf1->k != $bf2->k) throw new Exception('Unable to merge due to hash count difference.');
37
+ $length = strlen($bfout->bit_array);
38
+ if ($union){
39
+ $bfout->bit_array = $bf1->bit_array | $bf2->bit_array;
40
+ $bfout->n = $bf1->n + $bf2->n;
41
+ } else {
42
+ $bfout->bit_array = $bf1->bit_array & $bf2->bit_array;
43
+ $bfout->n = abs($bf1->n - $bf2->n);
44
+ }
45
+ }
46
+ public static function createFromProbability($n, $p){
47
+ if ($p <= 0 || $p >= 1) throw new Exception('Invalid false positive rate requested.');
48
+ if ($n <= 0) throw new Exception('Invalid capacity requested.');
49
+ $k = floor(log(1/$p,2));
50
+ $m = pow(2,ceil(log(-$n*log($p)/pow(log(2),2),2))); //approximate estimator method
51
+ return new self($m,$k);
52
+ }
53
+ public static function getUnion($bf1,$bf2){
54
+ $bf = new self($bf1->m,$bf1->k,$bf1->hash);
55
+ self::merge($bf1,$bf2,$bf,true);
56
+ return $bf;
57
+ }
58
+ public static function getIntersection($bf1,$bf2){
59
+ $bf = new self($bf1->m,$bf1->k,$bf1->hash);
60
+ self::merge($bf1,$bf2,$bf,false);
61
+ return $bf;
62
+ }
63
+ private $n = 0; // # of entries
64
+ private $m; // # of bits in array
65
+ private $k; // # of hash functions
66
+ private $k2;
67
+ private $mask;
68
+ private $bit_array; // data structure
69
+ public function __construct($m, $k){
70
+ if ($m < 8) throw new Exception('The bit array length must be at least 8 bits.');
71
+ if (($m & ($m - 1)) !== 0) throw new Exception('The bit array length must be power of 2.');
72
+ if ($m > 65536) throw new Exception('The maximum data structure size is 8KB.');
73
+ if ($k > 8) throw new Exception('The maximum bits to set is 8.');
74
+ $this->m = $m;
75
+ $this->k = $k;
76
+ $this->k2 = $k * 2;
77
+ $address_bits = (int)log($m,2);
78
+ $this->mask = (1 << $address_bits) - 8;
79
+ $this->bit_array = (binary)(str_repeat("\0",$this->getArraySize(true)));
80
+ }
81
+ public function __sleep() {
82
+ return array('n', 'm', 'k', 'k2', 'mask', 'bit_array');
83
+ }
84
+ public function calculateProbability($n = 0){
85
+ return pow(1-pow(1-1/$this->m,$this->k*($n ? $n : $this->n)),$this->k);
86
+ }
87
+ public function calculateCapacity($p){
88
+ return floor($this->m*log(2)/log($p,1-pow(1-1/$this->m,$this->m*log(2))));
89
+ }
90
+ public function getElementCount(){
91
+ return $this->n;
92
+ }
93
+ public function getArraySize($bytes = false){
94
+ return $this->m >> ($bytes ? 3 : 0);
95
+ }
96
+ public function getHashCount(){
97
+ return $this->k;
98
+ }
99
+ public function getInfo($p = null){
100
+ $units = array('','K','M','G','T','P','E','Z','Y');
101
+ $M = $this->getArraySize(true);
102
+ $magnitude = intval(floor(log($M,1024)));
103
+ $unit = $units[$magnitude];
104
+ $M /= pow(1024,$magnitude);
105
+ return 'Allocated '.$this->getArraySize().' bits ('.$M.' '.$unit.'Bytes)'.PHP_EOL.
106
+ 'Using '.$this->getHashCount(). ' (16b) hashes'.PHP_EOL.
107
+ 'Contains '.$this->getElementCount().' elements'.PHP_EOL.
108
+ (isset($p) ? 'Capacity of '.number_format($this->calculateCapacity($p)).' (p='.$p.')'.PHP_EOL : '');
109
+ }
110
+ public function add($key){
111
+ $hash = md5($key,true);
112
+ for ($index = 0; $index < $this->k2; $index++){
113
+ $hash_sub = (ord($hash[$index++]) << 8) | ord($hash[$index]);
114
+ $word = ($hash_sub & $this->mask) >> 3;
115
+ $this->bit_array[$word] = $this->bit_array[$word] | chr(1 << ($hash_sub & 7));
116
+ }
117
+ $this->n++;
118
+ }
119
+ public function contains($key){
120
+ $hash = md5($key,true);
121
+ for ($index = 0; $index < $this->k2; $index++){
122
+ $hash_sub = (ord($hash[$index++]) << 8) | ord($hash[$index]);
123
+ if ((ord($this->bit_array[($hash_sub & $this->mask) >> 3]) & (1 << ($hash_sub & 7))) === 0) return false;
124
+ }
125
+ return true;
126
+ }
127
+ public function unionWith($bf){
128
+ self::merge($this,$bf,$this,true);
129
+ }
130
+ public function intersectWith($bf){
131
+ self::merge($this,$bf,$this,false);
132
+ }
133
+ }
134
+ ?>
lib/wfScanEngine.php CHANGED
@@ -36,7 +36,7 @@ class wfScanEngine {
36
);
37
private $userPasswdQueue = "";
38
private $passwdHasIssues = false;
39
-
40
41
/**
42
* @var wordfenceDBScanner
@@ -73,7 +73,7 @@ class wfScanEngine {
73
}
74
75
public function __sleep(){ //Same order here as above for properties that are included in serialization
76
- return array('hasher', 'jobList', 'i', 'wp_version', 'apiKey', 'startTime', 'maxExecTime', 'publicScanEnabled', 'fileContentsResults', 'scanner', 'scanQueue', 'hoover', 'scanData', 'statusIDX', 'userPasswdQueue', 'passwdHasIssues', 'dbScanner', 'knownFilesLoader', 'metrics');
77
}
78
public function __construct(){
79
$this->startTime = time();
@@ -94,7 +94,7 @@ class wfScanEngine {
94
$this->jobList[] = 'knownFiles_init';
95
$this->jobList[] = 'knownFiles_main';
96
$this->jobList[] = 'knownFiles_finish';
97
- foreach (array('knownFiles', 'checkReadableConfig', 'fileContents',
98
// 'wpscan_fullPathDisclosure', 'wpscan_directoryListingEnabled',
99
'posts', 'comments', 'passwds', 'dns', 'diskSpace', 'oldVersions', 'suspiciousAdminUsers') as $scanType) {
100
if (wfConfig::get('scansEnabled_' . $scanType)) {
@@ -493,6 +493,7 @@ class wfScanEngine {
493
$this->i->updateSummaryItem('totalData', wfUtils::formatBytes($this->hasher->totalData));
494
$this->i->updateSummaryItem('totalFiles', $this->hasher->totalFiles);
495
$this->i->updateSummaryItem('totalDirs', $this->hasher->totalDirs);
496
$this->hasher = false;
497
}
498
private function scan_knownFiles_finish(){
@@ -529,6 +530,39 @@ class wfScanEngine {
529
wordfence::statusEnd($this->statusIDX['GSB'], $haveIssuesGSB);
530
}
531
532
533
private function scan_posts_init(){
534
$this->statusIDX['posts'] = wordfence::statusStart('Scanning posts for URLs in Google\'s Safe Browsing List');
@@ -1488,7 +1522,7 @@ class wfCommonBackupFileTest {
1488
* @return wfCommonBackupFileTest
1489
*/
1490
public static function createFromRootPath($path) {
1491
- return new self(home_url($path), ABSPATH . $path);
1492
}
1493
1494
private $url;
@@ -1584,3 +1618,7 @@ class wfCommonBackupFileTest {
1584
return $this->response;
1585
}
1586
}
36
);
37
private $userPasswdQueue = "";
38
private $passwdHasIssues = false;
39
+ private $suspectedFiles = false; //Files found with the ".suspected" extension
40
41
/**
42
* @var wordfenceDBScanner
73
}
74
75
public function __sleep(){ //Same order here as above for properties that are included in serialization
76
+ return array('hasher', 'jobList', 'i', 'wp_version', 'apiKey', 'startTime', 'maxExecTime', 'publicScanEnabled', 'fileContentsResults', 'scanner', 'scanQueue', 'hoover', 'scanData', 'statusIDX', 'userPasswdQueue', 'passwdHasIssues', 'suspectedFiles', 'dbScanner', 'knownFilesLoader', 'metrics');
77
}
78
public function __construct(){
79
$this->startTime = time();
94
$this->jobList[] = 'knownFiles_init';
95
$this->jobList[] = 'knownFiles_main';
96
$this->jobList[] = 'knownFiles_finish';
97
+ foreach (array('knownFiles', 'checkReadableConfig', 'fileContents', 'suspectedFiles',
98
// 'wpscan_fullPathDisclosure', 'wpscan_directoryListingEnabled',
99
'posts', 'comments', 'passwds', 'dns', 'diskSpace', 'oldVersions', 'suspiciousAdminUsers') as $scanType) {
100
if (wfConfig::get('scansEnabled_' . $scanType)) {
493
$this->i->updateSummaryItem('totalData', wfUtils::formatBytes($this->hasher->totalData));
494
$this->i->updateSummaryItem('totalFiles', $this->hasher->totalFiles);
495
$this->i->updateSummaryItem('totalDirs', $this->hasher->totalDirs);
496
+ $this->suspectedFiles = $this->hasher->getSuspectedFiles();
497
$this->hasher = false;
498
}
499
private function scan_knownFiles_finish(){
530
wordfence::statusEnd($this->statusIDX['GSB'], $haveIssuesGSB);
531
}
532
533
+ private function scan_suspectedFiles() {
534
+ $haveIssues = false;
535
+ $status = wordfence::statusStart("Scanning for publicly accessible quarantined files");
536
+
537
+ if (is_array($this->suspectedFiles) && count($this->suspectedFiles) > 0) {
538
+ foreach ($this->suspectedFiles as $file) {
539
+ wordfence::status(4, 'info', "Testing accessibility of: $file");
540
+ $test = wfPubliclyAccessibleFileTest::createFromRootPath($file);
541
+ if ($test->fileExists() && $test->isPubliclyAccessible()) {
542
+ $key = "publiclyAccessible" . bin2hex($test->getUrl());
543
+ if ($this->addIssue(
544
+ 'publiclyAccessible',
545
+ 2,
546
+ $key,
547
+ $key,
548
+ 'Publicly accessible quarantined file found: ' . esc_html($file),
549
+ '<a href="' . $test->getUrl() . '" target="_blank">' . $test->getUrl() . '</a> is publicly
550
+ accessible and may expose source code or sensitive information about your site. Files such as this one are commonly
551
+ checked for by scanners and should be removed or made inaccessible.',
552
+ array(
553
+ 'url' => $test->getUrl(),
554
+ 'file' => $file,
555
+ 'canDelete' => true,
556
+ )
557
+ )) {
558
+ $haveIssues = true;
559
+ }
560
+ }
561
+ }
562
+ }
563
+
564
+ wordfence::statusEnd($status, $haveIssues);
565
+ }
566
567
private function scan_posts_init(){
568
$this->statusIDX['posts'] = wordfence::statusStart('Scanning posts for URLs in Google\'s Safe Browsing List');
1522
* @return wfCommonBackupFileTest
1523
*/
1524
public static function createFromRootPath($path) {
1525
+ return new self(site_url($path), ABSPATH . $path);
1526
}
1527
1528
private $url;
1618
return $this->response;
1619
}
1620
}
1621
+
1622
+ class wfPubliclyAccessibleFileTest extends wfCommonBackupFileTest {
1623
+
1624
+ }
lib/wfUtils.php CHANGED
@@ -960,7 +960,7 @@ class wfUtils {
960
if (!$host) {
961
// This function works for IPv4 or IPv6
962
if (function_exists('gethostbyaddr')) {
963
- $host = gethostbyaddr($IP);
964
}
965
if (!$host) {
966
$ptr = false;
@@ -1277,7 +1277,7 @@ class wfUtils {
1277
1278
public static function htaccessAppend($code)
1279
{
1280
- $htaccess = ABSPATH . '/.htaccess';
1281
$content = self::htaccess();
1282
if (wfUtils::isNginx() || !is_writable($htaccess)) {
1283
return false;
@@ -1290,10 +1290,27 @@ class wfUtils {
1290
1291
return true;
1292
}
1293
1294
public static function htaccess() {
1295
- if (is_readable(ABSPATH . '/.htaccess') && !wfUtils::isNginx()) {
1296
- return file_get_contents(ABSPATH . '/.htaccess');
1297
}
1298
return "";
1299
}
960
if (!$host) {
961
// This function works for IPv4 or IPv6
962
if (function_exists('gethostbyaddr')) {
963
+ $host = @gethostbyaddr($IP);
964
}
965
if (!$host) {
966
$ptr = false;
1277
1278
public static function htaccessAppend($code)
1279
{
1280
+ $htaccess = wfCache::getHtaccessPath();
1281
$content = self::htaccess();
1282
if (wfUtils::isNginx() || !is_writable($htaccess)) {
1283
return false;
1290
1291
return true;
1292
}
1293
+
1294
+ public static function htaccessPrepend($code)
1295
+ {
1296
+ $htaccess = wfCache::getHtaccessPath();
1297
+ $content = self::htaccess();
1298
+ if (wfUtils::isNginx() || !is_writable($htaccess)) {
1299
+ return false;
1300
+ }
1301
+
1302
+ if (strpos($content, $code) === false) {
1303
+ // make sure we write this once
1304
+ file_put_contents($htaccess, trim($code) . "\n" . $content, LOCK_EX);
1305
+ }
1306
+
1307
+ return true;
1308
+ }
1309
1310
public static function htaccess() {
1311
+ $htaccess = wfCache::getHtaccessPath();
1312
+ if (is_readable($htaccess) && !wfUtils::isNginx()) {
1313
+ return file_get_contents($htaccess);
1314
}
1315
return "";
1316
}
lib/wordfenceClass.php CHANGED
@@ -13,6 +13,7 @@ require_once('wfConfig.php');
13
require_once('wfSchema.php');
14
require_once('wfCache.php');
15
require_once('wfCrypt.php');
16
require_once 'wfView.php';
17
require_once 'wfHelperString.php';
18
require_once 'wfDirectoryIterator.php';
@@ -544,6 +545,13 @@ SQL
544
545
//6.2.0
546
wfConfig::migrateCodeExecutionForUploadsPHP7();
547
548
//Must be the final line
549
}
@@ -585,6 +593,9 @@ SQL
585
}
586
587
self::initProtection();
588
589
//These access wfConfig::get('apiKey') and will fail if runInstall hasn't executed.
590
wfCache::setupCaching();
@@ -737,6 +748,8 @@ SQL
737
738
add_action('wordfence_batchReportBlockedAttempts', 'wordfence::wfsnBatchReportBlockedAttempts');
739
add_action('wordfence_batchReportFailedAttempts', 'wordfence::wfsnBatchReportFailedAttempts');
740
741
if (wfConfig::get('other_hideWPVersion')) {
742
add_filter('update_feedback', 'wordfence::restoreReadmeForUpgrade');
@@ -745,10 +758,37 @@ SQL
745
}
746
public static function _pluginPageActionLinks($links) {
747
if (!wfConfig::get('isPaid')) {
748
- $links = array_merge(array('aWordfencePluginCallout' => '<a href="https://www.wordfence.com/zz12/wordfence-signup/" target="_blank"><strong style="color: #FCB214; display: inline;">Upgrade To Premium</strong></a>'), $links);
749
- }
750
return $links;
751
}
752
/*
753
public static function cronAddSchedules($schedules){
754
$schedules['wfEachMinute'] = array(
@@ -1201,16 +1241,37 @@ SQL
1201
'IP' => wfUtils::getIP()
1202
));
1203
}
1204
-
1205
if(user_can($userID, 'update_core')){
1206
if(wfConfig::get('alertOn_adminLogin')){
1207
- wordfence::alert("Admin Login", "A user with username \"$username\" who has administrator access signed in to your WordPress site.", wfUtils::getIP());
1208
}
1209
} else {
1210
if(wfConfig::get('alertOn_nonAdminLogin')){
1211
- wordfence::alert("User login", "A non-admin user with username \"$username\" signed in to your WordPress site.", wfUtils::getIP());
1212
}
1213
}
1214
}
1215
public static function registrationFilter($errors, $santizedLogin, $userEmail){
1216
if(wfConfig::get('loginSec_blockAdminReg') && $santizedLogin == 'admin'){
@@ -2429,6 +2490,10 @@ SQL
2429
wfConfig::set('suPHPWAFUpdateChoice', '1');
2430
return array('ok' => 1);
2431
}
2432
public static function ajax_removeFromCache_callback(){
2433
$id = $_POST['id'];
2434
$link = get_permalink($id);
@@ -2916,24 +2981,54 @@ SQL
2916
if (!$issue) {
2917
return array('cerrorMsg' => "We could not find that issue in our database.");
2918
}
2919
-
2920
$file = $issue['data']['file'];
2921
- $localFile = ABSPATH . '/' . $file;
2922
$localFile = realpath($localFile);
2923
- if (strpos($localFile, ABSPATH) !== 0) {
2924
- return array('cerrorMsg' => "An invalid file was requested for deletion.");
2925
}
2926
- $localFile = substr($localFile, strlen(ABSPATH));
2927
-
2928
- if (!wfUtils::htaccessAppend("<Files \"{$localFile}\">
2929
- <IfModule mod_authz_core.c>
2930
- Require all denied
2931
</IfModule>
2932
- <IfModule !mod_authz_core.c>
2933
- Order deny,allow
2934
- Deny from all
2935
</IfModule>
2936
- </Files>")) {
2937
return array('cerrorMsg' => "You don't have permission to repair .htaccess. You need to either fix the file manually using FTP or change the file permissions and ownership so that your web server has write access to repair the file.");
2938
}
2939
$issues->updateIssue($_POST['issueID'], 'delete');
@@ -4159,7 +4254,7 @@ HTML;
4159
'activityLogUpdate', 'ticker', 'loadIssues', 'updateIssueStatus', 'deleteIssue', 'updateAllIssues',
4160
'reverseLookup', 'unlockOutIP', 'loadBlockRanges', 'unblockRange', 'blockIPUARange', 'whois', 'unblockIP',
4161
'blockIP', 'permBlockIP', 'loadStaticPanel', 'saveConfig', 'downloadHtaccess', 'checkFalconHtaccess',
4162
- 'updateConfig', 'saveCacheConfig', 'removeFromCache', 'autoUpdateChoice', 'adminEmailChoice', 'suPHPWAFUpdateChoice', 'saveCacheOptions', 'clearPageCache',
4163
'getCacheStats', 'clearAllBlocked', 'killScan', 'saveCountryBlocking', 'saveScanSchedule', 'tourClosed',
4164
'welcomeClosed', 'startTourAgain', 'downgradeLicense', 'addTwoFactor', 'twoFacActivate', 'twoFacDel',
4165
'loadTwoFactor', 'loadAvgSitePerf', 'sendTestEmail', 'addCacheExclusion', 'removeCacheExclusion',
@@ -4318,6 +4413,12 @@ HTML;
4318
echo '<div id="wordfenceAdminEmailWarning" class="fade error"><p><strong>You have not set an administrator email address to receive alerts for Wordfence.</strong> Please <a href="' . self::getMyOptionsURL() . '">click here to go to the Wordfence Options Page</a> and set an email address where you will receive security alerts from this site.</p><p><a class="button button-small" href="#" onclick="wordfenceExt.adminEmailChoice(\'mine\'); return false;"">Use My Email Address</a>
4319
<a class="button button-small wf-dismiss-link" href="#" onclick="wordfenceExt.adminEmailChoice(\'no\'); return false;">Dismiss</a></p></div>';
4320
}
4321
public static function autoUpdateNotice(){
4322
echo '<div id="wordfenceAutoUpdateChoice" class="fade error"><p><strong>Do you want Wordfence to stay up-to-date automatically?</strong>&nbsp;&nbsp;&nbsp;<a href="#" onclick="wordfenceExt.autoUpdateChoice(\'yes\'); return false;">Yes, enable auto-update.</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href="#" onclick="wordfenceExt.autoUpdateChoice(\'no\'); return false;">No thanks.</a></p></div>';
4323
}
@@ -4340,6 +4441,16 @@ HTML;
4340
}
4341
$warningAdded = true;
4342
}
4343
if(! $warningAdded){
4344
if(wfConfig::get('tourClosed') == '1' && (! wfConfig::get('autoUpdate')) && (! wfConfig::get('autoUpdateChoice'))){
4345
$warningAdded = true;
@@ -4384,7 +4495,9 @@ HTML;
4384
add_submenu_page("Wordfence", "Firewall", "Firewall", "activate_plugins", "WordfenceWAF", 'wordfence::menu_waf');
4385
add_submenu_page("Wordfence", "Live Traffic", "Live Traffic", "activate_plugins", "WordfenceActivity", 'wordfence::menu_activity');
4386
/* add_submenu_page('Wordfence', 'Site Performance', 'Site Performance', 'activate_plugins', 'WordfenceSitePerfStats', 'wordfence::menu_sitePerfStats'); */
4387
- add_submenu_page('Wordfence', 'Performance Setup', 'Performance Setup', 'activate_plugins', 'WordfenceSitePerf', 'wordfence::menu_sitePerf');
4388
add_submenu_page('Wordfence', 'Blocked IPs', 'Blocked IPs', 'activate_plugins', 'WordfenceBlockedIPs', 'wordfence::menu_blockedIPs');
4389
add_submenu_page('Wordfence', 'Password Audit', 'Password Audit', 'activate_plugins', 'WordfencePasswdAudit', 'wordfence::menu_passwd');
4390
@@ -5661,7 +5774,12 @@ to your httpd.conf if using Apache, or find documentation on how to disable dire
5661
) {
5662
status_header(404);
5663
nocache_headers();
5664
- include(get_404_template());
5665
exit;
5666
}
5667
return $query_vars;
13
require_once('wfSchema.php');
14
require_once('wfCache.php');
15
require_once('wfCrypt.php');
16
+ require_once('wfMD5BloomFilter.php');
17
require_once 'wfView.php';
18
require_once 'wfHelperString.php';
19
require_once 'wfDirectoryIterator.php';
545
546
//6.2.0
547
wfConfig::migrateCodeExecutionForUploadsPHP7();
548
+
549
+ //6.2.1
550
+ if ((wfConfig::get('cacheType') == 'php' || wfConfig::get('cacheType') == 'falcon') && !wfConfig::get('wf621HadFalconEnabled')) {
551
+ wfConfig::set('wf621HadFalconEnabled', true);
552
+
553
+ wp_schedule_single_event(time(), 'wordfence_sendFalconDeprecationNotice');
554
+ }
555
556
//Must be the final line
557
}
593
}
594
595
self::initProtection();
596
+
597
+ //Fix wp_mail bug when $_SERVER['SERVER_NAME'] is undefined
598
+ add_filter('wp_mail_from', 'wordfence::fixWPMailFromAddress');
599
600
//These access wfConfig::get('apiKey') and will fail if runInstall hasn't executed.
601
wfCache::setupCaching();
748
749
add_action('wordfence_batchReportBlockedAttempts', 'wordfence::wfsnBatchReportBlockedAttempts');
750
add_action('wordfence_batchReportFailedAttempts', 'wordfence::wfsnBatchReportFailedAttempts');
751
+
752
+ add_action('wordfence_sendFalconDeprecationNotice', 'wordfence::sendFalconDeprecationNotice');
753
754
if (wfConfig::get('other_hideWPVersion')) {
755
add_filter('update_feedback', 'wordfence::restoreReadmeForUpgrade');
758
}
759
public static function _pluginPageActionLinks($links) {
760
if (!wfConfig::get('isPaid')) {
761
+ $links = array_merge(array('aWordfencePluginCallout' => '<a href="https://www.wordfence.com/zz12/wordfence-signup/" target="_blank"><strong style="color: #11967A; display: inline;">Upgrade To Premium</strong></a>'), $links);
762
+ }
763
return $links;
764
}
765
+ public static function sendFalconDeprecationNotice() {
766
+ $url = network_admin_url('admin.php?page=WordfenceSitePerf');
767
+ $cacheName = (wfConfig::get('cacheType') == 'php' ? 'Basic' : 'Falcon');
768
+ wordfence::alert("Support for the Falcon and Basic cache will be removed", "This site currently has the {$cacheName} cache enabled, and it is scheduled to be removed in an upcoming release. Please investigate other caching options and then visit the cache settings page to manually disable the {$cacheName} cache. It will be disabled automatically when support is removed.\n\nCache Settings Page: {$url}\n", wfUtils::getIP());
769
+ }
770
+ public static function fixWPMailFromAddress($from_email) {
771
+ if ($from_email == 'wordpress@') { //$_SERVER['SERVER_NAME'] is undefined so we get an incomplete email address
772
+ wordfence::status(4, 'info', "wp_mail from address is incomplete, attempting to fix");
773
+ $urls = array(get_site_url(), get_home_url());
774
+ foreach ($urls as $u) {
775
+ if (!empty($u)) {
776
+ $u = preg_replace('#^[^/]*//+([^/]+).*$#', '\1', $u);
777
+ if (substr($u, 0, 4) == 'www.') {
778
+ $u = substr($u, 4);
779
+ }
780
+
781
+ if (!empty($u)) {
782
+ wordfence::status(4, 'info', "Fixing wp_mail from address: " . $from_email . $u);
783
+ return $from_email . $u;
784
+ }
785
+ }
786
+ }
787
+
788
+ //Can't fix it, return it as it was
789
+ }
790
+ return $from_email;
791
+ }
792
/*
793
public static function cronAddSchedules($schedules){
794
$schedules['wfEachMinute'] = array(
1241
'IP' => wfUtils::getIP()
1242
));
1243
}
1244
+
1245
+ $salt = wp_salt('logged_in');
1246
+ $cookiename = 'wf_loginalerted_' . hash_hmac('sha256', wfUtils::getIP() . '|' . $user->ID, $salt);
1247
+ $cookievalue = hash_hmac('sha256', $user->user_login, $salt);
1248
if(user_can($userID, 'update_core')){
1249
if(wfConfig::get('alertOn_adminLogin')){
1250
+ $shouldAlert = true;
1251
+ if (wfConfig::get('alertOn_firstAdminLoginOnly') && isset($_COOKIE[$cookiename])) {
1252
+ $shouldAlert = !hash_equals($cookievalue, $_COOKIE[$cookiename]);
1253
+ }
1254
+
1255
+ if ($shouldAlert) {
1256
+ wordfence::alert("Admin Login", "A user with username \"$username\" who has administrator access signed in to your WordPress site.", wfUtils::getIP());
1257
+ }
1258
}
1259
} else {
1260
if(wfConfig::get('alertOn_nonAdminLogin')){
1261
+ $shouldAlert = true;
1262
+ if (wfConfig::get('alertOn_firstNonAdminLoginOnly') && isset($_COOKIE[$cookiename])) {
1263
+ $shouldAlert = !hash_equals($cookievalue, $_COOKIE[$cookiename]);
1264
+ }
1265
+
1266
+ if ($shouldAlert) {
1267
+ wordfence::alert("User login", "A non-admin user with username \"$username\" signed in to your WordPress site.", wfUtils::getIP());
1268
+ }
1269
}
1270
}
1271
+
1272
+ if (wfConfig::get('alertOn_firstAdminLoginOnly') || wfConfig::get('alertOn_firstNonAdminLoginOnly')) {
1273
+ wfUtils::setcookie($cookiename, $cookievalue, time() + (86400 * 365), '/', null, null, true);
1274
+ }
1275
}
1276
public static function registrationFilter($errors, $santizedLogin, $userEmail){
1277
if(wfConfig::get('loginSec_blockAdminReg') && $santizedLogin == 'admin'){
2490
wfConfig::set('suPHPWAFUpdateChoice', '1');
2491
return array('ok' => 1);
2492
}
2493
+ public static function ajax_falconDeprecationChoice_callback() {
2494
+ wfConfig::set('falconDeprecationChoice', '1');
2495
+ return array('ok' => 1);
2496
+ }
2497
public static function ajax_removeFromCache_callback(){
2498
$id = $_POST['id'];
2499
$link = get_permalink($id);
2981
if (!$issue) {
2982
return array('cerrorMsg' => "We could not find that issue in our database.");
2983
}
2984
+
2985
+ if (!function_exists('get_home_path')) {
2986
+ include_once ABSPATH . 'wp-admin/includes/file.php';
2987
+ }
2988
+
2989
+ $homeURL = get_home_url();
2990
+ $components = parse_url($homeURL);
2991
+ if ($components === false) {
2992
+ return array('cerrorMsg' => "An error occurred while trying to hide the file.");
2993
+ }
2994
+
2995
+ $sitePath = '';
2996
+ if (isset($components['path'])) {
2997
+ $sitePath = trim($components['path'], '/');
2998
+ }
2999
+
3000
+ $homePath = get_home_path();
3001
$file = $issue['data']['file'];
3002
+ $localFile = ABSPATH . '/' . $file; //The scanner uses ABSPATH as its base rather than get_home_path()
3003
$localFile = realpath($localFile);
3004
+ if (strpos($localFile, $homePath) !== 0) {
3005
+ return array('cerrorMsg' => "An invalid file was requested for hiding.");
3006
}
3007
+ $localFile = substr($localFile, strlen($homePath));
3008
+ $absoluteURIPath = trim($sitePath . '/' . $localFile, '/');
3009
+ $regexLocalFile = preg_replace('#/#', '/+', preg_quote($absoluteURIPath));
3010
+ $filename = basename($localFile);
3011
+
3012
+ $htaccessContent = <<<HTACCESS
3013
+ <IfModule mod_rewrite.c>
3014
+ RewriteEngine On
3015
+ RewriteCond %{REQUEST_URI} ^/?{$regexLocalFile}$
3016
+ RewriteRule .* - [F,L,NC]
3017
</IfModule>
3018
+ <IfModule !mod_rewrite.c>
3019
+ <Files "{$filename}">
3020
+ <IfModule mod_authz_core.c>
3021
+ Require all denied
3022
+ </IfModule>
3023
+ <IfModule !mod_authz_core.c>
3024
+ Order deny,allow
3025
+ Deny from all
3026
+ </IfModule>
3027
+ </Files>
3028
</IfModule>
3029
+ HTACCESS;
3030
+
3031
+ if (!wfUtils::htaccessPrepend($htaccessContent)) {
3032
return array('cerrorMsg' => "You don't have permission to repair .htaccess. You need to either fix the file manually using FTP or change the file permissions and ownership so that your web server has write access to repair the file.");
3033
}
3034
$issues->updateIssue($_POST['issueID'], 'delete');
4254
'activityLogUpdate', 'ticker', 'loadIssues', 'updateIssueStatus', 'deleteIssue', 'updateAllIssues',
4255
'reverseLookup', 'unlockOutIP', 'loadBlockRanges', 'unblockRange', 'blockIPUARange', 'whois', 'unblockIP',
4256
'blockIP', 'permBlockIP', 'loadStaticPanel', 'saveConfig', 'downloadHtaccess', 'checkFalconHtaccess',
4257
+ 'updateConfig', 'saveCacheConfig', 'removeFromCache', 'autoUpdateChoice', 'adminEmailChoice', 'suPHPWAFUpdateChoice', 'falconDeprecationChoice', 'saveCacheOptions', 'clearPageCache',
4258
'getCacheStats', 'clearAllBlocked', 'killScan', 'saveCountryBlocking', 'saveScanSchedule', 'tourClosed',
4259
'welcomeClosed', 'startTourAgain', 'downgradeLicense', 'addTwoFactor', 'twoFacActivate', 'twoFacDel',
4260
'loadTwoFactor', 'loadAvgSitePerf', 'sendTestEmail', 'addCacheExclusion', 'removeCacheExclusion',
4413
echo '<div id="wordfenceAdminEmailWarning" class="fade error"><p><strong>You have not set an administrator email address to receive alerts for Wordfence.</strong> Please <a href="' . self::getMyOptionsURL() . '">click here to go to the Wordfence Options Page</a> and set an email address where you will receive security alerts from this site.</p><p><a class="button button-small" href="#" onclick="wordfenceExt.adminEmailChoice(\'mine\'); return false;"">Use My Email Address</a>
4414
<a class="button button-small wf-dismiss-link" href="#" onclick="wordfenceExt.adminEmailChoice(\'no\'); return false;">Dismiss</a></p></div>';
4415
}
4416
+ public static function falconDeprecationWarning() {
4417
+ $url = network_admin_url('admin.php?page=WordfenceSitePerf');
4418
+ $cacheName = (wfConfig::get('cacheType') == 'php' ? 'Basic' : 'Falcon');
4419
+ echo '<div id="wordfenceFalconDeprecationWarning" class="fade error"><p><strong>Support for the Falcon and Basic cache will be removed.</strong> This site currently has the ' . $cacheName . ' cache enabled, and it is scheduled to be removed in an upcoming release. Please investigate other caching options and then <a href="' . $url . '">click here to visit the cache settings page</a> to manually disable the cache. It will be disabled automatically when support is removed.</p><p>
4420
+ <a class="button button-small wf-dismiss-link" href="#" onclick="wordfenceExt.falconDeprecationChoice(\'no\'); return false;">Dismiss</a></p></div>';
4421
+ }
4422
public static function autoUpdateNotice(){
4423
echo '<div id="wordfenceAutoUpdateChoice" class="fade error"><p><strong>Do you want Wordfence to stay up-to-date automatically?</strong>&nbsp;&nbsp;&nbsp;<a href="#" onclick="wordfenceExt.autoUpdateChoice(\'yes\'); return false;">Yes, enable auto-update.</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href="#" onclick="wordfenceExt.autoUpdateChoice(\'no\'); return false;">No thanks.</a></p></div>';
4424
}
4441
}
4442
$warningAdded = true;
4443
}
4444
+
4445
+ $page = (isset($_GET['page']) ? $_GET['page'] : '');
4446
+ if ((wfConfig::get('cacheType') == 'php' || wfConfig::get('cacheType') == 'falcon') && !wfConfig::get('falconDeprecationChoice') && $page != 'WordfenceSitePerf') {
4447
+ $warningAdded = true;
4448
+ if(wfUtils::isAdminPageMU()){
4449
+ add_action('network_admin_notices', 'wordfence::falconDeprecationWarning');
4450
+ } else {
4451
+ add_action('admin_notices', 'wordfence::falconDeprecationWarning');
4452
+ }
4453
+ }
4454
if(! $warningAdded){
4455
if(wfConfig::get('tourClosed') == '1' && (! wfConfig::get('autoUpdate')) && (! wfConfig::get('autoUpdateChoice'))){
4456
$warningAdded = true;
4495
add_submenu_page("Wordfence", "Firewall", "Firewall", "activate_plugins", "WordfenceWAF", 'wordfence::menu_waf');
4496
add_submenu_page("Wordfence", "Live Traffic", "Live Traffic", "activate_plugins", "WordfenceActivity", 'wordfence::menu_activity');
4497
/* add_submenu_page('Wordfence', 'Site Performance', 'Site Performance', 'activate_plugins', 'WordfenceSitePerfStats', 'wordfence::menu_sitePerfStats'); */
4498
+ if (wfConfig::get('wf621HadFalconEnabled') || (defined('WF_ENABLE_FALCON') && WF_ENABLE_FALCON)) {
4499
+ add_submenu_page('Wordfence', 'Performance Setup', 'Performance Setup', 'activate_plugins', 'WordfenceSitePerf', 'wordfence::menu_sitePerf');
4500
+ }
4501
add_submenu_page('Wordfence', 'Blocked IPs', 'Blocked IPs', 'activate_plugins', 'WordfenceBlockedIPs', 'wordfence::menu_blockedIPs');
4502
add_submenu_page('Wordfence', 'Password Audit', 'Password Audit', 'activate_plugins', 'WordfencePasswdAudit', 'wordfence::menu_passwd');
4503
5774
) {
5775
status_header(404);
5776
nocache_headers();
5777
+
5778
+ $template = get_404_template();
5779
+ if ($template && file_exists($template)) {
5780
+ include($template);
5781
+ }
5782
+
5783
exit;
5784
}
5785
return $query_vars;
lib/wordfenceHash.php CHANGED
@@ -26,6 +26,8 @@ class wordfenceHash {
26
private $totalForks = 0;
27
private $alertedOnUnknownWordPressVersion = false;
28
private $foldersProcessed = array();
29
30
/**
31
* @param string $striplen
@@ -59,6 +61,8 @@ class wordfenceHash {
59
if(wfConfig::get('scansEnabled_coreUnknown')){
60
$this->coreUnknownEnabled = true;
61
}
62
63
$this->db = new wfDB();
64
@@ -112,13 +116,16 @@ class wordfenceHash {
112
if($this->coreUnknownEnabled){ $this->status['coreUnknown'] = wordfence::statusStart("Scanning for unknown files in wp-admin and wp-includes"); } else { wordfence::statusDisabled("Skipping unknown core file scan"); }
113
}
114
public function __sleep(){
115
- return array('striplen', 'totalFiles', 'totalDirs', 'totalData', 'stoppedOnFile', 'coreEnabled', 'pluginsEnabled', 'themesEnabled', 'malwareEnabled', 'coreUnknownEnabled', 'knownFiles', 'malwareData', 'haveIssues', 'status', 'possibleMalware', 'path', 'only', 'totalForks', 'alertedOnUnknownWordPressVersion', 'foldersProcessed');
116
}
117
public function __wakeup(){
118
$this->db = new wfDB();
119
$this->startTime = microtime(true);
120
$this->totalForks++;
121
}
122
public function run($engine){ //base path and 'only' is a list of files and dirs in the bast that are the only ones that should be processed. Everything else in base is ignored. If only is empty then everything is processed.
123
if($this->totalForks > 1000){
124
throw new Exception("Wordfence file scanner detected a possible infinite loop. Exiting on file: " . $this->stoppedOnFile);
@@ -237,6 +244,12 @@ class wordfenceHash {
237
}
238
private function processFile($realFile){
239
$file = substr($realFile, $this->striplen);
240
if (!$this->_shouldHashFile($realFile)) {
241
wordfence::status(4, 'info', "Skipping unneeded hash: {$realFile}");
242
return;
@@ -303,7 +316,7 @@ class wordfenceHash {
303
304
$this->haveIssues['core'] = true;
305
$this->engine->addIssue(
306
- 'file',
307
1,
308
'coreModified' . $file . $md5,
309
'coreModified' . $file,
@@ -337,7 +350,7 @@ class wordfenceHash {
337
$cKey = $this->knownFiles['plugins'][$file][2];
338
$this->haveIssues['plugins'] = true;
339
$this->engine->addIssue(
340
- 'file',
341
2,
342
'modifiedplugin' . $file . $md5,
343
'modifiedplugin' . $file,
@@ -374,7 +387,7 @@ class wordfenceHash {
374
$cKey = $this->knownFiles['themes'][$file][2];
375
$this->haveIssues['themes'] = true;
376
$this->engine->addIssue(
377
- 'file',
378
2,
379
'modifiedtheme' . $file . $md5,
380
'modifiedtheme' . $file,
@@ -402,7 +415,7 @@ class wordfenceHash {
402
if (strpos($realFile, $path) === 0) {
403
$this->haveIssues['coreUnknown'] = true;
404
$this->engine->addIssue(
405
- 'file',
406
2,
407
'coreUnknown' . $file . $md5,
408
'coreUnknown' . $file,
@@ -424,6 +437,8 @@ class wordfenceHash {
424
// we could split this into files who's path we recognize and file's who's path we recognize AND who have a valid sig.
425
// But because we want to scan files who's sig we don't recognize, regardless of known path or not, we only need one "knownFile" field.
426
$this->db->queryWrite("insert into " . $this->db->prefix() . "wfFileMods (filename, filenameMD5, knownFile, oldMD5, newMD5) values ('%s', unhex(md5('%s')), %d, '', unhex('%s')) ON DUPLICATE KEY UPDATE newMD5=unhex('%s'), knownFile=%d", $file, $file, $knownFile, $md5, $md5, $knownFile);
427
428
$this->totalFiles++;
429
$this->totalData += filesize($realFile); //We already checked if file overflows int in the fileTooBig routine above
@@ -455,7 +470,16 @@ class wordfenceHash {
455
return array($md5, $shac);
456
}
457
private function _shouldHashFile($fullPath) {
458
- $file = substr($fullPath, $this->striplen);
459
460
//Core File, return true
461
if ((isset($this->knownFiles['core']) && isset($this->knownFiles['core'][$file])) ||
26
private $totalForks = 0;
27
private $alertedOnUnknownWordPressVersion = false;
28
private $foldersProcessed = array();
29
+ private $filesProcessedBloomFilter = false;
30
+ private $suspectedFiles = array();
31
32
/**
33
* @param string $striplen
61
if(wfConfig::get('scansEnabled_coreUnknown')){
62
$this->coreUnknownEnabled = true;
63
}
64
+
65
+ $this->filesProcessedBloomFilter = new wfMD5BloomFilter(65536, 8); //65536,8 produces the lowest miss probability. Uses approximately 8 KB of memory + PHP object overhead
66
67
$this->db = new wfDB();
68
116
if($this->coreUnknownEnabled){ $this->status['coreUnknown'] = wordfence::statusStart("Scanning for unknown files in wp-admin and wp-includes"); } else { wordfence::statusDisabled("Skipping unknown core file scan"); }
117
}
118
public function __sleep(){
119
+ return array('striplen', 'totalFiles', 'totalDirs', 'totalData', 'stoppedOnFile', 'coreEnabled', 'pluginsEnabled', 'themesEnabled', 'malwareEnabled', 'coreUnknownEnabled', 'knownFiles', 'malwareData', 'haveIssues', 'status', 'possibleMalware', 'path', 'only', 'totalForks', 'alertedOnUnknownWordPressVersion', 'foldersProcessed', 'filesProcessedBloomFilter', 'suspectedFiles');
120
}
121
public function __wakeup(){
122
$this->db = new wfDB();
123
$this->startTime = microtime(true);
124
$this->totalForks++;
125
}
126
+ public function getSuspectedFiles() {
127
+ return array_keys($this->suspectedFiles);
128
+ }
129
public function run($engine){ //base path and 'only' is a list of files and dirs in the bast that are the only ones that should be processed. Everything else in base is ignored. If only is empty then everything is processed.
130
if($this->totalForks > 1000){
131
throw new Exception("Wordfence file scanner detected a possible infinite loop. Exiting on file: " . $this->stoppedOnFile);
244
}
245
private function processFile($realFile){
246
$file = substr($realFile, $this->striplen);
247
+
248
+ if (preg_match('/\.suspected#x2F;i', $file)) { //Already iterating over all files in the search areas so generate this list here
249
+ wordfence::status(4, 'info', "Found .suspected file: $file");
250
+ $this->suspectedFiles[$file] = 1;
251
+ }
252
+
253
if (!$this->_shouldHashFile($realFile)) {
254
wordfence::status(4, 'info', "Skipping unneeded hash: {$realFile}");
255
return;
316
317
$this->haveIssues['core'] = true;
318
$this->engine->addIssue(
319
+ 'knownfile',
320
1,
321
'coreModified' . $file . $md5,
322
'coreModified' . $file,
350
$cKey = $this->knownFiles['plugins'][$file][2];
351
$this->haveIssues['plugins'] = true;
352
$this->engine->addIssue(
353
+ 'knownfile',
354
2,
355
'modifiedplugin' . $file . $md5,
356
'modifiedplugin' . $file,
387
$cKey = $this->knownFiles['themes'][$file][2];
388
$this->haveIssues['themes'] = true;
389
$this->engine->addIssue(
390
+ 'knownfile',
391
2,
392
'modifiedtheme' . $file . $md5,
393
'modifiedtheme' . $file,
415
if (strpos($realFile, $path) === 0) {
416
$this->haveIssues['coreUnknown'] = true;
417
$this->engine->addIssue(
418
+ 'knownfile',
419
2,
420
'coreUnknown' . $file . $md5,
421
'coreUnknown' . $file,
437
// we could split this into files who's path we recognize and file's who's path we recognize AND who have a valid sig.
438
// But because we want to scan files who's sig we don't recognize, regardless of known path or not, we only need one "knownFile" field.
439
$this->db->queryWrite("insert into " . $this->db->prefix() . "wfFileMods (filename, filenameMD5, knownFile, oldMD5, newMD5) values ('%s', unhex(md5('%s')), %d, '', unhex('%s')) ON DUPLICATE KEY UPDATE newMD5=unhex('%s'), knownFile=%d", $file, $file, $knownFile, $md5, $md5, $knownFile);
440
+
441
+ $this->filesProcessedBloomFilter->add($file);
442
443
$this->totalFiles++;
444
$this->totalData += filesize($realFile); //We already checked if file overflows int in the fileTooBig routine above
470
return array($md5, $shac);
471
}
472
private function _shouldHashFile($fullPath) {
473
+ $file = substr($fullPath, $this->striplen);
474
+
475
+ //Already hashed and processed, return false
476
+ if ($this->filesProcessedBloomFilter->contains($file)) { //Might have hashed it, verify
477
+ $rec = $this->db->querySingleRec("SELECT * FROM " . $this->db->prefix() . "wfFileMods WHERE filename = '%s'", $file);
478
+ if ($rec !== null) {
479
+ wordfence::status(4, 'info', "Already hashed: {$file}");
480
+ return false;
481
+ }
482
+ }
483
484
//Core File, return true
485
if ((isset($this->knownFiles['core']) && isset($this->knownFiles['core'][$file])) ||
readme.txt CHANGED
@@ -1,11 +1,11 @@
1
=== Wordfence Security ===
2
Contributors: mmaunder
3
- Tags: security, secure, security plugin, wordpress security, login security, firewall, malware, antivirus, web application firewall, block hackers, country blocking, block hackers
4
Requires at least: 3.9
5
Tested up to: 4.6.1
6
- Stable tag: 6.2.0
7
8
- Secure your website with the most comprehensive WordPress security plugin. Firewall, malware scanner, blocking, live traffic, login security & more.
9
10
== Description ==
11
= THE MOST DOWNLOADED WORDPRESS SECURITY PLUGIN =
@@ -61,11 +61,7 @@ Wordfence Security is now Multi-Site compatible and includes Cellphone Sign-in w
61
62
= Multi-Site Security =
63
* Wordfence Security for multi-site also scans all posts and comments across all blogs from one admin panel.
64
- * WordPress Multi-Site (or WordPress MU in the older parlance) compatible.
65
-
66
- = Caching Features =
67
- * Includes Falcon Engine, the fastest WordPress caching engine available today. Falcon is faster because it reduces your web server disk and database activity to a minimum.
68
- * Wordfence includes two caching modes for compatability and has cache management features like the ability to clear the cache and monitor cache usage.
69
70
= IPv6 Compatible =
71
* Fully IPv6 compatible including all whois lookup, location, blocking and security functions.
@@ -107,8 +103,7 @@ Secure your website with Wordfence.
107
[Visit our support website which contains a FAQ and knowledgebase which is more comprehensive and updated frequently.](http://support.wordfence.com/?utm_source=repo&utm_medium=web&utm_campaign=pluginDesc)
108
109
= What does Wordfence Security do that other WordPress security plugins don't do? =
110
-
111
- * Wordfence Security is the only WordPress security plugin that is fully integrated with it's own high speed caching engine to avoid security and caching conflicts.
112
* Wordfence Security actually verifies your website source code integrity against the official WordPress repository and shows you the changes. We are the only plugin to do this.
113
* Wordfence Security provides two-factor authentication (Cellphone Sign-in) for paid members. We're the first plugin to offer this.
114
* Wordfence Security fully supports IPv6 including giving you the ability to look up the location of IPv6 addresses, block IPv6 ranges, detect IPv6 country and do a whois lookup on IPv6 addresses and more.
@@ -124,10 +119,8 @@ Yes. WordPress MU or Multi-Site as it's called now is fully supported. Using Wor
124
125
= Will Wordfence Security slow my site down? =
126
127
- No. Actually it will make your site up to 50X faster when Falcon Engine is enabled, up to 30 times faster with our PHP caching engine and even
128
- without caching Wordfence is extremely fast and uses techniques like caching it's own configuration data to avoid database lookups. Older
129
- versions of Wordfence did incur a slight performance penalty, but we have not only fixed this issue but knocked it out of the park. Wordfence
130
- now makes your site faster than any other caching plugin available!!
131
132
= How often is Wordfence Security updated? =
133
@@ -197,6 +190,21 @@ Secure your website with Wordfence.
197
198
== Changelog ==
199
200
= 6.2.0 =
201
* Improvement: Massive performance boost in file system scan.
202
* Improvement: Added low resource usage scan option for shared hosts.
1
=== Wordfence Security ===
2
Contributors: mmaunder
3
+ Tags: security, secure, security plugin, wordpress security, login security, firewall, malware, antivirus, web application firewall, block hackers, country blocking
4
Requires at least: 3.9
5
Tested up to: 4.6.1
6
+ Stable tag: 6.2.1
7
8
+ Secure your website with the most comprehensive WordPress security plugin. Firewall, malware scan, blocking, live traffic, login security & more.
9
10
== Description ==
11
= THE MOST DOWNLOADED WORDPRESS SECURITY PLUGIN =
61
62
= Multi-Site Security =
63
* Wordfence Security for multi-site also scans all posts and comments across all blogs from one admin panel.
64
+ * WordPress Multi-Site (or WordPress MU in the older parlance) compatible.
65
66
= IPv6 Compatible =
67
* Fully IPv6 compatible including all whois lookup, location, blocking and security functions.
103
[Visit our support website which contains a FAQ and knowledgebase which is more comprehensive and updated frequently.](http://support.wordfence.com/?utm_source=repo&utm_medium=web&utm_campaign=pluginDesc)
104
105
= What does Wordfence Security do that other WordPress security plugins don't do? =
106
+
107
* Wordfence Security actually verifies your website source code integrity against the official WordPress repository and shows you the changes. We are the only plugin to do this.
108
* Wordfence Security provides two-factor authentication (Cellphone Sign-in) for paid members. We're the first plugin to offer this.
109
* Wordfence Security fully supports IPv6 including giving you the ability to look up the location of IPv6 addresses, block IPv6 ranges, detect IPv6 country and do a whois lookup on IPv6 addresses and more.
119
120
= Will Wordfence Security slow my site down? =
121
122
+ No. Wordfence is extremely fast and uses techniques like caching its own configuration data to avoid database lookups and blocking malicious attacks that would slow down your site. Older
123
+ versions of Wordfence did incur a slight performance penalty, but we have not only fixed this issue but knocked it out of the park.
124
125
= How often is Wordfence Security updated? =
126
190
191
== Changelog ==
192
193
+ = 6.2.1 =
194
+ * Improvement: Now performing scanning for PHP code in all uploaded files in real-time.
195
+ * Improvement: Improved handling of bad characters and IPv6 ranges in Advanced Blocking.
196
+ * Improvement: Live traffic and scanning activity now display a paused notice when real-time updates are suspended while in the background.
197
+ * Improvement: The file system scan alerts for files flagged by antivirus software with a '.suspected' extension.
198
+ * Improvement: New alert option to get notified only when logins are from a new location/device.
199
+ * Change: First phase for removing the Falcon cache in place, which will add a notice of its pending removal.
200
+ * Fix: Included country flags for Kosovo and Curaçao.
201
+ * Fix: Fixed the .htaccess directives used to hide files found by the scanner.
202
+ * Fix: Dashboard widget shows correct status for failed logins by deleted users.
203
+ * Fix: Removed duplicate issues for modified files in the scan results.
204
+ * Fix: Suppressed warning from reverse lookup on IPv6 addresses without valid DNS records.
205
+ * Fix: Fixed file inclusion error with themes lacking a 404 page.
206
+ * Fix: CSS fixes for activity report email.
207
+
208
= 6.2.0 =
209
* Improvement: Massive performance boost in file system scan.
210
* Improvement: Added low resource usage scan option for shared hosts.
vendor/wordfence/wf-waf/src/init.php CHANGED
@@ -4,7 +4,7 @@ define('WFWAF_VERSION', '1.0.2');
4
define('WFWAF_PATH', dirname(__FILE__) . '/');
5
define('WFWAF_LIB_PATH', WFWAF_PATH . 'lib/');
6
define('WFWAF_VIEW_PATH', WFWAF_PATH . 'views/');
7
- define('WFWAF_API_URL_SEC', 'https://noc4.wordfence.com/v1.4/');
8
if (!defined('WFWAF_DEBUG')) {
9
define('WFWAF_DEBUG', false);
10
}
4
define('WFWAF_PATH', dirname(__FILE__) . '/');
5
define('WFWAF_LIB_PATH', WFWAF_PATH . 'lib/');
6
define('WFWAF_VIEW_PATH', WFWAF_PATH . 'views/');
7
+ define('WFWAF_API_URL_SEC', 'https://noc4.wordfence.com/v1.5/');
8
if (!defined('WFWAF_DEBUG')) {
9
define('WFWAF_DEBUG', false);
10
}
vendor/wordfence/wf-waf/src/lib/rules.php CHANGED
@@ -457,6 +457,7 @@ class wfWAFRuleComparison implements wfWAFRuleInterface {
457
'currentuserisnot',
458
'md5equals',
459
'filepatternsmatch',
460
);
461
462
/**
@@ -711,7 +712,7 @@ class wfWAFRuleComparison implements wfWAFRuleInterface {
711
if ($file['name'] == (string) $subject) {
712
$fh = @fopen($file['tmp_name'], 'r');
713
if (!$fh) {
714
- return false;
715
}
716
$totalRead = 0;
717
@@ -734,6 +735,122 @@ class wfWAFRuleComparison implements wfWAFRuleInterface {
734
735
return false;
736
}
737
738
/**
739
* @return mixed
457
'currentuserisnot',
458
'md5equals',
459
'filepatternsmatch',
460
+ 'filehasphp',
461
);
462
463
/**
712
if ($file['name'] == (string) $subject) {
713
$fh = @fopen($file['tmp_name'], 'r');
714
if (!$fh) {
715
+ continue;
716
}
717
$totalRead = 0;
718
735
736
return false;
737
}
738
+
739
+ public function fileHasPHP($subject) {
740
+ $request = $this->getWAF()->getRequest();
741
+ $files = $request->getFiles();
742
+ if (!is_array($files)) {
743
+ return false;
744
+ }
745
+
746
+ foreach ($files as $file) {
747
+ if ($file['name'] == (string) $subject) {
748
+ $fh = @fopen($file['tmp_name'], 'r');
749
+ if (!$fh) {
750
+ continue;
751
+ }
752
+
753
+ $totalRead = 0;
754
+ $hasExecutablePHP = false;
755
+ $possiblyHasExecutablePHP = false;
756
+ $hasOpenParen = false;
757
+ $hasCloseParen = false;
758
+ $backtickCount = 0;
759
+ $wrappedTokenCheckBytes = '';
760
+ $maxTokenSize = 15; //__halt_compiler
761
+ $possibleWrappedTokens = array('<?php', '<?=', '<?', '?>', 'exit', 'new', 'clone', 'echo', 'print', 'require', 'include', 'require_once', 'include_once', '__halt_compiler');
762
+
763
+ $readsize = 512 * 1024; //512k at a time
764
+ while (!feof($fh)) {
765
+ $data = fread($fh, $readsize);
766
+ $actualReadsize = strlen($data);
767
+ $totalRead += $actualReadsize;
768
+ if ($totalRead < 1) {
769
+ break;
770
+ }
771
+
772
+ //Make sure we didn't miss PHP split over a chunking boundary
773
+ $wrappedCheckLength = strlen($wrappedTokenCheckBytes);
774
+ if ($wrappedCheckLength > 0) {
775
+ $testBytes = $wrappedTokenCheckBytes . substr($data, 0, min($maxTokenSize, $actualReadsize));
776
+ foreach ($possibleWrappedTokens as $t) {
777
+ $position = strpos($testBytes, $t);
778
+ if ($position !== false && $position < $wrappedCheckLength && $position + strlen($t) >= $wrappedCheckLength) { //Found a token that starts before this segment of data and ends within it
779
+ $data = substr($wrappedTokenCheckBytes, $position) . $data;
780
+ break;
781
+ }
782
+ }
783
+ }
784
+
785
+ //Tokenize the data and check for PHP
786
+ $tokens = @token_get_all($data);
787
+ foreach ($tokens as $token) {
788
+ if (is_array($token)) {
789
+ switch ($token[0]) {
790
+ case T_OPEN_TAG:
791
+ $hasOpenParen = false;
792
+ $hasCloseParen = false;
793
+ $backtickCount = 0;
794
+ $possiblyHasExecutablePHP = false;
795
+ break;
796
+
797
+ case T_OPEN_TAG_WITH_ECHO:
798
+ $hasOpenParen = false;
799
+ $hasCloseParen = false;
800
+ $backtickCount = 0;
801
+ $possiblyHasExecutablePHP = true;
802
+ break;
803
+
804
+ case T_CLOSE_TAG:
805
+ if ($possiblyHasExecutablePHP) {
806
+ $hasExecutablePHP = true; //Assume the echo short tag outputted something useful
807
+ }
808
+ break 2;
809
+
810
+ case T_NEW:
811
+ case T_CLONE:
812
+ case T_ECHO:
813
+ case T_PRINT:
814
+ case T_REQUIRE:
815
+ case T_INCLUDE:
816
+ case T_REQUIRE_ONCE:
817
+ case T_INCLUDE_ONCE:
818
+ case T_HALT_COMPILER:
819
+ case T_EXIT:
820
+ $hasExecutablePHP = true;
821
+ break 2;
822
+ }
823
+ }
824
+ else {
825
+ switch ($token) {
826
+ case '(':
827
+ $hasOpenParen = true;
828
+ break;
829
+ case ')':
830
+ $hasCloseParen = true;
831
+ break;
832
+ case '`':
833
+ $backtickCount++;
834
+ break;
835
+ }
836
+ }
837
+ if (!$hasExecutablePHP && (($hasOpenParen && $hasCloseParen) || ($backtickCount > 1 && $backtickCount % 2 === 0))) {
838
+ $hasExecutablePHP = true;
839
+ break;
840
+ }
841
+ }
842
+
843
+ if ($hasExecutablePHP) {
844
+ return true;
845
+ }
846
+
847
+ $wrappedTokenCheckBytes = substr($data, - min($maxTokenSize, $actualReadsize));
848
+ }
849
+ }
850
+ }
851
+
852
+ return false;
853
+ }
854
855
/**
856
* @return mixed
views/reports/activity-report-email-inline.php CHANGED
@@ -89,8 +89,8 @@ a.comment-edit-link:hover { color: #21759b !important; }
89
@viewport { width: device-width !important; }
90
.main-navigation li a:hover { color: #000 !important; }
91
.main-navigation li a:focus { color: #000 !important; }
92
- .main-navigation ul li:hover &gt; ul { border-left: 0 !important; clip: inherit !important; overflow: inherit !important; height: inherit !important; width: inherit !important; }
93
- .main-navigation ul li:focus &gt; ul { border-left: 0 !important; clip: inherit !important; overflow: inherit !important; height: inherit !important; width: inherit !important; }
94
.main-navigation li ul li a:hover { background: #e3e3e3 !important; color: #444 !important; }
95
.main-navigation li ul li a:focus { background: #e3e3e3 !important; color: #444 !important; }
96
footer a[rel=bookmark]:after { content: " [" attr(href) "] " !important; }
89
@viewport { width: device-width !important; }
90
.main-navigation li a:hover { color: #000 !important; }
91
.main-navigation li a:focus { color: #000 !important; }
92
+ .main-navigation ul li:hover > ul { border-left: 0 !important; clip: inherit !important; overflow: inherit !important; height: inherit !important; width: inherit !important; }
93
+ .main-navigation ul li:focus > ul { border-left: 0 !important; clip: inherit !important; overflow: inherit !important; height: inherit !important; width: inherit !important; }
94
.main-navigation li ul li a:hover { background: #e3e3e3 !important; color: #444 !important; }
95
.main-navigation li ul li a:focus { background: #e3e3e3 !important; color: #444 !important; }
96
footer a[rel=bookmark]:after { content: " [" attr(href) "] " !important; }
views/waf/debug.php CHANGED
@@ -111,7 +111,7 @@ try {
111
margin: 20px 0px 8px;
112
}
113
pre, p {
114
- 8px 0px 20px;
115
}
116
pre.request-debug {
117
padding: 12px;
111
margin: 20px 0px 8px;
112
}
113
pre, p {
114
+ margin: 8px 0px 20px;
115
}
116
pre.request-debug {
117
padding: 12px;
waf/wfWAFUserIPRange.php CHANGED
@@ -50,9 +50,11 @@ class wfWAFUserIPRange {
50
51
// IPv6 range
52
} else if (strpos($ip_string, ':') !== false && strpos($ip, ':') !== false) {
53
- if (preg_match('/\[[a-f0-9]+\-[a-f0-9]+\]/', $ip_string)) {
54
- $IPparts = explode(':', strtolower(wfWAFUtils::expandIPv6Address($ip)));
55
- $whiteParts = explode(':', strtolower(self::expandIPv6Range($ip_string)));
56
$mismatch = false;
57
for ($i = 0; $i <= 7; $i++) {
58
if (preg_match('/^\[([a-f0-9]+)\-([a-f0-9]+)\]#x2F;i', $whiteParts[$i], $m)) {
@@ -219,6 +221,6 @@ class wfWAFUserIPRange {
219
* @param string|null $ip_string
220
*/
221
public function setIPString($ip_string) {
222
- $this->ip_string = $ip_string;
223
}
224
}
50
51
// IPv6 range
52
} else if (strpos($ip_string, ':') !== false && strpos($ip, ':') !== false) {
53
+ $ip = strtolower(wfWAFUtils::expandIPv6Address($ip));
54
+ $ip_string = strtolower(self::expandIPv6Range($ip_string));
55
+ if (preg_match('/\[[a-f0-9]+\-[a-f0-9]+\]/i', $ip_string)) {
56
+ $IPparts = explode(':', $ip);
57
+ $whiteParts = explode(':', $ip_string);
58
$mismatch = false;
59
for ($i = 0; $i <= 7; $i++) {
60
if (preg_match('/^\[([a-f0-9]+)\-([a-f0-9]+)\]#x2F;i', $whiteParts[$i], $m)) {
221
* @param string|null $ip_string
222
*/
223
public function setIPString($ip_string) {
224
+ $this->ip_string = preg_replace('/[\x{2013}-\x{2015}]/u', '-', $ip_string); //Replace em-dash, en-dash, and horizontal bar with a regular dash
225
}
226
}
wordfence.php CHANGED
@@ -2,16 +2,16 @@
2
/*
3
Plugin Name: Wordfence Security
4
Plugin URI: http://www.wordfence.com/
5
- Description: Wordfence Security - Anti-virus, Firewall and High Speed Cache
6
Author: Wordfence
7
- Version: 6.2.0
8
Author URI: http://www.wordfence.com/
9
Network: true
10
*/
11
if(defined('WP_INSTALLING') && WP_INSTALLING){
12
return;
13
}
14
- define('WORDFENCE_VERSION', '6.2.0');
15
define('WORDFENCE_BASENAME', function_exists('plugin_basename') ? plugin_basename(__FILE__) :
16
basename(dirname(__FILE__)) . '/' . basename(__FILE__));
17
2
/*
3
Plugin Name: Wordfence Security
4
Plugin URI: http://www.wordfence.com/
5
+ Description: Wordfence Security - Anti-virus, Firewall and Malware Scan
6
Author: Wordfence
7
+ Version: 6.2.1
8
Author URI: http://www.wordfence.com/
9
Network: true
10
*/
11
if(defined('WP_INSTALLING') && WP_INSTALLING){
12
return;
13
}
14
+ define('WORDFENCE_VERSION', '6.2.1');
15
define('WORDFENCE_BASENAME', function_exists('plugin_basename') ? plugin_basename(__FILE__) :
16
basename(dirname(__FILE__)) . '/' . basename(__FILE__));
17