Wordfence Security – Firewall & Malware Scan - Version 3.4.1

Version Description

  • Removed wfscan.php script and now using pseudo-ajax calls to fire off scans. Much more reliable.
  • Removed visitor.php script and now using pseudo-ajax calls to log human visits.
  • Added config option to allow admin to specify max execution time (advanced only!!).
  • Fixed issue that caused API calls to fail on MultiSite installs.
  • Fixed issue that caused comments to break on MultiSite installs under certain conditions.
  • Fixed issue that caused incorrect domain to be shown in live traffic view on multi-site installs.
  • Fixed issue where some proxies/firewalls send space delimited IP addresses in HTTP headers and Wordfence now handles that.
  • Fixed issue that caused Wordfence to capture activation errors of other plugins.
  • Geo IP database update to November 7th edition.
Download this release

Release Info

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

Code changes from version 3.3.7 to 3.4.1

js/admin.js CHANGED
@@ -932,7 +932,7 @@ window['wordfenceAdmin'] = {
932
}
933
}
934
for(var k in WFSLevels[level].otherParams){
935
- if(! /^(?:apiKey|securityLevel|alertEmails|liveTraf_ignoreUsers|liveTraf_ignoreIPs|liveTraf_ignoreUA|liveTraf_hitsMaxSize|maxMem)#x2F;.test(k)){
936
jQuery('#' + k).val(WFSLevels[level].otherParams[k]);
937
}
938
}
932
}
933
}
934
for(var k in WFSLevels[level].otherParams){
935
+ if(! /^(?:apiKey|securityLevel|alertEmails|liveTraf_ignoreUsers|liveTraf_ignoreIPs|liveTraf_ignoreUA|liveTraf_hitsMaxSize|maxMem|maxExecutionTime)#x2F;.test(k)){
936
jQuery('#' + k).val(WFSLevels[level].otherParams[k]);
937
}
938
}
lib/GeoIP.dat CHANGED
Binary file
lib/menu_options.php CHANGED
@@ -220,6 +220,7 @@ var WFSLevels = <?php echo json_encode(wfConfig::$securityLevels); ?>;
220
<tr><th>Check password strength on profile update</th><td><input type="checkbox" id="other_pwStrengthOnUpdate" class="wfConfigElem" name="other_pwStrengthOnUpdate" value="1" <?php $w->cb('other_pwStrengthOnUpdate'); ?> /></td></tr>
221
<tr><th>Participate in the Wordfence Security Network</th><td><input type="checkbox" id="other_WFNet" class="wfConfigElem" name="other_WFNet" value="1" <?php $w->cb('other_WFNet'); ?> /></td></tr>
222
<tr><th>Maximum memory Wordfence can use</th><td><input type="text" id="maxMem" name="maxMem" value="<?php $w->f('maxMem'); ?>" size="4" />Megabytes</td></tr>
223
<tr><th>Enable debugging mode (increases database load)</th><td><input type="checkbox" id="debugOn" class="wfConfigElem" name="debugOn" value="1" <?php $w->cb('debugOn'); ?> /></td></tr>
224
<tr><th>Delete Wordfence tables and data on deactivation?</th><td><input type="checkbox" id="deleteTablesOnDeact" class="wfConfigElem" name="deleteTablesOnDeact" value="1" <?php $w->cb('deleteTablesOnDeact'); ?> /></td></tr>
225
<tr><th colspan="2"><a href="<?php echo wfUtils::siteURLRelative(); ?>?_wfsf=sysinfo&nonce=<?php echo wp_create_nonce('wp-ajax'); ?>" target="_blank">Click to view your system's configuration in a new window</a></th></tr>
220
<tr><th>Check password strength on profile update</th><td><input type="checkbox" id="other_pwStrengthOnUpdate" class="wfConfigElem" name="other_pwStrengthOnUpdate" value="1" <?php $w->cb('other_pwStrengthOnUpdate'); ?> /></td></tr>
221
<tr><th>Participate in the Wordfence Security Network</th><td><input type="checkbox" id="other_WFNet" class="wfConfigElem" name="other_WFNet" value="1" <?php $w->cb('other_WFNet'); ?> /></td></tr>
222
<tr><th>Maximum memory Wordfence can use</th><td><input type="text" id="maxMem" name="maxMem" value="<?php $w->f('maxMem'); ?>" size="4" />Megabytes</td></tr>
223
+ <tr><th>Maximum execution time for each scan stage</th><td><input type="text" id="maxExecutionTime" name="maxExecutionTime" value="<?php $w->f('maxExecutionTime'); ?>" size="4" />Blank for default. Must be greater than 10.</td></tr>
224
<tr><th>Enable debugging mode (increases database load)</th><td><input type="checkbox" id="debugOn" class="wfConfigElem" name="debugOn" value="1" <?php $w->cb('debugOn'); ?> /></td></tr>
225
<tr><th>Delete Wordfence tables and data on deactivation?</th><td><input type="checkbox" id="deleteTablesOnDeact" class="wfConfigElem" name="deleteTablesOnDeact" value="1" <?php $w->cb('deleteTablesOnDeact'); ?> /></td></tr>
226
<tr><th colspan="2"><a href="<?php echo wfUtils::siteURLRelative(); ?>?_wfsf=sysinfo&nonce=<?php echo wp_create_nonce('wp-ajax'); ?>" target="_blank">Click to view your system's configuration in a new window</a></th></tr>
lib/wfAPI.php CHANGED
@@ -155,7 +155,12 @@ class wfAPI {
155
public function makeAPIQueryString(){
156
$siteurl = '';
157
if(function_exists('get_bloginfo')){
158
- $siteurl = get_bloginfo('siteurl');
159
}
160
return self::buildQuery(array(
161
'v' => $this->wordpressVersion,
155
public function makeAPIQueryString(){
156
$siteurl = '';
157
if(function_exists('get_bloginfo')){
158
+ if(is_multisite()){
159
+ $siteurl = network_home_url();
160
+ $siteurl = rtrim($siteurl, '/'); //Because previously we used get_bloginfo and it returns http://example.com without a '/' char.
161
+ } else {
162
+ $siteurl = get_bloginfo('siteurl');
163
+ }
164
}
165
return self::buildQuery(array(
166
'v' => $this->wordpressVersion,
lib/wfConfig.php CHANGED
@@ -48,7 +48,7 @@ class wfConfig {
48
),
49
"otherParams" => array(
50
'securityLevel' => '0',
51
- "alertEmails" => "", "liveTraf_ignoreUsers" => "", "liveTraf_ignoreIPs" => "", "liveTraf_ignoreUA" => "", "apiKey" => "", "maxMem" => '256', 'whitelisted' => '',
52
"neverBlockBG" => "neverBlockVerified",
53
"loginSec_countFailMins" => "5",
54
"loginSec_lockoutMins" => "5",
@@ -111,7 +111,7 @@ class wfConfig {
111
),
112
"otherParams" => array(
113
'securityLevel' => '1',
114
- "alertEmails" => "", "liveTraf_ignoreUsers" => "", "liveTraf_ignoreIPs" => "", "liveTraf_ignoreUA" => "", "apiKey" => "", "maxMem" => '256', 'whitelisted' => '',
115
"neverBlockBG" => "neverBlockVerified",
116
"loginSec_countFailMins" => "5",
117
"loginSec_lockoutMins" => "5",
@@ -174,7 +174,7 @@ class wfConfig {
174
),
175
"otherParams" => array(
176
'securityLevel' => '2',
177
- "alertEmails" => "", "liveTraf_ignoreUsers" => "", "liveTraf_ignoreIPs" => "", "liveTraf_ignoreUA" => "", "apiKey" => "", "maxMem" => '256', 'whitelisted' => '',
178
"neverBlockBG" => "neverBlockVerified",
179
"loginSec_countFailMins" => "240",
180
"loginSec_lockoutMins" => "240",
@@ -237,7 +237,7 @@ class wfConfig {
237
),
238
"otherParams" => array(
239
'securityLevel' => '3',
240
- "alertEmails" => "", "liveTraf_ignoreUsers" => "", "liveTraf_ignoreIPs" => "", "liveTraf_ignoreUA" => "", "apiKey" => "", "maxMem" => '256', 'whitelisted' => '',
241
"neverBlockBG" => "neverBlockVerified",
242
"loginSec_countFailMins" => "1440",
243
"loginSec_lockoutMins" => "1440",
@@ -300,7 +300,7 @@ class wfConfig {
300
),
301
"otherParams" => array(
302
'securityLevel' => '4',
303
- "alertEmails" => "", "liveTraf_ignoreUsers" => "", "liveTraf_ignoreIPs" => "", "liveTraf_ignoreUA" => "", "apiKey" => "", "maxMem" => '256', 'whitelisted' => '',
304
"neverBlockBG" => "neverBlockVerified",
305
"loginSec_countFailMins" => "1440",
306
"loginSec_lockoutMins" => "1440",
48
),
49
"otherParams" => array(
50
'securityLevel' => '0',
51
+ "alertEmails" => "", "liveTraf_ignoreUsers" => "", "liveTraf_ignoreIPs" => "", "liveTraf_ignoreUA" => "", "apiKey" => "", "maxMem" => '256', 'whitelisted' => '', 'maxExecutionTime' => '',
52
"neverBlockBG" => "neverBlockVerified",
53
"loginSec_countFailMins" => "5",
54
"loginSec_lockoutMins" => "5",
111
),
112
"otherParams" => array(
113
'securityLevel' => '1',
114
+ "alertEmails" => "", "liveTraf_ignoreUsers" => "", "liveTraf_ignoreIPs" => "", "liveTraf_ignoreUA" => "", "apiKey" => "", "maxMem" => '256', 'whitelisted' => '', 'maxExecutionTime' => '',
115
"neverBlockBG" => "neverBlockVerified",
116
"loginSec_countFailMins" => "5",
117
"loginSec_lockoutMins" => "5",
174
),
175
"otherParams" => array(
176
'securityLevel' => '2',
177
+ "alertEmails" => "", "liveTraf_ignoreUsers" => "", "liveTraf_ignoreIPs" => "", "liveTraf_ignoreUA" => "", "apiKey" => "", "maxMem" => '256', 'whitelisted' => '', 'maxExecutionTime' => '',
178
"neverBlockBG" => "neverBlockVerified",
179
"loginSec_countFailMins" => "240",
180
"loginSec_lockoutMins" => "240",
237
),
238
"otherParams" => array(
239
'securityLevel' => '3',
240
+ "alertEmails" => "", "liveTraf_ignoreUsers" => "", "liveTraf_ignoreIPs" => "", "liveTraf_ignoreUA" => "", "apiKey" => "", "maxMem" => '256', 'whitelisted' => '', 'maxExecutionTime' => '',
241
"neverBlockBG" => "neverBlockVerified",
242
"loginSec_countFailMins" => "1440",
243
"loginSec_lockoutMins" => "1440",
300
),
301
"otherParams" => array(
302
'securityLevel' => '4',
303
+ "alertEmails" => "", "liveTraf_ignoreUsers" => "", "liveTraf_ignoreIPs" => "", "liveTraf_ignoreUA" => "", "apiKey" => "", "maxMem" => '256', 'whitelisted' => '', 'maxExecutionTime' => '',
304
"neverBlockBG" => "neverBlockVerified",
305
"loginSec_countFailMins" => "1440",
306
"loginSec_lockoutMins" => "1440",
wfscan.php → lib/wfScan.php RENAMED
@@ -1,26 +1,4 @@
1
<?php
2
- /* Don't remove this line. WFSOURCEVISIBLE */
3
- define('WORDFENCE_VERSIONONLY_MODE', true); //So that we can include wordfence.php and get the version constant
4
- ignore_user_abort(true);
5
- $wordfence_wp_version = false;
6
- if ( !defined('ABSPATH') ) {
7
- /** Set up WordPress environment */
8
- if($_SERVER['SCRIPT_FILENAME']){
9
- $wfBaseDir = preg_replace('/[^\/]+\/[^\/]+\/[^\/]+\/wfscan\.php#x2F;', '', $_SERVER['SCRIPT_FILENAME']);
10
- require_once($wfBaseDir . 'wp-load.php');
11
- global $wp_version;
12
- global $wordfence_wp_version;
13
- require($wfBaseDir . 'wp-includes/version.php');
14
- $wordfence_wp_version = $wp_version;
15
- } else {
16
- require_once('../../../wp-load.php');
17
- require_once('../../../wp-includes/version.php');
18
- }
19
- }
20
- require_once('wordfence.php');
21
- require_once('lib/wordfenceConstants.php');
22
- require_once('lib/wfScanEngine.php');
23
-
24
class wfScan {
25
public static $debugMode = false;
26
public static $errorHandlingOn = true;
@@ -43,7 +21,7 @@ class wfScan {
43
self::status(4, 'info', "Scan engine received request.");
44
self::status(4, 'info', "Checking cronkey");
45
if(! $_GET['cronKey']){
46
- self::status(4, 'error', "Wordfence wfscan.php accessed directly, or WF did not receive a cronkey.");
47
echo "If you see this message it means Wordfence is working correctly. You should not access this URL directly. It is part of the Wordfence security plugin and is designed for internal use only.";
48
exit();
49
}
@@ -65,7 +43,6 @@ class wfScan {
65
}
66
/* --------- end cronkey check ---------- */
67
68
- wfUtils::iniSet('max_execution_time', 1800); //30 mins
69
self::status(4, 'info', "Becoming admin for scan");
70
self::becomeAdmin();
71
self::status(4, 'info', "Done become admin");
@@ -217,5 +194,4 @@ class wfScan {
217
wordfence::status($level, $type, $msg);
218
}
219
}
220
- wfScan::wfScanMain();
221
?>
1
<?php
2
class wfScan {
3
public static $debugMode = false;
4
public static $errorHandlingOn = true;
21
self::status(4, 'info', "Scan engine received request.");
22
self::status(4, 'info', "Checking cronkey");
23
if(! $_GET['cronKey']){
24
+ self::status(4, 'error', "Wordfence scan script accessed directly, or WF did not receive a cronkey.");
25
echo "If you see this message it means Wordfence is working correctly. You should not access this URL directly. It is part of the Wordfence security plugin and is designed for internal use only.";
26
exit();
27
}
43
}
44
/* --------- end cronkey check ---------- */
45
46
self::status(4, 'info', "Becoming admin for scan");
47
self::becomeAdmin();
48
self::status(4, 'info', "Done become admin");
194
wordfence::status($level, $type, $msg);
195
}
196
}
197
?>
lib/wfScanEngine.php CHANGED
@@ -21,7 +21,7 @@ class wfScanEngine {
21
private $apiKey = false;
22
private $startTime = 0;
23
private $scanStep = 0;
24
- public $maxExecTime = 10; //If more than $maxExecTime has elapsed since last check, fork a new scan process and continue
25
private $publicScanEnabled = false;
26
private $fileContentsResults = false;
27
private $scanner = false;
@@ -41,6 +41,7 @@ class wfScanEngine {
41
}
42
public function __construct(){
43
$this->startTime = time();
44
$this->i = new wfIssues();
45
$this->i->deleteNew();
46
$this->cycleStartTime = time();
@@ -851,72 +852,6 @@ class wfScanEngine {
851
throw new Exception("Scan was killed on administrator request.");
852
}
853
}
854
- private static function getOwnHostname(){
855
- if(preg_match('/https?:\/\/([^\/]+)/i', site_url(), $matches)){
856
- $host = $matches[1];
857
- } else {
858
- wordfence::status(2, 'error', "Warning: Could not extract hostname from site URL: " . site_url());
859
- $host = site_url();
860
- }
861
- return $host;
862
- }
863
- private static function tryCronURL(){
864
- if(! wfConfig::get('cronTestID')){
865
- wfConfig::set('cronTestID', wfUtils::bigRandomHex());
866
- }
867
- $URL = wfConfig::get('cronURL');
868
- $sendHeader = wfConfig::get('cronSendHeader');
869
- $opts = array(
870
- 'timeout' => 30, //Long timeout here which is fine because it should return immediately if there are no delays.
871
- 'blocking' => true,
872
- 'sslverify' => false
873
- );
874
- if($sendHeader){
875
- $host = self::getOwnHostname();
876
- $opts['headers'] = array( 'Host' => $host);
877
- }
878
- $testURL = $URL . '?test=1';
879
- wordfence::status(4, 'info', "Testing cron URL: $testURL");
880
- $result = wp_remote_post($testURL, $opts);
881
- if( is_array($result) && isset($result['body']) && preg_match('/WFCRONTESTOK:' . wfConfig::get('cronTestID') . '/', $result['body'])){
882
- wordfence::status(4, 'info', "Cron URL test success with: $testURL");
883
- return true;
884
- } else {
885
- wordfence::status(4, 'info', "Cron URL test fail with: $testURL");
886
- self::$cronTestFailedURLs[] = $testURL;
887
- }
888
- return false;
889
- }
890
- private static function detectCronURL(){
891
- $URL = wfConfig::get('cronURL');
892
- if($URL){
893
- if(self::tryCronURL()){
894
- return true;
895
- }
896
- }
897
-
898
- $host = self::getOwnHostname();
899
- $URLS = array();
900
- $URLS[] = array(false, plugins_url('wordfence/wfscan.php'));
901
- $URLS[] = array(true, preg_replace('/^https?:\/\/[^\/]+/i', 'http://127.0.0.1', $URLS[0][1]));
902
- $URLS[] = array(true, preg_replace('/^https?:\/\/[^\/]+/i', 'https://127.0.0.1', $URLS[0][1]));
903
- $withHostInsecure = 'http://' . $host . '/wp-content/plugins/wordfence/wfscan.php';
904
- $withHostSecure = 'https://' . $host . '/wp-content/plugins/wordfence/wfscan.php';
905
- if($URLS[0][1] != $withHostInsecure){
906
- $URLS[] = array(false, $withHostInsecure);
907
- }
908
- if($URLS[0][1] != $withHostSecure){
909
- $URLS[] = array(false, $withHostSecure);
910
- }
911
- foreach($URLS as $elem){
912
- wfConfig::set('cronSendHeader', $elem[0] ? 1 : 0);
913
- wfConfig::set('cronURL', $elem[1]);
914
- if(self::tryCronURL()){
915
- return true;
916
- }
917
- }
918
- return false;
919
- }
920
public static function startScan($isFork = false){
921
if(! $isFork){ //beginning of scan
922
wfConfig::set('wfKillRequested', 0);
@@ -924,31 +859,17 @@ class wfScanEngine {
924
if(wfUtils::isScanRunning()){
925
return "A scan is already running. Use the kill link if you would like to terminate the current scan.";
926
}
927
- if(! self::detectCronURL()){
928
- $msg = 'We could not determine how this WordPress server connects to itself. Please read <a href="http://www.wordfence.com/docs/wordfence-server-cant-connect-to-itself-error/" target="_blank">the documentation we provide on this page</a> which may help with this error. For your info, this machine\'s hostname is: ' . self::getOwnHostname();
929
- $msg .= "<br /><br />We tried the following URLs:<ul>";
930
- foreach(self::$cronTestFailedURLs as $URL){
931
- $msg .= '<li><a href="' . $URL . '" target="_blank">' . $URL . '</a></li>';
932
- }
933
- $msg .= '</ul>';
934
- return $msg;
935
- }
936
}
937
938
$cronKey = wfUtils::bigRandomHex();
939
wfConfig::set('currentCronKey', time() . ',' . $cronKey);
940
- $cronURL = wfConfig::get('cronURL') . '?isFork=' . ($isFork ? '1' : '0') . '&cronKey=' . $cronKey;
941
wordfence::status(4, 'info', "Starting cron at URL $cronURL");
942
$headers = array();
943
- if(wfConfig::get('cronSendHeader')){
944
- $headers['Host'] = self::getOwnHostname();
945
- }
946
wordfence::status(4, 'info', "Starting wp_remote_post");
947
- if($isFork){
948
- $timeout = 8; //2 seconds shorter than max execution time which ensures that only 2 HTTP processes are ever occupied
949
- } else {
950
- $timeout = 3; //3 seconds if we're kicking off the scan so that the Ajax call returns quickly and UI isn't too slow
951
- }
952
$result = wp_remote_post( $cronURL, array(
953
'timeout' => $timeout, //Must be less than max execution time or more than 2 HTTP children will be occupied by scan
954
'blocking' => true, //Non-blocking seems to block anyway, so we use blocking
@@ -961,6 +882,16 @@ class wfScanEngine {
961
public function processResponse($result){
962
return false;
963
}
964
}
965
966
?>
21
private $apiKey = false;
22
private $startTime = 0;
23
private $scanStep = 0;
24
+ public $maxExecTime = false; //If more than $maxExecTime has elapsed since last check, fork a new scan process and continue
25
private $publicScanEnabled = false;
26
private $fileContentsResults = false;
27
private $scanner = false;
41
}
42
public function __construct(){
43
$this->startTime = time();
44
+ $this->maxExecTime = self::getMaxExecutionTime() / 2;
45
$this->i = new wfIssues();
46
$this->i->deleteNew();
47
$this->cycleStartTime = time();
852
throw new Exception("Scan was killed on administrator request.");
853
}
854
}
855
public static function startScan($isFork = false){
856
if(! $isFork){ //beginning of scan
857
wfConfig::set('wfKillRequested', 0);
859
if(wfUtils::isScanRunning()){
860
return "A scan is already running. Use the kill link if you would like to terminate the current scan.";
861
}
862
}
863
864
$cronKey = wfUtils::bigRandomHex();
865
wfConfig::set('currentCronKey', time() . ',' . $cronKey);
866
+ $cronURL = admin_url('admin-ajax.php');
867
+ $cronURL .= '?action=wordfence_doScan&isFork=' . ($isFork ? '1' : '0') . '&cronKey=' . $cronKey;
868
wordfence::status(4, 'info', "Starting cron at URL $cronURL");
869
$headers = array();
870
wordfence::status(4, 'info', "Starting wp_remote_post");
871
+ $timeout = self::getMaxExecutionTime() - 2; //2 seconds shorter than max execution time which ensures that only 2 HTTP processes are ever occupied
872
+
873
$result = wp_remote_post( $cronURL, array(
874
'timeout' => $timeout, //Must be less than max execution time or more than 2 HTTP children will be occupied by scan
875
'blocking' => true, //Non-blocking seems to block anyway, so we use blocking
882
public function processResponse($result){
883
return false;
884
}
885
+ public static function getMaxExecutionTime(){
886
+ $maxExecutionTime = wfConfig::get('maxExecutionTime');
887
+ if(! is_numeric($maxExecutionTime)){
888
+ $maxExecutionTime = @ini_get('max_execution_time');
889
+ }
890
+ if(! is_numeric($maxExecutionTime)){
891
+ $maxExecutionTime = 15;
892
+ }
893
+ return $maxExecutionTime;
894
+ }
895
}
896
897
?>
lib/wfUtils.php CHANGED
@@ -96,6 +96,15 @@ class wfUtils {
96
break;
97
}
98
}
99
}
100
if(preg_match('/:\d+#x2F;', $IP)){
101
$IP = preg_replace('/:\d+#x2F;', '', $IP);
@@ -136,7 +145,12 @@ class wfUtils {
136
return false;
137
}
138
public static function getRequestedURL(){
139
- return (@$_SERVER['HTTPS'] ? 'https' : 'http') . '://' . $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI'];
140
}
141
142
public static function editUserLink($userID){
96
break;
97
}
98
}
99
+ } else if(preg_match('/(\d+)\.(\d+)\.(\d+)\.(\d+)\s+(\d+)\.(\d+)\.(\d+)\.(\d+)/', $IP)){
100
+ $parts = explode(' ', $IP); //Some users have "unknown 100.100.100.100" for example so we take the first thing that looks like an IP.
101
+ foreach($parts as $part){
102
+ if(preg_match('/(\d+)\.(\d+)\.(\d+)\.(\d+)/', $part)){
103
+ $IP = trim($part);
104
+ break;
105
+ }
106
+ }
107
+
108
}
109
if(preg_match('/:\d+#x2F;', $IP)){
110
$IP = preg_replace('/:\d+#x2F;', '', $IP);
145
return false;
146
}
147
public static function getRequestedURL(){
148
+ if(isset($_SERVER['HTTP_HOST']) && $_SERVER['HTTP_HOST']){
149
+ $host = $_SERVER['HTTP_HOST'];
150
+ } else {
151
+ $host = $_SERVER['SERVER_NAME'];
152
+ }
153
+ return (@$_SERVER['HTTPS'] ? 'https' : 'http') . '://' . $host . $_SERVER['REQUEST_URI'];
154
}
155
156
public static function editUserLink($userID){
lib/wordfenceClass.php CHANGED
@@ -217,9 +217,6 @@ class wordfence {
217
wfConfig::set('alertEmailMsgCount', 0);
218
}
219
220
- @chmod(dirname(__FILE__) . '/../wfscan.php', 0755);
221
- @chmod(dirname(__FILE__) . '/../visitor.php', 0755);
222
-
223
global $wpdb;
224
$prefix = $wpdb->base_prefix;
225
$db->queryIgnoreError("alter table $prefix"."wfConfig modify column val longblob");
@@ -244,6 +241,13 @@ class wordfence {
244
global $blog_id;
245
if($blog_id == 1 && get_option('wordfenceActivated') != 1){ return; } //Because the plugin is active once installed, even before it's network activated, for site 1 (WordPress team, why?!)
246
}
247
add_action('wordfence_start_scheduled_scan', 'wordfence::wordfenceStartScheduledScan');
248
add_action('wordfence_daily_cron', 'wordfence::dailyCron');
249
add_action('wordfence_hourly_cron', 'wordfence::hourlyCron');
@@ -279,6 +283,27 @@ class wordfence {
279
}
280
}
281
}
282
public static function ajaxReceiver(){
283
if(! wfUtils::isAdmin()){
284
die(json_encode(array('errorMsg' => "You appear to have logged out or you are not an admin. Please sign-out and sign-in again.")));
@@ -1132,7 +1157,6 @@ class wordfence {
1132
}
1133
private static function wfFunc_testtime(){
1134
header('Content-Type: text/plain');
1135
- wfUtils::iniSet('max_execution_time', 1800); //30 mins
1136
@error_reporting(E_ALL);
1137
wfUtils::iniSet('display_errors','On');
1138
set_error_handler('wordfence::memtest_error_handler', E_ALL);
@@ -1188,7 +1212,9 @@ class wordfence {
1188
exit();
1189
}
1190
public static function wp_head(){
1191
- echo '<script type="text/javascript">var src="' . wfUtils::getBaseURL() . 'visitor.php?hid=' . wfUtils::encrypt(self::$hitID) . '"; if(window.location.protocol == "https:"){ src = src.replace("http:", "https:"); } var wfHTImg = new Image(); wfHTImg.src=src;</script>';
1192
}
1193
public static function shutdownAction(){
1194
}
@@ -1427,8 +1453,12 @@ class wordfence {
1427
1428
if(($approved == 1 || $approved == 0) && wfConfig::get('other_scanComments')){
1429
$wf = new wfScanEngine();
1430
- if($wf->isBadComment($cData['comment_author'], $cData['comment_author_email'], $cData['comment_author_url'], $cData['comment_author_IP'], $cData['comment_content'])){
1431
- return 'spam';
1432
}
1433
}
1434
return $approved;
217
wfConfig::set('alertEmailMsgCount', 0);
218
}
219
220
global $wpdb;
221
$prefix = $wpdb->base_prefix;
222
$db->queryIgnoreError("alter table $prefix"."wfConfig modify column val longblob");
241
global $blog_id;
242
if($blog_id == 1 && get_option('wordfenceActivated') != 1){ return; } //Because the plugin is active once installed, even before it's network activated, for site 1 (WordPress team, why?!)
243
}
244
+ //User may be logged in or not, so register both handlers
245
+ add_action('wp_ajax_nopriv_wordfence_logHuman', 'wordfence::ajax_logHuman_callback');
246
+ add_action('wp_ajax_wordfence_logHuman', 'wordfence::ajax_logHuman_callback');
247
+ add_action('wp_ajax_nopriv_wordfence_doScan', 'wordfence::ajax_doScan_callback');
248
+ add_action('wp_ajax_wordfence_doScan', 'wordfence::ajax_doScan_callback');
249
+
250
+
251
add_action('wordfence_start_scheduled_scan', 'wordfence::wordfenceStartScheduledScan');
252
add_action('wordfence_daily_cron', 'wordfence::dailyCron');
253
add_action('wordfence_hourly_cron', 'wordfence::hourlyCron');
283
}
284
}
285
}
286
+ public static function ajax_doScan_callback(){
287
+ ignore_user_abort(true);
288
+ $wordfence_wp_version = false;
289
+ require(ABSPATH . 'wp-includes/version.php');
290
+ $wordfence_wp_version = $wp_version;
291
+ require('wfScan.php');
292
+ wfScan::wfScanMain();
293
+
294
+ } //END doScan
295
+ public static function ajax_logHuman_callback(){
296
+ $hid = $_GET['hid'];
297
+ $hid = wfUtils::decrypt($hid);
298
+ if(! preg_match('/^\d+#x2F;', $hid)){ exit(); }
299
+ $db = new wfDB();
300
+ global $wpdb; $p = $wpdb->base_prefix;
301
+ $db->query("update $p"."wfHits set jsRun=1 where id=%d", $hid);
302
+ if(! headers_sent()){ //suppress content-type warning in chrome
303
+ header('Content-type: image/gif');
304
+ }
305
+ die("");
306
+ }
307
public static function ajaxReceiver(){
308
if(! wfUtils::isAdmin()){
309
die(json_encode(array('errorMsg' => "You appear to have logged out or you are not an admin. Please sign-out and sign-in again.")));
1157
}
1158
private static function wfFunc_testtime(){
1159
header('Content-Type: text/plain');
1160
@error_reporting(E_ALL);
1161
wfUtils::iniSet('display_errors','On');
1162
set_error_handler('wordfence::memtest_error_handler', E_ALL);
1212
exit();
1213
}
1214
public static function wp_head(){
1215
+ $URL = admin_url('admin-ajax.php');
1216
+ $URL .= '?action=wordfence_logHuman&hid=' . wfUtils::encrypt(self::$hitID);
1217
+ echo '<script type="text/javascript">var src="' . $URL . '"; if(window.location.protocol == "https:"){ src = src.replace("http:", "https:"); } var wfHTImg = new Image(); wfHTImg.src=src;</script>';
1218
}
1219
public static function shutdownAction(){
1220
}
1453
1454
if(($approved == 1 || $approved == 0) && wfConfig::get('other_scanComments')){
1455
$wf = new wfScanEngine();
1456
+ try {
1457
+ if($wf->isBadComment($cData['comment_author'], $cData['comment_author_email'], $cData['comment_author_url'], $cData['comment_author_IP'], $cData['comment_content'])){
1458
+ return 'spam';
1459
+ }
1460
+ } catch(Exception $e){
1461
+ //This will most likely be an API exception because we can't contact the API, so we ignore it and let the normal comment mechanisms run.
1462
}
1463
}
1464
return $approved;
lib/wordfenceConstants.php CHANGED
@@ -2,7 +2,7 @@
2
define('WORDFENCE_API_VERSION', '2.4');
3
define('WORDFENCE_API_URL_SEC', 'https://noc1.wordfence.com/');
4
define('WORDFENCE_API_URL_NONSEC', 'http://noc1.wordfence.com/');
5
- define('WORDFENCE_MAX_SCAN_TIME', 600);
6
define('WORDFENCE_TRANSIENTS_TIMEOUT', 3600); //how long are items cached in seconds e.g. files downloaded for diffing
7
define('WORDFENCE_MAX_IPLOC_AGE', 604800); //1 week
8
define('WORDFENCE_CRAWLER_VERIFY_CACHE_TIME', 604800);
2
define('WORDFENCE_API_VERSION', '2.4');
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.
6
define('WORDFENCE_TRANSIENTS_TIMEOUT', 3600); //how long are items cached in seconds e.g. files downloaded for diffing
7
define('WORDFENCE_MAX_IPLOC_AGE', 604800); //1 week
8
define('WORDFENCE_CRAWLER_VERIFY_CACHE_TIME', 604800);
readme.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: mmaunder
3
Tags: wordpress, security, wordpress security, security plugin, secure, anti-virus, malware, firewall, antivirus, virus, google safe browsing, phishing, scrapers, hacking, wordfence, securty, secrity, secure
4
Requires at least: 3.3.1
5
Tested up to: 3.4.2
6
- Stable tag: 3.3.7
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
@@ -154,6 +154,17 @@ or a theme, because often these have been updated to fix a security hole.
154
155
== Changelog ==
156
157
= 3.3.7 =
158
* Upgrade immediately. Fixes possible XSS vulnerability in Wordfence "firewall unlock" form.
159
* Also added rate limiting to max of 10 requests per second to the unlock form.
3
Tags: wordpress, security, wordpress security, security plugin, secure, anti-virus, malware, firewall, antivirus, virus, google safe browsing, phishing, scrapers, hacking, wordfence, securty, secrity, secure
4
Requires at least: 3.3.1
5
Tested up to: 3.4.2
6
+ Stable tag: 3.4.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
154
155
== Changelog ==
156
157
+ = 3.4.1 =
158
+ * Removed wfscan.php script and now using pseudo-ajax calls to fire off scans. Much more reliable.
159
+ * Removed visitor.php script and now using pseudo-ajax calls to log human visits.
160
+ * Added config option to allow admin to specify max execution time (advanced only!!).
161
+ * Fixed issue that caused API calls to fail on MultiSite installs.
162
+ * Fixed issue that caused comments to break on MultiSite installs under certain conditions.
163
+ * Fixed issue that caused incorrect domain to be shown in live traffic view on multi-site installs.
164
+ * Fixed issue where some proxies/firewalls send space delimited IP addresses in HTTP headers and Wordfence now handles that.
165
+ * Fixed issue that caused Wordfence to capture activation errors of other plugins.
166
+ * Geo IP database update to November 7th edition.
167
+
168
= 3.3.7 =
169
* Upgrade immediately. Fixes possible XSS vulnerability in Wordfence "firewall unlock" form.
170
* Also added rate limiting to max of 10 requests per second to the unlock form.
visitor.php DELETED
@@ -1,33 +0,0 @@
1
- <?php
2
- define('WORDFENCE_VERSIONONLY_MODE', true); //So that we can include wordfence.php and get the version constant
3
- ignore_user_abort(true);
4
- if ( !defined('ABSPATH') ) {
5
- /** Set up WordPress environment */
6
- if($_SERVER['SCRIPT_FILENAME']){
7
- $wfBaseDir = preg_replace('/[^\/]+\/[^\/]+\/[^\/]+\/visitor\.php#x2F;', '', $_SERVER['SCRIPT_FILENAME']);
8
- require_once($wfBaseDir . 'wp-load.php');
9
- global $wp_version;
10
- global $wordfence_wp_version;
11
- require($wfBaseDir . 'wp-includes/version.php');
12
- $wordfence_wp_version = $wp_version;
13
- } else {
14
- require_once('../../../wp-load.php');
15
- require_once('../../../wp-includes/version.php');
16
- }
17
-
18
- }
19
- require_once('wordfence.php');
20
- require_once('lib/wfUtils.php');
21
- require_once('lib/wfDB.php');
22
- function wfVisitor(){
23
- $hid = $_GET['hid'];
24
- $hid = wfUtils::decrypt($hid);
25
- if(! preg_match('/^\d+#x2F;', $hid)){ exit(); }
26
- $db = new wfDB();
27
- global $wpdb; $p = $wpdb->base_prefix;
28
- $db->query("update $p"."wfHits set jsRun=1 where id=%d", $hid);
29
- exit();
30
- }
31
- wfVisitor();
32
-
33
- ?>
wordfence.php CHANGED
@@ -4,11 +4,13 @@ Plugin Name: Wordfence Security
4
Plugin URI: http://wordfence.com/
5
Description: Wordfence Security - Anti-virus and Firewall security plugin for WordPress
6
Author: Mark Maunder
7
- Version: 3.3.7
8
Author URI: http://wordfence.com/
9
*/
10
- define('WORDFENCE_VERSION', '3.3.7');
11
- add_action('activated_plugin','wordfence_save_activation_error'); function wordfence_save_activation_error(){ update_option('wf_plugin_act_error', ob_get_contents()); }
12
if(! defined('WORDFENCE_VERSIONONLY_MODE')){
13
if((int) @ini_get('memory_limit') < 64){
14
if(strpos(ini_get('disable_functions'), 'ini_set') === false){
4
Plugin URI: http://wordfence.com/
5
Description: Wordfence Security - Anti-virus and Firewall security plugin for WordPress
6
Author: Mark Maunder
7
+ Version: 3.4.1
8
Author URI: http://wordfence.com/
9
*/
10
+ define('WORDFENCE_VERSION', '3.4.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
+ }
14
if(! defined('WORDFENCE_VERSIONONLY_MODE')){
15
if((int) @ini_get('memory_limit') < 64){
16
if(strpos(ini_get('disable_functions'), 'ini_set') === false){