Version Description
- Removed unbuffered queries and switched to conventional queries that are memory efficient for better stability.
- Made scanning large numbers of URL's contained in things like awstats log files extremely memory efficient and way faster.
- Removed alerts about unknown files in core directory if they belong to an older wordpress version and are unchanged.
- Other performance improvements like using strpos instead of strstr.
- Moved "scan files outside base dir" option to be in correct place on config page.
Download this release
Release Info
Developer | mmaunder |
Plugin | Wordfence Security – Firewall & Malware Scan |
Version | 2.0.3 |
Comparing to | |
See all releases |
Code changes from version 2.0.2 to 2.0.3
- lib/menu_options.php +1 -1
- lib/wfAPI.php +0 -7
- lib/wfDB.php +1 -20
- lib/wfScanEngine.php +11 -14
- lib/wfSchema.php +8 -0
- lib/wordfenceConstants.php +1 -1
- lib/wordfenceURLHoover.php +22 -41
- readme.txt +8 -1
- wordfence.php +1 -1
lib/menu_options.php
CHANGED
@@ -75,6 +75,7 @@ var WFSLevels = <?php echo json_encode(wfConfig::$securityLevels); ?>;
|
|
75 |
<tr><th>Check the strength of passwords</th><td><input type="checkbox" id="scansEnabled_passwds" class="wfConfigElem" name="scansEnabled_passwds" value="1" <?php $w->cb('scansEnabled_passwds'); ?>/></td></tr>
|
76 |
<tr><th>Monitor disk space</th><td><input type="checkbox" id="scansEnabled_diskSpace" class="wfConfigElem" name="scansEnabled_diskSpace" value="1" <?php $w->cb('scansEnabled_diskSpace'); ?>/></td></tr>
|
77 |
<tr><th>Scan for unauthorized DNS changes</th><td><input type="checkbox" id="scansEnabled_dns" class="wfConfigElem" name="scansEnabled_dns" value="1" <?php $w->cb('scansEnabled_dns'); ?>/></td></tr>
|
|
|
78 |
<tr><td colspan="2">
|
79 |
<h3 class="wfConfigHeading">Firewall Rules</h3>
|
80 |
</td></tr>
|
@@ -185,7 +186,6 @@ var WFSLevels = <?php echo json_encode(wfConfig::$securityLevels); ?>;
|
|
185 |
<tr><th>Scan comments for malware and phishing URL's</th><td><input type="checkbox" id="other_scanComments" class="wfConfigElem" name="other_scanComments" value="1" <?php $w->cb('other_scanComments'); ?> /></td></tr>
|
186 |
<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>
|
187 |
<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>
|
188 |
-
<tr><th>Scan files outside your WordPress installation</th><td><input type="checkbox" id="other_scanOutside" class="wfConfigElem" name="other_scanOutside" value="1" <?php $w->cb('other_scanOutside'); ?> /></td></tr>
|
189 |
<tr><th>Your Wordfence API Key</th><td><input type="text" id="apiKey" name="apiKey" value="<?php $w->f('apiKey'); ?>" size="20" /></td></tr>
|
190 |
<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>
|
191 |
<tr><th colspan="2"><a href="/?_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>
|
75 |
<tr><th>Check the strength of passwords</th><td><input type="checkbox" id="scansEnabled_passwds" class="wfConfigElem" name="scansEnabled_passwds" value="1" <?php $w->cb('scansEnabled_passwds'); ?>/></td></tr>
|
76 |
<tr><th>Monitor disk space</th><td><input type="checkbox" id="scansEnabled_diskSpace" class="wfConfigElem" name="scansEnabled_diskSpace" value="1" <?php $w->cb('scansEnabled_diskSpace'); ?>/></td></tr>
|
77 |
<tr><th>Scan for unauthorized DNS changes</th><td><input type="checkbox" id="scansEnabled_dns" class="wfConfigElem" name="scansEnabled_dns" value="1" <?php $w->cb('scansEnabled_dns'); ?>/></td></tr>
|
78 |
+
<tr><th>Scan files outside your WordPress installation</th><td><input type="checkbox" id="other_scanOutside" class="wfConfigElem" name="other_scanOutside" value="1" <?php $w->cb('other_scanOutside'); ?> /></td></tr>
|
79 |
<tr><td colspan="2">
|
80 |
<h3 class="wfConfigHeading">Firewall Rules</h3>
|
81 |
</td></tr>
|
186 |
<tr><th>Scan comments for malware and phishing URL's</th><td><input type="checkbox" id="other_scanComments" class="wfConfigElem" name="other_scanComments" value="1" <?php $w->cb('other_scanComments'); ?> /></td></tr>
|
187 |
<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>
|
188 |
<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>
|
|
|
189 |
<tr><th>Your Wordfence API Key</th><td><input type="text" id="apiKey" name="apiKey" value="<?php $w->f('apiKey'); ?>" size="20" /></td></tr>
|
190 |
<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>
|
191 |
<tr><th colspan="2"><a href="/?_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
@@ -27,7 +27,6 @@ class wfAPI {
|
|
27 |
} else {
|
28 |
$this->errorMsg = "We could not fetch data from the API when calling '$action': " . $this->lastURLError;
|
29 |
}
|
30 |
-
wordfence::status(3, 'error', "API Error: " . $this->errorMsg);
|
31 |
return false;
|
32 |
}
|
33 |
|
@@ -38,11 +37,6 @@ class wfAPI {
|
|
38 |
if(empty($dat['errorMsg']) === false){
|
39 |
$this->errorMsg = $dat['errorMsg'];
|
40 |
}
|
41 |
-
if($this->errorMsg){
|
42 |
-
wordfence::status(3, 'error', "API Error: " . $this->errorMsg);
|
43 |
-
} else {
|
44 |
-
//wordfence::status(3, 'info', "Completed API call: $action");
|
45 |
-
}
|
46 |
return $dat;
|
47 |
}
|
48 |
public function curlWrite($h, $d){
|
@@ -114,7 +108,6 @@ class wfAPI {
|
|
114 |
$jdat = @json_decode($data, true);
|
115 |
if(is_array($jdat) && $jdat['errorMsg']){
|
116 |
$this->errorMsg = $jdat['errorMsg'];
|
117 |
-
wordfence::status(3, 'error', "Error in binary API call $func: " . $this->errorMsg);
|
118 |
return false;
|
119 |
}
|
120 |
}
|
27 |
} else {
|
28 |
$this->errorMsg = "We could not fetch data from the API when calling '$action': " . $this->lastURLError;
|
29 |
}
|
|
|
30 |
return false;
|
31 |
}
|
32 |
|
37 |
if(empty($dat['errorMsg']) === false){
|
38 |
$this->errorMsg = $dat['errorMsg'];
|
39 |
}
|
|
|
|
|
|
|
|
|
|
|
40 |
return $dat;
|
41 |
}
|
42 |
public function curlWrite($h, $d){
|
108 |
$jdat = @json_decode($data, true);
|
109 |
if(is_array($jdat) && $jdat['errorMsg']){
|
110 |
$this->errorMsg = $jdat['errorMsg'];
|
|
|
111 |
return false;
|
112 |
}
|
113 |
}
|
lib/wfDB.php
CHANGED
@@ -14,7 +14,7 @@ class wfDB {
|
|
14 |
$this->dbname = $dbname;
|
15 |
} else {
|
16 |
global $wpdb;
|
17 |
-
if(! $wpdb){ die("Not running under wordpress. Please supply db
|
18 |
$this->dbhost = $wpdb->dbhost;
|
19 |
$this->dbuser = $wpdb->dbuser;
|
20 |
$this->dbpassword = $wpdb->dbpassword;
|
@@ -94,25 +94,6 @@ class wfDB {
|
|
94 |
}
|
95 |
return $res;
|
96 |
}
|
97 |
-
public function uQuery(){ //sprintfString, arguments NOTE: Very important that there is no other DB activity between uQuery and when you call mysql_free_result on the return value of uQuery.
|
98 |
-
$args = func_get_args();
|
99 |
-
if(sizeof($args) == 1){
|
100 |
-
$query = $args[0];
|
101 |
-
} else if(sizeof($args) > 1){
|
102 |
-
for($i = 1; $i < sizeof($args); $i++){
|
103 |
-
$args[$i] = mysql_real_escape_string($args[$i]);
|
104 |
-
}
|
105 |
-
$query = call_user_func_array('sprintf', $args);
|
106 |
-
} else {
|
107 |
-
wfdie("No arguments passed to query()");
|
108 |
-
}
|
109 |
-
$res = mysql_unbuffered_query($query, $this->dbh);
|
110 |
-
$err = mysql_error();
|
111 |
-
if($err){
|
112 |
-
$trace=debug_backtrace(); $caller=array_shift($trace); error_log("Wordfence DB error in " . $caller['file'] . " line " . $caller['line'] . ": $err");
|
113 |
-
}
|
114 |
-
return $res;
|
115 |
-
}
|
116 |
private function wfdie($msg){
|
117 |
error_log($msg);
|
118 |
exit(1);
|
14 |
$this->dbname = $dbname;
|
15 |
} else {
|
16 |
global $wpdb;
|
17 |
+
if(! $wpdb){ die("Not running under wordpress. Please supply db credentials to constructor."); }
|
18 |
$this->dbhost = $wpdb->dbhost;
|
19 |
$this->dbuser = $wpdb->dbuser;
|
20 |
$this->dbpassword = $wpdb->dbpassword;
|
94 |
}
|
95 |
return $res;
|
96 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
97 |
private function wfdie($msg){
|
98 |
error_log($msg);
|
99 |
exit(1);
|
lib/wfScanEngine.php
CHANGED
@@ -274,11 +274,11 @@ class wfScanEngine {
|
|
274 |
$statusIDX = wordfence::statusStart('Scanning posts for URL\'s in Google\'s Safe Browsing List');
|
275 |
global $wpdb;
|
276 |
$wfdb = new wfDB();
|
277 |
-
|
278 |
-
$q1 = $wfdb->uQuery("select ID, post_title, post_type, post_date, post_content from $wpdb->posts where post_type IN ('page', 'post') and post_status = 'publish'");
|
279 |
$h = new wordfenceURLHoover($this->apiKey, $this->wp_version);
|
280 |
$postDat = array();
|
281 |
-
while($
|
|
|
282 |
$h->hoover($row['ID'], $row['post_title'] . ' ' . $row['post_content']);
|
283 |
$postDat[$row['ID']] = array(
|
284 |
'contentMD5' => md5($row['post_content']),
|
@@ -288,7 +288,6 @@ class wfScanEngine {
|
|
288 |
);
|
289 |
|
290 |
}
|
291 |
-
mysql_free_result($q1);
|
292 |
$this->status(2, 'info', "Examining URLs found in posts we scanned for dangerous websites");
|
293 |
$hooverResults = $h->getBaddies();
|
294 |
$this->status(2, 'info', "Done examining URls");
|
@@ -370,17 +369,20 @@ class wfScanEngine {
|
|
370 |
$statusIDX = wordfence::statusStart('Scanning comments for URL\'s in Google\'s Safe Browsing List');
|
371 |
global $wpdb;
|
372 |
$wfdb = new wfDB();
|
373 |
-
|
374 |
-
$q1 = $wfdb->uQuery("select comment_ID, comment_date, comment_type, comment_author, comment_author_url, comment_content from $wpdb->comments where comment_approved=1");
|
375 |
if( ! $q1){
|
376 |
wordfence::statusEndErr();
|
377 |
return;
|
378 |
}
|
|
|
|
|
|
|
|
|
|
|
379 |
$h = new wordfenceURLHoover($this->apiKey, $this->wp_version);
|
380 |
$commentDat = array();
|
381 |
-
$
|
382 |
-
|
383 |
-
$gotRow = true; //because we can't use mysql_num_rows on unbuffered queries
|
384 |
$h->hoover($row['comment_ID'], $row['comment_author_url'] . ' ' . $row['comment_author'] . ' ' . $row['comment_content']);
|
385 |
$commentDat[$row['comment_ID']] = array(
|
386 |
'contentMD5' => md5($row['comment_content'] . $row['comment_author'] . $row['comment_author_url']),
|
@@ -389,11 +391,6 @@ class wfScanEngine {
|
|
389 |
'date' => $row['comment_date']
|
390 |
);
|
391 |
}
|
392 |
-
mysql_free_result($q1);
|
393 |
-
if(! $gotRow){
|
394 |
-
wordfence::statusEnd($statusIDX, false);
|
395 |
-
return;
|
396 |
-
}
|
397 |
$hooverResults = $h->getBaddies();
|
398 |
if($h->errorMsg){
|
399 |
$this->errorStop($h->errorMsg);
|
274 |
$statusIDX = wordfence::statusStart('Scanning posts for URL\'s in Google\'s Safe Browsing List');
|
275 |
global $wpdb;
|
276 |
$wfdb = new wfDB();
|
277 |
+
$q1 = $wfdb->query("select ID from $wpdb->posts where post_type IN ('page', 'post') and post_status = 'publish'");
|
|
|
278 |
$h = new wordfenceURLHoover($this->apiKey, $this->wp_version);
|
279 |
$postDat = array();
|
280 |
+
while($idRow = mysql_fetch_assoc($q1)){
|
281 |
+
$row = $wfdb->querySingleRec("select ID, post_title, post_type, post_date, post_content from $wpdb->posts where ID=%d", $idRow['ID']);
|
282 |
$h->hoover($row['ID'], $row['post_title'] . ' ' . $row['post_content']);
|
283 |
$postDat[$row['ID']] = array(
|
284 |
'contentMD5' => md5($row['post_content']),
|
288 |
);
|
289 |
|
290 |
}
|
|
|
291 |
$this->status(2, 'info', "Examining URLs found in posts we scanned for dangerous websites");
|
292 |
$hooverResults = $h->getBaddies();
|
293 |
$this->status(2, 'info', "Done examining URls");
|
369 |
$statusIDX = wordfence::statusStart('Scanning comments for URL\'s in Google\'s Safe Browsing List');
|
370 |
global $wpdb;
|
371 |
$wfdb = new wfDB();
|
372 |
+
$q1 = $wfdb->query("select comment_ID from $wpdb->comments where comment_approved=1");
|
|
|
373 |
if( ! $q1){
|
374 |
wordfence::statusEndErr();
|
375 |
return;
|
376 |
}
|
377 |
+
if(! (mysql_num_rows($q1) > 0)){
|
378 |
+
wordfence::statusEnd($statusIDX, false);
|
379 |
+
return;
|
380 |
+
}
|
381 |
+
|
382 |
$h = new wordfenceURLHoover($this->apiKey, $this->wp_version);
|
383 |
$commentDat = array();
|
384 |
+
while($idRow = mysql_fetch_assoc($q1)){
|
385 |
+
$row = $wfdb->querySingleRec("select comment_ID, comment_date, comment_type, comment_author, comment_author_url, comment_content from $wpdb->comments where comment_ID=%d", $idRow['comment_ID']);
|
|
|
386 |
$h->hoover($row['comment_ID'], $row['comment_author_url'] . ' ' . $row['comment_author'] . ' ' . $row['comment_content']);
|
387 |
$commentDat[$row['comment_ID']] = array(
|
388 |
'contentMD5' => md5($row['comment_content'] . $row['comment_author'] . $row['comment_author_url']),
|
391 |
'date' => $row['comment_date']
|
392 |
);
|
393 |
}
|
|
|
|
|
|
|
|
|
|
|
394 |
$hooverResults = $h->getBaddies();
|
395 |
if($h->errorMsg){
|
396 |
$this->errorStop($h->errorMsg);
|
lib/wfSchema.php
CHANGED
@@ -134,6 +134,14 @@ class wfSchema {
|
|
134 |
ctime int UNSIGNED NOT NULL,
|
135 |
URI varchar(1000) NOT NULL,
|
136 |
KEY k1(ctime)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
137 |
) default charset=utf8"
|
138 |
);
|
139 |
private $db = false;
|
134 |
ctime int UNSIGNED NOT NULL,
|
135 |
URI varchar(1000) NOT NULL,
|
136 |
KEY k1(ctime)
|
137 |
+
) default charset=utf8",
|
138 |
+
'wfHoover' => "(
|
139 |
+
id int UNSIGNED auto_increment PRIMARY KEY,
|
140 |
+
owner text,
|
141 |
+
host text,
|
142 |
+
path text,
|
143 |
+
hostKey binary(4),
|
144 |
+
KEY k2(hostKey)
|
145 |
) default charset=utf8"
|
146 |
);
|
147 |
private $db = false;
|
lib/wordfenceConstants.php
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
<?php
|
2 |
-
define('WORDFENCE_VERSION', 1.
|
3 |
define('WORDFENCE_API_URL', 'https://noc1.wordfence.com/');
|
4 |
define('WORDFENCE_MAX_SCAN_TIME', 600);
|
5 |
define('WORDFENCE_TRANSIENTS_TIMEOUT', 3600); //how long are items cached in seconds e.g. files downloaded for diffing
|
1 |
<?php
|
2 |
+
define('WORDFENCE_VERSION', 1.4);
|
3 |
define('WORDFENCE_API_URL', 'https://noc1.wordfence.com/');
|
4 |
define('WORDFENCE_MAX_SCAN_TIME', 600);
|
5 |
define('WORDFENCE_TRANSIENTS_TIMEOUT', 3600); //how long are items cached in seconds e.g. files downloaded for diffing
|
lib/wordfenceURLHoover.php
CHANGED
@@ -3,16 +3,20 @@ require_once('wfAPI.php');
|
|
3 |
class wordfenceURLHoover {
|
4 |
private $debug = false;
|
5 |
private $URLsByID = array();
|
6 |
-
private $hostKeysByID = array();
|
7 |
public $errorMsg = false;
|
8 |
private $hostKeyCache = array();
|
9 |
private $api = false;
|
|
|
10 |
private $dRegex = 'aero|asia|biz|cat|com|coop|edu|gov|info|int|jobs|mil|mobi|museum|name|net|org|pro|tel|travel|xxx|ac|ad|ae|af|ag|ai|al|am|an|ao|aq|ar|as|at|au|aw|ax|az|ba|bb|bd|be|bf|bg|bh|bi|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|cr|cs|cu|cv|cx|cy|cz|dd|de|dj|dk|dm|do|dz|ec|ee|eg|eh|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gb|gd|ge|gf|gg|gh|gi|gl|gm|gn|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|im|in|io|iq|ir|is|it|je|jm|jo|jp|ke|kg|kh|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|me|mg|mh|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|mv|mw|mx|my|mz|na|nc|ne|nf|ng|ni|nl|no|np|nr|nu|nz|om|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|ps|pt|pw|py|qa|re|ro|rs|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|sk|sl|sm|sn|so|sr|ss|st|su|sv|sy|sz|tc|td|tf|tg|th|tj|tk|tl|tm|tn|to|tp|tr|tt|tv|tw|tz|ua|ug|uk|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|za|zm|zw|xn--lgbbat1ad8j|xn--fiqs8s|xn--fiqz9s|xn--wgbh1c|xn--j6w193g|xn--h2brj9c|xn--mgbbh1a71e|xn--fpcrj9c3d|xn--gecrj9c|xn--s9brj9c|xn--xkc2dl3a5ee0h|xn--45brj9c|xn--mgba3a4f16a|xn--mgbayh7gpa|xn--mgbc0a9azcg|xn--ygbi2ammx|xn--wgbl6a|xn--p1ai|xn--mgberp4a5d4ar|xn--90a3ac|xn--yfro4i67o|xn--clchc0ea0b2g2a9gcd|xn--3e0b707e|xn--fzc2c9e2c|xn--xkc2al3hye2a|xn--mgbtf8fl|xn--kprw13d|xn--kpry57d|xn--o3cw4h|xn--pgbs0dh|xn--mgbaam7a8h|xn--54b7fta0cc|xn--90ae|xn--node|xn--4dbrk0ce|xn--80ao21a|xn--mgb9awbf|xn--mgbai9azgqp6j|xn--j1amh|xn--mgb2ddes|xn--kgbechtv|xn--hgbk6aj7f53bba|xn--0zwm56d|xn--g6w251d|xn--80akhbyknj4f|xn--11b5bs3a9aj6g|xn--jxalpdlp|xn--9t4b11yi5a|xn--deba0ad|xn--zckzah|xn--hlcj6aya9esc7a';
|
11 |
public function __construct($apiKey, $wordpressVersion){
|
12 |
$this->api = new wfAPI($apiKey, $wordpressVersion);
|
|
|
|
|
|
|
|
|
13 |
}
|
14 |
public function hoover($id, $data){
|
15 |
-
if(
|
16 |
return;
|
17 |
}
|
18 |
if(! preg_match('/[a-zA-Z0-9\-]+\.(?:' . $this->dRegex . ')/i', $data)){
|
@@ -25,13 +29,11 @@ class wordfenceURLHoover {
|
|
25 |
}
|
26 |
private function dbg($msg){ if($this->debug){ error_log("DEBUG: $msg\n"); } }
|
27 |
public function addHost($id, $host, $path){
|
28 |
-
$this->dbg("Adding host with ID $id and $host $path");
|
29 |
$path = preg_replace_callback('/([^A-Za-z0-9\-\.\_\~:\/\?\#\[\]\@\!\$\&\'\(\)\*\+\,;\=]+)/', 'wordfenceURLHoover::urlenc', $path);
|
30 |
$host = strtolower($host);
|
31 |
$this->intAddHost($id, $host, $path);
|
32 |
}
|
33 |
public function addIP($id, $ipdata, $path){
|
34 |
-
$this->dbg("Adding IP with ID $id and $ipdata $path");
|
35 |
$path = preg_replace_callback('/([^A-Za-z0-9\-\.\_\~:\/\?\#\[\]\@\!\$\&\'\(\)\*\+\,;\=]+)/', 'wordfenceURLHoover::urlenc', $path);
|
36 |
if(strstr($ipdata, '.') === false && $ipdata >= 16777216 && $ipdata <= 4026531840){
|
37 |
$ipdata = long2ip($ipdata);
|
@@ -59,19 +61,11 @@ class wordfenceURLHoover {
|
|
59 |
if(strpos($path, '/') !== 0){
|
60 |
$path = '/';
|
61 |
}
|
62 |
-
|
63 |
-
if($elem[0] == $host && $elem[1] == $path){
|
64 |
-
$this->dbg("Host/Path $host $path already in URLsByID");
|
65 |
-
return false;
|
66 |
-
}
|
67 |
-
}
|
68 |
-
$this->dbg("Adding Host/Path $host $path to URLsByID");
|
69 |
-
$this->URLsByID[$id][] = array($host, $path);
|
70 |
return true;
|
71 |
}
|
72 |
private function makeHostKey($host){
|
73 |
if(isset($this->hostKeyCache[$host])){
|
74 |
-
$this->dbg("Returning cached hostkey for $host");
|
75 |
return $this->hostKeyCache[$host];
|
76 |
}
|
77 |
$hostParts = explode('.', $host);
|
@@ -82,25 +76,15 @@ class wordfenceURLHoover {
|
|
82 |
$hostKey = substr(hash('sha256', $hostParts[sizeof($hostParts) - 3] . '.' . $hostParts[sizeof($hostParts) - 2] . '.' . $hostParts[sizeof($hostParts) - 1] . '/', true), 0, 4);
|
83 |
}
|
84 |
$this->hostKeyCache[$host] = $hostKey;
|
85 |
-
$this->dbg("Returning uncached hostkey for $host");
|
86 |
return $hostKey;
|
87 |
}
|
88 |
public function getBaddies(){
|
89 |
$allHostKeys = array();
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
if(! in_array($hostKey, $allHostKeys)){
|
96 |
-
array_push($allHostKeys, $hostKey);
|
97 |
-
$this->dbg("Adding hostkey for $host");
|
98 |
-
}
|
99 |
-
if(! isset($this->hostKeysByID[$id])){
|
100 |
-
$this->hostKeysByID[$id] = array();
|
101 |
-
}
|
102 |
-
$this->hostKeysByID[$id] = $hostKey;
|
103 |
-
}
|
104 |
}
|
105 |
//Now call API and check if any hostkeys are bad.
|
106 |
//This is a shortcut, because if no hostkeys are bad it saves us having to check URLs
|
@@ -142,22 +126,19 @@ class wordfenceURLHoover {
|
|
142 |
$urlsToCheck = array();
|
143 |
//need to figure out which id's have bad hostkeys
|
144 |
//need to feed in all URL's from those id's where the hostkey matches a URL
|
145 |
-
foreach($
|
146 |
-
|
147 |
-
|
148 |
-
$
|
149 |
-
$
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
}
|
155 |
-
if(! in_array($url, $urlsToCheck[$id])){
|
156 |
-
$urlsToCheck[$id][] = $url;
|
157 |
-
}
|
158 |
}
|
159 |
}
|
160 |
}
|
|
|
161 |
if(sizeof($urlsToCheck) > 0){
|
162 |
$this->dbg("Checking " . sizeof($urlsToCheck) . " URLs");
|
163 |
$badURLs = $this->api->call('check_bad_urls', array(), array( 'toCheck' => json_encode($urlsToCheck)) );
|
3 |
class wordfenceURLHoover {
|
4 |
private $debug = false;
|
5 |
private $URLsByID = array();
|
|
|
6 |
public $errorMsg = false;
|
7 |
private $hostKeyCache = array();
|
8 |
private $api = false;
|
9 |
+
private $table = '';
|
10 |
private $dRegex = 'aero|asia|biz|cat|com|coop|edu|gov|info|int|jobs|mil|mobi|museum|name|net|org|pro|tel|travel|xxx|ac|ad|ae|af|ag|ai|al|am|an|ao|aq|ar|as|at|au|aw|ax|az|ba|bb|bd|be|bf|bg|bh|bi|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|cr|cs|cu|cv|cx|cy|cz|dd|de|dj|dk|dm|do|dz|ec|ee|eg|eh|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gb|gd|ge|gf|gg|gh|gi|gl|gm|gn|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|im|in|io|iq|ir|is|it|je|jm|jo|jp|ke|kg|kh|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|me|mg|mh|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|mv|mw|mx|my|mz|na|nc|ne|nf|ng|ni|nl|no|np|nr|nu|nz|om|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|ps|pt|pw|py|qa|re|ro|rs|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|sk|sl|sm|sn|so|sr|ss|st|su|sv|sy|sz|tc|td|tf|tg|th|tj|tk|tl|tm|tn|to|tp|tr|tt|tv|tw|tz|ua|ug|uk|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|za|zm|zw|xn--lgbbat1ad8j|xn--fiqs8s|xn--fiqz9s|xn--wgbh1c|xn--j6w193g|xn--h2brj9c|xn--mgbbh1a71e|xn--fpcrj9c3d|xn--gecrj9c|xn--s9brj9c|xn--xkc2dl3a5ee0h|xn--45brj9c|xn--mgba3a4f16a|xn--mgbayh7gpa|xn--mgbc0a9azcg|xn--ygbi2ammx|xn--wgbl6a|xn--p1ai|xn--mgberp4a5d4ar|xn--90a3ac|xn--yfro4i67o|xn--clchc0ea0b2g2a9gcd|xn--3e0b707e|xn--fzc2c9e2c|xn--xkc2al3hye2a|xn--mgbtf8fl|xn--kprw13d|xn--kpry57d|xn--o3cw4h|xn--pgbs0dh|xn--mgbaam7a8h|xn--54b7fta0cc|xn--90ae|xn--node|xn--4dbrk0ce|xn--80ao21a|xn--mgb9awbf|xn--mgbai9azgqp6j|xn--j1amh|xn--mgb2ddes|xn--kgbechtv|xn--hgbk6aj7f53bba|xn--0zwm56d|xn--g6w251d|xn--80akhbyknj4f|xn--11b5bs3a9aj6g|xn--jxalpdlp|xn--9t4b11yi5a|xn--deba0ad|xn--zckzah|xn--hlcj6aya9esc7a';
|
11 |
public function __construct($apiKey, $wordpressVersion){
|
12 |
$this->api = new wfAPI($apiKey, $wordpressVersion);
|
13 |
+
$this->db = new wfDB();
|
14 |
+
global $wpdb;
|
15 |
+
$this->table = $wpdb->prefix . 'wfHoover';
|
16 |
+
$this->db->query("truncate table $this->table");
|
17 |
}
|
18 |
public function hoover($id, $data){
|
19 |
+
if(strpos($data, '.') === false){
|
20 |
return;
|
21 |
}
|
22 |
if(! preg_match('/[a-zA-Z0-9\-]+\.(?:' . $this->dRegex . ')/i', $data)){
|
29 |
}
|
30 |
private function dbg($msg){ if($this->debug){ error_log("DEBUG: $msg\n"); } }
|
31 |
public function addHost($id, $host, $path){
|
|
|
32 |
$path = preg_replace_callback('/([^A-Za-z0-9\-\.\_\~:\/\?\#\[\]\@\!\$\&\'\(\)\*\+\,;\=]+)/', 'wordfenceURLHoover::urlenc', $path);
|
33 |
$host = strtolower($host);
|
34 |
$this->intAddHost($id, $host, $path);
|
35 |
}
|
36 |
public function addIP($id, $ipdata, $path){
|
|
|
37 |
$path = preg_replace_callback('/([^A-Za-z0-9\-\.\_\~:\/\?\#\[\]\@\!\$\&\'\(\)\*\+\,;\=]+)/', 'wordfenceURLHoover::urlenc', $path);
|
38 |
if(strstr($ipdata, '.') === false && $ipdata >= 16777216 && $ipdata <= 4026531840){
|
39 |
$ipdata = long2ip($ipdata);
|
61 |
if(strpos($path, '/') !== 0){
|
62 |
$path = '/';
|
63 |
}
|
64 |
+
$this->db->query("insert into $this->table (owner, host, path, hostKey) values ('%s', '%s', '%s', '%s')", $id, $host, $path, $this->makeHostKey($host));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
65 |
return true;
|
66 |
}
|
67 |
private function makeHostKey($host){
|
68 |
if(isset($this->hostKeyCache[$host])){
|
|
|
69 |
return $this->hostKeyCache[$host];
|
70 |
}
|
71 |
$hostParts = explode('.', $host);
|
76 |
$hostKey = substr(hash('sha256', $hostParts[sizeof($hostParts) - 3] . '.' . $hostParts[sizeof($hostParts) - 2] . '.' . $hostParts[sizeof($hostParts) - 1] . '/', true), 0, 4);
|
77 |
}
|
78 |
$this->hostKeyCache[$host] = $hostKey;
|
|
|
79 |
return $hostKey;
|
80 |
}
|
81 |
public function getBaddies(){
|
82 |
$allHostKeys = array();
|
83 |
+
$stime = microtime(true);
|
84 |
+
$allHostKeys = array();
|
85 |
+
$q1 = $this->db->query("select distinct hostKey as hostKey from $this->table");
|
86 |
+
while($hRec = mysql_fetch_assoc($q1)){
|
87 |
+
array_push($allHostKeys, $hRec['hostKey']);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
88 |
}
|
89 |
//Now call API and check if any hostkeys are bad.
|
90 |
//This is a shortcut, because if no hostkeys are bad it saves us having to check URLs
|
126 |
$urlsToCheck = array();
|
127 |
//need to figure out which id's have bad hostkeys
|
128 |
//need to feed in all URL's from those id's where the hostkey matches a URL
|
129 |
+
foreach($badHostKeys as $badHostKey){
|
130 |
+
$q1 = $this->db->query("select owner, host, path from $this->table where hostKey='%s'", $badHostKey);
|
131 |
+
while($rec = mysql_fetch_assoc($q1)){
|
132 |
+
$url = 'http://' . $rec['host'] . $rec['path'];
|
133 |
+
if(! isset($urlsToCheck[$rec['owner']])){
|
134 |
+
$urlsToCheck[$rec['owner']] = array();
|
135 |
+
}
|
136 |
+
if(! in_array($url, $urlsToCheck[$rec['owner']])){
|
137 |
+
$urlsToCheck[$rec['owner']][] = $url;
|
|
|
|
|
|
|
|
|
138 |
}
|
139 |
}
|
140 |
}
|
141 |
+
|
142 |
if(sizeof($urlsToCheck) > 0){
|
143 |
$this->dbg("Checking " . sizeof($urlsToCheck) . " URLs");
|
144 |
$badURLs = $this->api->call('check_bad_urls', array(), array( 'toCheck' => json_encode($urlsToCheck)) );
|
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.3.2
|
6 |
-
Stable tag: 2.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 |
= 2.0.2 =
|
156 |
* Fixed plugin upgrades so that css and scripts are not cached across versions.
|
157 |
|
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.3.2
|
6 |
+
Stable tag: 2.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 |
+
= 2.0.3 =
|
156 |
+
* Removed unbuffered queries and switched to conventional queries that are memory efficient for better stability.
|
157 |
+
* Made scanning large numbers of URL's contained in things like awstats log files extremely memory efficient and way faster.
|
158 |
+
* Removed alerts about unknown files in core directory if they belong to an older wordpress version and are unchanged.
|
159 |
+
* Other performance improvements like using strpos instead of strstr.
|
160 |
+
* Moved "scan files outside base dir" option to be in correct place on config page.
|
161 |
+
|
162 |
= 2.0.2 =
|
163 |
* Fixed plugin upgrades so that css and scripts are not cached across versions.
|
164 |
|
wordfence.php
CHANGED
@@ -4,7 +4,7 @@ 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: 2.0.
|
8 |
Author URI: http://wordfence.com/
|
9 |
*/
|
10 |
require_once('lib/wordfenceConstants.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: 2.0.3
|
8 |
Author URI: http://wordfence.com/
|
9 |
*/
|
10 |
require_once('lib/wordfenceConstants.php');
|