Version Description
- Feature: Prevent discovery of usernames through '?/author=N' scans. New option under login security which you can enable.
- Fix: Introduced new global hash whitelist on our servers that drastically reduces false positives in all scans especially theme and plugin scans.
- Fix: Fixed issue that corrupted .htaccess because stat cache would store file size and cause filesize() to report incorrect size when reading/writing .htaccess.
- Fix: Fixed LiteSpeed issue where Falcon Engine would not serve cached pages under LiteSpeed and LiteSpeed warned about unknown server variable in .htaccess.
- Fix: Fixed issue where Wordfence Security Network won't block known bad IP after first login attempt if "Don't let WordPress reveal valid users in login errors" option is not enabled.
- Fix: Sites installed under a directory would sometimes see Falcon not serving cached docs.
- Fix: If you are a premium customer and you have 2FA enabled and your key expires, fixed issue that may have caused you to get locked out.
- Improvement: If your Premium API key now expires, we simply downgrade you to free scanning and continue rather than disabling Wordfence.
- Improvement: Email warnings a few days before your Premium key expires so you have a chance to upgrade for uninterrupted service.
Download this release
Release Info
Developer | mmaunder |
Plugin | Wordfence Security – Firewall & Malware Scan |
Version | 5.0.6 |
Comparing to | |
See all releases |
Code changes from version 5.0.5 to 5.0.6
- js/admin.js +2 -0
- lib/menu_options.php +1 -0
- lib/wfAPI.php +9 -0
- lib/wfCache.php +15 -6
- lib/wfConfig.php +5 -0
- lib/wfUtils.php +7 -0
- lib/wordfenceClass.php +70 -6
- lib/wordfenceConstants.php +1 -1
- lib/wordfenceHash.php +77 -65
- lib/wordfenceScanner.php +115 -127
- readme.txt +14 -3
- wordfence.php +2 -2
js/admin.js
CHANGED
@@ -1224,6 +1224,8 @@ window['wordfenceAdmin'] = {
|
|
1224 |
}, function(res){
|
1225 |
if(res.ok){
|
1226 |
self.colorbox('400px', "Enabling Falcon Engine", 'First read this <a href="http://www.wordfence.com/introduction-to-wordfence-falcon-engine/" target="_blank">Introduction to Falcon Engine</a>. Falcon modifies your website configuration file which is called your .htaccess file. To enable Falcon we ask that you make a backup of this file. This is a safety precaution in case for some reason Falcon is not compatible with your site.<br /><br /><a href="' + WordfenceAdminVars.ajaxURL + '?action=wordfence_downloadHtaccess&nonce=' + self.nonce + '" onclick="jQuery(\'#wfNextBut\').prop(\'disabled\', false); return true;">Click here to download a backup copy of your .htaccess file now</a><br /><br /><input type="button" name="but1" id="wfNextBut" value="Click to Enable Falcon Engine" disabled="disabled" onclick="WFAD.confirmSwitchToFalcon(0);" />');
|
|
|
|
|
1227 |
} else if(res.err){
|
1228 |
self.colorbox('400px', "We encountered a problem", "We can't modify your .htaccess file for you because: " + res.err + "<br /><br />Advanced users: If you would like to manually enable Falcon yourself by editing your .htaccess, you can add the rules below to the beginning of your .htaccess file. Then click the button below to enable Falcon. Don't do this unless you understand website configuration.<br /><textarea style='width: 300px; height:100px;' readonly>" + jQuery('<div/>').text(res.code).html() + "</textarea><br /><input type='button' value='Enable Falcon after manually editing .htaccess' onclick='WFAD.confirmSwitchToFalcon(1);' />");
|
1229 |
}
|
1224 |
}, function(res){
|
1225 |
if(res.ok){
|
1226 |
self.colorbox('400px', "Enabling Falcon Engine", 'First read this <a href="http://www.wordfence.com/introduction-to-wordfence-falcon-engine/" target="_blank">Introduction to Falcon Engine</a>. Falcon modifies your website configuration file which is called your .htaccess file. To enable Falcon we ask that you make a backup of this file. This is a safety precaution in case for some reason Falcon is not compatible with your site.<br /><br /><a href="' + WordfenceAdminVars.ajaxURL + '?action=wordfence_downloadHtaccess&nonce=' + self.nonce + '" onclick="jQuery(\'#wfNextBut\').prop(\'disabled\', false); return true;">Click here to download a backup copy of your .htaccess file now</a><br /><br /><input type="button" name="but1" id="wfNextBut" value="Click to Enable Falcon Engine" disabled="disabled" onclick="WFAD.confirmSwitchToFalcon(0);" />');
|
1227 |
+
} else if(res.nginx){
|
1228 |
+
self.colorbox('400px', "Enabling Falcon Engine", 'You are using an Nginx web server and using a FastCGI processor like PHP5-FPM. To use Falcon you will need to manually modify your nginx.conf configuration file and reload your Nginx server for the changes to take effect. You can find the <a href="http://www.wordfence.com/blog/2014/05/nginx-wordfence-falcon-engine-php-fpm-fastcgi-fast-cgi/" target="_blank">rules you need to make these changes to nginx.conf on this page on wordfence.com</a>. Once you have made these changes, compressed cached files will be served to your visitors directly from Nginx making your site extremely fast. When you have made the changes and reloaded your Nginx server, you can click the button below to enable Falcon.<br /><br /><input type="button" name="but1" id="wfNextBut" value="Click to Enable Falcon Engine" onclick="WFAD.confirmSwitchToFalcon(0);" />');
|
1229 |
} else if(res.err){
|
1230 |
self.colorbox('400px', "We encountered a problem", "We can't modify your .htaccess file for you because: " + res.err + "<br /><br />Advanced users: If you would like to manually enable Falcon yourself by editing your .htaccess, you can add the rules below to the beginning of your .htaccess file. Then click the button below to enable Falcon. Don't do this unless you understand website configuration.<br /><textarea style='width: 300px; height:100px;' readonly>" + jQuery('<div/>').text(res.code).html() + "</textarea><br /><input type='button' value='Enable Falcon after manually editing .htaccess' onclick='WFAD.confirmSwitchToFalcon(1);' />");
|
1231 |
}
|
lib/menu_options.php
CHANGED
@@ -243,6 +243,7 @@ var WFSLevels = <?php echo json_encode(wfConfig::$securityLevels); ?>;
|
|
243 |
<tr><th>Immediately lock out invalid usernames</th><td><input type="checkbox" id="loginSec_lockInvalidUsers" class="wfConfigElem" name="loginSec_lockInvalidUsers" <?php $w->cb('loginSec_lockInvalidUsers'); ?> /></td></tr>
|
244 |
<tr><th>Don't let WordPress reveal valid users in login errors</th><td><input type="checkbox" id="loginSec_maskLoginErrors" class="wfConfigElem" name="loginSec_maskLoginErrors" <?php $w->cb('loginSec_maskLoginErrors'); ?> /></td></tr>
|
245 |
<tr><th>Prevent users registering 'admin' username if it doesn't exist</th><td><input type="checkbox" id="loginSec_blockAdminReg" class="wfConfigElem" name="loginSec_blockAdminReg" <?php $w->cb('loginSec_blockAdminReg'); ?> /></td></tr>
|
|
|
246 |
<tr><td colspan="2">
|
247 |
<div class="wfMarker" id="wfMarkerOtherOptions"></div>
|
248 |
<h3 class="wfConfigHeading">Other Options</h3>
|
243 |
<tr><th>Immediately lock out invalid usernames</th><td><input type="checkbox" id="loginSec_lockInvalidUsers" class="wfConfigElem" name="loginSec_lockInvalidUsers" <?php $w->cb('loginSec_lockInvalidUsers'); ?> /></td></tr>
|
244 |
<tr><th>Don't let WordPress reveal valid users in login errors</th><td><input type="checkbox" id="loginSec_maskLoginErrors" class="wfConfigElem" name="loginSec_maskLoginErrors" <?php $w->cb('loginSec_maskLoginErrors'); ?> /></td></tr>
|
245 |
<tr><th>Prevent users registering 'admin' username if it doesn't exist</th><td><input type="checkbox" id="loginSec_blockAdminReg" class="wfConfigElem" name="loginSec_blockAdminReg" <?php $w->cb('loginSec_blockAdminReg'); ?> /></td></tr>
|
246 |
+
<tr><th>Prevent discovery of usernames through '?/author=N' scans</th><td><input type="checkbox" id="loginSec_disableAuthorScan" class="wfConfigElem" name="loginSec_disableAuthorScan" <?php $w->cb('loginSec_disableAuthorScan'); ?> /></td></tr>
|
247 |
<tr><td colspan="2">
|
248 |
<div class="wfMarker" id="wfMarkerOtherOptions"></div>
|
249 |
<h3 class="wfConfigHeading">Other Options</h3>
|
lib/wfAPI.php
CHANGED
@@ -26,6 +26,15 @@ class wfAPI {
|
|
26 |
}
|
27 |
|
28 |
$dat = json_decode($json, true);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
29 |
if(! is_array($dat)){
|
30 |
throw new Exception("We received a data structure that is not the expected array when contacting the Wordfence scanning servers and calling the '$action' function.");
|
31 |
}
|
26 |
}
|
27 |
|
28 |
$dat = json_decode($json, true);
|
29 |
+
if(isset($dat['_isPaidKey'])){
|
30 |
+
wfConfig::set('keyExpDays', $dat['_keyExpDays']);
|
31 |
+
if($dat['_keyExpDays'] > -1){
|
32 |
+
wfConfig::set('isPaid', 1);
|
33 |
+
} else if($dat['_keyExpDays'] < 0){
|
34 |
+
wfConfig::set('isPaid', '');
|
35 |
+
}
|
36 |
+
}
|
37 |
+
|
38 |
if(! is_array($dat)){
|
39 |
throw new Exception("We received a data structure that is not the expected array when contacting the Wordfence scanning servers and calling the '$action' function.");
|
40 |
}
|
lib/wfCache.php
CHANGED
@@ -369,6 +369,7 @@ class wfCache {
|
|
369 |
}
|
370 |
flock($fh, LOCK_EX);
|
371 |
fseek($fh, 0, SEEK_SET); //start of file
|
|
|
372 |
$contents = fread($fh, filesize($htaccessPath));
|
373 |
if(! $contents){
|
374 |
fclose($fh);
|
@@ -388,17 +389,23 @@ class wfCache {
|
|
388 |
}
|
389 |
public static function getHtaccessCode(){
|
390 |
$siteURL = site_url();
|
|
|
391 |
$pathPrefix = "";
|
392 |
-
$matchCaps = '$1/$2~$3~$4~$5~$6';
|
393 |
if(preg_match('/^https?:\/\/[^\/]+\/(.+)$/i', $siteURL, $matches)){
|
394 |
$path = $matches[1];
|
395 |
$path = preg_replace('/^\//', '', $path);
|
396 |
$path = preg_replace('/\/$/', '', $path);
|
397 |
-
$pieces = explode('/', $path);
|
398 |
$pathPrefix = '/' . $path; // Which is: /my/path
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
399 |
if(count($pieces) == 1){
|
400 |
-
# No path: "/wp-content/wfcache/%{HTTP_HOST}_$1/$2~$3~$4~$5~$6_wfcache%{WRDFNC_HTTPS}.html%{ENV:WRDFNC_ENC}" [L]
|
401 |
-
# One path: "/mdm/wp-content/wfcache/%{HTTP_HOST}_mdm/$1~$2~$3~$4~$5_wfcache%{WRDFNC_HTTPS}.html%{ENV:WRDFNC_ENC}" [L]
|
402 |
$matchCaps = $pieces[0] . '/$1~$2~$3~$4~$5';
|
403 |
} else if(count($pieces) == 2){
|
404 |
$matchCaps = $pieces[0] . '/' . $pieces[1] . '/$1~$2~$3~$4';
|
@@ -448,8 +455,8 @@ class wfCache {
|
|
448 |
RewriteCond %{HTTP_COOKIE} !(comment_author|wp\-postpass|wf_logout|wordpress_logged_in|wptouch_switch_toggle|wpmp_switcher) [NC]
|
449 |
|
450 |
RewriteCond %{REQUEST_URI} \/*([^\/]*)\/*([^\/]*)\/*([^\/]*)\/*([^\/]*)\/*([^\/]*)(.*)$
|
451 |
-
RewriteCond "%{DOCUMENT_ROOT}{$pathPrefix}/wp-content/wfcache/%{HTTP_HOST}_%1/%2~%3~%4~%5~%6_wfcache%{WRDFNC_HTTPS}.html%{ENV:WRDFNC_ENC}" -f
|
452 |
-
RewriteRule \/*([^\/]*)\/*([^\/]*)\/*([^\/]*)\/*([^\/]*)\/*([^\/]*)(.*)$ "{$pathPrefix}/wp-content/wfcache/%{HTTP_HOST}_{$matchCaps}_wfcache%{WRDFNC_HTTPS}.html%{ENV:WRDFNC_ENC}" [L]
|
453 |
</IfModule>
|
454 |
#Do not remove this line. Disable Web caching in Wordfence to remove this data - WFCACHECODE
|
455 |
EOT;
|
@@ -479,6 +486,7 @@ EOT;
|
|
479 |
}
|
480 |
flock($fh, LOCK_EX);
|
481 |
fseek($fh, 0, SEEK_SET); //start of file
|
|
|
482 |
$contents = @fread($fh, filesize($htaccessPath));
|
483 |
if(! $contents){
|
484 |
fclose($fh);
|
@@ -556,6 +564,7 @@ EOT;
|
|
556 |
//Minimize time between lock/unlock
|
557 |
flock($fh, LOCK_EX);
|
558 |
fseek($fh, 0, SEEK_SET); //start of file
|
|
|
559 |
$contents = @fread($fh, filesize($htaccessPath));
|
560 |
if(! $contents){
|
561 |
fclose($fh);
|
369 |
}
|
370 |
flock($fh, LOCK_EX);
|
371 |
fseek($fh, 0, SEEK_SET); //start of file
|
372 |
+
clearstatcache();
|
373 |
$contents = fread($fh, filesize($htaccessPath));
|
374 |
if(! $contents){
|
375 |
fclose($fh);
|
389 |
}
|
390 |
public static function getHtaccessCode(){
|
391 |
$siteURL = site_url();
|
392 |
+
$homeURL = home_url();
|
393 |
$pathPrefix = "";
|
|
|
394 |
if(preg_match('/^https?:\/\/[^\/]+\/(.+)$/i', $siteURL, $matches)){
|
395 |
$path = $matches[1];
|
396 |
$path = preg_replace('/^\//', '', $path);
|
397 |
$path = preg_replace('/\/$/', '', $path);
|
|
|
398 |
$pathPrefix = '/' . $path; // Which is: /my/path
|
399 |
+
}
|
400 |
+
$matchCaps = '$1/$2~$3~$4~$5~$6';
|
401 |
+
if(preg_match('/^https?:\/\/[^\/]+\/(.+)$/i', $homeURL, $matches)){
|
402 |
+
$path = $matches[1];
|
403 |
+
$path = preg_replace('/^\//', '', $path);
|
404 |
+
$path = preg_replace('/\/$/', '', $path);
|
405 |
+
$pieces = explode('/', $path);
|
406 |
if(count($pieces) == 1){
|
407 |
+
# No path: "/wp-content/wfcache/%{HTTP_HOST}_$1/$2~$3~$4~$5~$6_wfcache%{ENV:WRDFNC_HTTPS}.html%{ENV:WRDFNC_ENC}" [L]
|
408 |
+
# One path: "/mdm/wp-content/wfcache/%{HTTP_HOST}_mdm/$1~$2~$3~$4~$5_wfcache%{ENV:WRDFNC_HTTPS}.html%{ENV:WRDFNC_ENC}" [L]
|
409 |
$matchCaps = $pieces[0] . '/$1~$2~$3~$4~$5';
|
410 |
} else if(count($pieces) == 2){
|
411 |
$matchCaps = $pieces[0] . '/' . $pieces[1] . '/$1~$2~$3~$4';
|
455 |
RewriteCond %{HTTP_COOKIE} !(comment_author|wp\-postpass|wf_logout|wordpress_logged_in|wptouch_switch_toggle|wpmp_switcher) [NC]
|
456 |
|
457 |
RewriteCond %{REQUEST_URI} \/*([^\/]*)\/*([^\/]*)\/*([^\/]*)\/*([^\/]*)\/*([^\/]*)(.*)$
|
458 |
+
RewriteCond "%{DOCUMENT_ROOT}{$pathPrefix}/wp-content/wfcache/%{HTTP_HOST}_%1/%2~%3~%4~%5~%6_wfcache%{ENV:WRDFNC_HTTPS}.html%{ENV:WRDFNC_ENC}" -f
|
459 |
+
RewriteRule \/*([^\/]*)\/*([^\/]*)\/*([^\/]*)\/*([^\/]*)\/*([^\/]*)(.*)$ "{$pathPrefix}/wp-content/wfcache/%{HTTP_HOST}_{$matchCaps}_wfcache%{ENV:WRDFNC_HTTPS}.html%{ENV:WRDFNC_ENC}" [L]
|
460 |
</IfModule>
|
461 |
#Do not remove this line. Disable Web caching in Wordfence to remove this data - WFCACHECODE
|
462 |
EOT;
|
486 |
}
|
487 |
flock($fh, LOCK_EX);
|
488 |
fseek($fh, 0, SEEK_SET); //start of file
|
489 |
+
clearstatcache();
|
490 |
$contents = @fread($fh, filesize($htaccessPath));
|
491 |
if(! $contents){
|
492 |
fclose($fh);
|
564 |
//Minimize time between lock/unlock
|
565 |
flock($fh, LOCK_EX);
|
566 |
fseek($fh, 0, SEEK_SET); //start of file
|
567 |
+
clearstatcache(); //Or we get the wrong size from a cached entry and corrupt the file
|
568 |
$contents = @fread($fh, filesize($htaccessPath));
|
569 |
if(! $contents){
|
570 |
fclose($fh);
|
lib/wfConfig.php
CHANGED
@@ -45,6 +45,7 @@ class wfConfig {
|
|
45 |
"loginSec_lockInvalidUsers" => false,
|
46 |
"loginSec_maskLoginErrors" => false,
|
47 |
"loginSec_blockAdminReg" => false,
|
|
|
48 |
"other_hideWPVersion" => false,
|
49 |
"other_noAnonMemberComments" => false,
|
50 |
"other_scanComments" => false,
|
@@ -119,6 +120,7 @@ class wfConfig {
|
|
119 |
"loginSec_lockInvalidUsers" => false,
|
120 |
"loginSec_maskLoginErrors" => true,
|
121 |
"loginSec_blockAdminReg" => true,
|
|
|
122 |
"other_hideWPVersion" => true,
|
123 |
"other_noAnonMemberComments" => true,
|
124 |
"other_scanComments" => true,
|
@@ -193,6 +195,7 @@ class wfConfig {
|
|
193 |
"loginSec_lockInvalidUsers" => false,
|
194 |
"loginSec_maskLoginErrors" => true,
|
195 |
"loginSec_blockAdminReg" => true,
|
|
|
196 |
"other_hideWPVersion" => true,
|
197 |
"other_noAnonMemberComments" => true,
|
198 |
"other_scanComments" => true,
|
@@ -267,6 +270,7 @@ class wfConfig {
|
|
267 |
"loginSec_lockInvalidUsers" => false,
|
268 |
"loginSec_maskLoginErrors" => true,
|
269 |
"loginSec_blockAdminReg" => true,
|
|
|
270 |
"other_hideWPVersion" => true,
|
271 |
"other_noAnonMemberComments" => true,
|
272 |
"other_scanComments" => true,
|
@@ -341,6 +345,7 @@ class wfConfig {
|
|
341 |
"loginSec_lockInvalidUsers" => true,
|
342 |
"loginSec_maskLoginErrors" => true,
|
343 |
"loginSec_blockAdminReg" => true,
|
|
|
344 |
"other_hideWPVersion" => true,
|
345 |
"other_noAnonMemberComments" => true,
|
346 |
"other_scanComments" => true,
|
45 |
"loginSec_lockInvalidUsers" => false,
|
46 |
"loginSec_maskLoginErrors" => false,
|
47 |
"loginSec_blockAdminReg" => false,
|
48 |
+
"loginSec_disableAuthorScan" => false,
|
49 |
"other_hideWPVersion" => false,
|
50 |
"other_noAnonMemberComments" => false,
|
51 |
"other_scanComments" => false,
|
120 |
"loginSec_lockInvalidUsers" => false,
|
121 |
"loginSec_maskLoginErrors" => true,
|
122 |
"loginSec_blockAdminReg" => true,
|
123 |
+
"loginSec_disableAuthorScan" => true,
|
124 |
"other_hideWPVersion" => true,
|
125 |
"other_noAnonMemberComments" => true,
|
126 |
"other_scanComments" => true,
|
195 |
"loginSec_lockInvalidUsers" => false,
|
196 |
"loginSec_maskLoginErrors" => true,
|
197 |
"loginSec_blockAdminReg" => true,
|
198 |
+
"loginSec_disableAuthorScan" => true,
|
199 |
"other_hideWPVersion" => true,
|
200 |
"other_noAnonMemberComments" => true,
|
201 |
"other_scanComments" => true,
|
270 |
"loginSec_lockInvalidUsers" => false,
|
271 |
"loginSec_maskLoginErrors" => true,
|
272 |
"loginSec_blockAdminReg" => true,
|
273 |
+
"loginSec_disableAuthorScan" => true,
|
274 |
"other_hideWPVersion" => true,
|
275 |
"other_noAnonMemberComments" => true,
|
276 |
"other_scanComments" => true,
|
345 |
"loginSec_lockInvalidUsers" => true,
|
346 |
"loginSec_maskLoginErrors" => true,
|
347 |
"loginSec_blockAdminReg" => true,
|
348 |
+
"loginSec_disableAuthorScan" => true,
|
349 |
"other_hideWPVersion" => true,
|
350 |
"other_noAnonMemberComments" => true,
|
351 |
"other_scanComments" => true,
|
lib/wfUtils.php
CHANGED
@@ -593,6 +593,13 @@ class wfUtils {
|
|
593 |
@setcookie($name, $value, $expire, $path);
|
594 |
}
|
595 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
596 |
}
|
597 |
|
598 |
|
593 |
@setcookie($name, $value, $expire, $path);
|
594 |
}
|
595 |
}
|
596 |
+
public static function isNginx(){
|
597 |
+
$sapi = php_sapi_name();
|
598 |
+
$serverSoft = $_SERVER['SERVER_SOFTWARE'];
|
599 |
+
if($sapi == 'fpm-fcgi' || stripos($serverSoft, 'nginx') !== false){
|
600 |
+
return true;
|
601 |
+
}
|
602 |
+
}
|
603 |
}
|
604 |
|
605 |
|
lib/wordfenceClass.php
CHANGED
@@ -72,8 +72,7 @@ class wordfence {
|
|
72 |
public static function hourlyCron(){
|
73 |
global $wpdb; $p = $wpdb->base_prefix;
|
74 |
$api = new wfAPI(wfConfig::get('apiKey'), wfUtils::getWPVersion());
|
75 |
-
|
76 |
-
|
77 |
if(wfConfig::get('other_WFNet')){
|
78 |
$wfdb = new wfDB();
|
79 |
$q1 = $wfdb->querySelect("select URI from $p"."wfNet404s where ctime > unix_timestamp() - 3600 limit 1000");
|
@@ -126,10 +125,43 @@ class wordfence {
|
|
126 |
}
|
127 |
}
|
128 |
}
|
|
|
|
|
|
|
129 |
public static function dailyCron(){
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
130 |
$wfdb = new wfDB();
|
131 |
global $wpdb; $p = $wpdb->base_prefix;
|
132 |
-
$api = new wfAPI(wfConfig::get('apiKey'), wfUtils::getWPVersion());
|
133 |
try {
|
134 |
$patData = $api->call('get_known_vuln_pattern');
|
135 |
if(is_array($patData) && $patData['pat']){
|
@@ -225,7 +257,7 @@ class wordfence {
|
|
225 |
}
|
226 |
wp_clear_scheduled_hook('wordfence_daily_cron');
|
227 |
wp_clear_scheduled_hook('wordfence_hourly_cron');
|
228 |
-
wp_schedule_event(time(), 'daily', 'wordfence_daily_cron');
|
229 |
wp_schedule_event(time(), 'hourly', 'wordfence_hourly_cron');
|
230 |
$db = new wfDB();
|
231 |
|
@@ -342,6 +374,10 @@ class wordfence {
|
|
342 |
add_action('validate_password_reset', 'wordfence::validatePassword', 10, 2 );
|
343 |
}
|
344 |
|
|
|
|
|
|
|
|
|
345 |
add_filter('pre_comment_approved', 'wordfence::preCommentApprovedFilter', '99', 2);
|
346 |
add_filter('authenticate', 'wordfence::authenticateFilter', 99, 3);
|
347 |
//html|xhtml|atom|rss2|rdf|comment|export
|
@@ -370,6 +406,21 @@ class wordfence {
|
|
370 |
}
|
371 |
}
|
372 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
373 |
public static function ajax_testAjax_callback(){
|
374 |
die("WFSCANTESTOK");
|
375 |
}
|
@@ -665,7 +716,7 @@ class wordfence {
|
|
665 |
public static function authenticateFilter($authResult){
|
666 |
$IP = wfUtils::getIP();
|
667 |
$secEnabled = wfConfig::get('loginSecurityEnabled');
|
668 |
-
if($secEnabled && (! self::getLog()->isWhitelisted($IP)) ){
|
669 |
$twoFactorUsers = wfConfig::get_ser('twoFactorUsers', array());
|
670 |
if(isset($twoFactorUsers) && is_array($twoFactorUsers) && sizeof($twoFactorUsers) > 0){
|
671 |
$userDat = $_POST['wordfence_userDat'];
|
@@ -678,6 +729,9 @@ class wordfence {
|
|
678 |
} else if($_POST['wordfence_authFactor'] == $t[2]){
|
679 |
$api = new wfAPI(wfConfig::get('apiKey'), wfUtils::getWPVersion());
|
680 |
$codeResult = $api->call('twoFactor_verification', array(), array('phone' => $t[1]) );
|
|
|
|
|
|
|
681 |
if(isset($codeResult['ok']) && $codeResult['ok']){
|
682 |
$t[2] = $codeResult['code'];
|
683 |
$t[4] = time() + 1800; //30 minutes until code expires
|
@@ -696,6 +750,10 @@ class wordfence {
|
|
696 |
if($t[0] == $userDat->ID && $t[3] == 'activated'){ //Yup, enabled, so lets send the code
|
697 |
$api = new wfAPI(wfConfig::get('apiKey'), wfUtils::getWPVersion());
|
698 |
$codeResult = $api->call('twoFactor_verification', array(), array('phone' => $t[1]) );
|
|
|
|
|
|
|
|
|
699 |
if(isset($codeResult['ok']) && $codeResult['ok']){
|
700 |
$t[2] = $codeResult['code'];
|
701 |
$t[4] = time() + 1800; //30 minutes until code expires
|
@@ -714,7 +772,7 @@ class wordfence {
|
|
714 |
if(self::getLog()->isWhitelisted($IP)){
|
715 |
return $authResult;
|
716 |
}
|
717 |
-
if(wfConfig::get('other_WFNet') && is_wp_error($authResult) && ($authResult->get_error_code() == 'invalid_username' || $authResult->get_error_code() == 'incorrect_password')
|
718 |
if($maxBlockTime = self::wfsnIsBlocked($IP, 'brute')){
|
719 |
self::getLog()->blockIP($IP, "Blocked by Wordfence Security Network", true, false, $maxBlockTime);
|
720 |
}
|
@@ -1374,6 +1432,9 @@ class wordfence {
|
|
1374 |
return array('ok' => 1);
|
1375 |
}
|
1376 |
public static function ajax_checkFalconHtaccess_callback(){
|
|
|
|
|
|
|
1377 |
$file = wfCache::getHtaccessPath();
|
1378 |
if(! $file){
|
1379 |
return array('err' => "We could not find your .htaccess file to modify it.", 'code' => wfCache::getHtaccessCode() );
|
@@ -1581,6 +1642,9 @@ class wordfence {
|
|
1581 |
} catch (Exception $e){
|
1582 |
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: " . htmlentities($e->getMessage()) );
|
1583 |
}
|
|
|
|
|
|
|
1584 |
}
|
1585 |
return array('ok' => 1, 'reload' => $reload, 'paidKeyMsg' => $paidKeyMsg );
|
1586 |
}
|
72 |
public static function hourlyCron(){
|
73 |
global $wpdb; $p = $wpdb->base_prefix;
|
74 |
$api = new wfAPI(wfConfig::get('apiKey'), wfUtils::getWPVersion());
|
75 |
+
|
|
|
76 |
if(wfConfig::get('other_WFNet')){
|
77 |
$wfdb = new wfDB();
|
78 |
$q1 = $wfdb->querySelect("select URI from $p"."wfNet404s where ctime > unix_timestamp() - 3600 limit 1000");
|
125 |
}
|
126 |
}
|
127 |
}
|
128 |
+
private function keyAlert($msg){
|
129 |
+
self::alert($msg, $msg . " To ensure uninterrupted Premium Wordfence protection on your site,\nplease renew your API key by visiting http://www.wordfence.com/ Sign in, go to your dashboard,\nselect the key about to expire and click the button to renew that API key.", false);
|
130 |
+
}
|
131 |
public static function dailyCron(){
|
132 |
+
$api = new wfAPI(wfConfig::get('apiKey'), wfUtils::getWPVersion());
|
133 |
+
$keyData = $api->call('ping_api_key');
|
134 |
+
if(isset($keyData['_isPaidKey']) && $keyData['_isPaidKey']){
|
135 |
+
$keyExpDays = $keyData['_keyExpDays'];
|
136 |
+
$keyIsExpired = $keyData['_expired'];
|
137 |
+
if($keyExpDays > 15){
|
138 |
+
wfConfig::set('keyExp15Sent', '');
|
139 |
+
wfConfig::set('keyExp7Sent', '');
|
140 |
+
wfConfig::set('keyExp2Sent', '');
|
141 |
+
wfConfig::set('keyExp1Sent', '');
|
142 |
+
wfConfig::set('keyExpFinalSent', '');
|
143 |
+
} else if($keyExpDays <= 15 && $keyExpDays > 0){
|
144 |
+
if($keyExpDays <= 15 && $keyExpDays >= 11 && (! wfConfig::get('keyExp15Sent'))){
|
145 |
+
wfConfig::set('keyExp15Sent', 1);
|
146 |
+
self::keyAlert("Your Premium Wordfence API Key expires in less than 2 weeks.");
|
147 |
+
} else if($keyExpDays <= 7 && $keyExpDays >= 4 && (! wfConfig::get('keyExp7Sent'))){
|
148 |
+
wfConfig::set('keyExp7Sent', 1);
|
149 |
+
self::keyAlert("Your Premium Wordfence API Key expires in less than a week.");
|
150 |
+
} else if($keyExpDays == 2 && (! wfConfig::get('keyExp2Sent'))){
|
151 |
+
wfConfig::set('keyExp2Sent', 1);
|
152 |
+
self::keyAlert("Your Premium Wordfence API Key expires in 2 days.");
|
153 |
+
} else if($keyExpDays == 1 && (! wfConfig::get('keyExp1Sent'))){
|
154 |
+
wfConfig::set('keyExp1Sent', 1);
|
155 |
+
self::keyAlert("Your Premium Wordfence API Key expires in 1 day.");
|
156 |
+
}
|
157 |
+
} else if($keyIsExpired && (! wfConfig::get('keyExpFinalSent')) ){
|
158 |
+
wfConfig::set('keyExpFinalSent', 1);
|
159 |
+
self::keyAlert("Your Wordfence Premium API Key has Expired!");
|
160 |
+
}
|
161 |
+
}
|
162 |
+
|
163 |
$wfdb = new wfDB();
|
164 |
global $wpdb; $p = $wpdb->base_prefix;
|
|
|
165 |
try {
|
166 |
$patData = $api->call('get_known_vuln_pattern');
|
167 |
if(is_array($patData) && $patData['pat']){
|
257 |
}
|
258 |
wp_clear_scheduled_hook('wordfence_daily_cron');
|
259 |
wp_clear_scheduled_hook('wordfence_hourly_cron');
|
260 |
+
wp_schedule_event(time(), 'daily', 'wordfence_daily_cron'); //'daily'
|
261 |
wp_schedule_event(time(), 'hourly', 'wordfence_hourly_cron');
|
262 |
$db = new wfDB();
|
263 |
|
374 |
add_action('validate_password_reset', 'wordfence::validatePassword', 10, 2 );
|
375 |
}
|
376 |
|
377 |
+
//For debugging
|
378 |
+
//add_filter( 'cron_schedules', 'wordfence::cronAddSchedules' );
|
379 |
+
|
380 |
+
add_filter('wp_redirect', 'wordfence::wpRedirectFilter', 99, 2);
|
381 |
add_filter('pre_comment_approved', 'wordfence::preCommentApprovedFilter', '99', 2);
|
382 |
add_filter('authenticate', 'wordfence::authenticateFilter', 99, 3);
|
383 |
//html|xhtml|atom|rss2|rdf|comment|export
|
406 |
}
|
407 |
}
|
408 |
}
|
409 |
+
/* For debugging:
|
410 |
+
public static function cronAddSchedules($schedules){
|
411 |
+
$schedules['wfEachMinute'] = array(
|
412 |
+
'interval' => 60,
|
413 |
+
'display' => __( 'Once a Minute' )
|
414 |
+
);
|
415 |
+
return $schedules;
|
416 |
+
}
|
417 |
+
*/
|
418 |
+
public static function wpRedirectFilter($URL, $status){
|
419 |
+
if(isset($_GET['author']) && preg_match('/^https?:\/\/[^\/]+\/author\/.+/i', $URL) && wfConfig::get('loginSec_disableAuthorScan') ){ //author query variable is present and we're about to redirect to a URL that starts with http://blah/author/...
|
420 |
+
return home_url(); //Send the user to the home URL (as opposed to site_url() which is not the home page on some sites)
|
421 |
+
}
|
422 |
+
return $URL;
|
423 |
+
}
|
424 |
public static function ajax_testAjax_callback(){
|
425 |
die("WFSCANTESTOK");
|
426 |
}
|
716 |
public static function authenticateFilter($authResult){
|
717 |
$IP = wfUtils::getIP();
|
718 |
$secEnabled = wfConfig::get('loginSecurityEnabled');
|
719 |
+
if($secEnabled && (! self::getLog()->isWhitelisted($IP)) && wfConfig::get('isPaid') ){
|
720 |
$twoFactorUsers = wfConfig::get_ser('twoFactorUsers', array());
|
721 |
if(isset($twoFactorUsers) && is_array($twoFactorUsers) && sizeof($twoFactorUsers) > 0){
|
722 |
$userDat = $_POST['wordfence_userDat'];
|
729 |
} else if($_POST['wordfence_authFactor'] == $t[2]){
|
730 |
$api = new wfAPI(wfConfig::get('apiKey'), wfUtils::getWPVersion());
|
731 |
$codeResult = $api->call('twoFactor_verification', array(), array('phone' => $t[1]) );
|
732 |
+
if(isset($codeResult['notPaid']) && $codeResult['notPaid']){
|
733 |
+
break; //Let them sign in without two factor
|
734 |
+
}
|
735 |
if(isset($codeResult['ok']) && $codeResult['ok']){
|
736 |
$t[2] = $codeResult['code'];
|
737 |
$t[4] = time() + 1800; //30 minutes until code expires
|
750 |
if($t[0] == $userDat->ID && $t[3] == 'activated'){ //Yup, enabled, so lets send the code
|
751 |
$api = new wfAPI(wfConfig::get('apiKey'), wfUtils::getWPVersion());
|
752 |
$codeResult = $api->call('twoFactor_verification', array(), array('phone' => $t[1]) );
|
753 |
+
if(isset($codeResult['notPaid']) && $codeResult['notPaid']){
|
754 |
+
break; //Let them sign in without two factor if their API key has expired or they're not paid and for some reason they have this set up.
|
755 |
+
}
|
756 |
+
|
757 |
if(isset($codeResult['ok']) && $codeResult['ok']){
|
758 |
$t[2] = $codeResult['code'];
|
759 |
$t[4] = time() + 1800; //30 minutes until code expires
|
772 |
if(self::getLog()->isWhitelisted($IP)){
|
773 |
return $authResult;
|
774 |
}
|
775 |
+
if(wfConfig::get('other_WFNet') && is_wp_error($authResult) && ($authResult->get_error_code() == 'invalid_username' || $authResult->get_error_code() == 'incorrect_password') ){
|
776 |
if($maxBlockTime = self::wfsnIsBlocked($IP, 'brute')){
|
777 |
self::getLog()->blockIP($IP, "Blocked by Wordfence Security Network", true, false, $maxBlockTime);
|
778 |
}
|
1432 |
return array('ok' => 1);
|
1433 |
}
|
1434 |
public static function ajax_checkFalconHtaccess_callback(){
|
1435 |
+
if(wfUtils::isNginx()){
|
1436 |
+
return array('nginx' => 1);
|
1437 |
+
}
|
1438 |
$file = wfCache::getHtaccessPath();
|
1439 |
if(! $file){
|
1440 |
return array('err' => "We could not find your .htaccess file to modify it.", 'code' => wfCache::getHtaccessCode() );
|
1642 |
} catch (Exception $e){
|
1643 |
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: " . htmlentities($e->getMessage()) );
|
1644 |
}
|
1645 |
+
} else {
|
1646 |
+
$api = new wfAPI($opts['apiKey'], wfUtils::getWPVersion());
|
1647 |
+
$res = $api->call('ping_api_key', array(), array());
|
1648 |
}
|
1649 |
return array('ok' => 1, 'reload' => $reload, 'paidKeyMsg' => $paidKeyMsg );
|
1650 |
}
|
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.10');
|
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/wordfenceHash.php
CHANGED
@@ -1,7 +1,6 @@
|
|
1 |
<?php
|
2 |
require_once('wordfenceClass.php');
|
3 |
class wordfenceHash {
|
4 |
-
private $whitespace = array("\n","\r","\t"," ");
|
5 |
private $engine = false;
|
6 |
private $db = false;
|
7 |
private $startTime = false;
|
@@ -213,7 +212,7 @@ class wordfenceHash {
|
|
213 |
} else {
|
214 |
wordfence::status(4, 'info', "Scanning: $realFile");
|
215 |
}
|
216 |
-
$wfHash =
|
217 |
if($wfHash){
|
218 |
$md5 = strtoupper($wfHash[0]);
|
219 |
$shac = strtoupper($wfHash[1]);
|
@@ -228,55 +227,59 @@ class wordfenceHash {
|
|
228 |
if($this->coreEnabled){
|
229 |
$localFile = ABSPATH . '/' . preg_replace('/^[\.\/]+/', '', $file);
|
230 |
$fileContents = @file_get_contents($localFile);
|
231 |
-
if($fileContents && (! preg_match('/<\?' . 'php[\r\n\s\t]*\/\/[\r\n\s\t]*Silence is golden\.[\r\n\s\t]*(?:\?>)?[\r\n\s\t]*$/s', $fileContents))){
|
232 |
-
|
233 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
234 |
$this->engine->addIssue(
|
235 |
'file',
|
236 |
-
|
237 |
-
'
|
238 |
-
'
|
239 |
-
'
|
240 |
-
"This
|
241 |
array(
|
242 |
'file' => $file,
|
243 |
-
'cType' => '
|
244 |
'canDiff' => true,
|
245 |
'canFix' => true,
|
246 |
-
'canDelete' => false
|
|
|
|
|
|
|
247 |
)
|
248 |
);
|
249 |
}
|
250 |
}
|
251 |
-
}
|
252 |
-
} else if(isset($this->knownFiles['plugins'][$file])){
|
253 |
-
if(in_array($shac, $this->knownFiles['plugins'][$file])){
|
254 |
-
$knownFile = 1;
|
255 |
-
} else {
|
256 |
-
if($this->pluginsEnabled){
|
257 |
-
$itemName = $this->knownFiles['plugins'][$file][0];
|
258 |
-
$itemVersion = $this->knownFiles['plugins'][$file][1];
|
259 |
-
$cKey = $this->knownFiles['plugins'][$file][2];
|
260 |
-
$this->haveIssues['plugins'] = true;
|
261 |
-
$this->engine->addIssue(
|
262 |
-
'file',
|
263 |
-
2,
|
264 |
-
'modifiedplugin' . $file . $md5,
|
265 |
-
'modifiedplugin' . $file,
|
266 |
-
'Modified plugin file: ' . $file,
|
267 |
-
"This file belongs to plugin \"$itemName\" version \"$itemVersion\" and has been modified from the file that is distributed by WordPress.org for this version. Please use the link to see how the file has changed. If you have modified this file yourself, you can safely ignore this warning. If you see a lot of changed files in a plugin that have been made by the author, then try uninstalling and reinstalling the plugin to force an upgrade. Doing this is a workaround for plugin authors who don't manage their code correctly. [See our FAQ on www.wordfence.com for more info]",
|
268 |
-
array(
|
269 |
-
'file' => $file,
|
270 |
-
'cType' => 'plugin',
|
271 |
-
'canDiff' => true,
|
272 |
-
'canFix' => true,
|
273 |
-
'canDelete' => false,
|
274 |
-
'cName' => $itemName,
|
275 |
-
'cVersion' => $itemVersion,
|
276 |
-
'cKey' => $cKey
|
277 |
-
)
|
278 |
-
);
|
279 |
-
}
|
280 |
|
281 |
}
|
282 |
} else if(isset($this->knownFiles['themes'][$file])){
|
@@ -284,28 +287,30 @@ class wordfenceHash {
|
|
284 |
$knownFile = 1;
|
285 |
} else {
|
286 |
if($this->themesEnabled){
|
287 |
-
|
288 |
-
|
289 |
-
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
|
304 |
-
|
305 |
-
|
306 |
-
|
307 |
-
|
308 |
-
|
|
|
|
|
309 |
}
|
310 |
|
311 |
}
|
@@ -330,7 +335,7 @@ class wordfenceHash {
|
|
330 |
//wordfence::status(2, 'error', "Could not gen hash for file (probably because we don't have permission to access the file): $realFile");
|
331 |
}
|
332 |
}
|
333 |
-
public function wfHash($file){
|
334 |
wfUtils::errorsOff();
|
335 |
$md5 = @md5_file($file, false);
|
336 |
wfUtils::errorsOn();
|
@@ -342,7 +347,7 @@ class wordfenceHash {
|
|
342 |
}
|
343 |
$ctx = hash_init('sha256');
|
344 |
while (!feof($fp)) {
|
345 |
-
hash_update($ctx, str_replace(
|
346 |
}
|
347 |
$shac = hash_final($ctx, false);
|
348 |
return array($md5, $shac);
|
@@ -354,5 +359,12 @@ class wordfenceHash {
|
|
354 |
}
|
355 |
return false;
|
356 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
357 |
}
|
358 |
?>
|
1 |
<?php
|
2 |
require_once('wordfenceClass.php');
|
3 |
class wordfenceHash {
|
|
|
4 |
private $engine = false;
|
5 |
private $db = false;
|
6 |
private $startTime = false;
|
212 |
} else {
|
213 |
wordfence::status(4, 'info', "Scanning: $realFile");
|
214 |
}
|
215 |
+
$wfHash = self::wfHash($realFile);
|
216 |
if($wfHash){
|
217 |
$md5 = strtoupper($wfHash[0]);
|
218 |
$shac = strtoupper($wfHash[1]);
|
227 |
if($this->coreEnabled){
|
228 |
$localFile = ABSPATH . '/' . preg_replace('/^[\.\/]+/', '', $file);
|
229 |
$fileContents = @file_get_contents($localFile);
|
230 |
+
if($fileContents && (! preg_match('/<\?' . 'php[\r\n\s\t]*\/\/[\r\n\s\t]*Silence is golden\.[\r\n\s\t]*(?:\?>)?[\r\n\s\t]*$/s', $fileContents))){ //<?php
|
231 |
+
if(! $this->isSafeFile($shac)){
|
232 |
+
|
233 |
+
$this->haveIssues['core'] = true;
|
234 |
+
$this->engine->addIssue(
|
235 |
+
'file',
|
236 |
+
1,
|
237 |
+
'coreModified' . $file . $md5,
|
238 |
+
'coreModified' . $file,
|
239 |
+
'WordPress core file modified: ' . $file,
|
240 |
+
"This WordPress core file has been modified and differs from the original file distributed with this version of WordPress.",
|
241 |
+
array(
|
242 |
+
'file' => $file,
|
243 |
+
'cType' => 'core',
|
244 |
+
'canDiff' => true,
|
245 |
+
'canFix' => true,
|
246 |
+
'canDelete' => false
|
247 |
+
)
|
248 |
+
);
|
249 |
+
}
|
250 |
+
}
|
251 |
+
}
|
252 |
+
}
|
253 |
+
} else if(isset($this->knownFiles['plugins'][$file])){
|
254 |
+
if(in_array($shac, $this->knownFiles['plugins'][$file])){
|
255 |
+
$knownFile = 1;
|
256 |
+
} else {
|
257 |
+
if($this->pluginsEnabled){
|
258 |
+
if(! $this->isSafeFile($shac)){
|
259 |
+
$itemName = $this->knownFiles['plugins'][$file][0];
|
260 |
+
$itemVersion = $this->knownFiles['plugins'][$file][1];
|
261 |
+
$cKey = $this->knownFiles['plugins'][$file][2];
|
262 |
+
$this->haveIssues['plugins'] = true;
|
263 |
$this->engine->addIssue(
|
264 |
'file',
|
265 |
+
2,
|
266 |
+
'modifiedplugin' . $file . $md5,
|
267 |
+
'modifiedplugin' . $file,
|
268 |
+
'Modified plugin file: ' . $file,
|
269 |
+
"This file belongs to plugin \"$itemName\" version \"$itemVersion\" and has been modified from the file that is distributed by WordPress.org for this version. Please use the link to see how the file has changed. If you have modified this file yourself, you can safely ignore this warning. If you see a lot of changed files in a plugin that have been made by the author, then try uninstalling and reinstalling the plugin to force an upgrade. Doing this is a workaround for plugin authors who don't manage their code correctly. [See our FAQ on www.wordfence.com for more info]",
|
270 |
array(
|
271 |
'file' => $file,
|
272 |
+
'cType' => 'plugin',
|
273 |
'canDiff' => true,
|
274 |
'canFix' => true,
|
275 |
+
'canDelete' => false,
|
276 |
+
'cName' => $itemName,
|
277 |
+
'cVersion' => $itemVersion,
|
278 |
+
'cKey' => $cKey
|
279 |
)
|
280 |
);
|
281 |
}
|
282 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
283 |
|
284 |
}
|
285 |
} else if(isset($this->knownFiles['themes'][$file])){
|
287 |
$knownFile = 1;
|
288 |
} else {
|
289 |
if($this->themesEnabled){
|
290 |
+
if(! $this->isSafeFile($shac)){
|
291 |
+
$itemName = $this->knownFiles['themes'][$file][0];
|
292 |
+
$itemVersion = $this->knownFiles['themes'][$file][1];
|
293 |
+
$cKey = $this->knownFiles['themes'][$file][2];
|
294 |
+
$this->haveIssues['themes'] = true;
|
295 |
+
$this->engine->addIssue(
|
296 |
+
'file',
|
297 |
+
2,
|
298 |
+
'modifiedtheme' . $file . $md5,
|
299 |
+
'modifiedtheme' . $file,
|
300 |
+
'Modified theme file: ' . $file,
|
301 |
+
"This file belongs to theme \"$itemName\" version \"$itemVersion\" and has been modified from the original distribution. It is common for site owners to modify their theme files, so if you have modified this file yourself you can safely ignore this warning.",
|
302 |
+
array(
|
303 |
+
'file' => $file,
|
304 |
+
'cType' => 'theme',
|
305 |
+
'canDiff' => true,
|
306 |
+
'canFix' => true,
|
307 |
+
'canDelete' => false,
|
308 |
+
'cName' => $itemName,
|
309 |
+
'cVersion' => $itemVersion,
|
310 |
+
'cKey' => $cKey
|
311 |
+
)
|
312 |
+
);
|
313 |
+
}
|
314 |
}
|
315 |
|
316 |
}
|
335 |
//wordfence::status(2, 'error', "Could not gen hash for file (probably because we don't have permission to access the file): $realFile");
|
336 |
}
|
337 |
}
|
338 |
+
public static function wfHash($file){
|
339 |
wfUtils::errorsOff();
|
340 |
$md5 = @md5_file($file, false);
|
341 |
wfUtils::errorsOn();
|
347 |
}
|
348 |
$ctx = hash_init('sha256');
|
349 |
while (!feof($fp)) {
|
350 |
+
hash_update($ctx, str_replace( array("\n","\r","\t"," ") ,"",fread($fp, 65536)));
|
351 |
}
|
352 |
$shac = hash_final($ctx, false);
|
353 |
return array($md5, $shac);
|
359 |
}
|
360 |
return false;
|
361 |
}
|
362 |
+
private function isSafeFile($shac){
|
363 |
+
$result = $this->engine->api->call('is_safe_file', array(), array('shac' => strtoupper($shac)));
|
364 |
+
if(isset($result['isSafe']) && $result['isSafe'] == 1){
|
365 |
+
return true;
|
366 |
+
}
|
367 |
+
return false;
|
368 |
+
}
|
369 |
}
|
370 |
?>
|
lib/wordfenceScanner.php
CHANGED
@@ -13,6 +13,7 @@ class wordfenceScanner {
|
|
13 |
private $startTime = false;
|
14 |
private $lastStatusTime = false;
|
15 |
private $patterns = "";
|
|
|
16 |
public function __sleep(){
|
17 |
return array('path', 'results', 'errorMsg', 'apiKey', 'wordpressVersion', 'urlHoover', 'totalFilesScanned', 'startTime', 'lastStatusTime', 'patterns');
|
18 |
}
|
@@ -132,94 +133,52 @@ class wordfenceScanner {
|
|
132 |
}
|
133 |
if($isPHP || wfConfig::get('scansEnabled_scanImages') ){
|
134 |
if(strpos($data, '$allowed'.'Sites') !== false && strpos($data, "define ('VER"."SION', '1.") !== false && strpos($data, "TimThum"."b script created by") !== false){
|
135 |
-
$this->
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
'
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
|
|
|
|
150 |
} else if(strpos($file, 'lib/wordfenceScanner.php') === false && preg_match($this->patterns['sigPattern'], $data, $matches)){
|
151 |
-
$this->
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
'
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
|
|
|
|
166 |
|
167 |
}
|
168 |
-
/*
|
169 |
-
$longestNospace = wfUtils::longestNospace($data);
|
170 |
-
if($longestNospace > 1000 && (strpos($data, $this->patterns['pat1']) !== false || preg_match('/preg_replace\([^\(]+\/[a-z]*e/', $data)) ){
|
171 |
-
$this->addResult(array(
|
172 |
-
'type' => 'file',
|
173 |
-
'severity' => 1,
|
174 |
-
'ignoreP' => $this->path . $file,
|
175 |
-
'ignoreC' => $fileSum,
|
176 |
-
'shortMsg' => "This file may contain malicious executable code",
|
177 |
-
'longMsg' => "This file is a PHP executable file and contains a line $longestNospace characters long without spaces that may be encoded data along with functions that may be used to execute that code. If you know about this file you can choose to ignore it to exclude it from future scans.",
|
178 |
-
'data' => array(
|
179 |
-
'file' => $file,
|
180 |
-
'canDiff' => false,
|
181 |
-
'canFix' => false,
|
182 |
-
'canDelete' => true
|
183 |
-
)
|
184 |
-
));
|
185 |
-
break;
|
186 |
-
}
|
187 |
-
*/
|
188 |
if(preg_match($this->patterns['pat2'], $data)){
|
189 |
-
$this->
|
190 |
-
'type' => 'file',
|
191 |
-
'severity' => 1,
|
192 |
-
'ignoreP' => $this->path . $file,
|
193 |
-
'ignoreC' => $fileSum,
|
194 |
-
'shortMsg' => "This file may contain malicious executable code",
|
195 |
-
'longMsg' => "This file is a PHP executable file and contains an " . $this->patterns['word1'] . " function and " . $this->patterns['word2'] . " decoding function on the same line. This is a common technique used by hackers to hide and execute code. If you know about this file you can choose to ignore it to exclude it from future scans.",
|
196 |
-
'data' => array(
|
197 |
-
'file' => $file,
|
198 |
-
'canDiff' => false,
|
199 |
-
'canFix' => false,
|
200 |
-
'canDelete' => true
|
201 |
-
)
|
202 |
-
));
|
203 |
-
break;
|
204 |
-
}
|
205 |
-
if(wfConfig::get('scansEnabled_highSense')){
|
206 |
-
$badStringFound = false;
|
207 |
-
if(strpos($data, $this->patterns['badstrings'][0]) !== false){
|
208 |
-
for($i = 1; $i < sizeof($this->patterns['badstrings']); $i++){
|
209 |
-
if(strpos($data, $this->patterns['badstrings'][$i]) !== false){
|
210 |
-
$badStringFound = $this->patterns['badstrings'][$i];
|
211 |
-
break;
|
212 |
-
}
|
213 |
-
}
|
214 |
-
}
|
215 |
-
if($badStringFound){
|
216 |
$this->addResult(array(
|
217 |
'type' => 'file',
|
218 |
'severity' => 1,
|
219 |
'ignoreP' => $this->path . $file,
|
220 |
'ignoreC' => $fileSum,
|
221 |
'shortMsg' => "This file may contain malicious executable code",
|
222 |
-
'longMsg' => "This file is a PHP executable file and contains
|
223 |
'data' => array(
|
224 |
'file' => $file,
|
225 |
'canDiff' => false,
|
@@ -230,6 +189,36 @@ class wordfenceScanner {
|
|
230 |
break;
|
231 |
}
|
232 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
233 |
if(! $dontScanForURLs){
|
234 |
$this->urlHoover->hoover($file, $data);
|
235 |
}
|
@@ -267,39 +256,43 @@ class wordfenceScanner {
|
|
267 |
continue;
|
268 |
}
|
269 |
if($result['badList'] == 'goog-malware-shavar'){
|
270 |
-
$this->
|
271 |
-
|
272 |
-
|
273 |
-
|
274 |
-
|
275 |
-
|
276 |
-
|
277 |
-
|
278 |
-
'
|
279 |
-
|
280 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
|
|
|
|
|
286 |
} else if($result['badList'] == 'googpub-phish-shavar'){
|
287 |
-
$this->
|
288 |
-
|
289 |
-
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
-
'
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
|
|
|
|
303 |
}
|
304 |
}
|
305 |
}
|
@@ -309,23 +302,6 @@ class wordfenceScanner {
|
|
309 |
private function writeScanningStatus(){
|
310 |
wordfence::status(2, 'info', "Scanned contents of " . $this->totalFilesScanned . " additional files at " . sprintf('%.2f', ($this->totalFilesScanned / (microtime(true) - $this->startTime))) . " per second");
|
311 |
}
|
312 |
-
private function addEncIssue($ignoreP, $ignoreC, $encoding, $file){
|
313 |
-
$this->addResult(array(
|
314 |
-
'type' => 'file',
|
315 |
-
'severity' => 1,
|
316 |
-
'ignoreP' => $ignoreP,
|
317 |
-
'ignoreC' => $ignoreC,
|
318 |
-
'shortMsg' => "File contains $encoding encoded programming language: " . $file,
|
319 |
-
'longMsg' => "This file contains programming language code that has been encoded using $encoding. This is often used by hackers to hide their tracks.",
|
320 |
-
'data' => array(
|
321 |
-
'file' => $file,
|
322 |
-
'canDiff' => false,
|
323 |
-
'canFix' => false,
|
324 |
-
'canDelete' => true
|
325 |
-
)
|
326 |
-
));
|
327 |
-
|
328 |
-
}
|
329 |
public static function containsCode($arr){
|
330 |
foreach($arr as $elem){
|
331 |
if(preg_match($this->patterns['pat3'], $elem)){
|
@@ -351,6 +327,18 @@ class wordfenceScanner {
|
|
351 |
//We don't have a results for this file so append
|
352 |
$this->results[] = $result;
|
353 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
354 |
}
|
355 |
|
356 |
?>
|
13 |
private $startTime = false;
|
14 |
private $lastStatusTime = false;
|
15 |
private $patterns = "";
|
16 |
+
private $api = false;
|
17 |
public function __sleep(){
|
18 |
return array('path', 'results', 'errorMsg', 'apiKey', 'wordpressVersion', 'urlHoover', 'totalFilesScanned', 'startTime', 'lastStatusTime', 'patterns');
|
19 |
}
|
133 |
}
|
134 |
if($isPHP || wfConfig::get('scansEnabled_scanImages') ){
|
135 |
if(strpos($data, '$allowed'.'Sites') !== false && strpos($data, "define ('VER"."SION', '1.") !== false && strpos($data, "TimThum"."b script created by") !== false){
|
136 |
+
if(! $this->isSafeFile($this->path . $file)){
|
137 |
+
$this->addResult(array(
|
138 |
+
'type' => 'file',
|
139 |
+
'severity' => 1,
|
140 |
+
'ignoreP' => $this->path . $file,
|
141 |
+
'ignoreC' => $fileSum,
|
142 |
+
'shortMsg' => "File is an old version of TimThumb which is vulnerable.",
|
143 |
+
'longMsg' => "This file appears to be an old version of the TimThumb script which makes your system vulnerable to attackers. Please upgrade the theme or plugin that uses this or remove it.",
|
144 |
+
'data' => array(
|
145 |
+
'file' => $file,
|
146 |
+
'canDiff' => false,
|
147 |
+
'canFix' => false,
|
148 |
+
'canDelete' => true
|
149 |
+
)
|
150 |
+
));
|
151 |
+
break;
|
152 |
+
}
|
153 |
} else if(strpos($file, 'lib/wordfenceScanner.php') === false && preg_match($this->patterns['sigPattern'], $data, $matches)){
|
154 |
+
if(! $this->isSafeFile($this->path . $file)){
|
155 |
+
$this->addResult(array(
|
156 |
+
'type' => 'file',
|
157 |
+
'severity' => 1,
|
158 |
+
'ignoreP' => $this->path . $file,
|
159 |
+
'ignoreC' => $fileSum,
|
160 |
+
'shortMsg' => "This file appears to be malicious",
|
161 |
+
'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>.",
|
162 |
+
'data' => array(
|
163 |
+
'file' => $file,
|
164 |
+
'canDiff' => false,
|
165 |
+
'canFix' => false,
|
166 |
+
'canDelete' => true
|
167 |
+
)
|
168 |
+
));
|
169 |
+
break;
|
170 |
+
}
|
171 |
|
172 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
173 |
if(preg_match($this->patterns['pat2'], $data)){
|
174 |
+
if(! $this->isSafeFile($this->path . $file)){
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
175 |
$this->addResult(array(
|
176 |
'type' => 'file',
|
177 |
'severity' => 1,
|
178 |
'ignoreP' => $this->path . $file,
|
179 |
'ignoreC' => $fileSum,
|
180 |
'shortMsg' => "This file may contain malicious executable code",
|
181 |
+
'longMsg' => "This file is a PHP executable file and contains an " . $this->patterns['word1'] . " function and " . $this->patterns['word2'] . " decoding function on the same line. This is a common technique used by hackers to hide and execute code. If you know about this file you can choose to ignore it to exclude it from future scans.",
|
182 |
'data' => array(
|
183 |
'file' => $file,
|
184 |
'canDiff' => false,
|
189 |
break;
|
190 |
}
|
191 |
}
|
192 |
+
if(wfConfig::get('scansEnabled_highSense')){
|
193 |
+
$badStringFound = false;
|
194 |
+
if(strpos($data, $this->patterns['badstrings'][0]) !== false){
|
195 |
+
for($i = 1; $i < sizeof($this->patterns['badstrings']); $i++){
|
196 |
+
if(strpos($data, $this->patterns['badstrings'][$i]) !== false){
|
197 |
+
$badStringFound = $this->patterns['badstrings'][$i];
|
198 |
+
break;
|
199 |
+
}
|
200 |
+
}
|
201 |
+
}
|
202 |
+
if($badStringFound){
|
203 |
+
if(! $this->isSafeFile($this->path . $file)){
|
204 |
+
$this->addResult(array(
|
205 |
+
'type' => 'file',
|
206 |
+
'severity' => 1,
|
207 |
+
'ignoreP' => $this->path . $file,
|
208 |
+
'ignoreC' => $fileSum,
|
209 |
+
'shortMsg' => "This file may contain malicious executable code",
|
210 |
+
'longMsg' => "This file is a PHP executable file and contains the word 'eval' (without quotes) and the word '" . $badStringFound . "' (without quotes). The eval() function along with an encoding function like the one mentioned are commonly used by hackers to hide their code. If you know about this file you can choose to ignore it to exclude it from future scans.",
|
211 |
+
'data' => array(
|
212 |
+
'file' => $file,
|
213 |
+
'canDiff' => false,
|
214 |
+
'canFix' => false,
|
215 |
+
'canDelete' => true
|
216 |
+
)
|
217 |
+
));
|
218 |
+
break;
|
219 |
+
}
|
220 |
+
}
|
221 |
+
}
|
222 |
if(! $dontScanForURLs){
|
223 |
$this->urlHoover->hoover($file, $data);
|
224 |
}
|
256 |
continue;
|
257 |
}
|
258 |
if($result['badList'] == 'goog-malware-shavar'){
|
259 |
+
if(! $this->isSafeFile($this->path . $file)){
|
260 |
+
$this->addResult(array(
|
261 |
+
'type' => 'file',
|
262 |
+
'severity' => 1,
|
263 |
+
'ignoreP' => $this->path . $file,
|
264 |
+
'ignoreC' => md5_file($this->path . $file),
|
265 |
+
'shortMsg' => "File contains suspected malware URL: " . $this->path . $file,
|
266 |
+
'longMsg' => "This file contains a suspected malware URL listed on Google's list of malware sites. Wordfence decodes " . $this->patterns['word3'] . " when scanning files so the URL may not be visible if you view this file. The URL is: " . $result['URL'] . " - More info available at <a href=\"http://safebrowsing.clients.google.com/safebrowsing/diagnostic?site=" . urlencode($result['URL']) . "&client=googlechrome&hl=en-US\" target=\"_blank\">Google Safe Browsing diagnostic page</a>.",
|
267 |
+
'data' => array(
|
268 |
+
'file' => $file,
|
269 |
+
'badURL' => $result['URL'],
|
270 |
+
'canDiff' => false,
|
271 |
+
'canFix' => false,
|
272 |
+
'canDelete' => true,
|
273 |
+
'gsb' => 'goog-malware-shavar'
|
274 |
+
)
|
275 |
+
));
|
276 |
+
}
|
277 |
} else if($result['badList'] == 'googpub-phish-shavar'){
|
278 |
+
if(! $this->isSafeFile($this->path . $file)){
|
279 |
+
$this->addResult(array(
|
280 |
+
'type' => 'file',
|
281 |
+
'severity' => 1,
|
282 |
+
'ignoreP' => $this->path . $file,
|
283 |
+
'ignoreC' => md5_file($this->path . $file),
|
284 |
+
'shortMsg' => "File contains suspected phishing URL: " . $this->path . $file,
|
285 |
+
'longMsg' => "This file contains a URL that is a suspected phishing site that is currently listed on Google's list of known phishing sites. The URL is: " . $result['URL'],
|
286 |
+
'data' => array(
|
287 |
+
'file' => $file,
|
288 |
+
'badURL' => $result['URL'],
|
289 |
+
'canDiff' => false,
|
290 |
+
'canFix' => false,
|
291 |
+
'canDelete' => true,
|
292 |
+
'gsb' => 'googpub-phish-shavar'
|
293 |
+
)
|
294 |
+
));
|
295 |
+
}
|
296 |
}
|
297 |
}
|
298 |
}
|
302 |
private function writeScanningStatus(){
|
303 |
wordfence::status(2, 'info', "Scanned contents of " . $this->totalFilesScanned . " additional files at " . sprintf('%.2f', ($this->totalFilesScanned / (microtime(true) - $this->startTime))) . " per second");
|
304 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
305 |
public static function containsCode($arr){
|
306 |
foreach($arr as $elem){
|
307 |
if(preg_match($this->patterns['pat3'], $elem)){
|
327 |
//We don't have a results for this file so append
|
328 |
$this->results[] = $result;
|
329 |
}
|
330 |
+
private function isSafeFile($file){
|
331 |
+
if(! $this->api){
|
332 |
+
$this->api = new wfAPI($this->apiKey, $this->wordpressVersion);
|
333 |
+
}
|
334 |
+
|
335 |
+
$wfHash = wordfenceHash::wfHash($file);
|
336 |
+
$result = $this->api->call('is_safe_file', array(), array('shac' => strtoupper($wfHash[1])));
|
337 |
+
if(isset($result['isSafe']) && $result['isSafe'] == 1){
|
338 |
+
return true;
|
339 |
+
}
|
340 |
+
return false;
|
341 |
+
}
|
342 |
}
|
343 |
|
344 |
?>
|
readme.txt
CHANGED
@@ -1,11 +1,11 @@
|
|
1 |
=== Wordfence Security ===
|
2 |
Contributors: mmaunder
|
3 |
-
Tags: wordpress, security, performance, speed, caching, cache, caching plugin, wordpress cache, wordpress caching, 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, security, secure, htaccess, login, log, users, login alerts, lock, chmod, maintenance, plugin, private, privacy, protection, permissions, 503, base64, injection, code, encode, script, attack, hack, hackers, block, blocked, prevent, prevention, RFI, XSS, CRLF, CSRF, SQL Injection, vulnerability, website security, WordPress security, security log, logging, HTTP log, error log, login security, personal security, infrastructure security, firewall security, front-end security, web server security, proxy security, reverse proxy security, secure website, secure login, two factor security, maximum login security, heartbleed, heart bleed, heartbleed vulnerability, openssl vulnerability
|
4 |
Requires at least: 3.3.1
|
5 |
Tested up to: 3.9
|
6 |
-
Stable tag: 5.0.
|
7 |
|
8 |
-
Wordfence Security is a free enterprise class security plugin that makes your site up to 50 times faster and more secure.
|
9 |
|
10 |
== Description ==
|
11 |
|
@@ -162,6 +162,17 @@ cause a security hole on your site.
|
|
162 |
|
163 |
== Changelog ==
|
164 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
165 |
= 5.0.5 =
|
166 |
* Fix: Removed mysql_real_escape_string because it’s deprecated. Using WP’s internal escape.
|
167 |
* Fix: Wordfence issues list would be deleted halfway through scan under certain conditions.
|
1 |
=== Wordfence Security ===
|
2 |
Contributors: mmaunder
|
3 |
+
Tags: wordpress, security, performance, speed, caching, cache, caching plugin, wordpress cache, wordpress caching, 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, security, secure, htaccess, login, log, users, login alerts, lock, chmod, maintenance, plugin, private, privacy, protection, permissions, 503, base64, injection, code, encode, script, attack, hack, hackers, block, blocked, prevent, prevention, RFI, XSS, CRLF, CSRF, SQL Injection, vulnerability, website security, WordPress security, security log, logging, HTTP log, error log, login security, personal security, infrastructure security, firewall security, front-end security, web server security, proxy security, reverse proxy security, secure website, secure login, two factor security, maximum login security, heartbleed, heart bleed, heartbleed vulnerability, openssl vulnerability, nginx, litespeed, php5-fpm
|
4 |
Requires at least: 3.3.1
|
5 |
Tested up to: 3.9
|
6 |
+
Stable tag: 5.0.6
|
7 |
|
8 |
+
Wordfence Security is a free enterprise class security and performance plugin that makes your site up to 50 times faster and more secure.
|
9 |
|
10 |
== Description ==
|
11 |
|
162 |
|
163 |
== Changelog ==
|
164 |
|
165 |
+
= 5.0.6 =
|
166 |
+
* Feature: Prevent discovery of usernames through '?/author=N' scans. New option under login security which you can enable.
|
167 |
+
* Fix: Introduced new global hash whitelist on our servers that drastically reduces false positives in all scans especially theme and plugin scans.
|
168 |
+
* Fix: Fixed issue that corrupted .htaccess because stat cache would store file size and cause filesize() to report incorrect size when reading/writing .htaccess.
|
169 |
+
* Fix: Fixed LiteSpeed issue where Falcon Engine would not serve cached pages under LiteSpeed and LiteSpeed warned about unknown server variable in .htaccess.
|
170 |
+
* Fix: Fixed issue where Wordfence Security Network won't block known bad IP after first login attempt if "Don't let WordPress reveal valid users in login errors" option is not enabled.
|
171 |
+
* Fix: Sites installed under a directory would sometimes see Falcon not serving cached docs.
|
172 |
+
* Fix: If you are a premium customer and you have 2FA enabled and your key expires, fixed issue that may have caused you to get locked out.
|
173 |
+
* Improvement: If your Premium API key now expires, we simply downgrade you to free scanning and continue rather than disabling Wordfence.
|
174 |
+
* Improvement: Email warnings a few days before your Premium key expires so you have a chance to upgrade for uninterrupted service.
|
175 |
+
|
176 |
= 5.0.5 =
|
177 |
* Fix: Removed mysql_real_escape_string because it’s deprecated. Using WP’s internal escape.
|
178 |
* Fix: Wordfence issues list would be deleted halfway through scan under certain conditions.
|
wordfence.php
CHANGED
@@ -4,13 +4,13 @@ Plugin Name: Wordfence Security
|
|
4 |
Plugin URI: http://www.wordfence.com/
|
5 |
Description: Wordfence Security - Anti-virus, Firewal and Site Speedup
|
6 |
Author: Wordfence
|
7 |
-
Version: 5.0.
|
8 |
Author URI: http://www.wordfence.com/
|
9 |
*/
|
10 |
if(defined('WP_INSTALLING') && WP_INSTALLING){
|
11 |
return;
|
12 |
}
|
13 |
-
define('WORDFENCE_VERSION', '5.0.
|
14 |
if(get_option('wordfenceActivated') != 1){
|
15 |
add_action('activated_plugin','wordfence_save_activation_error'); function wordfence_save_activation_error(){ update_option('wf_plugin_act_error', ob_get_contents()); }
|
16 |
}
|
4 |
Plugin URI: http://www.wordfence.com/
|
5 |
Description: Wordfence Security - Anti-virus, Firewal and Site Speedup
|
6 |
Author: Wordfence
|
7 |
+
Version: 5.0.6
|
8 |
Author URI: http://www.wordfence.com/
|
9 |
*/
|
10 |
if(defined('WP_INSTALLING') && WP_INSTALLING){
|
11 |
return;
|
12 |
}
|
13 |
+
define('WORDFENCE_VERSION', '5.0.6');
|
14 |
if(get_option('wordfenceActivated') != 1){
|
15 |
add_action('activated_plugin','wordfence_save_activation_error'); function wordfence_save_activation_error(){ update_option('wf_plugin_act_error', ob_get_contents()); }
|
16 |
}
|