Wordfence Security – Firewall & Malware Scan - Version 3.4.4

Version Description

  • Fixed issue that caused scans to not complete.
  • Fixed issue that caused scans to launch a large number of child processes due to very short scan timeout.
  • Fixed issue that caused websites that don't know their own hostname to not be able to scan.
  • Added workaround for a bug in Better WP Security breaking Wordfence due to their code overwriting the WP version.
  • Optimized the way we calculate max execution time for each process while scanning.
Download this release

Release Info

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

Code changes from version 3.4.1 to 3.4.4

lib/menu_options.php CHANGED
@@ -220,7 +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>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>
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 9.</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/wfScanEngine.php CHANGED
@@ -17,7 +17,6 @@ class wfScanEngine {
17
private $hashes = false;
18
private $jobList = array();
19
private $i = false;
20
- private $wp_version = false;
21
private $apiKey = false;
22
private $startTime = 0;
23
private $scanStep = 0;
@@ -41,7 +40,7 @@ class wfScanEngine {
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();
@@ -93,7 +92,9 @@ class wfScanEngine {
93
}
94
}
95
public function fork(){
96
if(wfConfig::set_ser('wfsd_engine', $this, true)){
97
self::startScan(true);
98
} //Otherwise there was an error so don't start another scan.
99
exit(0);
@@ -860,37 +861,65 @@ class wfScanEngine {
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
876
'sslverify' => false,
877
- 'headers' => $headers
878
- ) );
879
- wordfence::status(4, 'info', "Scan process ended after forking.");
880
return false; //No error
881
}
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
17
private $hashes = false;
18
private $jobList = array();
19
private $i = false;
20
private $apiKey = false;
21
private $startTime = 0;
22
private $scanStep = 0;
40
}
41
public function __construct(){
42
$this->startTime = time();
43
+ $this->maxExecTime = self::getMaxExecutionTime();
44
$this->i = new wfIssues();
45
$this->i->deleteNew();
46
$this->cycleStartTime = time();
92
}
93
}
94
public function fork(){
95
+ wordfence::status(4, 'info', "Entered fork()");
96
if(wfConfig::set_ser('wfsd_engine', $this, true)){
97
+ wordfence::status(4, 'info', "Calling startScan(true)");
98
self::startScan(true);
99
} //Otherwise there was an error so don't start another scan.
100
exit(0);
861
return "A scan is already running. Use the kill link if you would like to terminate the current scan.";
862
}
863
}
864
$timeout = self::getMaxExecutionTime() - 2; //2 seconds shorter than max execution time which ensures that only 2 HTTP processes are ever occupied
865
+ $testURL = admin_url('admin-ajax.php') . '?action=wordfence_testAjax';
866
+ $testResult = wp_remote_post($testURL, array(
867
+ 'timeout' => $timeout,
868
+ 'blocking' => true,
869
'sslverify' => false,
870
+ 'headers' => array()
871
+ ));
872
+
873
+ $cronKey = wfUtils::bigRandomHex();
874
+ wfConfig::set('currentCronKey', time() . ',' . $cronKey);
875
+ if( (! is_wp_error($testResult)) && is_array($testResult) && strstr($testResult['body'], 'WFSCANTESTOK') !== false){
876
+ //ajax requests can be sent by the server to itself
877
+ $cronURL = admin_url('admin-ajax.php');
878
+ $cronURL .= '?action=wordfence_doScan&isFork=' . ($isFork ? '1' : '0') . '&cronKey=' . $cronKey;
879
+ $headers = array();
880
+ wordfence::status(4, 'info', "Starting cron with normal ajax at URL $cronURL");
881
+ $result = wp_remote_post( $cronURL, array(
882
+ 'timeout' => $timeout, //Must be less than max execution time or more than 2 HTTP children will be occupied by scan
883
+ 'blocking' => true, //Non-blocking seems to block anyway, so we use blocking
884
+ 'sslverify' => false,
885
+ 'headers' => $headers
886
+ ) );
887
+ wordfence::status(4, 'info', "Scan process ended after forking.");
888
+ } else {
889
+ $cronURL = admin_url('admin-ajax.php');
890
+ $cronURL = preg_replace('/^(https?:\/\/)/i', '$1noc1.wordfence.com/scanp/', $cronURL);
891
+ $cronURL .= '?action=wordfence_doScan&isFork=' . ($isFork ? '1' : '0') . '&cronKey=' . $cronKey;
892
+ $headers = array();
893
+ wordfence::status(4, 'info', "Starting cron via proxy at URL $cronURL");
894
+ $result = wp_remote_post( $cronURL, array(
895
+ 'timeout' => $timeout, //Must be less than max execution time or more than 2 HTTP children will be occupied by scan
896
+ 'blocking' => true, //Non-blocking seems to block anyway, so we use blocking
897
+ 'sslverify' => false,
898
+ 'headers' => $headers
899
+ ) );
900
+ wordfence::status(4, 'info', "Scan process ended after forking.");
901
+ }
902
return false; //No error
903
}
904
public function processResponse($result){
905
return false;
906
}
907
public static function getMaxExecutionTime(){
908
+ $config = wfConfig::get('maxExecutionTime');
909
+ wordfence::status(4, 'info', "Got value from wf config maxExecutionTime: $config");
910
+ if(is_numeric($config) && $config >= 10){
911
+ wordfence::status(4, 'info', "getMaxExecutionTime() returning config value: $config");
912
+ return $config;
913
+ }
914
+ $ini = @ini_get('max_execution_time');
915
+ wordfence::status(4, 'info', "Got max_execution_time value from ini: $ini");
916
+ if(is_numeric($ini) && $ini >= 10){
917
+ $ini = floor($ini / 2);
918
+ wordfence::status(4, 'info', "getMaxExecutionTime() returning half ini value: $ini");
919
+ return $ini;
920
+ }
921
+ wordfence::status(4, 'info', "getMaxExecutionTime() returning default of: 15");
922
+ return 15;
923
}
924
}
925
lib/wfUtils.php CHANGED
@@ -197,11 +197,10 @@ class wfUtils {
197
error_log("Caller for " . $caller['file'] . " line " . $caller['line'] . " is " . $c2['file'] . ' line ' . $c2['line']);
198
}
199
public static function getWPVersion(){
200
- global $wp_version;
201
- global $wordfence_wp_version;
202
- if(isset($wordfence_wp_version)){
203
- return $wordfence_wp_version;
204
} else {
205
return $wp_version;
206
}
207
}
@@ -305,7 +304,6 @@ class wfUtils {
305
}
306
$toResolve = array();
307
$db = new wfDB();
308
- global $wp_version;
309
global $wpdb;
310
$locsTable = $wpdb->base_prefix . 'wfLocs';
311
$IPLocs = array();
@@ -332,7 +330,7 @@ class wfUtils {
332
}
333
}
334
if(sizeof($toResolve) > 0){
335
- $api = new wfAPI(wfConfig::get('apiKey'), $wp_version);
336
try {
337
$freshIPs = $api->call('resolve_ips', array(), array(
338
'ips' => implode(',', $toResolve)
197
error_log("Caller for " . $caller['file'] . " line " . $caller['line'] . " is " . $c2['file'] . ' line ' . $c2['line']);
198
}
199
public static function getWPVersion(){
200
+ if(wordfence::$wordfence_wp_version){
201
+ return wordfence::$wordfence_wp_version;
202
} else {
203
+ global $wp_version;
204
return $wp_version;
205
}
206
}
304
}
305
$toResolve = array();
306
$db = new wfDB();
307
global $wpdb;
308
$locsTable = $wpdb->base_prefix . 'wfLocs';
309
$IPLocs = array();
330
}
331
}
332
if(sizeof($toResolve) > 0){
333
+ $api = new wfAPI(wfConfig::get('apiKey'), wfUtils::getWPVersion());
334
try {
335
$freshIPs = $api->call('resolve_ips', array(), array(
336
'ips' => implode(',', $toResolve)
lib/wordfenceClass.php CHANGED
@@ -13,6 +13,7 @@ require_once('wfConfig.php');
13
require_once('wfSchema.php');
14
class wordfence {
15
public static $printStatus = false;
16
protected static $lastURLError = false;
17
protected static $curlContent = "";
18
protected static $curlDataWritten = 0;
@@ -246,6 +247,8 @@ class wordfence {
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');
@@ -283,11 +286,14 @@ class wordfence {
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
13
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;
247
add_action('wp_ajax_wordfence_logHuman', 'wordfence::ajax_logHuman_callback');
248
add_action('wp_ajax_nopriv_wordfence_doScan', 'wordfence::ajax_doScan_callback');
249
add_action('wp_ajax_wordfence_doScan', 'wordfence::ajax_doScan_callback');
250
+ add_action('wp_ajax_nopriv_wordfence_testAjax', 'wordfence::ajax_testAjax_callback');
251
+ add_action('wp_ajax_wordfence_testAjax', 'wordfence::ajax_testAjax_callback');
252
253
254
add_action('wordfence_start_scheduled_scan', 'wordfence::wordfenceStartScheduledScan');
286
}
287
}
288
}
289
+ public static function ajax_testAjax_callback(){
290
+ die("WFSCANTESTOK");
291
+ }
292
public static function ajax_doScan_callback(){
293
ignore_user_abort(true);
294
+ self::$wordfence_wp_version = false;
295
require(ABSPATH . 'wp-includes/version.php');
296
+ self::$wordfence_wp_version = $wp_version;
297
require('wfScan.php');
298
wfScan::wfScanMain();
299
lib/wordfenceHash.php CHANGED
@@ -192,6 +192,7 @@ class wordfenceHash {
192
$file = substr($realFile, $this->striplen);
193
if( (! $this->stoppedOnFile) && microtime(true) - $this->startTime > $this->engine->maxExecTime){ //max X seconds but don't allow fork if we're looking for the file we stopped on. Search mode is VERY fast.
194
$this->stoppedOnFile = $file;
195
$this->engine->fork();
196
//exits
197
}
192
$file = substr($realFile, $this->striplen);
193
if( (! $this->stoppedOnFile) && microtime(true) - $this->startTime > $this->engine->maxExecTime){ //max X seconds but don't allow fork if we're looking for the file we stopped on. Search mode is VERY fast.
194
$this->stoppedOnFile = $file;
195
+ wordfence::status(4, 'info', "Calling fork() from wordfenceHash::processFile with maxExecTime: " . $this->engine->maxExecTime);
196
$this->engine->fork();
197
//exits
198
}
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.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,6 +154,13 @@ or a theme, because often these have been updated to fix a security hole.
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.
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.4
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.4 =
158
+ * Fixed issue that caused scans to not complete.
159
+ * Fixed issue that caused scans to launch a large number of child processes due to very short scan timeout.
160
+ * Fixed issue that caused websites that don't know their own hostname to not be able to scan.
161
+ * Added workaround for a bug in Better WP Security breaking Wordfence due to their code overwriting the WP version.
162
+ * Optimized the way we calculate max execution time for each process while scanning.
163
+
164
= 3.4.1 =
165
* Removed wfscan.php script and now using pseudo-ajax calls to fire off scans. Much more reliable.
166
* Removed visitor.php script and now using pseudo-ajax calls to log human visits.
wordfence.php CHANGED
@@ -4,10 +4,10 @@ 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.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
}
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.4
8
Author URI: http://wordfence.com/
9
*/
10
+ define('WORDFENCE_VERSION', '3.4.4');
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
}