Version Description
- Added Cellphone Sign-in (Two Factor Authentication) for paid members. Stop brute-force attacks permanently! See new "Cellphone Sign-in" menu option.
- Added ability to enforce strong passwords when accounts are created or users change their password. See Wordfence 'options' page under 'Login Security Options'.
- Added new backdoor/malware signatures including detection for spamming scripts, youtube spam scripts and a new attack shell.
- Fixed issue: Under some conditions, files not part of core or a known theme or plugin would be excluded from a scan.
- Fixes from Juliette R. F. Remove warnings for unset variables. Fix options 'save' spinner spinning infinitely on some platforms. Removed redundant error handling code.
- Added ability to downgrade a paid license to free.
Download this release
Release Info
Developer | mmaunder |
Plugin | Wordfence Security – Firewall & Malware Scan |
Version | 3.8.1 |
Comparing to | |
See all releases |
Code changes from version 3.7.2 to 3.8.1
- css/main.css +2 -2
- js/admin.js +71 -3
- lib/menu_options.php +23 -9
- lib/menu_rangeBlocking.php +1 -1
- lib/menu_twoFactor.php +105 -0
- lib/menu_whois.php +2 -2
- lib/schedWeekEntry.php +1 -1
- lib/wfConfig.php +5 -0
- lib/wfLog.php +7 -5
- lib/wfScan.php +1 -1
- lib/whois/whois.idna.php +3 -3
- lib/whois/whois.main.php +1 -1
- lib/wordfenceClass.php +254 -11
- lib/wordfenceConstants.php +1 -1
- lib/wordfenceScanner.php +16 -13
- readme.txt +16 -13
- wordfence.php +2 -2
css/main.css
CHANGED
@@ -295,8 +295,8 @@ input.wfStartScanButton { width: 160px; text-align: left; padding-left: 20px; }
|
|
295 |
#paidCover {
|
296 |
}
|
297 |
.paidInnerMsg {
|
298 |
-
width:
|
299 |
-
margin:
|
300 |
color: #000;
|
301 |
font-size: 18px;
|
302 |
font-family: Georgia, Times;
|
295 |
#paidCover {
|
296 |
}
|
297 |
.paidInnerMsg {
|
298 |
+
width: 500px;
|
299 |
+
margin: 150px auto 0 auto;
|
300 |
color: #000;
|
301 |
font-size: 18px;
|
302 |
font-family: Georgia, Times;
|
js/admin.js
CHANGED
@@ -83,8 +83,17 @@ window['wordfenceAdmin'] = {
|
|
83 |
startTicker = true;
|
84 |
if(! this.tourClosed){
|
85 |
var self = this;
|
86 |
-
this.tour('wfWelcomeContent4', 'wfHeading', 'top', 'left', "Learn
|
87 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
88 |
} else if(jQuery('#wordfenceMode_countryBlocking').length > 0){
|
89 |
this.mode = 'countryBlocking';
|
90 |
startTicker = false;
|
@@ -144,6 +153,13 @@ window['wordfenceAdmin'] = {
|
|
144 |
tourFinish: function(){
|
145 |
this.ajax('wordfence_tourClosed', {}, function(res){});
|
146 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
147 |
tour: function(contentID, elemID, edge, align, buttonLabel, buttonCallback){
|
148 |
var self = this;
|
149 |
if(this.currentPointer){
|
@@ -1054,10 +1070,10 @@ window['wordfenceAdmin'] = {
|
|
1054 |
jQuery('.wfAjax24').hide();
|
1055 |
if(res.ok){
|
1056 |
if(res['paidKeyMsg']){
|
1057 |
-
self.colorbox('400px', "Congratulations! You have been upgraded to Premium Scanning.", "You have upgraded to a Premium API key. Once this page reloads, you can choose which premium scanning options you would like to enable and then click save. Click the button below to reload this page now.<br /><br /><center><input type='button' name='wfReload' value='Reload page and enable Premium options' onclick='window.location.reload();' /></center>");
|
1058 |
return;
|
1059 |
} else if(res['reload'] == 'reload' || WFAD.reloadConfigPage){
|
1060 |
-
self.colorbox('400px', "Please reload this page", "You selected a config option that requires a page reload. Click the button below to reload this page to update the menu.<br /><br /><center><input type='button' name='wfReload' value='Reload page' onclick='window.location.reload();' /></center>");
|
1061 |
return;
|
1062 |
} else {
|
1063 |
self.pulse('.wfSavedMsg');
|
@@ -1267,6 +1283,58 @@ window['wordfenceAdmin'] = {
|
|
1267 |
self.pulse('.wfSaveMsg');
|
1268 |
});
|
1269 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1270 |
getQueryParam: function(name){
|
1271 |
name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
|
1272 |
var regexS = "[\\?&]" + name + "=([^&#]*)";
|
83 |
startTicker = true;
|
84 |
if(! this.tourClosed){
|
85 |
var self = this;
|
86 |
+
this.tour('wfWelcomeContent4', 'wfHeading', 'top', 'left', "Learn about Cellphone Sign-in", function(){ self.tourRedir('WordfenceTwoFactor'); });
|
87 |
}
|
88 |
+
} else if(jQuery('#wordfenceMode_twoFactor').length > 0){
|
89 |
+
this.mode = 'twoFactor';
|
90 |
+
startTicker = false;
|
91 |
+
if(! this.tourClosed){
|
92 |
+
var self = this;
|
93 |
+
this.tour('wfWelcomeTwoFactor', 'wfHeading', 'top', 'left', "Learn how to Block Countries", function(){ self.tourRedir('WordfenceCountryBlocking'); });
|
94 |
+
}
|
95 |
+
this.loadTwoFactor();
|
96 |
+
|
97 |
} else if(jQuery('#wordfenceMode_countryBlocking').length > 0){
|
98 |
this.mode = 'countryBlocking';
|
99 |
startTicker = false;
|
153 |
tourFinish: function(){
|
154 |
this.ajax('wordfence_tourClosed', {}, function(res){});
|
155 |
},
|
156 |
+
downgradeLicense: function(){
|
157 |
+
this.colorbox('400px', "Confirm Downgrade", "Are you sure you want to downgrade your Wordfence Premium License? This will disable all Premium features and return you to the free version of Wordfence. <a href=\"https://www.wordfence.com/manage-wordfence-api-keys/\" target=\"_blank\">Click here to renew your paid membership</a> or click the button below to confirm you want to downgrade.<br /><br /><input type=\"button\" value=\"Downgrade and disable Premium features\" onclick=\"WFAD.downgradeLicenseConfirm();\" /><br />");
|
158 |
+
},
|
159 |
+
downgradeLicenseConfirm: function(){
|
160 |
+
jQuery.colorbox.close();
|
161 |
+
this.ajax('wordfence_downgradeLicense', {}, function(res){ location.reload(true); });
|
162 |
+
},
|
163 |
tour: function(contentID, elemID, edge, align, buttonLabel, buttonCallback){
|
164 |
var self = this;
|
165 |
if(this.currentPointer){
|
1070 |
jQuery('.wfAjax24').hide();
|
1071 |
if(res.ok){
|
1072 |
if(res['paidKeyMsg']){
|
1073 |
+
self.colorbox('400px', "Congratulations! You have been upgraded to Premium Scanning.", "You have upgraded to a Premium API key. Once this page reloads, you can choose which premium scanning options you would like to enable and then click save. Click the button below to reload this page now.<br /><br /><center><input type='button' name='wfReload' value='Reload page and enable Premium options' onclick='window.location.reload(true);' /></center>");
|
1074 |
return;
|
1075 |
} else if(res['reload'] == 'reload' || WFAD.reloadConfigPage){
|
1076 |
+
self.colorbox('400px', "Please reload this page", "You selected a config option that requires a page reload. Click the button below to reload this page to update the menu.<br /><br /><center><input type='button' name='wfReload' value='Reload page' onclick='window.location.reload(true);' /></center>");
|
1077 |
return;
|
1078 |
} else {
|
1079 |
self.pulse('.wfSavedMsg');
|
1283 |
self.pulse('.wfSaveMsg');
|
1284 |
});
|
1285 |
},
|
1286 |
+
twoFacStatus: function(msg){
|
1287 |
+
jQuery('#wfTwoFacMsg').html(msg);
|
1288 |
+
jQuery('#wfTwoFacMsg').fadeIn(function(){
|
1289 |
+
setTimeout(function(){ jQuery('#wfTwoFacMsg').fadeOut(); }, 2000);
|
1290 |
+
});
|
1291 |
+
},
|
1292 |
+
addTwoFactor: function(username, phone){
|
1293 |
+
var self = this;
|
1294 |
+
this.ajax('wordfence_addTwoFactor', {
|
1295 |
+
username: username,
|
1296 |
+
phone: phone
|
1297 |
+
}, function(res){
|
1298 |
+
if(res.ok){
|
1299 |
+
self.twoFacStatus('User added! Check the user\'s phone to get the activation code.');
|
1300 |
+
jQuery('<div id="twoFacCont_' + res.userID + '">' + jQuery('#wfTwoFacUserTmpl').tmpl(res).html() + '</div>').prependTo(jQuery('#wfTwoFacUsers'));
|
1301 |
+
}
|
1302 |
+
});
|
1303 |
+
},
|
1304 |
+
twoFacActivate: function(userID, code){
|
1305 |
+
var self = this;
|
1306 |
+
this.ajax('wordfence_twoFacActivate', {
|
1307 |
+
userID: userID,
|
1308 |
+
code: code
|
1309 |
+
}, function(res){
|
1310 |
+
if(res.ok){
|
1311 |
+
jQuery('#twoFacCont_' + res.userID).html(
|
1312 |
+
jQuery('#wfTwoFacUserTmpl').tmpl(res)
|
1313 |
+
);
|
1314 |
+
self.twoFacStatus('Cellphone Sign-in activated for user.');
|
1315 |
+
}
|
1316 |
+
});
|
1317 |
+
},
|
1318 |
+
delTwoFac: function(userID){
|
1319 |
+
this.ajax('wordfence_twoFacDel', {
|
1320 |
+
userID: userID
|
1321 |
+
}, function(res){
|
1322 |
+
if(res.ok){
|
1323 |
+
jQuery('#twoFacCont_' + res.userID).fadeOut(function(){ jQuery(this).remove(); });
|
1324 |
+
}
|
1325 |
+
});
|
1326 |
+
},
|
1327 |
+
loadTwoFactor: function(){
|
1328 |
+
this.ajax('wordfence_loadTwoFactor', {}, function(res){
|
1329 |
+
if(res.users && res.users.length > 0){
|
1330 |
+
for(var i = 0; i < res.users.length; i++){
|
1331 |
+
jQuery('<div id="twoFacCont_' + res.users[i].userID + '">' +
|
1332 |
+
jQuery('#wfTwoFacUserTmpl').tmpl(res.users[i]).html() +
|
1333 |
+
+ '</div>').appendTo(jQuery('#wfTwoFacUsers'));
|
1334 |
+
}
|
1335 |
+
}
|
1336 |
+
});
|
1337 |
+
},
|
1338 |
getQueryParam: function(name){
|
1339 |
name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
|
1340 |
var regexS = "[\\?&]" + name + "=([^&#]*)";
|
lib/menu_options.php
CHANGED
@@ -15,6 +15,22 @@ var WFSLevels = <?php echo json_encode(wfConfig::$securityLevels); ?>;
|
|
15 |
|
16 |
<form id="wfConfigForm">
|
17 |
<table class="wfConfigForm">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
18 |
<tr><td colspan="2"><h2>Basic Options</h2></td></tr>
|
19 |
<tr><th class="wfConfigEnable">Enable firewall </th><td><input type="checkbox" id="firewallEnabled" class="wfConfigElem" name="firewallEnabled" value="1" <?php $w->cb('firewallEnabled'); ?> /> <span style="color: #F00;">NOTE:</span> This checkbox enables ALL firewall functions including IP, country and advanced blocking and the "Firewall Rules" below.</td></tr>
|
20 |
<tr><td colspan="2"> </td></tr>
|
@@ -26,15 +42,7 @@ var WFSLevels = <?php echo json_encode(wfConfig::$securityLevels); ?>;
|
|
26 |
<tr><td colspan="2"> </td></tr>
|
27 |
|
28 |
<tr><th>Where to email alerts:</th><td><input type="text" id="alertEmails" name="alertEmails" value="<?php $w->f('alertEmails'); ?>" size="50" /> <span class="wfTipText">Separate multiple emails with commas</span></td></tr>
|
29 |
-
<tr><th
|
30 |
-
</td></tr>
|
31 |
-
<tr><th>Key type currently active:</th><td>
|
32 |
-
<?php if(wfConfig::get('isPaid')){ ?>
|
33 |
-
The currently active API Key is a Premium Key. <span style="font-weight: bold; color: #0A0;">Premium scanning enabled!</span>
|
34 |
-
<?php } else {?>
|
35 |
-
The currently active API Key is a <span style="color: #F00; font-weight: bold;">Free Key</a>. <a href="https://www.wordfence.com/choose-a-wordfence-membership-type/?s2-ssl=yes" target="_blank">Upgrade to Premium Scanning now.</a>
|
36 |
-
<?php } ?>
|
37 |
-
</td></tr>
|
38 |
<tr><th>Security Level:</th><td>
|
39 |
<select id="securityLevel" name="securityLevel" onchange="WFAD.changeSecurityLevel(); return true;">
|
40 |
<option value="0"<?php $w->sel('securityLevel', '0'); ?>>Level 0: Disable all Wordfence security measures</option>
|
@@ -147,6 +155,12 @@ var WFSLevels = <?php echo json_encode(wfConfig::$securityLevels); ?>;
|
|
147 |
<div class="wfMarker" id="wfMarkerLoginSecurity"></div>
|
148 |
<h3 class="wfConfigHeading">Login Security Options</h3>
|
149 |
</td></tr>
|
|
|
|
|
|
|
|
|
|
|
|
|
150 |
<tr><th>Lock out after how many login failures</th><td>
|
151 |
<select id="loginSec_maxFailures" class="wfConfigElem" name="loginSec_maxFailures">
|
152 |
<option value="1"<?php $w->sel('loginSec_maxFailures', '1'); ?>>1</option>
|
15 |
|
16 |
<form id="wfConfigForm">
|
17 |
<table class="wfConfigForm">
|
18 |
+
<tr><td colspan="2"><h2>License</h2></td></tr>
|
19 |
+
|
20 |
+
<tr><th>Your Wordfence API Key:</th><td><input type="text" id="apiKey" name="apiKey" value="<?php $w->f('apiKey'); ?>" size="80" /></td></tr>
|
21 |
+
<tr><th>Key type currently active:</th><td>
|
22 |
+
<?php if(wfConfig::get('isPaid')){ ?>
|
23 |
+
The currently active API Key is a Premium Key. <span style="font-weight: bold; color: #0A0;">Premium scanning enabled!</span>
|
24 |
+
<?php } else {?>
|
25 |
+
The currently active API Key is a <span style="color: #F00; font-weight: bold;">Free Key</a>. <a href="https://www.wordfence.com/wordfence-signup/" target="_blank">Upgrade to Premium Scanning now.</a>
|
26 |
+
<?php } ?>
|
27 |
+
</td></tr>
|
28 |
+
<tr><td colspan="2">
|
29 |
+
<?php if(wfConfig::get('isPaid')){ ?>
|
30 |
+
<table border="0"><tr><td><a href="https://www.wordfence.com/manage-wordfence-api-keys/" target="_blank"><input type="button" value="Renew your premium license" /></a></td><td> </td><td><input type="button" value="Downgrade to a free license" onclick="WFAD.downgradeLicense();" /></td></tr></table>
|
31 |
+
<?php } ?>
|
32 |
+
|
33 |
+
|
34 |
<tr><td colspan="2"><h2>Basic Options</h2></td></tr>
|
35 |
<tr><th class="wfConfigEnable">Enable firewall </th><td><input type="checkbox" id="firewallEnabled" class="wfConfigElem" name="firewallEnabled" value="1" <?php $w->cb('firewallEnabled'); ?> /> <span style="color: #F00;">NOTE:</span> This checkbox enables ALL firewall functions including IP, country and advanced blocking and the "Firewall Rules" below.</td></tr>
|
36 |
<tr><td colspan="2"> </td></tr>
|
42 |
<tr><td colspan="2"> </td></tr>
|
43 |
|
44 |
<tr><th>Where to email alerts:</th><td><input type="text" id="alertEmails" name="alertEmails" value="<?php $w->f('alertEmails'); ?>" size="50" /> <span class="wfTipText">Separate multiple emails with commas</span></td></tr>
|
45 |
+
<tr><th colspan="2"> </th></tr>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
46 |
<tr><th>Security Level:</th><td>
|
47 |
<select id="securityLevel" name="securityLevel" onchange="WFAD.changeSecurityLevel(); return true;">
|
48 |
<option value="0"<?php $w->sel('securityLevel', '0'); ?>>Level 0: Disable all Wordfence security measures</option>
|
155 |
<div class="wfMarker" id="wfMarkerLoginSecurity"></div>
|
156 |
<h3 class="wfConfigHeading">Login Security Options</h3>
|
157 |
</td></tr>
|
158 |
+
<tr><th>Enforce strong passwords?</th><td>
|
159 |
+
<select class="wfConfigElem" id="loginSec_strongPasswds" name="loginSec_strongPasswds">
|
160 |
+
<option value="">Do not force users to use strong passwords</option>
|
161 |
+
<option value="pubs"<?php $w->sel('loginSec_strongPasswds', 'pubs'); ?>>Force admins and publishers to use strong passwords (recommended)</option>
|
162 |
+
<option value="all"<?php $w->sel('loginSec_strongPasswds', 'all'); ?>>Force all members to use strong passwords</option>
|
163 |
+
</select>
|
164 |
<tr><th>Lock out after how many login failures</th><td>
|
165 |
<select id="loginSec_maxFailures" class="wfConfigElem" name="loginSec_maxFailures">
|
166 |
<option value="1"<?php $w->sel('loginSec_maxFailures', '1'); ?>>1</option>
|
lib/menu_rangeBlocking.php
CHANGED
@@ -15,7 +15,7 @@
|
|
15 |
</ul>
|
16 |
</div>
|
17 |
<table class="wfConfigForm">
|
18 |
-
<tr><th>Block anyone that has an IP address in this range:</th><td><input id="ipRange" type="text" size="30" maxlength="255" value="<?php if($_GET['wfBlockRange']){ echo $_GET['wfBlockRange']; } ?>" onkeyup="WFAD.calcRangeTotal();"> <span id="wfShowRangeTotal"></span></td></tr>
|
19 |
<tr><td></td><td style="padding-bottom: 15px;"><strong>Examples:</strong> 192.168.200.200 - 192.168.200.220</td></tr>
|
20 |
<tr><th>...you can also enter a User-Agent (browser) that matches:</th><td><input id="uaRange" type="text" size="30" maxlength="255" > (Case insensitive)</td></tr>
|
21 |
<tr><td></td><td style="padding-bottom: 15px;"><strong>Examples:</strong> *badRobot*, AnotherBadRobot*, *someKindOfSuffix</td></tr>
|
15 |
</ul>
|
16 |
</div>
|
17 |
<table class="wfConfigForm">
|
18 |
+
<tr><th>Block anyone that has an IP address in this range:</th><td><input id="ipRange" type="text" size="30" maxlength="255" value="<?php if( isset( $_GET['wfBlockRange'] ) && $_GET['wfBlockRange']){ echo $_GET['wfBlockRange']; } ?>" onkeyup="WFAD.calcRangeTotal();"> <span id="wfShowRangeTotal"></span></td></tr>
|
19 |
<tr><td></td><td style="padding-bottom: 15px;"><strong>Examples:</strong> 192.168.200.200 - 192.168.200.220</td></tr>
|
20 |
<tr><th>...you can also enter a User-Agent (browser) that matches:</th><td><input id="uaRange" type="text" size="30" maxlength="255" > (Case insensitive)</td></tr>
|
21 |
<tr><td></td><td style="padding-bottom: 15px;"><strong>Examples:</strong> *badRobot*, AnotherBadRobot*, *someKindOfSuffix</td></tr>
|
lib/menu_twoFactor.php
ADDED
@@ -0,0 +1,105 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<div class="wordfenceModeElem" id="wordfenceMode_twoFactor"></div>
|
2 |
+
<div class="wrap" id="paidWrap">
|
3 |
+
<div class="wordfence-lock-icon wordfence-icon32"><br /></div><h2 id="wfHeading">Cellphone Sign-in</h2>
|
4 |
+
<div class="wordfenceWrap" style="margin: 20px 20px 20px 30px;">
|
5 |
+
<p style="width: 500px;">
|
6 |
+
Wordfence's Cellphone Sign-in uses a technique called "Two Factor Authentication" which is used by banks, government agencies and military world-wide as one of the most secure forms of remote system authentication.
|
7 |
+
It's now available from Wordfence for your WordPress website. "Two Factor" relies on two things: Something you know (your password) and something you have (your cellphone).
|
8 |
+
To access your website, you need to know your password and have your cellphone with you.
|
9 |
+
<br /><br />
|
10 |
+
Cellphone sign-in is a two step sign-in process. When you enable this feature for a member, they first sign-in using their username and password.
|
11 |
+
Then they receive an SMS on their cellphone containing a code. Then they sign in again using their username, and they reenter their
|
12 |
+
password with a space and the code they received at the end of the password.
|
13 |
+
<br /><br />
|
14 |
+
Cellphone Sign-in eliminates all common forms of brute force hacking. For a hacker to access a user account with Cellphone Sign-in enabled, they would have to steal
|
15 |
+
a member's cellphone to access their account.
|
16 |
+
We recommend you enable Cellphone Sign-in for all Administrator level accounts.
|
17 |
+
</p>
|
18 |
+
<p>
|
19 |
+
To enable Cellphone Sign-in Authentication for a user account:
|
20 |
+
<ol>
|
21 |
+
<li>Enter the username.</li>
|
22 |
+
<li>Enter a phone number where the code will be sent when the member wants to sign in.</li>
|
23 |
+
<li>Hit the enable button.</li>
|
24 |
+
<li>An activation code is sent to the member's phone.</li>
|
25 |
+
<li>Get the activation code from the member and enter it next to the username in the list below.</li>
|
26 |
+
<li>Click the "Enable" button to enable Cellphone Sign-in for that member.</li>
|
27 |
+
<li>From now on the user will only be able to sign-in by using Cellphone Sign-in.</li>
|
28 |
+
</ol>
|
29 |
+
<br />
|
30 |
+
<table border="0">
|
31 |
+
<tr><td>Enter a username to enable Cellphone Sign-in:</td><td><input type="text" id="wfUsername" value="" size="20" /></td></tr>
|
32 |
+
<tr><td>Enter a phone number where the code will be sent:</td><td><input type="text" id="wfPhone" value="" size="20" />Format: +1-123-555-5034</td></tr>
|
33 |
+
<tr><td colspan="2"><input type="button" value="Enable Cellphone Sign-in" onclick="WFAD.addTwoFactor(jQuery('#wfUsername').val(), jQuery('#wfPhone').val());" /></td></tr>
|
34 |
+
</table>
|
35 |
+
</p>
|
36 |
+
<div style="height: 20px;">
|
37 |
+
<div id="wfTwoFacMsg" style="color: #F00;">
|
38 |
+
|
39 |
+
</div>
|
40 |
+
</div>
|
41 |
+
<div id="wfTwoFacUsers">
|
42 |
+
|
43 |
+
</div>
|
44 |
+
</div>
|
45 |
+
</div>
|
46 |
+
|
47 |
+
<script type="text/x-jquery-template" id="wfTwoFacUserTmpl">
|
48 |
+
<div>
|
49 |
+
<table border="0"><tr>
|
50 |
+
<td style="width: 100px;">${username}</td>
|
51 |
+
<td style="width: 150px;">${phone}</td>
|
52 |
+
<td>
|
53 |
+
{{if status == 'activated'}}
|
54 |
+
<span style="color: #0A0;">Cellphone Sign-in Enabled</span>
|
55 |
+
{{else}}
|
56 |
+
Enter activation code:<input type="text" id="wfActivate" size="4" /><input type="button" value="Activate" onclick="WFAD.twoFacActivate('${userID}', jQuery('#wfActivate').val());" />
|
57 |
+
{{/if}}
|
58 |
+
</td>
|
59 |
+
<td> <a href="#" onclick="WFAD.delTwoFac('${userID}'); return false;">[Delete]</a></td>
|
60 |
+
</tr>
|
61 |
+
</table>
|
62 |
+
</div>
|
63 |
+
</script>
|
64 |
+
<script type="text/javascript">
|
65 |
+
<?php
|
66 |
+
if( (! wfConfig::get('isPaid')) && (wfConfig::get('tourClosed', 0) == '1') ){
|
67 |
+
echo 'WFAD.paidUsersOnly("Wordfence Cellphone Sign-in uses a technique called \'Two Factor Authentication\'. Two Factor Authentication is used by banks, government agencies and military world-wide as one of the most secure forms of remote system authentication. It\'s now available for all paid Wordfence members to permanently stop all brute force hacks. <br /><br />When you enable Cellphone Sign-in on a member\'s account, they complete a two-step process to sign in. First they enter their username and password as per normal. If the username and password are correct, we send a code to their phone. Then they enter their username and their password again but this time they add a space and the code to the end of their password. This form of authentication provides the highest level of security. It is called Two Factor in the security industry because it relies on two factors: Something you know (your password) and something you have (your phone).");';
|
68 |
+
}
|
69 |
+
?>
|
70 |
+
</script>
|
71 |
+
<script type="text/x-jquery-template" id="wfWelcomeTwoFactor">
|
72 |
+
<div>
|
73 |
+
<h3>Secure Sign-in using your Cellphone</h3>
|
74 |
+
<strong><p>Want to permanently block all brute-force hacks?</p></strong>
|
75 |
+
<p>
|
76 |
+
The premium version of Wordfence includes Cellphone Sign-in, also called Two Factor Authentication in the security industry.
|
77 |
+
When you enable Cellphone Sign-in on a member's account, they need to complete a
|
78 |
+
two step process to sign in. First they enter their username and password
|
79 |
+
as usual to sign-into your WordPress website. Then they're told
|
80 |
+
that a code was sent to their phone. Once they get the code, they sign
|
81 |
+
into your site again and this time they add a space and the code to the end of their password.
|
82 |
+
</p>
|
83 |
+
<p>
|
84 |
+
This technique is called Two Factor Authentication because it relies on two factors:
|
85 |
+
Something you know (your password) and something you have (your phone).
|
86 |
+
It is used by banks and military world-wide as a way to dramatically increase
|
87 |
+
security.
|
88 |
+
</p>
|
89 |
+
<p>
|
90 |
+
<?php
|
91 |
+
if(wfConfig::get('isPaid')){
|
92 |
+
?>
|
93 |
+
You have upgraded to the premium version of Wordfence and have full access
|
94 |
+
to this feature along with our other premium features.
|
95 |
+
<?php
|
96 |
+
} else {
|
97 |
+
?>
|
98 |
+
If you would like access to this premium feature, please
|
99 |
+
<a href="https://www.wordfence.com/choose-a-wordfence-membership-type/?s2-ssl=yes" target="_blank">upgrade to our premium version</a>.
|
100 |
+
<?php
|
101 |
+
}
|
102 |
+
?>
|
103 |
+
</p>
|
104 |
+
</div>
|
105 |
+
</script>
|
lib/menu_whois.php
CHANGED
@@ -24,7 +24,7 @@ if(! function_exists('fsockopen')){
|
|
24 |
<input type="text" name="whois" id="wfwhois" value="" size="40" maxlength="255" onkeydown="if(event.keyCode == 13){ WFAD.whois(jQuery('#wfwhois').val()); }" /> <input type="button" name="whoisbutton" id="whoisbutton" class="button-primary" value="Look up IP or Domain" onclick="WFAD.whois(jQuery('#wfwhois').val());" />
|
25 |
|
26 |
</p>
|
27 |
-
<?php if($_GET['wfnetworkblock']){ ?>
|
28 |
<h2>How to block a network</h2>
|
29 |
<p style="width: 600px;">
|
30 |
You've chosen to block the network that <span style="color: #F00;"><?php echo $_GET['whoisval']; ?></span> is part of.
|
@@ -50,7 +50,7 @@ if(! function_exists('fsockopen')){
|
|
50 |
</div>
|
51 |
</script>
|
52 |
<script type="text/javascript">
|
53 |
-
var whoisval = "<?php echo $_GET['whoisval']; ?>";
|
54 |
if(whoisval){
|
55 |
jQuery(function(){
|
56 |
jQuery('#wfwhois').val(whoisval);
|
24 |
<input type="text" name="whois" id="wfwhois" value="" size="40" maxlength="255" onkeydown="if(event.keyCode == 13){ WFAD.whois(jQuery('#wfwhois').val()); }" /> <input type="button" name="whoisbutton" id="whoisbutton" class="button-primary" value="Look up IP or Domain" onclick="WFAD.whois(jQuery('#wfwhois').val());" />
|
25 |
|
26 |
</p>
|
27 |
+
<?php if( isset( $_GET['wfnetworkblock'] ) && $_GET['wfnetworkblock']){ ?>
|
28 |
<h2>How to block a network</h2>
|
29 |
<p style="width: 600px;">
|
30 |
You've chosen to block the network that <span style="color: #F00;"><?php echo $_GET['whoisval']; ?></span> is part of.
|
50 |
</div>
|
51 |
</script>
|
52 |
<script type="text/javascript">
|
53 |
+
var whoisval = "<?php if( isset( $_GET['whoisval'] ) ) { echo $_GET['whoisval']; } ?>";
|
54 |
if(whoisval){
|
55 |
jQuery(function(){
|
56 |
jQuery('#wfwhois').val(whoisval);
|
lib/schedWeekEntry.php
CHANGED
@@ -20,7 +20,7 @@
|
|
20 |
}
|
21 |
echo '</tr><tr><th></th><td></td>';
|
22 |
for($hour = 0; $hour <= 23; $hour++){
|
23 |
-
$checked = ($sched[$dayIndex][$hour] ? 'checked' : '');
|
24 |
echo '<td><input class="wfSchedCheckbox" type="checkbox" id="wfSchedDay_' . $dayIndex . '_' . $hour . '" ' . $checked . ' /></td>';
|
25 |
}
|
26 |
?>
|
20 |
}
|
21 |
echo '</tr><tr><th></th><td></td>';
|
22 |
for($hour = 0; $hour <= 23; $hour++){
|
23 |
+
$checked = ( isset( $sched[$dayIndex] ) && $sched[$dayIndex][$hour] ? 'checked' : '');
|
24 |
echo '<td><input class="wfSchedCheckbox" type="checkbox" id="wfSchedDay_' . $dayIndex . '_' . $hour . '" ' . $checked . ' /></td>';
|
25 |
}
|
26 |
?>
|
lib/wfConfig.php
CHANGED
@@ -54,6 +54,7 @@ class wfConfig {
|
|
54 |
"neverBlockBG" => "neverBlockVerified",
|
55 |
"loginSec_countFailMins" => "5",
|
56 |
"loginSec_lockoutMins" => "5",
|
|
|
57 |
'loginSec_maxFailures' => "500",
|
58 |
'loginSec_maxForgotPasswd' => "500",
|
59 |
'maxGlobalRequests' => "DISABLED",
|
@@ -119,6 +120,7 @@ class wfConfig {
|
|
119 |
"neverBlockBG" => "neverBlockVerified",
|
120 |
"loginSec_countFailMins" => "5",
|
121 |
"loginSec_lockoutMins" => "5",
|
|
|
122 |
'loginSec_maxFailures' => "50",
|
123 |
'loginSec_maxForgotPasswd' => "50",
|
124 |
'maxGlobalRequests' => "DISABLED",
|
@@ -184,6 +186,7 @@ class wfConfig {
|
|
184 |
"neverBlockBG" => "neverBlockVerified",
|
185 |
"loginSec_countFailMins" => "240",
|
186 |
"loginSec_lockoutMins" => "240",
|
|
|
187 |
'loginSec_maxFailures' => "20",
|
188 |
'loginSec_maxForgotPasswd' => "20",
|
189 |
'maxGlobalRequests' => "DISABLED",
|
@@ -249,6 +252,7 @@ class wfConfig {
|
|
249 |
"neverBlockBG" => "neverBlockVerified",
|
250 |
"loginSec_countFailMins" => "1440",
|
251 |
"loginSec_lockoutMins" => "1440",
|
|
|
252 |
'loginSec_maxFailures' => "10",
|
253 |
'loginSec_maxForgotPasswd' => "10",
|
254 |
'maxGlobalRequests' => "960",
|
@@ -314,6 +318,7 @@ class wfConfig {
|
|
314 |
"neverBlockBG" => "neverBlockVerified",
|
315 |
"loginSec_countFailMins" => "1440",
|
316 |
"loginSec_lockoutMins" => "1440",
|
|
|
317 |
'loginSec_maxFailures' => "5",
|
318 |
'loginSec_maxForgotPasswd' => "5",
|
319 |
'maxGlobalRequests' => "960",
|
54 |
"neverBlockBG" => "neverBlockVerified",
|
55 |
"loginSec_countFailMins" => "5",
|
56 |
"loginSec_lockoutMins" => "5",
|
57 |
+
'loginSec_strongPasswds' => '',
|
58 |
'loginSec_maxFailures' => "500",
|
59 |
'loginSec_maxForgotPasswd' => "500",
|
60 |
'maxGlobalRequests' => "DISABLED",
|
120 |
"neverBlockBG" => "neverBlockVerified",
|
121 |
"loginSec_countFailMins" => "5",
|
122 |
"loginSec_lockoutMins" => "5",
|
123 |
+
'loginSec_strongPasswds' => 'pubs',
|
124 |
'loginSec_maxFailures' => "50",
|
125 |
'loginSec_maxForgotPasswd' => "50",
|
126 |
'maxGlobalRequests' => "DISABLED",
|
186 |
"neverBlockBG" => "neverBlockVerified",
|
187 |
"loginSec_countFailMins" => "240",
|
188 |
"loginSec_lockoutMins" => "240",
|
189 |
+
'loginSec_strongPasswds' => 'pubs',
|
190 |
'loginSec_maxFailures' => "20",
|
191 |
'loginSec_maxForgotPasswd' => "20",
|
192 |
'maxGlobalRequests' => "DISABLED",
|
252 |
"neverBlockBG" => "neverBlockVerified",
|
253 |
"loginSec_countFailMins" => "1440",
|
254 |
"loginSec_lockoutMins" => "1440",
|
255 |
+
'loginSec_strongPasswds' => 'all',
|
256 |
'loginSec_maxFailures' => "10",
|
257 |
'loginSec_maxForgotPasswd' => "10",
|
258 |
'maxGlobalRequests' => "960",
|
318 |
"neverBlockBG" => "neverBlockVerified",
|
319 |
"loginSec_countFailMins" => "1440",
|
320 |
"loginSec_lockoutMins" => "1440",
|
321 |
+
'loginSec_strongPasswds' => 'all',
|
322 |
'loginSec_maxFailures' => "5",
|
323 |
'loginSec_maxForgotPasswd' => "5",
|
324 |
'maxGlobalRequests' => "960",
|
lib/wfLog.php
CHANGED
@@ -397,7 +397,7 @@ class wfLog {
|
|
397 |
$res['blocked'] = $this->getDB()->querySingle("select blockedTime from " . $this->blocksTable . " where IP=%s and (permanent = 1 OR (blockedTime + %s > unix_timestamp()))", $res['IP'], wfConfig::get('blockedTime'));
|
398 |
$res['IP'] = wfUtils::inet_ntoa($res['IP']);
|
399 |
$res['extReferer'] = false;
|
400 |
-
if($res['referer']){
|
401 |
$refURL = parse_url($res['referer']);
|
402 |
if(is_array($refURL) && $refURL['host']){
|
403 |
$refHost = strtolower(preg_replace('/^www\./i', '', $refURL['host']));
|
@@ -414,15 +414,17 @@ class wfLog {
|
|
414 |
}
|
415 |
if($q){
|
416 |
$queryVars = array();
|
417 |
-
|
418 |
-
|
419 |
-
$
|
|
|
|
|
420 |
}
|
421 |
}
|
422 |
}
|
423 |
}
|
424 |
if($res['extReferer']){
|
425 |
-
if ( stristr( $referringPage['host'], 'google.' ) )
|
426 |
{
|
427 |
parse_str( $referringPage['query'], $queryVars );
|
428 |
echo $queryVars['q']; // This is the search term used
|
397 |
$res['blocked'] = $this->getDB()->querySingle("select blockedTime from " . $this->blocksTable . " where IP=%s and (permanent = 1 OR (blockedTime + %s > unix_timestamp()))", $res['IP'], wfConfig::get('blockedTime'));
|
398 |
$res['IP'] = wfUtils::inet_ntoa($res['IP']);
|
399 |
$res['extReferer'] = false;
|
400 |
+
if( isset( $res['referer'] ) && $res['referer']){
|
401 |
$refURL = parse_url($res['referer']);
|
402 |
if(is_array($refURL) && $refURL['host']){
|
403 |
$refHost = strtolower(preg_replace('/^www\./i', '', $refURL['host']));
|
414 |
}
|
415 |
if($q){
|
416 |
$queryVars = array();
|
417 |
+
if( isset( $refURL['query'] ) ) {
|
418 |
+
parse_str($refURL['query'], $queryVars);
|
419 |
+
if(isset($queryVars[$q])){
|
420 |
+
$res['searchTerms'] = $queryVars[$q];
|
421 |
+
}
|
422 |
}
|
423 |
}
|
424 |
}
|
425 |
}
|
426 |
if($res['extReferer']){
|
427 |
+
if ( isset( $referringPage ) && stristr( $referringPage['host'], 'google.' ) )
|
428 |
{
|
429 |
parse_str( $referringPage['query'], $queryVars );
|
430 |
echo $queryVars['q']; // This is the search term used
|
lib/wfScan.php
CHANGED
@@ -12,7 +12,7 @@ class wfScan {
|
|
12 |
if(! wordfence::wfSchemaExists()){
|
13 |
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.");
|
14 |
}
|
15 |
-
if($_GET['test'] == '1'){
|
16 |
echo "WFCRONTESTOK:" . wfConfig::get('cronTestID');
|
17 |
self::status(4, 'info', "Cron test received and message printed");
|
18 |
exit();
|
12 |
if(! wordfence::wfSchemaExists()){
|
13 |
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.");
|
14 |
}
|
15 |
+
if( isset( $_GET['test'] ) && $_GET['test'] == '1'){
|
16 |
echo "WFCRONTESTOK:" . wfConfig::get('cronTestID');
|
17 |
self::status(4, 'info', "Cron test received and message printed");
|
18 |
exit();
|
lib/whois/whois.idna.php
CHANGED
@@ -51,7 +51,7 @@
|
|
51 |
* @version 0.5.1
|
52 |
*
|
53 |
*/
|
54 |
-
class
|
55 |
{
|
56 |
/**
|
57 |
* Holds all relevant mapping tables, loaded from a seperate file on construct
|
@@ -942,7 +942,7 @@ class idna_convert
|
|
942 |
* Adapter class for aligning the API of idna_convert with that of Net_IDNA
|
943 |
* @author Matthias Sommerfeld <mso@phlylabs.de>
|
944 |
*/
|
945 |
-
class Net_IDNA_php4 extends
|
946 |
{
|
947 |
/**
|
948 |
* Sets a new option value. Available options and values:
|
@@ -966,4 +966,4 @@ class Net_IDNA_php4 extends idna_convert
|
|
966 |
}
|
967 |
}
|
968 |
|
969 |
-
?>
|
51 |
* @version 0.5.1
|
52 |
*
|
53 |
*/
|
54 |
+
class wordfence_idna_convert
|
55 |
{
|
56 |
/**
|
57 |
* Holds all relevant mapping tables, loaded from a seperate file on construct
|
942 |
* Adapter class for aligning the API of idna_convert with that of Net_IDNA
|
943 |
* @author Matthias Sommerfeld <mso@phlylabs.de>
|
944 |
*/
|
945 |
+
class Net_IDNA_php4 extends wordfence_idna_convert
|
946 |
{
|
947 |
/**
|
948 |
* Sets a new option value. Available options and values:
|
966 |
}
|
967 |
}
|
968 |
|
969 |
+
?>
|
lib/whois/whois.main.php
CHANGED
@@ -82,7 +82,7 @@ class Whois extends WhoisClient
|
|
82 |
|
83 |
$query = trim($query);
|
84 |
|
85 |
-
$IDN = new
|
86 |
|
87 |
if ($is_utf)
|
88 |
$query = $IDN->encode($query);
|
82 |
|
83 |
$query = trim($query);
|
84 |
|
85 |
+
$IDN = new wordfence_idna_convert();
|
86 |
|
87 |
if ($is_utf)
|
88 |
$query = $IDN->encode($query);
|
lib/wordfenceClass.php
CHANGED
@@ -14,6 +14,7 @@ require_once('wfSchema.php');
|
|
14 |
class wordfence {
|
15 |
public static $printStatus = false;
|
16 |
public static $wordfence_wp_version = false;
|
|
|
17 |
protected static $lastURLError = false;
|
18 |
protected static $curlContent = "";
|
19 |
protected static $curlDataWritten = 0;
|
@@ -259,12 +260,15 @@ class wordfence {
|
|
259 |
add_action('init', 'wordfence::initAction');
|
260 |
add_action('template_redirect', 'wordfence::templateRedir');
|
261 |
add_action('shutdown', 'wordfence::shutdownAction');
|
262 |
-
add_action('wp_authenticate','wordfence::authAction');
|
263 |
add_action('login_init','wordfence::loginInitAction');
|
264 |
add_action('wp_login','wordfence::loginAction');
|
265 |
add_action('wp_logout','wordfence::logoutAction');
|
266 |
add_action('profile_update', 'wordfence::profileUpdateAction', '99', 2);
|
267 |
add_action('lostpassword_post', 'wordfence::lostPasswordPost', '1');
|
|
|
|
|
|
|
268 |
//add_filter('cron_schedules', 'wordfence::moreCronReccurences');
|
269 |
add_filter('pre_comment_approved', 'wordfence::preCommentApprovedFilter', '99', 2);
|
270 |
add_filter('authenticate', 'wordfence::authenticateFilter', 99, 3);
|
@@ -338,6 +342,61 @@ class wordfence {
|
|
338 |
}
|
339 |
$returnArr['nonce'] = wp_create_nonce('wp-ajax');
|
340 |
die(json_encode($returnArr));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
341 |
}
|
342 |
public static function lostPasswordPost(){
|
343 |
$IP = wfUtils::getIP();
|
@@ -496,10 +555,57 @@ class wordfence {
|
|
496 |
}
|
497 |
public static function authenticateFilter($authResult){
|
498 |
$IP = wfUtils::getIP();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
499 |
if(self::getLog()->isWhitelisted($IP)){
|
500 |
return $authResult;
|
501 |
}
|
502 |
-
if(
|
503 |
if(is_wp_error($authResult) && $authResult->get_error_code() == 'invalid_username' && wfConfig::get('loginSec_lockInvalidUsers')){
|
504 |
self::lockOutIP($IP, "Used an invalid username '" . $_POST['log'] . "' to try to sign in.");
|
505 |
require('wfLockedOut.php');
|
@@ -536,12 +642,19 @@ class wordfence {
|
|
536 |
require('wfLockedOut.php');
|
537 |
}
|
538 |
}
|
539 |
-
public static function authAction($username){
|
540 |
if(self::isLockedOut(wfUtils::getIP())){
|
541 |
require('wfLockedOut.php');
|
542 |
}
|
543 |
if(! $username){ return; }
|
544 |
$userDat = get_user_by('login', $username);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
545 |
if($userDat){
|
546 |
require_once( ABSPATH . 'wp-includes/class-phpass.php');
|
547 |
$hasher = new PasswordHash(8, TRUE);
|
@@ -589,6 +702,122 @@ class wordfence {
|
|
589 |
return array('errorMsg' => $e->getMessage());
|
590 |
}
|
591 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
592 |
public static function ajax_saveScanSchedule_callback(){
|
593 |
if(! wfConfig::get('isPaid')){
|
594 |
return array('errorMsg' => "Sorry but this feature is only available for paid customers.");
|
@@ -742,6 +971,21 @@ class wordfence {
|
|
742 |
wfConfig::set('tourClosed', 0);
|
743 |
return array('ok' => 1);
|
744 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
745 |
public static function ajax_tourClosed_callback(){
|
746 |
wfConfig::set('tourClosed', 1);
|
747 |
return array('ok' => 1);
|
@@ -890,12 +1134,7 @@ class wordfence {
|
|
890 |
return array('errorMsg' => "Your options have been saved. However we noticed you changed your API key and we tried to verify it with the Wordfence servers and received an error: " . $e->getMessage());
|
891 |
}
|
892 |
}
|
893 |
-
|
894 |
-
if($err){
|
895 |
-
return array('errorMsg' => $err);
|
896 |
-
} else {
|
897 |
-
return array('ok' => 1, 'reload' => $reload, 'paidKeyMsg' => $paidKeyMsg );
|
898 |
-
}
|
899 |
}
|
900 |
public static function ajax_clearAllBlocked_callback(){
|
901 |
$op = $_POST['op'];
|
@@ -1353,7 +1592,7 @@ class wordfence {
|
|
1353 |
}
|
1354 |
public static function wfFunc_diff(){
|
1355 |
$result = self::getWPFileContent($_GET['file'], $_GET['cType'], $_GET['cName'], $_GET['cVersion']);
|
1356 |
-
if($result['errorMsg']){
|
1357 |
echo $result['errorMsg'];
|
1358 |
exit(0);
|
1359 |
} else if(! $result['fileContent']){
|
@@ -1395,7 +1634,7 @@ class wordfence {
|
|
1395 |
}
|
1396 |
public static function admin_init(){
|
1397 |
if(! wfUtils::isAdmin()){ return; }
|
1398 |
-
foreach(array('activate', 'scan', 'sendActivityLog', 'restoreFile', 'deleteFile', 'removeExclusion', 'activityLogUpdate', 'ticker', 'loadIssues', 'updateIssueStatus', 'deleteIssue', 'updateAllIssues', 'reverseLookup', 'unlockOutIP', 'loadBlockRanges', 'unblockRange', 'blockIPUARange', 'whois', 'unblockIP', 'blockIP', 'permBlockIP', 'loadStaticPanel', 'saveConfig', 'clearAllBlocked', 'killScan', 'saveCountryBlocking', 'saveScanSchedule', 'tourClosed', 'startTourAgain') as $func){
|
1399 |
add_action('wp_ajax_wordfence_' . $func, 'wordfence::ajaxReceiver');
|
1400 |
}
|
1401 |
|
@@ -1494,6 +1733,7 @@ class wordfence {
|
|
1494 |
add_submenu_page("Wordfence", "Live Traffic", "Live Traffic", "activate_plugins", "WordfenceActivity", 'wordfence::menu_activity');
|
1495 |
}
|
1496 |
add_submenu_page('Wordfence', 'Blocked IPs', 'Blocked IPs', 'activate_plugins', 'WordfenceBlockedIPs', 'wordfence::menu_blockedIPs');
|
|
|
1497 |
add_submenu_page("Wordfence", "Country Blocking", "Country Blocking", "activate_plugins", "WordfenceCountryBlocking", 'wordfence::menu_countryBlocking');
|
1498 |
add_submenu_page("Wordfence", "Scan Schedule", "Scan Schedule", "activate_plugins", "WordfenceScanSchedule", 'wordfence::menu_scanSchedule');
|
1499 |
add_submenu_page("Wordfence", "Whois Lookup", "Whois Lookup", "activate_plugins", "WordfenceWhois", 'wordfence::menu_whois');
|
@@ -1509,6 +1749,9 @@ class wordfence {
|
|
1509 |
public static function menu_scanSchedule(){
|
1510 |
require 'menu_scanSchedule.php';
|
1511 |
}
|
|
|
|
|
|
|
1512 |
public static function menu_countryBlocking(){
|
1513 |
require 'menu_countryBlocking.php';
|
1514 |
}
|
14 |
class wordfence {
|
15 |
public static $printStatus = false;
|
16 |
public static $wordfence_wp_version = false;
|
17 |
+
private static $passwordCodePattern = '/\s+(wf[a-z0-9]+)$/i';
|
18 |
protected static $lastURLError = false;
|
19 |
protected static $curlContent = "";
|
20 |
protected static $curlDataWritten = 0;
|
260 |
add_action('init', 'wordfence::initAction');
|
261 |
add_action('template_redirect', 'wordfence::templateRedir');
|
262 |
add_action('shutdown', 'wordfence::shutdownAction');
|
263 |
+
add_action('wp_authenticate','wordfence::authAction', 1, 2);
|
264 |
add_action('login_init','wordfence::loginInitAction');
|
265 |
add_action('wp_login','wordfence::loginAction');
|
266 |
add_action('wp_logout','wordfence::logoutAction');
|
267 |
add_action('profile_update', 'wordfence::profileUpdateAction', '99', 2);
|
268 |
add_action('lostpassword_post', 'wordfence::lostPasswordPost', '1');
|
269 |
+
add_action('user_profile_update_errors', 'wordfence::validateProfileUpdate', 0, 3 );
|
270 |
+
add_action('validate_password_reset', 'wordfence::validatePassword', 10, 2 );
|
271 |
+
|
272 |
//add_filter('cron_schedules', 'wordfence::moreCronReccurences');
|
273 |
add_filter('pre_comment_approved', 'wordfence::preCommentApprovedFilter', '99', 2);
|
274 |
add_filter('authenticate', 'wordfence::authenticateFilter', 99, 3);
|
342 |
}
|
343 |
$returnArr['nonce'] = wp_create_nonce('wp-ajax');
|
344 |
die(json_encode($returnArr));
|
345 |
+
exit;
|
346 |
+
}
|
347 |
+
public static function validateProfileUpdate($errors, $update, $userData){
|
348 |
+
wordfence::validatePassword($errors, $userData);
|
349 |
+
}
|
350 |
+
public static function validatePassword($errors, $userData){
|
351 |
+
$password = ( isset( $_POST[ 'pass1' ] ) && trim( $_POST[ 'pass1' ] ) ) ? $_POST[ 'pass1' ] : false;
|
352 |
+
$user_id = isset( $userData->ID ) ? $userData->ID : false;
|
353 |
+
$username = isset( $_POST["user_login"] ) ? $_POST["user_login"] : $userData->user_login;
|
354 |
+
if($password == false){ return $errors; }
|
355 |
+
if($errors->get_error_data("pass") ){ return $errors; }
|
356 |
+
$enforce = false;
|
357 |
+
if(wfConfig::get('loginSec_strongPasswds') == 'pubs'){
|
358 |
+
if(user_can($user_id, 'publish_posts')){
|
359 |
+
$enforce = true;
|
360 |
+
}
|
361 |
+
} else if(wfConfig::get('loginSec_strongPasswds') == 'all'){
|
362 |
+
$enforce = true;
|
363 |
+
}
|
364 |
+
if($enforce){
|
365 |
+
if(! wordfence::isStrongPasswd($password, $username)){
|
366 |
+
$errors->add('pass', "Please choose a stronger password. Try including numbers, symbols and a mix of upper and lower case letters and remove common words.");
|
367 |
+
return $errors;
|
368 |
+
}
|
369 |
+
}
|
370 |
+
$twoFactorUsers = wfConfig::get_ser('twoFactorUsers', array());
|
371 |
+
if(preg_match(self::$passwordCodePattern, $password) && isset($twoFactorUsers) && is_array($twoFactorUsers) && sizeof($twoFactorUsers) > 0){
|
372 |
+
$errors->add('pass', "Passwords containing a space followed by 'wf' without quotes are not allowed.");
|
373 |
+
return $errors;
|
374 |
+
}
|
375 |
+
return $errors;
|
376 |
+
}
|
377 |
+
function isStrongPasswd($passwd, $username ) {
|
378 |
+
$strength = 0;
|
379 |
+
if(strlen( $passwd ) < 5)
|
380 |
+
return false;
|
381 |
+
if(strtolower( $passwd ) == strtolower( $username ) )
|
382 |
+
return false;
|
383 |
+
if(preg_match('/(?:password|passwd|mypass|wordpress)/i', $passwd)){
|
384 |
+
return false;
|
385 |
+
}
|
386 |
+
if($num = preg_match_all( "/\d/", $passwd, $matches) ){
|
387 |
+
$strength += ((int)$num * 10);
|
388 |
+
}
|
389 |
+
if ( preg_match( "/[a-z]/", $passwd ) )
|
390 |
+
$strength += 26;
|
391 |
+
if ( preg_match( "/[A-Z]/", $passwd ) )
|
392 |
+
$strength += 26;
|
393 |
+
if ($num = preg_match_all( "/[^a-zA-Z0-9]/", $passwd, $matches)){
|
394 |
+
$strength += (31 * (int)$num);
|
395 |
+
|
396 |
+
}
|
397 |
+
if($strength > 60){
|
398 |
+
return true;
|
399 |
+
}
|
400 |
}
|
401 |
public static function lostPasswordPost(){
|
402 |
$IP = wfUtils::getIP();
|
555 |
}
|
556 |
public static function authenticateFilter($authResult){
|
557 |
$IP = wfUtils::getIP();
|
558 |
+
$secEnabled = wfConfig::get('loginSecurityEnabled');
|
559 |
+
if($secEnabled){
|
560 |
+
$twoFactorUsers = wfConfig::get_ser('twoFactorUsers', array());
|
561 |
+
if(isset($twoFactorUsers) && is_array($twoFactorUsers) && sizeof($twoFactorUsers) > 0){
|
562 |
+
$userDat = $_POST['wordfence_userDat'];
|
563 |
+
if(get_class($authResult) == 'WP_User'){ //Valid username and password either with or without the 'wf...' code. Users is now logged in at this point.
|
564 |
+
if(isset($_POST['wordfence_authFactor']) && $_POST['wordfence_authFactor']){ //user entered a valid user and password with ' wf....' appended
|
565 |
+
foreach($twoFactorUsers as &$t){
|
566 |
+
if($t[0] == $userDat->ID && $t[3] == 'activated'){
|
567 |
+
if($_POST['wordfence_authFactor'] == $t[2] && $t[4] > time()){
|
568 |
+
//Do nothing and allow user to sign in. Their passwd has already been modified to be the passwd without the code.
|
569 |
+
} else if($_POST['wordfence_authFactor'] == $t[2]){
|
570 |
+
$api = new wfAPI(wfConfig::get('apiKey'), wfUtils::getWPVersion());
|
571 |
+
$codeResult = $api->call('twoFactor_verification', array(), array('phone' => $t[1]) );
|
572 |
+
if(isset($codeResult['ok']) && $codeResult['ok']){
|
573 |
+
$t[2] = $codeResult['code'];
|
574 |
+
$t[4] = time() + 1800; //30 minutes until code expires
|
575 |
+
wfConfig::set_ser('twoFactorUsers', $twoFactorUsers); //save the code the user needs to enter and return an error.
|
576 |
+
return new WP_Error( 'twofactor_required', __( '<strong>CODE EXPIRED. CHECK YOUR PHONE:</strong> The code you entered has expired. Codes are only valid for 30 minutes for security reasons. We have sent you a new code. Please sign in using your username and your password followed by a space and the new code we sent you.'));
|
577 |
+
} else {
|
578 |
+
break; //No new code was received. Let them sign in with the expired code.
|
579 |
+
}
|
580 |
+
} else { //Bad code, so cancel the login and return an error to user.
|
581 |
+
return new WP_Error( 'twofactor_required', __( '<strong>INVALID CODE</strong>: You need to enter your password followed by a space and the code we sent to your phone. The code should start with \'wf\' and should be four characters. e.g. wfAB12. In this case you would enter your password as: \'mypassword wfAB12\' without quotes.'));
|
582 |
+
}
|
583 |
+
} //No user matches and has TF activated so let user sign in.
|
584 |
+
}
|
585 |
+
} else { //valid login with no code entered
|
586 |
+
foreach($twoFactorUsers as &$t){
|
587 |
+
if($t[0] == $userDat->ID && $t[3] == 'activated'){ //Yup, enabled, so lets send the code
|
588 |
+
$api = new wfAPI(wfConfig::get('apiKey'), wfUtils::getWPVersion());
|
589 |
+
$codeResult = $api->call('twoFactor_verification', array(), array('phone' => $t[1]) );
|
590 |
+
if(isset($codeResult['ok']) && $codeResult['ok']){
|
591 |
+
$t[2] = $codeResult['code'];
|
592 |
+
$t[4] = time() + 1800; //30 minutes until code expires
|
593 |
+
wfConfig::set_ser('twoFactorUsers', $twoFactorUsers); //save the code the user needs to enter and return an error.
|
594 |
+
return new WP_Error( 'twofactor_required', __( '<strong>CHECK YOUR PHONE</strong>: A code has been sent to your phone and will arrive within 30 seconds. Please sign in again and add a space and the code to the end of your password.' ) );
|
595 |
+
} else { //oops, our API returned an error.
|
596 |
+
break; //Let them sign in without two factor because the API is broken and we don't want to lock users out of their own systems.
|
597 |
+
}
|
598 |
+
} //User is not present in two factor list or is not activated. Sign in without twofactor.
|
599 |
+
} //Two facto users is empty. Sign in without two factor.
|
600 |
+
}
|
601 |
+
}
|
602 |
+
}
|
603 |
+
}
|
604 |
+
|
605 |
if(self::getLog()->isWhitelisted($IP)){
|
606 |
return $authResult;
|
607 |
}
|
608 |
+
if($secEnabled){
|
609 |
if(is_wp_error($authResult) && $authResult->get_error_code() == 'invalid_username' && wfConfig::get('loginSec_lockInvalidUsers')){
|
610 |
self::lockOutIP($IP, "Used an invalid username '" . $_POST['log'] . "' to try to sign in.");
|
611 |
require('wfLockedOut.php');
|
642 |
require('wfLockedOut.php');
|
643 |
}
|
644 |
}
|
645 |
+
public static function authAction($username, $passwd){
|
646 |
if(self::isLockedOut(wfUtils::getIP())){
|
647 |
require('wfLockedOut.php');
|
648 |
}
|
649 |
if(! $username){ return; }
|
650 |
$userDat = get_user_by('login', $username);
|
651 |
+
$_POST['wordfence_userDat'] = $userDat;
|
652 |
+
if(preg_match(self::$passwordCodePattern, $passwd, $matches)){
|
653 |
+
$_POST['wordfence_authFactor'] = $matches[1];
|
654 |
+
$passwd = preg_replace('/^(.+)\s+(wf[a-z0-9]+)$/i', '$1', $passwd);
|
655 |
+
$_POST['pwd'] = $passwd;
|
656 |
+
}
|
657 |
+
|
658 |
if($userDat){
|
659 |
require_once( ABSPATH . 'wp-includes/class-phpass.php');
|
660 |
$hasher = new PasswordHash(8, TRUE);
|
702 |
return array('errorMsg' => $e->getMessage());
|
703 |
}
|
704 |
}
|
705 |
+
public static function ajax_addTwoFactor_callback(){
|
706 |
+
$username = $_POST['username'];
|
707 |
+
$phone = $_POST['phone'];
|
708 |
+
$user = get_user_by('login', $username);
|
709 |
+
if(! $user){
|
710 |
+
return array('errorMsg' => "The username you specified does not exist.");
|
711 |
+
}
|
712 |
+
if(! preg_match('/^\+\d[\d\-]+$/', $phone)){
|
713 |
+
return array('errorMsg' => "The phone number you entered must start with a '+', then country code and then area code and number. It can only contain the starting plus sign and then numbers and dashes. It can not contain spaces. For example, a number in the United States with country code '1' would look like this: +1-123-555-1234");
|
714 |
+
}
|
715 |
+
$api = new wfAPI(wfConfig::get('apiKey'), wfUtils::getWPVersion());
|
716 |
+
try {
|
717 |
+
$codeResult = $api->call('twoFactor_verification', array(), array('phone' => $phone));
|
718 |
+
} catch(Exception $e){
|
719 |
+
return array('errorMsg' => "Could not contact Wordfence servers to generate a verification code: " . $e->getMessage());
|
720 |
+
}
|
721 |
+
if(isset($codeResult['ok']) && $codeResult['ok']){
|
722 |
+
$code = $codeResult['code'];
|
723 |
+
} else if(isset($codeResult['errorMsg']) && $codeResult['errorMsg']){
|
724 |
+
return array('errorMsg' => $codeResult['errorMsg']);
|
725 |
+
} else {
|
726 |
+
return array('errorMsg' => "We could not generate a verification code.");
|
727 |
+
}
|
728 |
+
self::twoFactorAdd($user->ID, $phone, $code);
|
729 |
+
return array(
|
730 |
+
'ok' => 1,
|
731 |
+
'userID' => $user->ID,
|
732 |
+
'username' => $username,
|
733 |
+
'phone' => $phone
|
734 |
+
);
|
735 |
+
}
|
736 |
+
public static function ajax_twoFacActivate_callback(){
|
737 |
+
$userID = $_POST['userID'];
|
738 |
+
$code = $_POST['code'];
|
739 |
+
$twoFactorUsers = wfConfig::get_ser('twoFactorUsers', array());
|
740 |
+
if(! is_array($twoFactorUsers)){
|
741 |
+
$twoFactorUsers = array();
|
742 |
+
}
|
743 |
+
$found = false;
|
744 |
+
$user = false;
|
745 |
+
for($i = 0; $i < sizeof($twoFactorUsers); $i++){
|
746 |
+
if($twoFactorUsers[$i][0] == $userID){
|
747 |
+
if($twoFactorUsers[$i][2] == $code){
|
748 |
+
$twoFactorUsers[$i][3] = 'activated';
|
749 |
+
$found = true;
|
750 |
+
$user = $twoFactorUsers[$i];
|
751 |
+
break;
|
752 |
+
} else {
|
753 |
+
return array('errorMsg' => "That is not the correct code. Please look for an SMS containing an activation code on the phone with number: " . $twoFactorUsers[$i][1]);
|
754 |
+
}
|
755 |
+
}
|
756 |
+
}
|
757 |
+
if(! $found){
|
758 |
+
return array('errorMsg' => "We could not find the user you are trying to activate. They may have been removed from the list of Cellphone Sign-in users. Please reload this page.");
|
759 |
+
}
|
760 |
+
wfConfig::set_ser('twoFactorUsers', $twoFactorUsers);
|
761 |
+
$WPuser = get_userdata($userID);
|
762 |
+
return array(
|
763 |
+
'ok' => 1,
|
764 |
+
'userID' => $userID,
|
765 |
+
'username' => $WPuser->user_login,
|
766 |
+
'phone' => $user[1],
|
767 |
+
'status' => 'activated'
|
768 |
+
);
|
769 |
+
}
|
770 |
+
private static function twoFactorAdd($ID, $phone, $code){
|
771 |
+
$twoFactorUsers = wfConfig::get_ser('twoFactorUsers', array());
|
772 |
+
if(! is_array($twoFactorUsers)){
|
773 |
+
$twoFactorUsers = array();
|
774 |
+
}
|
775 |
+
for($i = 0; $i < sizeof($twoFactorUsers); $i++){
|
776 |
+
if($twoFactorUsers[$i][0] == $ID || (! $twoFactorUsers[$i][0]) ){
|
777 |
+
array_splice($twoFactorUsers, $i, 1);
|
778 |
+
$i--;
|
779 |
+
}
|
780 |
+
}
|
781 |
+
array_push($twoFactorUsers, array($ID, $phone, $code, 'notActivated', time() + (86400 * 100))); //expiry of code is 100 days in future
|
782 |
+
wfConfig::set_ser('twoFactorUsers', $twoFactorUsers);
|
783 |
+
}
|
784 |
+
public static function ajax_loadTwoFactor_callback(){
|
785 |
+
$users = wfConfig::get_ser('twoFactorUsers', array());
|
786 |
+
$ret = array();
|
787 |
+
foreach($users as $user){
|
788 |
+
$WPuser = get_userdata($user[0]);
|
789 |
+
if($user){
|
790 |
+
array_push($ret, array(
|
791 |
+
'userID' => $user[0],
|
792 |
+
'username' => $WPuser->user_login,
|
793 |
+
'phone' => $user[1],
|
794 |
+
'status' => $user[3]
|
795 |
+
));
|
796 |
+
}
|
797 |
+
}
|
798 |
+
return array('ok' => 1, 'users' => $ret);
|
799 |
+
}
|
800 |
+
public static function ajax_twoFacDel_callback(){
|
801 |
+
$ID = $_POST['userID'];
|
802 |
+
$twoFactorUsers = wfConfig::get_ser('twoFactorUsers', array());
|
803 |
+
if(! is_array($twoFactorUsers)){
|
804 |
+
$twoFactorUsers = array();
|
805 |
+
}
|
806 |
+
$deleted = false;
|
807 |
+
for($i = 0; $i < sizeof($twoFactorUsers); $i++){
|
808 |
+
if($twoFactorUsers[$i][0] == $ID){
|
809 |
+
array_splice($twoFactorUsers, $i, 1);
|
810 |
+
$deleted = true;
|
811 |
+
$i--;
|
812 |
+
}
|
813 |
+
}
|
814 |
+
wfConfig::set_ser('twoFactorUsers', $twoFactorUsers);
|
815 |
+
if($deleted){
|
816 |
+
return array('ok' => 1, 'userID' => $ID);
|
817 |
+
} else {
|
818 |
+
return array('errorMsg' => "That user has already been removed from the list.");
|
819 |
+
}
|
820 |
+
}
|
821 |
public static function ajax_saveScanSchedule_callback(){
|
822 |
if(! wfConfig::get('isPaid')){
|
823 |
return array('errorMsg' => "Sorry but this feature is only available for paid customers.");
|
971 |
wfConfig::set('tourClosed', 0);
|
972 |
return array('ok' => 1);
|
973 |
}
|
974 |
+
public static function ajax_downgradeLicense_callback(){
|
975 |
+
$api = new wfAPI('', wfUtils::getWPVersion());
|
976 |
+
try {
|
977 |
+
$keyData = $api->call('get_anon_api_key');
|
978 |
+
if($keyData['ok'] && $keyData['apiKey']){
|
979 |
+
wfConfig::set('apiKey', $keyData['apiKey']);
|
980 |
+
wfConfig::set('isPaid', 0);
|
981 |
+
} else {
|
982 |
+
throw new Exception("Could not understand the response we received from the Wordfence servers when applying for a free API key.");
|
983 |
+
}
|
984 |
+
} catch(Exception $e){
|
985 |
+
return array('errorMsg' => "Could not fetch free API key from Wordfence: " . $e->getMessage());
|
986 |
+
}
|
987 |
+
return array('ok' => 1);
|
988 |
+
}
|
989 |
public static function ajax_tourClosed_callback(){
|
990 |
wfConfig::set('tourClosed', 1);
|
991 |
return array('ok' => 1);
|
1134 |
return array('errorMsg' => "Your options have been saved. However we noticed you changed your API key and we tried to verify it with the Wordfence servers and received an error: " . $e->getMessage());
|
1135 |
}
|
1136 |
}
|
1137 |
+
return array('ok' => 1, 'reload' => $reload, 'paidKeyMsg' => $paidKeyMsg );
|
|
|
|
|
|
|
|
|
|
|
1138 |
}
|
1139 |
public static function ajax_clearAllBlocked_callback(){
|
1140 |
$op = $_POST['op'];
|
1592 |
}
|
1593 |
public static function wfFunc_diff(){
|
1594 |
$result = self::getWPFileContent($_GET['file'], $_GET['cType'], $_GET['cName'], $_GET['cVersion']);
|
1595 |
+
if( isset( $result['errorMsg'] ) && $result['errorMsg']){
|
1596 |
echo $result['errorMsg'];
|
1597 |
exit(0);
|
1598 |
} else if(! $result['fileContent']){
|
1634 |
}
|
1635 |
public static function admin_init(){
|
1636 |
if(! wfUtils::isAdmin()){ return; }
|
1637 |
+
foreach(array('activate', 'scan', 'sendActivityLog', 'restoreFile', 'deleteFile', 'removeExclusion', 'activityLogUpdate', 'ticker', 'loadIssues', 'updateIssueStatus', 'deleteIssue', 'updateAllIssues', 'reverseLookup', 'unlockOutIP', 'loadBlockRanges', 'unblockRange', 'blockIPUARange', 'whois', 'unblockIP', 'blockIP', 'permBlockIP', 'loadStaticPanel', 'saveConfig', 'clearAllBlocked', 'killScan', 'saveCountryBlocking', 'saveScanSchedule', 'tourClosed', 'startTourAgain', 'downgradeLicense', 'addTwoFactor', 'twoFacActivate', 'twoFacDel', 'loadTwoFactor') as $func){
|
1638 |
add_action('wp_ajax_wordfence_' . $func, 'wordfence::ajaxReceiver');
|
1639 |
}
|
1640 |
|
1733 |
add_submenu_page("Wordfence", "Live Traffic", "Live Traffic", "activate_plugins", "WordfenceActivity", 'wordfence::menu_activity');
|
1734 |
}
|
1735 |
add_submenu_page('Wordfence', 'Blocked IPs', 'Blocked IPs', 'activate_plugins', 'WordfenceBlockedIPs', 'wordfence::menu_blockedIPs');
|
1736 |
+
add_submenu_page("Wordfence", "Cellphone Sign-in", "Cellphone Sign-in", "activate_plugins", "WordfenceTwoFactor", 'wordfence::menu_twoFactor');
|
1737 |
add_submenu_page("Wordfence", "Country Blocking", "Country Blocking", "activate_plugins", "WordfenceCountryBlocking", 'wordfence::menu_countryBlocking');
|
1738 |
add_submenu_page("Wordfence", "Scan Schedule", "Scan Schedule", "activate_plugins", "WordfenceScanSchedule", 'wordfence::menu_scanSchedule');
|
1739 |
add_submenu_page("Wordfence", "Whois Lookup", "Whois Lookup", "activate_plugins", "WordfenceWhois", 'wordfence::menu_whois');
|
1749 |
public static function menu_scanSchedule(){
|
1750 |
require 'menu_scanSchedule.php';
|
1751 |
}
|
1752 |
+
public static function menu_twoFactor(){
|
1753 |
+
require 'menu_twoFactor.php';
|
1754 |
+
}
|
1755 |
public static function menu_countryBlocking(){
|
1756 |
require 'menu_countryBlocking.php';
|
1757 |
}
|
lib/wordfenceConstants.php
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
<?php
|
2 |
-
define('WORDFENCE_API_VERSION', '2.
|
3 |
define('WORDFENCE_API_URL_SEC', 'https://noc1.wordfence.com/');
|
4 |
define('WORDFENCE_API_URL_NONSEC', 'http://noc1.wordfence.com/');
|
5 |
define('WORDFENCE_MAX_SCAN_TIME', 86400); //Increased this from 10 mins to 1 day because very big scans run for a long time. Users can use kill.
|
1 |
<?php
|
2 |
+
define('WORDFENCE_API_VERSION', '2.7');
|
3 |
define('WORDFENCE_API_URL_SEC', 'https://noc1.wordfence.com/');
|
4 |
define('WORDFENCE_API_URL_NONSEC', 'http://noc1.wordfence.com/');
|
5 |
define('WORDFENCE_MAX_SCAN_TIME', 86400); //Increased this from 10 mins to 1 day because very big scans run for a long time. Users can use kill.
|
lib/wordfenceScanner.php
CHANGED
@@ -36,7 +36,9 @@ class wordfenceScanner {
|
|
36 |
}
|
37 |
private function setupSigs(){
|
38 |
$this->api = new wfAPI($this->apiKey, $this->wordpressVersion);
|
39 |
-
$sigData = $this->api->call('get_patterns', array(), array());
|
|
|
|
|
40 |
if(! (is_array($sigData) && isset($sigData['sigPattern'])) ){
|
41 |
throw new Exception("Wordfence could not get the attack signature patterns from the scanning server.");
|
42 |
}
|
@@ -50,17 +52,18 @@ class wordfenceScanner {
|
|
50 |
$this->lastStatusTime = microtime(true);
|
51 |
}
|
52 |
$db = new wfDB();
|
53 |
-
$
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
|
|
|
|
62 |
}
|
63 |
-
|
64 |
foreach($res1 as $rec1){
|
65 |
$db->queryWrite("update " . $db->prefix() . "wfFileMods set oldMD5 = newMD5 where filenameMD5='%s'", $rec1['filenameMD5']); //A way to mark as scanned so that if we come back from a sleep we don't rescan this one.
|
66 |
$file = $rec1['filename'];
|
@@ -134,8 +137,8 @@ class wordfenceScanner {
|
|
134 |
'severity' => 1,
|
135 |
'ignoreP' => $this->path . $file,
|
136 |
'ignoreC' => $fileSum,
|
137 |
-
'shortMsg' => "This file appears to be
|
138 |
-
'longMsg' => "This file appears to be
|
139 |
'data' => array(
|
140 |
'file' => $file,
|
141 |
'canDiff' => false,
|
36 |
}
|
37 |
private function setupSigs(){
|
38 |
$this->api = new wfAPI($this->apiKey, $this->wordpressVersion);
|
39 |
+
$sigData = $this->api->call('get_patterns', array(), array());
|
40 |
+
//For testing, comment out above two, include server sig file and get local sigs
|
41 |
+
//$sigData = wfSigs::getSigData();
|
42 |
if(! (is_array($sigData) && isset($sigData['sigPattern'])) ){
|
43 |
throw new Exception("Wordfence could not get the attack signature patterns from the scanning server.");
|
44 |
}
|
52 |
$this->lastStatusTime = microtime(true);
|
53 |
}
|
54 |
$db = new wfDB();
|
55 |
+
$lastCount = 'whatever';
|
56 |
+
while(true){
|
57 |
+
$thisCount = $db->querySingle("select count(*) from " . $db->prefix() . "wfFileMods where oldMD5 != newMD5 and knownFile=0");
|
58 |
+
if($thisCount == $lastCount){
|
59 |
+
//count should always be decreasing. If not, we're in an infinite loop so lets catch it early
|
60 |
+
break;
|
61 |
+
}
|
62 |
+
$lastCount = $thisCount;
|
63 |
+
$res1 = $db->querySelect("select filename, filenameMD5, hex(newMD5) as newMD5 from " . $db->prefix() . "wfFileMods where oldMD5 != newMD5 and knownFile=0 limit 500");
|
64 |
+
if(sizeof($res1) < 1){
|
65 |
+
break;
|
66 |
}
|
|
|
67 |
foreach($res1 as $rec1){
|
68 |
$db->queryWrite("update " . $db->prefix() . "wfFileMods set oldMD5 = newMD5 where filenameMD5='%s'", $rec1['filenameMD5']); //A way to mark as scanned so that if we come back from a sleep we don't rescan this one.
|
69 |
$file = $rec1['filename'];
|
137 |
'severity' => 1,
|
138 |
'ignoreP' => $this->path . $file,
|
139 |
'ignoreC' => $fileSum,
|
140 |
+
'shortMsg' => "This file appears to be malicious",
|
141 |
+
'longMsg' => "This file appears to be installed by a hacker to perform malicious activity. If you know about this file you can choose to ignore it to exclude it from future scans. The text we found in this file that matches a known malicious file is: <strong style=\"color: #F00;\">\"" . $matches[1] . "\"</strong>.",
|
142 |
'data' => array(
|
143 |
'file' => $file,
|
144 |
'canDiff' => false,
|
readme.txt
CHANGED
@@ -1,24 +1,26 @@
|
|
1 |
=== Wordfence Security ===
|
2 |
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.5.1
|
6 |
-
Stable tag: 3.
|
7 |
|
8 |
Wordfence Security is a free enterprise class security plugin that includes a firewall, virus scanning, real-time traffic with geolocation and more.
|
9 |
|
10 |
== Description ==
|
11 |
|
12 |
-
Wordfence Security is a free enterprise class security plugin that includes a firewall, anti-virus scanning, malicious URL scanning and live traffic including crawlers. Wordfence is the only WordPress security plugin that can verify and repair your core, theme and plugin files, even if you don't have backups.
|
13 |
|
14 |
-
Wordfence is now Multi-Site compatible.
|
15 |
|
16 |
[Remember to visit our support forums if you have questions or comments.](http://wordfence.com/forums/)
|
17 |
|
18 |
-
Wordfence is 100% free. We also offer a Premium API key that lets you block countries and schedule scans for specific times.
|
19 |
|
20 |
Wordfence:
|
21 |
|
|
|
|
|
22 |
* Scans core files, themes and plugins against WordPress.org repository versions to check their integrity.
|
23 |
* Includes a firewall to block common security threats like fake Googlebots, malicious scans from hackers and botnets.
|
24 |
* Includes advanced IP and Domain WHOIS to report malicious IP's or networks and block entire networks using the firewall.
|
@@ -70,7 +72,7 @@ To install Wordfence on WordPress Multi-Site installations (support is currently
|
|
70 |
|
71 |
== Frequently Asked Questions ==
|
72 |
|
73 |
-
[
|
74 |
|
75 |
= What does Wordfence Security do that other WordPress security plugins don't do? =
|
76 |
|
@@ -137,13 +139,6 @@ version of timthumb (which the creator of Wordfence wrote and donated to the tim
|
|
137 |
caused the problem. However we do scan for old version of timthumb for good measure to make sure they don't
|
138 |
cause a security hole on your site.
|
139 |
|
140 |
-
= People keep telling me that WordPress itself has security problems. Is that true? =
|
141 |
-
|
142 |
-
In general, no it's not. The WordPress team work very hard to keep the awesome software they have produced secure and in the
|
143 |
-
rare cases when a security hole is found, they fix it very quickly. Most responsible plugin authors also fix security holes
|
144 |
-
as soon as they are told about them. That's why Wordfence will warn you if you're running an old version of WordPress, a plugin
|
145 |
-
or a theme, because often these have been updated to fix a security hole.
|
146 |
-
|
147 |
|
148 |
== Screenshots ==
|
149 |
|
@@ -155,6 +150,14 @@ or a theme, because often these have been updated to fix a security hole.
|
|
155 |
|
156 |
== Changelog ==
|
157 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
158 |
= 3.7.2 =
|
159 |
* Fixed issue that caused locked out IP's to not appear, or to appear with incorrect "locked out until" time.
|
160 |
|
1 |
=== Wordfence Security ===
|
2 |
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, two factor, cellphone sign-in, cellphone signin, cellphone, twofactor
|
4 |
Requires at least: 3.3.1
|
5 |
Tested up to: 3.5.1
|
6 |
+
Stable tag: 3.8.1
|
7 |
|
8 |
Wordfence Security is a free enterprise class security plugin that includes a firewall, virus scanning, real-time traffic with geolocation and more.
|
9 |
|
10 |
== Description ==
|
11 |
|
12 |
+
Wordfence Security is a free enterprise class security plugin that includes a firewall, anti-virus scanning, cellphone sign-in (two factor authentication), malicious URL scanning and live traffic including crawlers. Wordfence is the only WordPress security plugin that can verify and repair your core, theme and plugin files, even if you don't have backups.
|
13 |
|
14 |
+
Wordfence is now Multi-Site compatible and includes Cellphone Sign-in which permanently secures your website from brute force hacks.
|
15 |
|
16 |
[Remember to visit our support forums if you have questions or comments.](http://wordfence.com/forums/)
|
17 |
|
18 |
+
Wordfence is 100% free. We also offer a Premium API key that gives you Cellphone Sign-in via SMS, lets you block countries and schedule scans for specific times.
|
19 |
|
20 |
Wordfence:
|
21 |
|
22 |
+
* Sign-in using your password and your cellphone. This is called Two Factor Authentication and is used by banks, government agencies and military world-wide.
|
23 |
+
* Enforce strong passwords among your administrators, publishers and users.
|
24 |
* Scans core files, themes and plugins against WordPress.org repository versions to check their integrity.
|
25 |
* Includes a firewall to block common security threats like fake Googlebots, malicious scans from hackers and botnets.
|
26 |
* Includes advanced IP and Domain WHOIS to report malicious IP's or networks and block entire networks using the firewall.
|
72 |
|
73 |
== Frequently Asked Questions ==
|
74 |
|
75 |
+
[Visit our Website FAQ which is more comprehensive and updated frequently.](http://www.wordfence.com/docs/frequently-asked-questions/)
|
76 |
|
77 |
= What does Wordfence Security do that other WordPress security plugins don't do? =
|
78 |
|
139 |
caused the problem. However we do scan for old version of timthumb for good measure to make sure they don't
|
140 |
cause a security hole on your site.
|
141 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
142 |
|
143 |
== Screenshots ==
|
144 |
|
150 |
|
151 |
== Changelog ==
|
152 |
|
153 |
+
= 3.8.1 =
|
154 |
+
* Added Cellphone Sign-in (Two Factor Authentication) for paid members. Stop brute-force attacks permanently! See new "Cellphone Sign-in" menu option.
|
155 |
+
* Added ability to enforce strong passwords when accounts are created or users change their password. See Wordfence 'options' page under 'Login Security Options'.
|
156 |
+
* Added new backdoor/malware signatures including detection for spamming scripts, youtube spam scripts and a new attack shell.
|
157 |
+
* Fixed issue: Under some conditions, files not part of core or a known theme or plugin would be excluded from a scan.
|
158 |
+
* Fixes from Juliette R. F. Remove warnings for unset variables. Fix options 'save' spinner spinning infinitely on some platforms. Removed redundant error handling code.
|
159 |
+
* Added ability to downgrade a paid license to free.
|
160 |
+
|
161 |
= 3.7.2 =
|
162 |
* Fixed issue that caused locked out IP's to not appear, or to appear with incorrect "locked out until" time.
|
163 |
|
wordfence.php
CHANGED
@@ -4,10 +4,10 @@ Plugin Name: Wordfence Security
|
|
4 |
Plugin URI: http://www.wordfence.com/
|
5 |
Description: Wordfence Security - Anti-virus and Firewall security plugin for WordPress
|
6 |
Author: Mark Maunder
|
7 |
-
Version: 3.
|
8 |
Author URI: http://www.wordfence.com/
|
9 |
*/
|
10 |
-
define('WORDFENCE_VERSION', '3.
|
11 |
if(get_option('wordfenceActivated') != 1){
|
12 |
add_action('activated_plugin','wordfence_save_activation_error'); function wordfence_save_activation_error(){ update_option('wf_plugin_act_error', ob_get_contents()); }
|
13 |
}
|
4 |
Plugin URI: http://www.wordfence.com/
|
5 |
Description: Wordfence Security - Anti-virus and Firewall security plugin for WordPress
|
6 |
Author: Mark Maunder
|
7 |
+
Version: 3.8.1
|
8 |
Author URI: http://www.wordfence.com/
|
9 |
*/
|
10 |
+
define('WORDFENCE_VERSION', '3.8.1');
|
11 |
if(get_option('wordfenceActivated') != 1){
|
12 |
add_action('activated_plugin','wordfence_save_activation_error'); function wordfence_save_activation_error(){ update_option('wf_plugin_act_error', ob_get_contents()); }
|
13 |
}
|