Version Description
- Issue that caused all core files to show as missing has been fixed.
- We now handle all API server errors gracefully using exceptions.
- If your installation didn't activate correctly you now get a friendly message.
- Removed unused menu_config.php code.
- The 503 message now tells you why your access to the site has been limited so that admin's can tune firewall rules better.
- We no longer reuse the WordPress wpdb handle because we get better stability with our own connection.
Download this release
Release Info
Developer | mmaunder |
Plugin | Wordfence Security – Firewall & Malware Scan |
Version | 3.0.3 |
Comparing to | |
See all releases |
Code changes from version 3.0.2 to 3.0.3
- js/admin.js +0 -19
- lib/menu_config.php +0 -27
- lib/wf503.php +11 -2
- lib/wfAPI.php +15 -23
- lib/wfConfig.php +25 -25
- lib/wfDB.php +15 -31
- lib/wfLog.php +6 -4
- lib/wfScanEngine.php +16 -34
- lib/wfUtils.php +32 -27
- lib/wordfenceClass.php +98 -92
- lib/wordfenceHash.php +10 -10
- lib/wordfenceURLHoover.php +0 -8
- readme.txt +12 -1
- wfscan.php +8 -1
- wordfence.php +2 -2
js/admin.js
CHANGED
@@ -327,25 +327,6 @@ window['wordfenceAdmin'] = {
|
|
327 |
}
|
328 |
}, false, false);
|
329 |
},
|
330 |
-
activateWF: function(key){
|
331 |
-
jQuery('.wfAjax24').show();
|
332 |
-
this.ajax('wordfence_activate', {
|
333 |
-
key: jQuery('#wordfenceKey').val(),
|
334 |
-
email: jQuery('#email').val()
|
335 |
-
},
|
336 |
-
function(res){
|
337 |
-
jQuery('.wfAjax24').hide();
|
338 |
-
if(res.ok){
|
339 |
-
window.location = "admin.php?page=Wordfence&wfAct=" + Math.floor(Math.random()*999999999);
|
340 |
-
return;
|
341 |
-
} else if(res.errorAlert){
|
342 |
-
jQuery.colorbox({ width: '400px', html:
|
343 |
-
"<h3>An error occurred:</h3><p>" + res.errorAlert + "</p>"
|
344 |
-
});
|
345 |
-
}
|
346 |
-
|
347 |
-
});
|
348 |
-
},
|
349 |
killScan: function(){
|
350 |
var self = this;
|
351 |
this.ajax('wordfence_killScan', {}, function(res){
|
327 |
}
|
328 |
}, false, false);
|
329 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
330 |
killScan: function(){
|
331 |
var self = this;
|
332 |
this.ajax('wordfence_killScan', {}, function(res){
|
lib/menu_config.php
DELETED
@@ -1,27 +0,0 @@
|
|
1 |
-
<div class="wrap wordfence">
|
2 |
-
<div class="wordfence-lock-icon wordfence-icon32"><br /></div><h2>Welcome to Wordfence</h2>
|
3 |
-
<table class="form-table">
|
4 |
-
<tr><th><nobr>Enter your Wordfence API key:</nobr></th><td><input type="text" id="wordfenceKey" size="30" value="" /> (<a href="http://wordfence.com/signup-step2/" target="_blank">click here to get a free API key</a>)</td></tr>
|
5 |
-
<tr><th><nobr>Enter an email to send alerts to:</nobr></th><td><input type="text" id="email" size="30" value="<?php echo htmlspecialchars(get_option('admin_email')); ?>" /></td></tr>
|
6 |
-
<tr><td colspan="2">
|
7 |
-
<table border="0" cellpadding="0" cellspacing="0"><tr><td>
|
8 |
-
<input type="button" name="submit" id="submit" class="button-primary" value="Save Changes and Activate Wordfence" onclick="wordfenceAdmin.activateWF(); return false;" />
|
9 |
-
</td><td>
|
10 |
-
<div class="wfAjax24"></div>
|
11 |
-
</td></tr></table>
|
12 |
-
|
13 |
-
</td></tr>
|
14 |
-
</table>
|
15 |
-
|
16 |
-
</div>
|
17 |
-
<script type="text/x-jquery-template" id="wfActivateError">
|
18 |
-
<div>
|
19 |
-
<h3>Wordfence Activation Failed</h3>
|
20 |
-
<p>
|
21 |
-
We could not activate your Wordfence. The error was:
|
22 |
-
<br /><br />
|
23 |
-
${err}
|
24 |
-
<br /><br />
|
25 |
-
</p>
|
26 |
-
</div>
|
27 |
-
</script>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
lib/wf503.php
CHANGED
@@ -1,9 +1,18 @@
|
|
1 |
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
|
2 |
<html><head>
|
3 |
-
<title>
|
4 |
</head><body>
|
5 |
-
<h1>
|
6 |
<p>Your access to this service has been temporarily limited. Please try again in a few minutes. (HTTP response code 503)</p>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
7 |
<hr>
|
8 |
<br /><br />
|
9 |
<?php require('wfUnlockMsg.php'); ?>
|
1 |
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
|
2 |
<html><head>
|
3 |
+
<title>Wordfence has limited your access</title>
|
4 |
</head><body>
|
5 |
+
<h1>Wordfence has limited your access to this site</h1>
|
6 |
<p>Your access to this service has been temporarily limited. Please try again in a few minutes. (HTTP response code 503)</p>
|
7 |
+
<p>Reason: <span style="color: #F00;"><?php echo $reason; ?></span></p>
|
8 |
+
<p><b>Important note for site admins: </b>If you are the administrator of this website note that your access has been limited because you broke one of the Wordfence firewall rules.
|
9 |
+
The reason you access was limited is: <b>"<?php echo $reason; ?>"</b>. If this is a false positive, meaning that your access to your own site has been limited incorrectly, then you
|
10 |
+
will need to regain access to your site, go to the Wordfence "options" page, go to the section for Firewall Rules and disable the rule that caused you to be blocked. For example,
|
11 |
+
if you were blocked because it was detected that you are a fake Google crawler, then disable the rule that blocks fake google crawlers. Or if you were blocked because you
|
12 |
+
were accessing your site too quickly, then increase the number of accesses allowed per minute. If you're still having trouble, then simply disable the Wordfence firwall and you will
|
13 |
+
still benefit from the other security features that Wordfence provides. You will find instructions below on how to regain access if you are a site administrator.
|
14 |
+
</p>
|
15 |
+
|
16 |
<hr>
|
17 |
<br /><br />
|
18 |
<?php require('wfUnlockMsg.php'); ?>
|
lib/wfAPI.php
CHANGED
@@ -2,40 +2,33 @@
|
|
2 |
require_once('wordfenceConstants.php');
|
3 |
require_once('wordfenceClass.php');
|
4 |
class wfAPI {
|
5 |
-
public $errorMsg = false;
|
6 |
-
public $lastURLError = '';
|
7 |
public $lastHTTPStatus = '';
|
8 |
public $lastCurlErrorNo = '';
|
9 |
private $curlDataWritten = 0;
|
10 |
private $curlContent = 0;
|
11 |
private $APIKey = '';
|
12 |
private $wordpressVersion = '';
|
|
|
13 |
public function __construct($apiKey, $wordpressVersion){
|
14 |
$this->APIKey = $apiKey;
|
15 |
$this->wordpressVersion = $wordpressVersion;
|
16 |
}
|
17 |
public function call($action, $getParams = array(), $postParams = array()){
|
18 |
-
$this->errorMsg = false;
|
19 |
$json = $this->getURL($this->getAPIURL() . '/v' . WORDFENCE_API_VERSION . '/?' . $this->makeAPIQueryString() . '&' . http_build_query(
|
20 |
array_merge(
|
21 |
array('action' => $action),
|
22 |
$getParams
|
23 |
)), $postParams);
|
24 |
if(! $json){
|
25 |
-
|
26 |
-
$this->errorMsg = "Wordfence is currently down for maintenance. Please try again later.";
|
27 |
-
} else {
|
28 |
-
$this->errorMsg = "We could not fetch data from the API when calling '$action': " . $this->lastURLError;
|
29 |
-
}
|
30 |
-
return false;
|
31 |
}
|
32 |
|
33 |
$dat = json_decode($json, true);
|
34 |
if(! is_array($dat)){
|
35 |
-
|
36 |
}
|
37 |
-
if(
|
38 |
-
|
39 |
}
|
40 |
return $dat;
|
41 |
}
|
@@ -48,7 +41,6 @@ class wfAPI {
|
|
48 |
}
|
49 |
}
|
50 |
protected function getURL($url, $postParams = array()){
|
51 |
-
$this->lastURLError = '';
|
52 |
if(function_exists('curl_init')){
|
53 |
$this->curlDataWritten = 0;
|
54 |
$this->curlContent = "";
|
@@ -70,17 +62,15 @@ class wfAPI {
|
|
70 |
curl_close($curl);
|
71 |
return $this->curlContent;
|
72 |
} else {
|
73 |
-
$
|
74 |
-
$this->lastHTTPStatus = $httpStatus;
|
75 |
curl_close($curl);
|
76 |
-
|
77 |
}
|
78 |
} else {
|
79 |
$data = $this->fileGet($url, $postParams);
|
80 |
if($data === false){
|
81 |
$err = error_get_last();
|
82 |
-
|
83 |
-
return false;
|
84 |
}
|
85 |
return $data;
|
86 |
}
|
@@ -109,7 +99,6 @@ class wfAPI {
|
|
109 |
return @file_get_contents($url, false, $context, -1);
|
110 |
}
|
111 |
public function binCall($func, $postData){
|
112 |
-
$this->errorMsg = false;
|
113 |
$url = $this->getAPIURL() . '/v' . WORDFENCE_API_VERSION . '/?' . $this->makeAPIQueryString() . '&action=' . $func;
|
114 |
if(function_exists('curl_init')){
|
115 |
$curl = curl_init($url);
|
@@ -127,19 +116,22 @@ class wfAPI {
|
|
127 |
}
|
128 |
$data = curl_exec($curl);
|
129 |
$httpStatus = curl_getinfo($curl, CURLINFO_HTTP_CODE);
|
|
|
|
|
|
|
|
|
|
|
130 |
} else {
|
131 |
$data = $this->fileGet($url, $postData);
|
132 |
if($data === false){
|
133 |
-
|
134 |
-
return false;
|
135 |
}
|
136 |
$httpStatus = '200';
|
137 |
}
|
138 |
if(preg_match('/\{.*errorMsg/', $data)){
|
139 |
$jdat = @json_decode($data, true);
|
140 |
if(is_array($jdat) && $jdat['errorMsg']){
|
141 |
-
|
142 |
-
return false;
|
143 |
}
|
144 |
}
|
145 |
return array('code' => $httpStatus, 'data' => $data);
|
2 |
require_once('wordfenceConstants.php');
|
3 |
require_once('wordfenceClass.php');
|
4 |
class wfAPI {
|
|
|
|
|
5 |
public $lastHTTPStatus = '';
|
6 |
public $lastCurlErrorNo = '';
|
7 |
private $curlDataWritten = 0;
|
8 |
private $curlContent = 0;
|
9 |
private $APIKey = '';
|
10 |
private $wordpressVersion = '';
|
11 |
+
private static $maintMsg = "The Wordfence scanning server may be down for maintenance.";
|
12 |
public function __construct($apiKey, $wordpressVersion){
|
13 |
$this->APIKey = $apiKey;
|
14 |
$this->wordpressVersion = $wordpressVersion;
|
15 |
}
|
16 |
public function call($action, $getParams = array(), $postParams = array()){
|
|
|
17 |
$json = $this->getURL($this->getAPIURL() . '/v' . WORDFENCE_API_VERSION . '/?' . $this->makeAPIQueryString() . '&' . http_build_query(
|
18 |
array_merge(
|
19 |
array('action' => $action),
|
20 |
$getParams
|
21 |
)), $postParams);
|
22 |
if(! $json){
|
23 |
+
throw new Exception(self::$maintMsg);
|
|
|
|
|
|
|
|
|
|
|
24 |
}
|
25 |
|
26 |
$dat = json_decode($json, true);
|
27 |
if(! is_array($dat)){
|
28 |
+
throw new Exception("We could not understand the Wordfence API response when calling '$action'.");
|
29 |
}
|
30 |
+
if(is_array($dat) && isset($dat['errorMsg'])){
|
31 |
+
throw new Exception($dat['errorMsg']);
|
32 |
}
|
33 |
return $dat;
|
34 |
}
|
41 |
}
|
42 |
}
|
43 |
protected function getURL($url, $postParams = array()){
|
|
|
44 |
if(function_exists('curl_init')){
|
45 |
$this->curlDataWritten = 0;
|
46 |
$this->curlContent = "";
|
62 |
curl_close($curl);
|
63 |
return $this->curlContent;
|
64 |
} else {
|
65 |
+
$cerror = curl_error($curl);
|
|
|
66 |
curl_close($curl);
|
67 |
+
throw new Exception(self::$maintMsg . " Got HTTP status code [$httpStatus] and curl error: $cerror");
|
68 |
}
|
69 |
} else {
|
70 |
$data = $this->fileGet($url, $postParams);
|
71 |
if($data === false){
|
72 |
$err = error_get_last();
|
73 |
+
throw new Exception(self::$maintMsg . " Got HTTP error: " . $err);
|
|
|
74 |
}
|
75 |
return $data;
|
76 |
}
|
99 |
return @file_get_contents($url, false, $context, -1);
|
100 |
}
|
101 |
public function binCall($func, $postData){
|
|
|
102 |
$url = $this->getAPIURL() . '/v' . WORDFENCE_API_VERSION . '/?' . $this->makeAPIQueryString() . '&action=' . $func;
|
103 |
if(function_exists('curl_init')){
|
104 |
$curl = curl_init($url);
|
116 |
}
|
117 |
$data = curl_exec($curl);
|
118 |
$httpStatus = curl_getinfo($curl, CURLINFO_HTTP_CODE);
|
119 |
+
if($httpStatus != 200){
|
120 |
+
$cError = curl_error($curl);
|
121 |
+
curl_close($curl);
|
122 |
+
throw new Exception(self::$maintMsg . " Got HTTP status [$httpStatus] and curl error: $cError");
|
123 |
+
}
|
124 |
} else {
|
125 |
$data = $this->fileGet($url, $postData);
|
126 |
if($data === false){
|
127 |
+
throw new Exception(self::$maintMsg . " Got HTTP error: " . error_get_last());
|
|
|
128 |
}
|
129 |
$httpStatus = '200';
|
130 |
}
|
131 |
if(preg_match('/\{.*errorMsg/', $data)){
|
132 |
$jdat = @json_decode($data, true);
|
133 |
if(is_array($jdat) && $jdat['errorMsg']){
|
134 |
+
throw new Exception($jdat['errorMsg']);
|
|
|
135 |
}
|
136 |
}
|
137 |
return array('code' => $httpStatus, 'data' => $data);
|
lib/wfConfig.php
CHANGED
@@ -117,19 +117,19 @@ class wfConfig {
|
|
117 |
"loginSec_lockoutMins" => "5",
|
118 |
'loginSec_maxFailures' => "50",
|
119 |
'loginSec_maxForgotPasswd' => "50",
|
120 |
-
'maxGlobalRequests' => "
|
121 |
'maxGlobalRequests_action' => "throttle",
|
122 |
-
'maxRequestsCrawlers' => "
|
123 |
'maxRequestsCrawlers_action' => "throttle",
|
124 |
-
'maxRequestsHumans' => "
|
125 |
'maxRequestsHumans_action' => "throttle",
|
126 |
-
'max404Crawlers' => "
|
127 |
'max404Crawlers_action' => "throttle",
|
128 |
-
'max404Humans' => "
|
129 |
'max404Humans_action' => "throttle",
|
130 |
-
'maxScanHits' => "
|
131 |
'maxScanHits_action' => "throttle",
|
132 |
-
'blockedTime' => "
|
133 |
)
|
134 |
),
|
135 |
array( //level 2
|
@@ -180,19 +180,19 @@ class wfConfig {
|
|
180 |
"loginSec_lockoutMins" => "240",
|
181 |
'loginSec_maxFailures' => "20",
|
182 |
'loginSec_maxForgotPasswd' => "20",
|
183 |
-
'maxGlobalRequests' => "
|
184 |
'maxGlobalRequests_action' => "throttle",
|
185 |
-
'maxRequestsCrawlers' => "
|
186 |
'maxRequestsCrawlers_action' => "throttle",
|
187 |
-
'maxRequestsHumans' => "
|
188 |
'maxRequestsHumans_action' => "throttle",
|
189 |
-
'max404Crawlers' => "
|
190 |
'max404Crawlers_action' => "throttle",
|
191 |
-
'max404Humans' => "
|
192 |
'max404Humans_action' => "throttle",
|
193 |
-
'maxScanHits' => "
|
194 |
'maxScanHits_action' => "throttle",
|
195 |
-
'blockedTime' => "
|
196 |
)
|
197 |
),
|
198 |
array( //level 3
|
@@ -248,14 +248,14 @@ class wfConfig {
|
|
248 |
'maxRequestsCrawlers' => "960",
|
249 |
'maxRequestsCrawlers_action' => "throttle",
|
250 |
'maxRequestsHumans' => "60",
|
251 |
-
'maxRequestsHumans_action' => "
|
252 |
'max404Crawlers' => "60",
|
253 |
-
'max404Crawlers_action' => "
|
254 |
-
'max404Humans' => "
|
255 |
-
'max404Humans_action' => "
|
256 |
-
'maxScanHits' => "
|
257 |
-
'maxScanHits_action' => "
|
258 |
-
'blockedTime' => "
|
259 |
)
|
260 |
),
|
261 |
array( //level 4
|
@@ -312,13 +312,13 @@ class wfConfig {
|
|
312 |
'maxRequestsCrawlers_action' => "throttle",
|
313 |
'maxRequestsHumans' => "30",
|
314 |
'maxRequestsHumans_action' => "block",
|
315 |
-
'max404Crawlers' => "
|
316 |
'max404Crawlers_action' => "block",
|
317 |
-
'max404Humans' => "
|
318 |
'max404Humans_action' => "block",
|
319 |
-
'maxScanHits' => "
|
320 |
'maxScanHits_action' => "block",
|
321 |
-
'blockedTime' => "
|
322 |
)
|
323 |
)
|
324 |
);
|
117 |
"loginSec_lockoutMins" => "5",
|
118 |
'loginSec_maxFailures' => "50",
|
119 |
'loginSec_maxForgotPasswd' => "50",
|
120 |
+
'maxGlobalRequests' => "DISABLED",
|
121 |
'maxGlobalRequests_action' => "throttle",
|
122 |
+
'maxRequestsCrawlers' => "DISABLED",
|
123 |
'maxRequestsCrawlers_action' => "throttle",
|
124 |
+
'maxRequestsHumans' => "DISABLED",
|
125 |
'maxRequestsHumans_action' => "throttle",
|
126 |
+
'max404Crawlers' => "DISABLED",
|
127 |
'max404Crawlers_action' => "throttle",
|
128 |
+
'max404Humans' => "DISABLED",
|
129 |
'max404Humans_action' => "throttle",
|
130 |
+
'maxScanHits' => "DISABLED",
|
131 |
'maxScanHits_action' => "throttle",
|
132 |
+
'blockedTime' => "300"
|
133 |
)
|
134 |
),
|
135 |
array( //level 2
|
180 |
"loginSec_lockoutMins" => "240",
|
181 |
'loginSec_maxFailures' => "20",
|
182 |
'loginSec_maxForgotPasswd' => "20",
|
183 |
+
'maxGlobalRequests' => "DISABLED",
|
184 |
'maxGlobalRequests_action' => "throttle",
|
185 |
+
'maxRequestsCrawlers' => "DISABLED",
|
186 |
'maxRequestsCrawlers_action' => "throttle",
|
187 |
+
'maxRequestsHumans' => "DISABLED",
|
188 |
'maxRequestsHumans_action' => "throttle",
|
189 |
+
'max404Crawlers' => "DISABLED",
|
190 |
'max404Crawlers_action' => "throttle",
|
191 |
+
'max404Humans' => "DISABLED",
|
192 |
'max404Humans_action' => "throttle",
|
193 |
+
'maxScanHits' => "DISABLED",
|
194 |
'maxScanHits_action' => "throttle",
|
195 |
+
'blockedTime' => "300"
|
196 |
)
|
197 |
),
|
198 |
array( //level 3
|
248 |
'maxRequestsCrawlers' => "960",
|
249 |
'maxRequestsCrawlers_action' => "throttle",
|
250 |
'maxRequestsHumans' => "60",
|
251 |
+
'maxRequestsHumans_action' => "throttle",
|
252 |
'max404Crawlers' => "60",
|
253 |
+
'max404Crawlers_action' => "throttle",
|
254 |
+
'max404Humans' => "60",
|
255 |
+
'max404Humans_action' => "throttle",
|
256 |
+
'maxScanHits' => "30",
|
257 |
+
'maxScanHits_action' => "throttle",
|
258 |
+
'blockedTime' => "1800"
|
259 |
)
|
260 |
),
|
261 |
array( //level 4
|
312 |
'maxRequestsCrawlers_action' => "throttle",
|
313 |
'maxRequestsHumans' => "30",
|
314 |
'maxRequestsHumans_action' => "block",
|
315 |
+
'max404Crawlers' => "30",
|
316 |
'max404Crawlers_action' => "block",
|
317 |
+
'max404Humans' => "60",
|
318 |
'max404Humans_action' => "block",
|
319 |
+
'maxScanHits' => "10",
|
320 |
'maxScanHits_action' => "block",
|
321 |
+
'blockedTime' => "7200"
|
322 |
)
|
323 |
)
|
324 |
);
|
lib/wfDB.php
CHANGED
@@ -37,41 +37,22 @@ class wfDB {
|
|
37 |
}
|
38 |
}
|
39 |
}
|
40 |
-
|
|
|
|
|
|
|
|
|
41 |
$dbh = mysql_connect( $this->dbhost, $this->dbuser, $this->dbpassword, true );
|
42 |
-
if($dbh === false){
|
43 |
-
self::criticalError("Wordfence could not connect to your database. Error was: " . mysql_error());
|
44 |
-
return;
|
45 |
-
}
|
46 |
mysql_select_db($this->dbname, $dbh);
|
47 |
-
$
|
48 |
-
|
49 |
-
|
50 |
-
//Set big packets for set_ser when it serializes a scan in between forks
|
51 |
-
$this->queryIgnoreError("SET GLOBAL max_allowed_packet=256*1024*1024");
|
52 |
-
} else {
|
53 |
-
$handleKey = md5($dbhost . $dbuser . $dbpassword . $dbname);
|
54 |
-
if(isset(self::$dbhCache[$handleKey])){
|
55 |
-
$this->dbh = self::$dbhCache[$handleKey];
|
56 |
} else {
|
57 |
-
|
58 |
-
|
59 |
-
$dbh = $wpdb->dbh;
|
60 |
-
self::$dbhCache[$handleKey] = $dbh;
|
61 |
-
$this->dbh = self::$dbhCache[$handleKey];
|
62 |
-
} else {
|
63 |
-
$dbh = mysql_connect( $this->dbhost, $this->dbuser, $this->dbpassword, true );
|
64 |
-
if($dbh === false){
|
65 |
-
self::criticalError("Wordfence could not connect to your database. The error was: " . mysql_error());
|
66 |
-
return;
|
67 |
-
}
|
68 |
-
mysql_select_db($this->dbname, $dbh);
|
69 |
-
self::$dbhCache[$handleKey] = $dbh;
|
70 |
-
$this->dbh = self::$dbhCache[$handleKey];
|
71 |
-
$this->query("SET NAMES 'utf8'");
|
72 |
-
}
|
73 |
-
$this->queryIgnoreError("SET GLOBAL max_allowed_packet=256*1024*1024");
|
74 |
}
|
|
|
|
|
|
|
75 |
}
|
76 |
}
|
77 |
public function querySingleRec(){
|
@@ -202,6 +183,9 @@ class wfDB {
|
|
202 |
global $wpdb;
|
203 |
return $wpdb->base_prefix;
|
204 |
}
|
|
|
|
|
|
|
205 |
}
|
206 |
|
207 |
?>
|
37 |
}
|
38 |
}
|
39 |
}
|
40 |
+
//We tried reusing wpdb but got disconnection errors from many users.
|
41 |
+
$handleKey = md5($dbhost . $dbuser . $dbpassword . $dbname);
|
42 |
+
if( (! $createNewHandle) && isset(self::$dbhCache[$handleKey]) && mysql_ping(self::$dbhCache[$handleKey]) ){
|
43 |
+
$this->dbh = self::$dbhCache[$handleKey];
|
44 |
+
} else {
|
45 |
$dbh = mysql_connect( $this->dbhost, $this->dbuser, $this->dbpassword, true );
|
|
|
|
|
|
|
|
|
46 |
mysql_select_db($this->dbname, $dbh);
|
47 |
+
if($createNewHandle){
|
48 |
+
$this->dbh = $dbh;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
49 |
} else {
|
50 |
+
self::$dbhCache[$handleKey] = $dbh;
|
51 |
+
$this->dbh = self::$dbhCache[$handleKey];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
52 |
}
|
53 |
+
$this->query("SET NAMES 'utf8'");
|
54 |
+
$this->queryIgnoreError("SET GLOBAL max_allowed_packet=256*1024*1024");
|
55 |
+
$this->queryIgnoreError("SET GLOBAL wait_timeout=28800");
|
56 |
}
|
57 |
}
|
58 |
public function querySingleRec(){
|
183 |
global $wpdb;
|
184 |
return $wpdb->base_prefix;
|
185 |
}
|
186 |
+
public function getAffectedRows(){
|
187 |
+
return mysql_affected_rows($this->dbh);
|
188 |
+
}
|
189 |
}
|
190 |
|
191 |
?>
|
lib/wfLog.php
CHANGED
@@ -475,9 +475,11 @@ class wfLog {
|
|
475 |
}
|
476 |
public function firewallBadIPs(){
|
477 |
$IP = wfUtils::inet_aton(wfUtils::getIP());
|
478 |
-
if($
|
|
|
|
|
479 |
$this->getDB()->query("update " . $this->blocksTable . " set lastAttempt=unix_timestamp(), blockedHits = blockedHits + 1 where IP=%s", $IP);
|
480 |
-
$this->do503($secsToGo);
|
481 |
}
|
482 |
}
|
483 |
private function takeBlockingAction($configVar, $reason){
|
@@ -502,12 +504,12 @@ class wfLog {
|
|
502 |
wordfence::status(2, 'info', "Throttling IP $IP. $reason");
|
503 |
$secsToGo = 60;
|
504 |
}
|
505 |
-
$this->do503($secsToGo);
|
506 |
} else {
|
507 |
return;
|
508 |
}
|
509 |
}
|
510 |
-
private function do503($secsToGo
|
511 |
header('HTTP/1.1 503 Service Temporarily Unavailable');
|
512 |
header('Status: 503 Service Temporarily Unavailable');
|
513 |
if($secsToGo){
|
475 |
}
|
476 |
public function firewallBadIPs(){
|
477 |
$IP = wfUtils::inet_aton(wfUtils::getIP());
|
478 |
+
if($rec = $this->getDB()->querySingleRec("select (blockedTime + %s) - unix_timestamp() as secsToGo, reason from " . $this->blocksTable . " where IP=%s and (permanent=1 OR blockedTime + %s > unix_timestamp())", wfConfig::get('blockedTime'), $IP, wfConfig::get('blockedTime'))){
|
479 |
+
$secsToGo = $rec['secsToGo'];
|
480 |
+
$reason = $rec[1];
|
481 |
$this->getDB()->query("update " . $this->blocksTable . " set lastAttempt=unix_timestamp(), blockedHits = blockedHits + 1 where IP=%s", $IP);
|
482 |
+
$this->do503($secsToGo, $rec['reason']);
|
483 |
}
|
484 |
}
|
485 |
private function takeBlockingAction($configVar, $reason){
|
504 |
wordfence::status(2, 'info', "Throttling IP $IP. $reason");
|
505 |
$secsToGo = 60;
|
506 |
}
|
507 |
+
$this->do503($secsToGo, $reason);
|
508 |
} else {
|
509 |
return;
|
510 |
}
|
511 |
}
|
512 |
+
private function do503($secsToGo, $reason){
|
513 |
header('HTTP/1.1 503 Service Temporarily Unavailable');
|
514 |
header('Status: 503 Service Temporarily Unavailable');
|
515 |
if($secsToGo){
|
lib/wfScanEngine.php
CHANGED
@@ -17,7 +17,6 @@ class wfScanEngine {
|
|
17 |
private $i = false;
|
18 |
private $wp_version = false;
|
19 |
private $apiKey = false;
|
20 |
-
private $errorStopped = false;
|
21 |
private $startTime = 0;
|
22 |
private $scanStep = 0;
|
23 |
private $maxExecTime = 10; //If more than $maxExecTime has elapsed since last check, fork a new scan process and continue
|
@@ -38,7 +37,7 @@ class wfScanEngine {
|
|
38 |
'unknown' => false
|
39 |
);
|
40 |
public function __sleep(){ //Same order here as above for properties that are included in serialization
|
41 |
-
return array('hasher', 'hashes', 'jobList', 'i', 'wp_version', 'apiKey', '
|
42 |
}
|
43 |
public function __construct(){
|
44 |
$this->startTime = time();
|
@@ -71,18 +70,18 @@ class wfScanEngine {
|
|
71 |
try {
|
72 |
self::checkForKill();
|
73 |
$this->doScan();
|
|
|
74 |
self::checkForKill();
|
75 |
-
if(! $this->errorStopped){
|
76 |
-
wfConfig::set('lastScanCompleted', 'ok');
|
77 |
-
}
|
78 |
//updating this scan ID will trigger the scan page to load/reload the results.
|
79 |
$this->i->setScanTimeNow();
|
80 |
//scan ID only incremented at end of scan to make UI load new results
|
81 |
$this->emailNewIssues();
|
|
|
82 |
} catch(Exception $e){
|
83 |
-
|
|
|
|
|
84 |
}
|
85 |
-
wordfence::scheduleNextScan(true);
|
86 |
}
|
87 |
public function forkIfNeeded(){
|
88 |
self::checkForKill();
|
@@ -106,9 +105,6 @@ class wfScanEngine {
|
|
106 |
$jobName = $this->jobList[0];
|
107 |
call_user_func(array($this, 'scan_' . $jobName));
|
108 |
array_shift($this->jobList); //only shift once we're done because we may pause halfway through a job and need to pick up where we left off
|
109 |
-
if($this->errorStopped){
|
110 |
-
return;
|
111 |
-
}
|
112 |
self::checkForKill();
|
113 |
$this->fork();
|
114 |
}
|
@@ -128,10 +124,6 @@ class wfScanEngine {
|
|
128 |
private function scan_knownFiles_init(){
|
129 |
$this->status(1, 'info', "Contacting Wordfence to initiate scan");
|
130 |
$this->api->call('log_scan', array(), array());
|
131 |
-
if($this->api->errorMsg){
|
132 |
-
$this->errorStop($this->api->errorMsg);
|
133 |
-
return;
|
134 |
-
}
|
135 |
if(wfConfig::get('scansEnabled_core')){
|
136 |
$this->coreScanEnabled = true;
|
137 |
$this->statusIDX['core'] = wordfence::statusStart("Comparing core WordPress files against originals in repository");
|
@@ -241,16 +233,15 @@ class wfScanEngine {
|
|
241 |
'hashStorageID' => $this->hasher->getHashStorageID()
|
242 |
);
|
243 |
$content = json_encode($scanData);
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
wordfence::statusEndErr();
|
248 |
-
|
249 |
}
|
250 |
if(! is_array($dataArr)){
|
251 |
-
$this->errorStop("We received an empty response from the Wordfence server when scanning core, plugin and theme files.");
|
252 |
wordfence::statusEndErr();
|
253 |
-
|
254 |
}
|
255 |
//Data is an encoded string of <4 bytes of total length including these 4 bytes><2 bytes of filename length><filename>
|
256 |
$totalUStrLen = unpack('N', substr($dataArr['data'], 0, 4));
|
@@ -258,9 +249,8 @@ class wfScanEngine {
|
|
258 |
$this->unknownFiles = substr($dataArr['data'], 4, ($totalUStrLen - 4)); //subtruct the first 4 bytes which is an INT that is the total length of unknown string including the 4 bytes
|
259 |
$resultArr = json_decode(substr($dataArr['data'], $totalUStrLen), true);
|
260 |
if(! (is_array($resultArr) && isset($resultArr['results'])) ){
|
261 |
-
$this->errorStop("We received an incorrect response from the Wordfence server when scanning core, plugin and theme files.");
|
262 |
wordfence::statusEndErr();
|
263 |
-
|
264 |
}
|
265 |
|
266 |
$this->status(2, 'info', "Processing scan results");
|
@@ -296,7 +286,7 @@ class wfScanEngine {
|
|
296 |
private function scan_fileContents_finish(){
|
297 |
$this->status(2, 'info', "Done file contents scan");
|
298 |
if($this->scanner->errorMsg){
|
299 |
-
|
300 |
}
|
301 |
$this->scanner = null;
|
302 |
$haveIssues = false;
|
@@ -352,9 +342,8 @@ class wfScanEngine {
|
|
352 |
$hooverResults = $this->hoover->getBaddies();
|
353 |
$this->status(2, 'info', "Done examining URls");
|
354 |
if($this->hoover->errorMsg){
|
355 |
-
$this->errorStop($this->hoover->errorMsg);
|
356 |
wordfence::statusEndErr();
|
357 |
-
|
358 |
|
359 |
}
|
360 |
$haveIssues = false;
|
@@ -450,9 +439,8 @@ class wfScanEngine {
|
|
450 |
private function scan_comments_finish(){
|
451 |
$hooverResults = $this->hoover->getBaddies();
|
452 |
if($this->hoover->errorMsg){
|
453 |
-
$this->errorStop($this->hoover->errorMsg);
|
454 |
wordfence::statusEndErr();
|
455 |
-
|
456 |
}
|
457 |
$haveIssues = false;
|
458 |
foreach($hooverResults as $idString => $hresults){
|
@@ -817,11 +805,6 @@ class wfScanEngine {
|
|
817 |
}
|
818 |
wordfence::statusEnd($this->statusIDX['oldVersions'], $haveIssues);
|
819 |
}
|
820 |
-
private function errorStop($msg){
|
821 |
-
$this->errorStopped = true;
|
822 |
-
$this->status(1, 'error', $msg);
|
823 |
-
wfConfig::set('lastScanCompleted', $msg);
|
824 |
-
}
|
825 |
public function status($level, $type, $msg){
|
826 |
wordfence::status($level, $type, $msg);
|
827 |
}
|
@@ -835,9 +818,8 @@ class wfScanEngine {
|
|
835 |
$kill = wfConfig::get('wfKillRequested', 0);
|
836 |
if($kill && time() - $kill < 600){ //Kill lasts for 10 minutes
|
837 |
$wfdb = new wfDB();
|
838 |
-
wordfence::status(2, 'info', "Killing current scan");
|
839 |
wordfence::status(10, 'info', "SUM_KILLED:Previous scan was killed successfully.");
|
840 |
-
|
841 |
}
|
842 |
}
|
843 |
public static function startScan($isFork = false){
|
17 |
private $i = false;
|
18 |
private $wp_version = false;
|
19 |
private $apiKey = false;
|
|
|
20 |
private $startTime = 0;
|
21 |
private $scanStep = 0;
|
22 |
private $maxExecTime = 10; //If more than $maxExecTime has elapsed since last check, fork a new scan process and continue
|
37 |
'unknown' => false
|
38 |
);
|
39 |
public function __sleep(){ //Same order here as above for properties that are included in serialization
|
40 |
+
return array('hasher', 'hashes', 'jobList', 'i', 'wp_version', 'apiKey', 'startTime', 'scanStep', 'maxExecTime', 'malwareScanEnabled', 'pluginScanEnabled', 'coreScanEnabled', 'themeScanEnabled', 'unknownFiles', 'fileContentsResults', 'scanner', 'scanQueue', 'hoover', 'scanData', 'statusIDX');
|
41 |
}
|
42 |
public function __construct(){
|
43 |
$this->startTime = time();
|
70 |
try {
|
71 |
self::checkForKill();
|
72 |
$this->doScan();
|
73 |
+
wfConfig::set('lastScanCompleted', 'ok');
|
74 |
self::checkForKill();
|
|
|
|
|
|
|
75 |
//updating this scan ID will trigger the scan page to load/reload the results.
|
76 |
$this->i->setScanTimeNow();
|
77 |
//scan ID only incremented at end of scan to make UI load new results
|
78 |
$this->emailNewIssues();
|
79 |
+
wordfence::scheduleNextScan(true);
|
80 |
} catch(Exception $e){
|
81 |
+
wfConfig::set('lastScanCompleted', $e->getMessage());
|
82 |
+
wordfence::scheduleNextScan(true);
|
83 |
+
throw $e;
|
84 |
}
|
|
|
85 |
}
|
86 |
public function forkIfNeeded(){
|
87 |
self::checkForKill();
|
105 |
$jobName = $this->jobList[0];
|
106 |
call_user_func(array($this, 'scan_' . $jobName));
|
107 |
array_shift($this->jobList); //only shift once we're done because we may pause halfway through a job and need to pick up where we left off
|
|
|
|
|
|
|
108 |
self::checkForKill();
|
109 |
$this->fork();
|
110 |
}
|
124 |
private function scan_knownFiles_init(){
|
125 |
$this->status(1, 'info', "Contacting Wordfence to initiate scan");
|
126 |
$this->api->call('log_scan', array(), array());
|
|
|
|
|
|
|
|
|
127 |
if(wfConfig::get('scansEnabled_core')){
|
128 |
$this->coreScanEnabled = true;
|
129 |
$this->statusIDX['core'] = wordfence::statusStart("Comparing core WordPress files against originals in repository");
|
233 |
'hashStorageID' => $this->hasher->getHashStorageID()
|
234 |
);
|
235 |
$content = json_encode($scanData);
|
236 |
+
try {
|
237 |
+
$dataArr = $this->api->binCall('main_scan', $content);
|
238 |
+
} catch(Exception $e){
|
239 |
wordfence::statusEndErr();
|
240 |
+
throw $e;
|
241 |
}
|
242 |
if(! is_array($dataArr)){
|
|
|
243 |
wordfence::statusEndErr();
|
244 |
+
throw new Exception("We received an empty response from the Wordfence server when scanning core, plugin and theme files.");
|
245 |
}
|
246 |
//Data is an encoded string of <4 bytes of total length including these 4 bytes><2 bytes of filename length><filename>
|
247 |
$totalUStrLen = unpack('N', substr($dataArr['data'], 0, 4));
|
249 |
$this->unknownFiles = substr($dataArr['data'], 4, ($totalUStrLen - 4)); //subtruct the first 4 bytes which is an INT that is the total length of unknown string including the 4 bytes
|
250 |
$resultArr = json_decode(substr($dataArr['data'], $totalUStrLen), true);
|
251 |
if(! (is_array($resultArr) && isset($resultArr['results'])) ){
|
|
|
252 |
wordfence::statusEndErr();
|
253 |
+
throw new Exception("We received an incorrect response from the Wordfence server when scanning core, plugin and theme files.");
|
254 |
}
|
255 |
|
256 |
$this->status(2, 'info', "Processing scan results");
|
286 |
private function scan_fileContents_finish(){
|
287 |
$this->status(2, 'info', "Done file contents scan");
|
288 |
if($this->scanner->errorMsg){
|
289 |
+
throw new Exception($this->scanner->errorMsg);
|
290 |
}
|
291 |
$this->scanner = null;
|
292 |
$haveIssues = false;
|
342 |
$hooverResults = $this->hoover->getBaddies();
|
343 |
$this->status(2, 'info', "Done examining URls");
|
344 |
if($this->hoover->errorMsg){
|
|
|
345 |
wordfence::statusEndErr();
|
346 |
+
throw new Exception($this->hoover->errorMsg);
|
347 |
|
348 |
}
|
349 |
$haveIssues = false;
|
439 |
private function scan_comments_finish(){
|
440 |
$hooverResults = $this->hoover->getBaddies();
|
441 |
if($this->hoover->errorMsg){
|
|
|
442 |
wordfence::statusEndErr();
|
443 |
+
throw new Exception($this->hoover->errorMsg);
|
444 |
}
|
445 |
$haveIssues = false;
|
446 |
foreach($hooverResults as $idString => $hresults){
|
805 |
}
|
806 |
wordfence::statusEnd($this->statusIDX['oldVersions'], $haveIssues);
|
807 |
}
|
|
|
|
|
|
|
|
|
|
|
808 |
public function status($level, $type, $msg){
|
809 |
wordfence::status($level, $type, $msg);
|
810 |
}
|
818 |
$kill = wfConfig::get('wfKillRequested', 0);
|
819 |
if($kill && time() - $kill < 600){ //Kill lasts for 10 minutes
|
820 |
$wfdb = new wfDB();
|
|
|
821 |
wordfence::status(10, 'info', "SUM_KILLED:Previous scan was killed successfully.");
|
822 |
+
throw new Exception("Scan was killed on administrator request.");
|
823 |
}
|
824 |
}
|
825 |
public static function startScan($isFork = false){
|
lib/wfUtils.php
CHANGED
@@ -308,35 +308,40 @@ class wfUtils {
|
|
308 |
}
|
309 |
if(sizeof($toResolve) > 0){
|
310 |
$api = new wfAPI(wfConfig::get('apiKey'), $wp_version);
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
(
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
-
|
327 |
-
|
328 |
-
|
329 |
-
|
330 |
-
|
331 |
-
|
332 |
-
|
333 |
-
|
334 |
-
|
335 |
-
|
336 |
-
|
337 |
-
|
|
|
|
|
338 |
}
|
339 |
}
|
|
|
|
|
|
|
340 |
}
|
341 |
}
|
342 |
return $IPLocs;
|
308 |
}
|
309 |
if(sizeof($toResolve) > 0){
|
310 |
$api = new wfAPI(wfConfig::get('apiKey'), $wp_version);
|
311 |
+
try {
|
312 |
+
$freshIPs = $api->call('resolve_ips', array(), array(
|
313 |
+
'ips' => implode(',', $toResolve)
|
314 |
+
));
|
315 |
+
if(is_array($freshIPs)){
|
316 |
+
foreach($freshIPs as $IP => $value){
|
317 |
+
if($value == 'failed'){
|
318 |
+
$db->query("insert IGNORE into " . $locsTable . " (IP, ctime, failed) values (%s, unix_timestamp(), 1)", ($isInt ? $IP : self::inet_aton($IP)) );
|
319 |
+
$IPLocs[$IP] = false;
|
320 |
+
} else {
|
321 |
+
$db->query("insert IGNORE into " . $locsTable . " (IP, ctime, failed, city, region, countryName, countryCode, lat, lon) values (%s, unix_timestamp(), 0, '%s', '%s', '%s', '%s', %s, %s)",
|
322 |
+
($isInt ? $IP : self::inet_aton($IP)),
|
323 |
+
$value[3], //city
|
324 |
+
$value[2], //region
|
325 |
+
$value[1], //countryName
|
326 |
+
$value[0],//countryCode
|
327 |
+
$value[4],//lat
|
328 |
+
$value[5]//lon
|
329 |
+
);
|
330 |
+
$IPLocs[$IP] = array(
|
331 |
+
'IP' => $IP,
|
332 |
+
'city' => $value[3],
|
333 |
+
'region' => $value[2],
|
334 |
+
'countryName' => $value[1],
|
335 |
+
'countryCode' => $value[0],
|
336 |
+
'lat' => $value[4],
|
337 |
+
'lon' => $value[5]
|
338 |
+
);
|
339 |
+
}
|
340 |
}
|
341 |
}
|
342 |
+
} catch(Exception $e){
|
343 |
+
wordfence::status(2, 'error', "Call to Wordfence API to resolve IPs failed: " . $e->getMessage());
|
344 |
+
return array();
|
345 |
}
|
346 |
}
|
347 |
return $IPLocs;
|
lib/wordfenceClass.php
CHANGED
@@ -46,12 +46,17 @@ class wordfence {
|
|
46 |
public static function hourlyCron(){
|
47 |
global $wpdb; $p = $wpdb->base_prefix;
|
48 |
$api = new wfAPI(wfConfig::get('apiKey'), wfUtils::getWPVersion());
|
49 |
-
|
50 |
-
|
51 |
-
if(
|
52 |
-
|
|
|
|
|
53 |
}
|
|
|
|
|
54 |
}
|
|
|
55 |
|
56 |
if(wfConfig::get('other_WFNet')){
|
57 |
$wfdb = new wfDB();
|
@@ -62,7 +67,11 @@ class wordfence {
|
|
62 |
}
|
63 |
$wfdb->query("truncate table $p"."wfNet404s");
|
64 |
if(sizeof($URIs) > 0){
|
65 |
-
|
|
|
|
|
|
|
|
|
66 |
}
|
67 |
|
68 |
$q2 = $wfdb->query("select INET_NTOA(IP) as IP from $p"."wfVulnScanners where ctime > unix_timestamp() - 3600");
|
@@ -79,18 +88,22 @@ class wordfence {
|
|
79 |
}
|
80 |
if(strlen($lockCont) > 0 || strlen($scanCont) > 0){
|
81 |
$cont = pack('N', strlen($lockCont) / 4) . $lockCont . pack('N', strlen($scanCont) / 4) . $scanCont;
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
|
|
|
|
92 |
}
|
93 |
}
|
|
|
|
|
94 |
}
|
95 |
}
|
96 |
}
|
@@ -161,14 +174,16 @@ class wordfence {
|
|
161 |
|
162 |
if(! wfConfig::get('apiKey')){
|
163 |
$api = new wfAPI('', wfUtils::getWPVersion());
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
|
|
|
|
172 |
}
|
173 |
}
|
174 |
wp_clear_scheduled_hook('wordfence_daily_cron');
|
@@ -225,6 +240,9 @@ class wordfence {
|
|
225 |
add_action('wp_logout','wordfence::logoutAction');
|
226 |
add_action('profile_update', 'wordfence::profileUpdateAction', '99', 2);
|
227 |
add_action('lostpassword_post', 'wordfence::lostPasswordPost', '1');
|
|
|
|
|
|
|
228 |
add_filter('pre_comment_approved', 'wordfence::preCommentApprovedFilter', '99', 2);
|
229 |
add_filter('authenticate', 'wordfence::authenticateFilter', 99, 3);
|
230 |
//html|xhtml|atom|rss2|rdf|comment|export
|
@@ -475,20 +493,21 @@ class wordfence {
|
|
475 |
return array('errorMsg' => "An invalid type was specified to get file.");
|
476 |
}
|
477 |
$api = new wfAPI(wfConfig::get('apiKey'), wfUtils::getWPVersion());
|
478 |
-
|
479 |
-
'
|
480 |
-
|
481 |
-
|
482 |
-
|
483 |
-
|
484 |
-
|
485 |
-
|
486 |
-
|
487 |
-
|
488 |
-
|
489 |
-
|
490 |
-
|
491 |
-
|
|
|
492 |
}
|
493 |
}
|
494 |
public static function ajax_sendActivityLog_callback(){
|
@@ -602,18 +621,20 @@ class wordfence {
|
|
602 |
$paidKeyMsg = false;
|
603 |
if($opts['apiKey'] != wfConfig::get('apiKey')){
|
604 |
$api = new wfAPI($opts['apiKey'], wfUtils::getWPVersion());
|
605 |
-
|
606 |
-
|
607 |
-
|
608 |
-
|
609 |
-
|
610 |
-
|
611 |
-
$
|
|
|
|
|
|
|
|
|
612 |
}
|
613 |
-
}
|
614 |
-
return array('errorMsg' => $
|
615 |
-
} else {
|
616 |
-
return array('errorMsg' => "We could not change your API key. Please try again in a few minutes.");
|
617 |
}
|
618 |
}
|
619 |
|
@@ -861,37 +882,6 @@ class wordfence {
|
|
861 |
'file' => $localFile
|
862 |
);
|
863 |
}
|
864 |
-
public static function ajax_activate_callback(){
|
865 |
-
$key = trim($_POST['key']);
|
866 |
-
$email = trim($_POST['email']);
|
867 |
-
$key = preg_replace('/[^a-fA-F0-9]+/', '', $key);
|
868 |
-
if(strlen($key) < 10){
|
869 |
-
return array("errorAlert" => "You entered an invalid API key." );
|
870 |
-
}
|
871 |
-
if(! preg_match('/.+\@.+/', $email)){
|
872 |
-
return array("errorAlert" => "Please enter a valid email address where Wordfence can send alerts.");
|
873 |
-
}
|
874 |
-
|
875 |
-
wfConfig::set('apiKey', $key);
|
876 |
-
wfConfig::set('alertEmails', $email);
|
877 |
-
$api = new wfAPI(wfConfig::get('apiKey'), wfUtils::getWPVersion());
|
878 |
-
$result = $api->call('activate', array(), array());
|
879 |
-
if($api->errorMsg){
|
880 |
-
wfConfig::set('apiKey', '');
|
881 |
-
return array("errorMsg" => $api->errorMsg );
|
882 |
-
}
|
883 |
-
if($result['ok'] && isset($result['isPaid'])){
|
884 |
-
wfConfig::set('isPaid', $result['isPaid']);
|
885 |
-
$err = wfScanEngine::startScan();
|
886 |
-
if($err){
|
887 |
-
return array('errorMsg' => $err);
|
888 |
-
} else {
|
889 |
-
return array("ok" => 1);
|
890 |
-
}
|
891 |
-
} else {
|
892 |
-
return array('errorAlert' => "An unknown error occurred trying to activate Wordfence. Please try again in a few minutes." );
|
893 |
-
}
|
894 |
-
}
|
895 |
public static function ajax_scan_callback(){
|
896 |
self::status(4, 'info', "Ajax request received to start scan.");
|
897 |
$err = wfScanEngine::startScan();
|
@@ -1147,6 +1137,10 @@ class wordfence {
|
|
1147 |
|
1148 |
}
|
1149 |
}
|
|
|
|
|
|
|
|
|
1150 |
public static function admin_menus(){
|
1151 |
if(! wfUtils::isAdmin()){ return; }
|
1152 |
if(! wfConfig::get('alertEmails')){
|
@@ -1156,6 +1150,13 @@ class wordfence {
|
|
1156 |
add_action('admin_notices', 'wordfence::configure_warning');
|
1157 |
}
|
1158 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1159 |
add_submenu_page("Wordfence", "Scan", "Scan", "activate_plugins", "Wordfence", 'wordfence::menu_scan');
|
1160 |
add_menu_page('Wordfence', 'Wordfence', 'activate_plugins', 'Wordfence', 'wordfence::menu_scan', wfUtils::getBaseURL() . 'images/wordfence-logo-16x16.png');
|
1161 |
if(wfConfig::get('liveTrafficEnabled')){
|
@@ -1170,9 +1171,6 @@ class wordfence {
|
|
1170 |
public static function menu_blockedIPs(){
|
1171 |
require 'menu_blockedIPs.php';
|
1172 |
}
|
1173 |
-
public static function menu_config(){
|
1174 |
-
require 'menu_config.php';
|
1175 |
-
}
|
1176 |
public static function menu_activity(){
|
1177 |
require 'menu_activity.php';
|
1178 |
}
|
@@ -1201,7 +1199,7 @@ class wordfence {
|
|
1201 |
}
|
1202 |
}
|
1203 |
public static function genFilter($gen, $type){
|
1204 |
-
if(wfConfig::get('
|
1205 |
return '';
|
1206 |
} else {
|
1207 |
return $gen;
|
@@ -1270,16 +1268,17 @@ class wordfence {
|
|
1270 |
return;
|
1271 |
}
|
1272 |
$api = new wfAPI(wfConfig::get('apiKey'), wfUtils::getWPVersion());
|
1273 |
-
|
1274 |
-
|
1275 |
-
|
1276 |
-
|
1277 |
-
|
1278 |
-
|
1279 |
-
|
|
|
|
|
|
|
1280 |
}
|
1281 |
-
wp_clear_scheduled_hook('wordfence_scheduled_scan');
|
1282 |
-
wp_schedule_single_event(time() + $secsToGo, 'wordfence_scheduled_scan');
|
1283 |
} else {
|
1284 |
wp_clear_scheduled_hook('wordfence_scheduled_scan');
|
1285 |
}
|
@@ -1344,5 +1343,12 @@ class wordfence {
|
|
1344 |
}
|
1345 |
return self::$debugOn;
|
1346 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1347 |
}
|
1348 |
?>
|
46 |
public static function hourlyCron(){
|
47 |
global $wpdb; $p = $wpdb->base_prefix;
|
48 |
$api = new wfAPI(wfConfig::get('apiKey'), wfUtils::getWPVersion());
|
49 |
+
try {
|
50 |
+
$patData = $api->call('get_known_vuln_pattern');
|
51 |
+
if(is_array($patData) && $patData['pat']){
|
52 |
+
if(@preg_match($patData['pat'], 'wordfence_test_vuln_match')){
|
53 |
+
wfConfig::set('vulnRegex', $pat);
|
54 |
+
}
|
55 |
}
|
56 |
+
} catch(Exception $e){
|
57 |
+
wordfence::status(2, 'error', "Could not fetch vulnerability patterns in hourly scheduled job: " . $e->getMessage());
|
58 |
}
|
59 |
+
|
60 |
|
61 |
if(wfConfig::get('other_WFNet')){
|
62 |
$wfdb = new wfDB();
|
67 |
}
|
68 |
$wfdb->query("truncate table $p"."wfNet404s");
|
69 |
if(sizeof($URIs) > 0){
|
70 |
+
try {
|
71 |
+
$api->call('send_net_404s', array(), array( 'URIs' => json_encode($URIs) ));
|
72 |
+
} catch(Exception $e){
|
73 |
+
//Ignore
|
74 |
+
}
|
75 |
}
|
76 |
|
77 |
$q2 = $wfdb->query("select INET_NTOA(IP) as IP from $p"."wfVulnScanners where ctime > unix_timestamp() - 3600");
|
88 |
}
|
89 |
if(strlen($lockCont) > 0 || strlen($scanCont) > 0){
|
90 |
$cont = pack('N', strlen($lockCont) / 4) . $lockCont . pack('N', strlen($scanCont) / 4) . $scanCont;
|
91 |
+
try {
|
92 |
+
$resp = $api->binCall('get_net_bad_ips', $cont);
|
93 |
+
if($resp['code'] == 200){
|
94 |
+
$len = strlen($resp['data']);
|
95 |
+
$reason = "WFSN: Blocked by Wordfence Security Network";
|
96 |
+
$wfdb->query("delete from $p"."wfBlocks where wfsn=1");
|
97 |
+
if($len > 0 && $len % 4 == 0){
|
98 |
+
for($i = 0; $i < $len; $i += 4){
|
99 |
+
list($ipLong) = array_values(unpack('N', substr($resp['data'], $i, 4)));
|
100 |
+
$IPStr = long2ip($ipLong);
|
101 |
+
self::getLog()->blockIP($IPStr, $reason, true);
|
102 |
+
}
|
103 |
}
|
104 |
}
|
105 |
+
} catch(Exception $e){
|
106 |
+
//Ignore
|
107 |
}
|
108 |
}
|
109 |
}
|
174 |
|
175 |
if(! wfConfig::get('apiKey')){
|
176 |
$api = new wfAPI('', wfUtils::getWPVersion());
|
177 |
+
try {
|
178 |
+
$keyData = $api->call('get_anon_api_key');
|
179 |
+
if($keyData['ok'] && $keyData['apiKey']){
|
180 |
+
wfConfig::set('apiKey', $keyData['apiKey']);
|
181 |
+
} else {
|
182 |
+
throw new Exception("Could not understand the response we received from the Wordfence servers when applying for a free API key.");
|
183 |
+
}
|
184 |
+
} catch(Exception $e){
|
185 |
+
error_log("Could not fetch free API key from Wordfence: " . $e->getMessage());
|
186 |
+
return;
|
187 |
}
|
188 |
}
|
189 |
wp_clear_scheduled_hook('wordfence_daily_cron');
|
240 |
add_action('wp_logout','wordfence::logoutAction');
|
241 |
add_action('profile_update', 'wordfence::profileUpdateAction', '99', 2);
|
242 |
add_action('lostpassword_post', 'wordfence::lostPasswordPost', '1');
|
243 |
+
/* For testing cron jobs
|
244 |
+
add_filter('cron_schedules', 'wordfence::moreCronReccurences');
|
245 |
+
*/
|
246 |
add_filter('pre_comment_approved', 'wordfence::preCommentApprovedFilter', '99', 2);
|
247 |
add_filter('authenticate', 'wordfence::authenticateFilter', 99, 3);
|
248 |
//html|xhtml|atom|rss2|rdf|comment|export
|
493 |
return array('errorMsg' => "An invalid type was specified to get file.");
|
494 |
}
|
495 |
$api = new wfAPI(wfConfig::get('apiKey'), wfUtils::getWPVersion());
|
496 |
+
try {
|
497 |
+
$contResult = $api->binCall('get_wp_file_content', array(
|
498 |
+
'v' => wfUtils::getWPVersion(),
|
499 |
+
'file' => $file,
|
500 |
+
'cType' => $cType,
|
501 |
+
'cName' => $cName,
|
502 |
+
'cVersion' => $cVersion
|
503 |
+
));
|
504 |
+
if($contResult['data']){
|
505 |
+
return array('fileContent' => $contResult['data']);
|
506 |
+
} else {
|
507 |
+
throw new Exception("We could not fetch a core WordPress file from the Wordfence API.");
|
508 |
+
}
|
509 |
+
} catch (Exception $e){
|
510 |
+
return array('errorMsg' => $e->getMessage());
|
511 |
}
|
512 |
}
|
513 |
public static function ajax_sendActivityLog_callback(){
|
621 |
$paidKeyMsg = false;
|
622 |
if($opts['apiKey'] != wfConfig::get('apiKey')){
|
623 |
$api = new wfAPI($opts['apiKey'], wfUtils::getWPVersion());
|
624 |
+
try {
|
625 |
+
$res = $api->call('check_api_key', array(), array());
|
626 |
+
if($res['ok'] && isset($res['isPaid'])){
|
627 |
+
wfConfig::set('apiKey', $opts['apiKey']);
|
628 |
+
$reload = 'reload';
|
629 |
+
wfConfig::set('isPaid', $res['isPaid']);
|
630 |
+
if($res['isPaid']){
|
631 |
+
$paidKeyMsg = true;
|
632 |
+
}
|
633 |
+
} else {
|
634 |
+
throw new Exception("We could not understand the Wordfence API server reply when updating your API key.");
|
635 |
}
|
636 |
+
} catch (Exception $e){
|
637 |
+
return array('errorMsg' => $e->getMessage());
|
|
|
|
|
638 |
}
|
639 |
}
|
640 |
|
882 |
'file' => $localFile
|
883 |
);
|
884 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
885 |
public static function ajax_scan_callback(){
|
886 |
self::status(4, 'info', "Ajax request received to start scan.");
|
887 |
$err = wfScanEngine::startScan();
|
1137 |
|
1138 |
}
|
1139 |
}
|
1140 |
+
public static function noKeyError(){
|
1141 |
+
echo '<div id="wordfenceConfigWarning" class="fade error"><p><strong>Wordfence is not configured correctly.</strong> Go to your plugins menu and disable and re-enable Wordfence and this should fix the problem.</p></div>';
|
1142 |
+
}
|
1143 |
+
|
1144 |
public static function admin_menus(){
|
1145 |
if(! wfUtils::isAdmin()){ return; }
|
1146 |
if(! wfConfig::get('alertEmails')){
|
1150 |
add_action('admin_notices', 'wordfence::configure_warning');
|
1151 |
}
|
1152 |
}
|
1153 |
+
if(! wfConfig::get('apiKey')){
|
1154 |
+
if(wfUtils::isAdminPageMU()){
|
1155 |
+
add_action('network_admin_notices', 'wordfence::noKeyError');
|
1156 |
+
} else {
|
1157 |
+
add_action('admin_notices', 'wordfence::noKeyError');
|
1158 |
+
}
|
1159 |
+
}
|
1160 |
add_submenu_page("Wordfence", "Scan", "Scan", "activate_plugins", "Wordfence", 'wordfence::menu_scan');
|
1161 |
add_menu_page('Wordfence', 'Wordfence', 'activate_plugins', 'Wordfence', 'wordfence::menu_scan', wfUtils::getBaseURL() . 'images/wordfence-logo-16x16.png');
|
1162 |
if(wfConfig::get('liveTrafficEnabled')){
|
1171 |
public static function menu_blockedIPs(){
|
1172 |
require 'menu_blockedIPs.php';
|
1173 |
}
|
|
|
|
|
|
|
1174 |
public static function menu_activity(){
|
1175 |
require 'menu_activity.php';
|
1176 |
}
|
1199 |
}
|
1200 |
}
|
1201 |
public static function genFilter($gen, $type){
|
1202 |
+
if(wfConfig::get('other_hideWPVersion')){
|
1203 |
return '';
|
1204 |
} else {
|
1205 |
return $gen;
|
1268 |
return;
|
1269 |
}
|
1270 |
$api = new wfAPI(wfConfig::get('apiKey'), wfUtils::getWPVersion());
|
1271 |
+
try {
|
1272 |
+
$result = $api->call('get_next_scan_time', array(), array());
|
1273 |
+
$secsToGo = 3600 * 6; //In case we can't contact the API, schedule next scan 6 hours from now.
|
1274 |
+
if(is_array($result) && $result['secsToGo'] > 1800){
|
1275 |
+
$secsToGo = $result['secsToGo'];
|
1276 |
+
}
|
1277 |
+
wp_clear_scheduled_hook('wordfence_scheduled_scan');
|
1278 |
+
wp_schedule_single_event(time() + $secsToGo, 'wordfence_scheduled_scan');
|
1279 |
+
} catch (Exception $e){
|
1280 |
+
return $e->getMessage();
|
1281 |
}
|
|
|
|
|
1282 |
} else {
|
1283 |
wp_clear_scheduled_hook('wordfence_scheduled_scan');
|
1284 |
}
|
1343 |
}
|
1344 |
return self::$debugOn;
|
1345 |
}
|
1346 |
+
/* For testing cron jobs
|
1347 |
+
public static function moreCronReccurences(){
|
1348 |
+
return array(
|
1349 |
+
Feveryminute' => array('interval' => 60, 'display' => 'Once Every Minute'),
|
1350 |
+
);
|
1351 |
+
}
|
1352 |
+
*/
|
1353 |
}
|
1354 |
?>
|
lib/wordfenceHash.php
CHANGED
@@ -22,7 +22,7 @@ class wordfenceHash {
|
|
22 |
private $lastStatusTime = false;
|
23 |
public function __sleep(){ //same order as above
|
24 |
if(sizeof($this->fileQ) > 0){
|
25 |
-
|
26 |
}
|
27 |
return array('whitespace', 'totalData', 'totalFiles', 'totalDirs', 'linesOfPHP', 'linesOfJCH', 'striplen', 'hashPacket', 'hashStorageID', 'hashingStartTime', 'lastStatusTime');
|
28 |
}
|
@@ -47,7 +47,7 @@ class wordfenceHash {
|
|
47 |
$path .= '/';
|
48 |
}
|
49 |
if(! is_readable($path)){
|
50 |
-
|
51 |
exit();
|
52 |
}
|
53 |
$files = scandir($path);
|
@@ -127,11 +127,15 @@ class wordfenceHash {
|
|
127 |
}
|
128 |
private function writeFileQueue(){
|
129 |
$sql = "insert into " . $this->table . " (filename) values ";
|
|
|
130 |
foreach($this->fileQ as $val){
|
|
|
131 |
$sql .= "('" . mysql_real_escape_string($val) . "'),";
|
132 |
}
|
133 |
-
|
134 |
-
|
|
|
|
|
135 |
$this->fileQ = array();
|
136 |
}
|
137 |
private function processFile($file){
|
@@ -176,23 +180,19 @@ class wordfenceHash {
|
|
176 |
}
|
177 |
if($this->hashStorageID){
|
178 |
$dataArr = $this->api->binCall('add_hash_chunk', "WFID:" . pack('N', $this->hashStorageID) . $this->hashPacket);
|
179 |
-
if($this->api->errorMsg){ wordfence::status(1, 'error', $this->api->errorMsg); exit(); }
|
180 |
$this->hashPacket = "";
|
181 |
if(is_array($dataArr) && isset($dataArr['data']) && $dataArr['data'] == $this->hashStorageID){
|
182 |
//keep going
|
183 |
} else {
|
184 |
-
|
185 |
-
return false;
|
186 |
}
|
187 |
} else {
|
188 |
$dataArr = $this->api->binCall('add_hash_chunk', "WFST:" . $this->hashPacket);
|
189 |
-
if($this->api->errorMsg){ wordfence::status(1, 'error', $this->api->errorMsg); exit(); }
|
190 |
$this->hashPacket = "";
|
191 |
if(is_array($dataArr) && isset($dataArr['data']) && preg_match('/^\d+$/', $dataArr['data'])){
|
192 |
$this->hashStorageID = $dataArr['data'];
|
193 |
} else {
|
194 |
-
|
195 |
-
return false;
|
196 |
}
|
197 |
}
|
198 |
}
|
22 |
private $lastStatusTime = false;
|
23 |
public function __sleep(){ //same order as above
|
24 |
if(sizeof($this->fileQ) > 0){
|
25 |
+
throw new Exception("Sanity fail. fileQ is not empty. Has: " . sizeof($this->fileQ));
|
26 |
}
|
27 |
return array('whitespace', 'totalData', 'totalFiles', 'totalDirs', 'linesOfPHP', 'linesOfJCH', 'striplen', 'hashPacket', 'hashStorageID', 'hashingStartTime', 'lastStatusTime');
|
28 |
}
|
47 |
$path .= '/';
|
48 |
}
|
49 |
if(! is_readable($path)){
|
50 |
+
throw new Exception("Could not read directory $path to do scan.");
|
51 |
exit();
|
52 |
}
|
53 |
$files = scandir($path);
|
127 |
}
|
128 |
private function writeFileQueue(){
|
129 |
$sql = "insert into " . $this->table . " (filename) values ";
|
130 |
+
$added = false;
|
131 |
foreach($this->fileQ as $val){
|
132 |
+
$added = true;
|
133 |
$sql .= "('" . mysql_real_escape_string($val) . "'),";
|
134 |
}
|
135 |
+
if($added){
|
136 |
+
$sql = rtrim($sql, ',');
|
137 |
+
$this->db->query($sql);
|
138 |
+
}
|
139 |
$this->fileQ = array();
|
140 |
}
|
141 |
private function processFile($file){
|
180 |
}
|
181 |
if($this->hashStorageID){
|
182 |
$dataArr = $this->api->binCall('add_hash_chunk', "WFID:" . pack('N', $this->hashStorageID) . $this->hashPacket);
|
|
|
183 |
$this->hashPacket = "";
|
184 |
if(is_array($dataArr) && isset($dataArr['data']) && $dataArr['data'] == $this->hashStorageID){
|
185 |
//keep going
|
186 |
} else {
|
187 |
+
throw new Exception("Could not store an additional chunk of hash data on Wordfence servers with ID: " . $this->hashStorageID);
|
|
|
188 |
}
|
189 |
} else {
|
190 |
$dataArr = $this->api->binCall('add_hash_chunk', "WFST:" . $this->hashPacket);
|
|
|
191 |
$this->hashPacket = "";
|
192 |
if(is_array($dataArr) && isset($dataArr['data']) && preg_match('/^\d+$/', $dataArr['data'])){
|
193 |
$this->hashStorageID = $dataArr['data'];
|
194 |
} else {
|
195 |
+
throw new Exception("Could not store hash data on Wordfence servers. Got response: " . var_export($dataArr, true));
|
|
|
196 |
}
|
197 |
}
|
198 |
}
|
lib/wordfenceURLHoover.php
CHANGED
@@ -121,10 +121,6 @@ class wordfenceURLHoover {
|
|
121 |
$this->dbg("Checking " . sizeof($allHostKeys) . " hostkeys");
|
122 |
$resp = $this->api->binCall('check_host_keys', implode('', $allHostKeys));
|
123 |
$this->dbg("Done hostkey check");
|
124 |
-
if($this->api->errorMsg){
|
125 |
-
$this->errorMsg = $this->api->errorMsg;
|
126 |
-
return false;
|
127 |
-
}
|
128 |
|
129 |
$badHostKeys = array();
|
130 |
if($resp['code'] == 200){
|
@@ -170,10 +166,6 @@ class wordfenceURLHoover {
|
|
170 |
$this->dbg("Checking " . sizeof($urlsToCheck) . " URLs");
|
171 |
$badURLs = $this->api->call('check_bad_urls', array(), array( 'toCheck' => json_encode($urlsToCheck)) );
|
172 |
$this->dbg("Done URL check");
|
173 |
-
if($this->api->errorMsg){
|
174 |
-
$this->errorMsg = $this->api->errorMsg;
|
175 |
-
return false;
|
176 |
-
}
|
177 |
if(is_array($badURLs) && sizeof($badURLs) > 0){
|
178 |
$finalResults = array();
|
179 |
foreach($badURLs as $file => $badSiteList){
|
121 |
$this->dbg("Checking " . sizeof($allHostKeys) . " hostkeys");
|
122 |
$resp = $this->api->binCall('check_host_keys', implode('', $allHostKeys));
|
123 |
$this->dbg("Done hostkey check");
|
|
|
|
|
|
|
|
|
124 |
|
125 |
$badHostKeys = array();
|
126 |
if($resp['code'] == 200){
|
166 |
$this->dbg("Checking " . sizeof($urlsToCheck) . " URLs");
|
167 |
$badURLs = $this->api->call('check_bad_urls', array(), array( 'toCheck' => json_encode($urlsToCheck)) );
|
168 |
$this->dbg("Done URL check");
|
|
|
|
|
|
|
|
|
169 |
if(is_array($badURLs) && sizeof($badURLs) > 0){
|
170 |
$finalResults = array();
|
171 |
foreach($badURLs as $file => $badSiteList){
|
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
|
6 |
-
Stable tag: 3.0.
|
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 |
|
@@ -152,6 +152,13 @@ or a theme, because often these have been updated to fix a security hole.
|
|
152 |
5. If you're technically minded, this is the under-the-hood view of Wordfence options where you can fine-tune your security settings.
|
153 |
|
154 |
== Changelog ==
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
155 |
|
156 |
= 3.0.2 =
|
157 |
* Overall this release is a very important upgrade. It drastically reduces memory usage on systems with large files from hundreds of megs to around 8 megs max memory used per scan.
|
@@ -411,6 +418,10 @@ or a theme, because often these have been updated to fix a security hole.
|
|
411 |
* Initial public release of Wordfence.
|
412 |
|
413 |
== Upgrade Notice ==
|
|
|
|
|
|
|
|
|
414 |
|
415 |
= 3.0.2 =
|
416 |
Upgrade immediately. This release drastically reduces memory, reduces new DB connections created by
|
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
|
6 |
+
Stable tag: 3.0.3
|
7 |
|
8 |
Wordfence Security is a free enterprise class security plugin that includes a firewall, virus scanning, real-time traffic with geolocation and more.
|
9 |
|
152 |
5. If you're technically minded, this is the under-the-hood view of Wordfence options where you can fine-tune your security settings.
|
153 |
|
154 |
== Changelog ==
|
155 |
+
= 3.0.3 =
|
156 |
+
* Issue that caused all core files to show as missing has been fixed.
|
157 |
+
* We now handle all API server errors gracefully using exceptions.
|
158 |
+
* If your installation didn't activate correctly you now get a friendly message.
|
159 |
+
* Removed unused menu_config.php code.
|
160 |
+
* The 503 message now tells you why your access to the site has been limited so that admin's can tune firewall rules better.
|
161 |
+
* We no longer reuse the WordPress wpdb handle because we get better stability with our own connection.
|
162 |
|
163 |
= 3.0.2 =
|
164 |
* Overall this release is a very important upgrade. It drastically reduces memory usage on systems with large files from hundreds of megs to around 8 megs max memory used per scan.
|
418 |
* Initial public release of Wordfence.
|
419 |
|
420 |
== Upgrade Notice ==
|
421 |
+
= 3.0.3 =
|
422 |
+
Upgrade immediately. This release fixes an issue that caused Wordfence to show all your core files
|
423 |
+
missing under certain conditions. It was usually caused by high load on our scanning server and the
|
424 |
+
plugin not handling an error condition halfway through the scan correctly.
|
425 |
|
426 |
= 3.0.2 =
|
427 |
Upgrade immediately. This release drastically reduces memory, reduces new DB connections created by
|
wfscan.php
CHANGED
@@ -106,7 +106,14 @@ class wfScan {
|
|
106 |
wordfence::statusPrep(); //Re-initializes all status counters
|
107 |
$scan = new wfScanEngine();
|
108 |
}
|
109 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
110 |
wfUtils::clearScanLock();
|
111 |
self::logPeakMemory();
|
112 |
wordfence::status(2, 'info', "Wordfence used " . sprintf('%.2f', (wfConfig::get('wfPeakMemory') - self::$peakMemAtStart) / 1024 / 1024) . "MB of memory for scan. Server peak memory usage was: " . sprintf('%.2f', wfConfig::get('wfPeakMemory') / 1024 / 1024) . "MB");
|
106 |
wordfence::statusPrep(); //Re-initializes all status counters
|
107 |
$scan = new wfScanEngine();
|
108 |
}
|
109 |
+
try {
|
110 |
+
$scan->go();
|
111 |
+
} catch (Exception $e){
|
112 |
+
wfUtils::clearScanLock();
|
113 |
+
wordfence::status(2, 'error', "Scan terminated with error: " . $e->getMessage());
|
114 |
+
wordfence::status(10, 'info', "SUM_KILLED:Previous scan terminated with an error. See below.");
|
115 |
+
exit();
|
116 |
+
}
|
117 |
wfUtils::clearScanLock();
|
118 |
self::logPeakMemory();
|
119 |
wordfence::status(2, 'info', "Wordfence used " . sprintf('%.2f', (wfConfig::get('wfPeakMemory') - self::$peakMemAtStart) / 1024 / 1024) . "MB of memory for scan. Server peak memory usage was: " . sprintf('%.2f', wfConfig::get('wfPeakMemory') / 1024 / 1024) . "MB");
|
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.0.
|
8 |
Author URI: http://wordfence.com/
|
9 |
*/
|
10 |
-
define('WORDFENCE_VERSION', '3.0.
|
11 |
if(! defined('WORDFENCE_VERSIONONLY_MODE')){
|
12 |
require_once('lib/wordfenceConstants.php');
|
13 |
require_once('lib/wordfenceClass.php');
|
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.0.3
|
8 |
Author URI: http://wordfence.com/
|
9 |
*/
|
10 |
+
define('WORDFENCE_VERSION', '3.0.3');
|
11 |
if(! defined('WORDFENCE_VERSIONONLY_MODE')){
|
12 |
require_once('lib/wordfenceConstants.php');
|
13 |
require_once('lib/wordfenceClass.php');
|