Version Description
Download this release
Release Info
Developer | mmaunder |
Plugin | Wordfence Security – Firewall & Malware Scan |
Version | 3.6.3 |
Comparing to | |
See all releases |
Code changes from version 3.6.1 to 3.6.3
- css/main.css +18 -1
- images/bh_120x60_01.gif +0 -0
- images/bh_120x60_02.gif +0 -0
- images/bh_120x60_03.gif +0 -0
- images/bh_120x60_04.gif +0 -0
- images/bh_120x60_05.gif +0 -0
- lib/menu_activity.php +1 -1
- lib/menu_blockedIPs.php +1 -1
- lib/menu_options.php +1 -1
- lib/menu_rangeBlocking.php +2 -10
- lib/menu_scan.php +1 -1
- lib/menu_whois.php +1 -1
- lib/pageTitle.php +16 -0
- lib/viewFullActivityLog.php +2 -2
- lib/wfConfig.php +12 -29
- lib/wfCrawl.php +4 -4
- lib/wfDB.php +44 -173
- lib/wfGeoIP.php +4 -4
- lib/wfIssues.php +9 -9
- lib/wfLog.php +43 -65
- lib/wfScanEngine.php +9 -17
- lib/wfSchema.php +9 -8
- lib/wfUtils.php +13 -15
- lib/wordfenceClass.php +40 -34
- lib/wordfenceHash.php +3 -3
- lib/wordfenceScanner.php +4 -4
- lib/wordfenceURLHoover.php +6 -5
- readme.txt +14 -1
- wordfence.php +2 -2
css/main.css
CHANGED
@@ -40,7 +40,24 @@ div.wordfenceLive p {
|
|
40 |
margin: 7px 5px 0 0;
|
41 |
float: left;
|
42 |
}
|
43 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
44 |
background-image: url(../images/wordfence-logo-32x32.png);
|
45 |
}
|
46 |
|
40 |
margin: 7px 5px 0 0;
|
41 |
float: left;
|
42 |
}
|
43 |
+
#wfHeading {
|
44 |
+
white-space: nowrap;
|
45 |
+
}
|
46 |
+
a.bluehostBanner {
|
47 |
+
width: 120px;
|
48 |
+
height: 60px;
|
49 |
+
padding: 0;
|
50 |
+
margin: 0px 0 0px 0px;
|
51 |
+
display: block;
|
52 |
+
border-width: 0;
|
53 |
+
}
|
54 |
+
a.bluehostBanner1 { background-image: url(../images/bh_120x60_01.gif); }
|
55 |
+
a.bluehostBanner2 { background-image: url(../images/bh_120x60_02.gif); }
|
56 |
+
a.bluehostBanner3 { background-image: url(../images/bh_120x60_03.gif); }
|
57 |
+
a.bluehostBanner4 { background-image: url(../images/bh_120x60_04.gif); }
|
58 |
+
a.bluehostBanner5 { background-image: url(../images/bh_120x60_05.gif); }
|
59 |
+
|
60 |
+
div.wordfence-lock-icon {
|
61 |
background-image: url(../images/wordfence-logo-32x32.png);
|
62 |
}
|
63 |
|
images/bh_120x60_01.gif
ADDED
Binary file
|
images/bh_120x60_02.gif
ADDED
Binary file
|
images/bh_120x60_03.gif
ADDED
Binary file
|
images/bh_120x60_04.gif
ADDED
Binary file
|
images/bh_120x60_05.gif
ADDED
Binary file
|
lib/menu_activity.php
CHANGED
@@ -1,6 +1,6 @@
|
|
1 |
<div class="wordfenceModeElem" id="wordfenceMode_activity"></div>
|
2 |
<div class="wrap wordfence">
|
3 |
-
|
4 |
<div class="wordfenceLive">
|
5 |
<table border="0" cellpadding="0" cellspacing="0">
|
6 |
<tr><td><h2>Wordfence Live Activity:</h2></td><td id="wfLiveStatus"></td></tr>
|
1 |
<div class="wordfenceModeElem" id="wordfenceMode_activity"></div>
|
2 |
<div class="wrap wordfence">
|
3 |
+
<?php $pageTitle = "Live Site Activity"; include('pageTitle.php'); ?>
|
4 |
<div class="wordfenceLive">
|
5 |
<table border="0" cellpadding="0" cellspacing="0">
|
6 |
<tr><td><h2>Wordfence Live Activity:</h2></td><td id="wfLiveStatus"></td></tr>
|
lib/menu_blockedIPs.php
CHANGED
@@ -1,6 +1,6 @@
|
|
1 |
<div class="wordfenceModeElem" id="wordfenceMode_blockedIPs"></div>
|
2 |
<div class="wrap">
|
3 |
-
|
4 |
<div class="wordfenceLive">
|
5 |
<table border="0" cellpadding="0" cellspacing="0">
|
6 |
<tr><td><h2>Wordfence Live Activity:</h2></td><td id="wfLiveStatus"></td></tr>
|
1 |
<div class="wordfenceModeElem" id="wordfenceMode_blockedIPs"></div>
|
2 |
<div class="wrap">
|
3 |
+
<?php $pageTitle = "Wordfence Blocked IPs"; include('pageTitle.php'); ?>
|
4 |
<div class="wordfenceLive">
|
5 |
<table border="0" cellpadding="0" cellspacing="0">
|
6 |
<tr><td><h2>Wordfence Live Activity:</h2></td><td id="wfLiveStatus"></td></tr>
|
lib/menu_options.php
CHANGED
@@ -6,7 +6,7 @@ var WFSLevels = <?php echo json_encode(wfConfig::$securityLevels); ?>;
|
|
6 |
</script>
|
7 |
<div class="wordfenceModeElem" id="wordfenceMode_options"></div>
|
8 |
<div class="wrap">
|
9 |
-
|
10 |
<div class="wordfenceLive">
|
11 |
<table border="0" cellpadding="0" cellspacing="0">
|
12 |
<tr><td><h2>Wordfence Live Activity:</h2></td><td id="wfLiveStatus"></td></tr>
|
6 |
</script>
|
7 |
<div class="wordfenceModeElem" id="wordfenceMode_options"></div>
|
8 |
<div class="wrap">
|
9 |
+
<?php $pageTitle = "Wordfence Options"; include('pageTitle.php'); ?>
|
10 |
<div class="wordfenceLive">
|
11 |
<table border="0" cellpadding="0" cellspacing="0">
|
12 |
<tr><td><h2>Wordfence Live Activity:</h2></td><td id="wfLiveStatus"></td></tr>
|
lib/menu_rangeBlocking.php
CHANGED
@@ -1,6 +1,6 @@
|
|
1 |
<div class="wordfenceModeElem" id="wordfenceMode_rangeBlocking"></div>
|
2 |
<div class="wrap" id="paidWrap">
|
3 |
-
|
4 |
<div class="wordfenceWrap" style="margin: 20px 20px 20px 30px;">
|
5 |
<p>
|
6 |
<div style="width: 600px; margin-bottom: 15px;">
|
@@ -31,14 +31,6 @@
|
|
31 |
</p>
|
32 |
</div>
|
33 |
</div>
|
34 |
-
<script type="text/javascript">
|
35 |
-
<?php
|
36 |
-
if( (! wfConfig::get('isPaid')) && (wfConfig::get('tourClosed', 0) == '1') ){
|
37 |
-
echo 'WFAD.paidUsersOnly("Range and Internet Service Provider blocking is only available to paid members.");';
|
38 |
-
}
|
39 |
-
?>
|
40 |
-
</script>
|
41 |
-
|
42 |
<script type="text/x-jquery-template" id="wfBlockedRangesTmpl">
|
43 |
<div>
|
44 |
<div style="border-bottom: 1px solid #CCC; padding-bottom: 10px; margin-bottom: 10px;">
|
@@ -60,7 +52,7 @@ if( (! wfConfig::get('isPaid')) && (wfConfig::get('tourClosed', 0) == '1') ){
|
|
60 |
<ul>
|
61 |
<li>${totalBlocked} blocked hits</li>
|
62 |
{{if lastBlockedAgo}}
|
63 |
-
<li>Last blocked: ${lastBlockedAgo}</li>
|
64 |
{{/if}}
|
65 |
</ul>
|
66 |
</td></tr>
|
1 |
<div class="wordfenceModeElem" id="wordfenceMode_rangeBlocking"></div>
|
2 |
<div class="wrap" id="paidWrap">
|
3 |
+
<?php $pageTitle = "Advanced Blocking"; include('pageTitle.php'); ?>
|
4 |
<div class="wordfenceWrap" style="margin: 20px 20px 20px 30px;">
|
5 |
<p>
|
6 |
<div style="width: 600px; margin-bottom: 15px;">
|
31 |
</p>
|
32 |
</div>
|
33 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
34 |
<script type="text/x-jquery-template" id="wfBlockedRangesTmpl">
|
35 |
<div>
|
36 |
<div style="border-bottom: 1px solid #CCC; padding-bottom: 10px; margin-bottom: 10px;">
|
52 |
<ul>
|
53 |
<li>${totalBlocked} blocked hits</li>
|
54 |
{{if lastBlockedAgo}}
|
55 |
+
<li>Last blocked: ${lastBlockedAgo} ago</li>
|
56 |
{{/if}}
|
57 |
</ul>
|
58 |
</td></tr>
|
lib/menu_scan.php
CHANGED
@@ -1,6 +1,6 @@
|
|
1 |
<div class="wordfenceModeElem" id="wordfenceMode_scan"></div>
|
2 |
<div class="wrap wordfence">
|
3 |
-
|
4 |
<div class="wordfenceWrap">
|
5 |
<div class="wordfenceScanButton">
|
6 |
<table border="0" cellpadding="0" cellspacing="0" style="width: 800px;">
|
1 |
<div class="wordfenceModeElem" id="wordfenceMode_scan"></div>
|
2 |
<div class="wrap wordfence">
|
3 |
+
<?php $pageTitle = "Wordfence Scan"; include('pageTitle.php'); ?>
|
4 |
<div class="wordfenceWrap">
|
5 |
<div class="wordfenceScanButton">
|
6 |
<table border="0" cellpadding="0" cellspacing="0" style="width: 800px;">
|
lib/menu_whois.php
CHANGED
@@ -1,6 +1,6 @@
|
|
1 |
<div class="wordfenceModeElem" id="wordfenceMode_whois"></div>
|
2 |
<div class="wrap" id="paidWrap">
|
3 |
-
|
4 |
<div class="wordfenceWrap" style="margin: 20px 20px 20px 30px;">
|
5 |
<p style="width: 600px;">
|
6 |
Wordfence WHOIS queries the WHOIS servers on the Internet and gets information about domain name or IP address owners. This helps you determine who is hacking your site and helps you report them to the relevant authorities. If you see a malicious IP address, do a WHOIS lookup, find out who is responsible for that IP address and send an email reporting them to the 'abuse' email address provided.<br /><br />
|
1 |
<div class="wordfenceModeElem" id="wordfenceMode_whois"></div>
|
2 |
<div class="wrap" id="paidWrap">
|
3 |
+
<?php $pageTitle = "WHOIS Lookup"; include('pageTitle.php'); ?>
|
4 |
<div class="wordfenceWrap" style="margin: 20px 20px 20px 30px;">
|
5 |
<p style="width: 600px;">
|
6 |
Wordfence WHOIS queries the WHOIS servers on the Internet and gets information about domain name or IP address owners. This helps you determine who is hacking your site and helps you report them to the relevant authorities. If you see a malicious IP address, do a WHOIS lookup, find out who is responsible for that IP address and send an email reporting them to the 'abuse' email address provided.<br /><br />
|
lib/pageTitle.php
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php if(! wfConfig::get('isPaid')){ ?>
|
2 |
+
<table border="0">
|
3 |
+
<tr>
|
4 |
+
<td style="padding-right: 50px;">
|
5 |
+
<div class="wordfence-lock-icon wordfence-icon32"><br /></div><h2 id="wfHeading"><?php echo $pageTitle; ?></h2>
|
6 |
+
</td><td style="width: 450px; padding-top: 10px;">
|
7 |
+
You're using the Free version of Wordfence which you can support by visiting <a href="http://www.bluehost.com/track/wordfence/wfplghead" target="_blank">Bluehost.com</a>. We recommend <a href="http://www.bluehost.com/track/wordfence/wfplghead" target="_blank">Bluehost for WordPress hosting</a> and use them for our own WordPress websites. <a href="http://www.bluehost.com/track/wordfence/wfplghead" target="_blank">»Visit Bluehost now»</a>
|
8 |
+
</td>
|
9 |
+
<td style="width: 120px; padding-top: 10px;">
|
10 |
+
<a href="http://www.bluehost.com/track/wordfence/wfplghead" target="_blank" class="bluehostBanner bluehostBanner<?php echo rand(1,5); ?>"></a>
|
11 |
+
</td>
|
12 |
+
</tr>
|
13 |
+
</table>
|
14 |
+
<?php } else { ?>
|
15 |
+
<div class="wordfence-lock-icon wordfence-icon32"><br /></div><h2 id="wfHeading"><?php echo $pageTitle; ?></h2>
|
16 |
+
<?php } ?>
|
lib/viewFullActivityLog.php
CHANGED
@@ -13,9 +13,9 @@ $db = new wfDB();
|
|
13 |
global $wpdb;
|
14 |
$debugOn = wfConfig::get('debugOn', 0);
|
15 |
$table = $wpdb->base_prefix . 'wfStatus';
|
16 |
-
$q = $db->
|
17 |
$timeOffset = 3600 * get_option('gmt_offset');
|
18 |
-
|
19 |
if($r['level'] < 4 || $debugOn){
|
20 |
echo '<div' . ($r['type'] == 'error' ? ' class="error"' : '') . '>[' . date('M d H:i:s', $r['ctime'] + $timeOffset) . ':' . $r['ctime'] . ':' . $r['level'] . ':' . $r['type'] . '] ' . htmlspecialchars($r['msg']) . "</div>\n";
|
21 |
}
|
13 |
global $wpdb;
|
14 |
$debugOn = wfConfig::get('debugOn', 0);
|
15 |
$table = $wpdb->base_prefix . 'wfStatus';
|
16 |
+
$q = $db->querySelect("select ctime, level, type, msg from $table order by ctime desc");
|
17 |
$timeOffset = 3600 * get_option('gmt_offset');
|
18 |
+
foreach($q as $r){
|
19 |
if($r['level'] < 4 || $debugOn){
|
20 |
echo '<div' . ($r['type'] == 'error' ? ' class="error"' : '') . '>[' . date('M d H:i:s', $r['ctime'] + $timeOffset) . ':' . $r['ctime'] . ':' . $r['level'] . ':' . $r['type'] . '] ' . htmlspecialchars($r['msg']) . "</div>\n";
|
21 |
}
|
lib/wfConfig.php
CHANGED
@@ -385,7 +385,7 @@ class wfConfig {
|
|
385 |
return;
|
386 |
}
|
387 |
|
388 |
-
self::getDB()->
|
389 |
self::$cache[$key] = $val;
|
390 |
}
|
391 |
public static function get($key, $default = false){
|
@@ -421,30 +421,19 @@ class wfConfig {
|
|
421 |
}
|
422 |
}
|
423 |
}
|
424 |
-
self::getDB()->reconnect();
|
425 |
-
//We do our own query handling here because we are dealing with some very big strings
|
426 |
-
$dbh = self::getDB()->getDBH();
|
427 |
-
$res = mysql_query("select val from " . self::table() . " where name='" . mysql_real_escape_string($key) . "'", $dbh);
|
428 |
-
$err = mysql_error();
|
429 |
-
if($err){
|
430 |
-
$trace=debug_backtrace();
|
431 |
-
$caller=array_shift($trace);
|
432 |
-
wordfence::status(2, 'error', "Wordfence DB error in " . $caller['file'] . " line " . $caller['line'] . ": $err");
|
433 |
-
return false;
|
434 |
-
}
|
435 |
|
436 |
-
|
437 |
-
|
438 |
-
|
|
|
439 |
}
|
440 |
return $default;
|
441 |
}
|
442 |
public static function set_ser($key, $val, $canUseDisk = false){
|
443 |
-
//We serialize some very big values so this is
|
444 |
// because we would have to concatenate $val twice into the query which could also exceed max packet for the mysql server
|
445 |
-
self::getDB()->reconnect();
|
446 |
-
$dbh = self::getDB()->getDBH();
|
447 |
$serialized = serialize($val);
|
|
|
448 |
$tempFilename = 'wordfence_tmpfile_' . $key . '.php';
|
449 |
if((strlen($serialized) * 1.1) > self::getDB()->getMaxAllowedPacketBytes()){ //If it's greater than max_allowed_packet + 10% for escaping and SQL
|
450 |
if($canUseDisk){
|
@@ -481,18 +470,12 @@ class wfConfig {
|
|
481 |
}
|
482 |
$exists = self::getDB()->querySingle("select name from " . self::table() . " where name='%s'", $key);
|
483 |
if($exists){
|
484 |
-
|
485 |
} else {
|
486 |
-
|
487 |
-
}
|
488 |
-
$err = mysql_error();
|
489 |
-
if($err){
|
490 |
-
$trace=debug_backtrace();
|
491 |
-
$caller=array_shift($trace);
|
492 |
-
wordfence::status(2, 'error', "Wordfence DB error in " . $caller['file'] . " line " . $caller['line'] . ": $err");
|
493 |
-
return false;
|
494 |
}
|
495 |
}
|
|
|
496 |
return true;
|
497 |
}
|
498 |
private static function deleteOldTempFile($filename){
|
@@ -539,8 +522,8 @@ class wfConfig {
|
|
539 |
}
|
540 |
public static function getArray(){
|
541 |
$ret = array();
|
542 |
-
$q = self::getDB()->
|
543 |
-
|
544 |
self::$cache[$row['name']] = $row['val'];
|
545 |
}
|
546 |
return self::$cache;
|
385 |
return;
|
386 |
}
|
387 |
|
388 |
+
self::getDB()->queryWrite("insert into " . self::table() . " (name, val) values ('%s', '%s') ON DUPLICATE KEY UPDATE val='%s'", $key, $val, $val);
|
389 |
self::$cache[$key] = $val;
|
390 |
}
|
391 |
public static function get($key, $default = false){
|
421 |
}
|
422 |
}
|
423 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
424 |
|
425 |
+
$res = self::getDB()->querySingle("select val from " . self::table() . " where name=%s", $key);
|
426 |
+
self::getDB()->flush(); //clear cache
|
427 |
+
if($res){
|
428 |
+
return unserialize($res);
|
429 |
}
|
430 |
return $default;
|
431 |
}
|
432 |
public static function set_ser($key, $val, $canUseDisk = false){
|
433 |
+
//We serialize some very big values so this is memory efficient. We don't make any copies of $val and don't use ON DUPLICATE KEY UPDATE
|
434 |
// because we would have to concatenate $val twice into the query which could also exceed max packet for the mysql server
|
|
|
|
|
435 |
$serialized = serialize($val);
|
436 |
+
$val = '';
|
437 |
$tempFilename = 'wordfence_tmpfile_' . $key . '.php';
|
438 |
if((strlen($serialized) * 1.1) > self::getDB()->getMaxAllowedPacketBytes()){ //If it's greater than max_allowed_packet + 10% for escaping and SQL
|
439 |
if($canUseDisk){
|
470 |
}
|
471 |
$exists = self::getDB()->querySingle("select name from " . self::table() . " where name='%s'", $key);
|
472 |
if($exists){
|
473 |
+
self::getDB()->queryWrite("update " . self::table() . " set val=%s where name=%s", $serialized, $key);
|
474 |
} else {
|
475 |
+
self::getDB()->queryWrite("insert IGNORE into " . self::table() . " (name, val) values (%s, %s)", $key, $serialized);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
476 |
}
|
477 |
}
|
478 |
+
self::getDB()->flush();
|
479 |
return true;
|
480 |
}
|
481 |
private static function deleteOldTempFile($filename){
|
522 |
}
|
523 |
public static function getArray(){
|
524 |
$ret = array();
|
525 |
+
$q = self::getDB()->querySelect("select name, val from " . self::table());
|
526 |
+
foreach($q as $row){
|
527 |
self::$cache[$row['name']] = $row['val'];
|
528 |
}
|
529 |
return self::$cache;
|
lib/wfCrawl.php
CHANGED
@@ -24,7 +24,7 @@ class wfCrawl {
|
|
24 |
$wfLog = new wfLog(wfConfig::get('apiKey'), wfUtils::getWPVersion());
|
25 |
$host = wfUtils::reverseLookup($IP);
|
26 |
if(! $host){
|
27 |
-
$db->
|
28 |
return false;
|
29 |
}
|
30 |
if(preg_match($hostPattern, $host)){
|
@@ -37,14 +37,14 @@ class wfCrawl {
|
|
37 |
}
|
38 |
}
|
39 |
if($addrsMatch){
|
40 |
-
$db->
|
41 |
return true;
|
42 |
} else {
|
43 |
-
$db->
|
44 |
return false;
|
45 |
}
|
46 |
} else {
|
47 |
-
$db->
|
48 |
return false;
|
49 |
}
|
50 |
}
|
24 |
$wfLog = new wfLog(wfConfig::get('apiKey'), wfUtils::getWPVersion());
|
25 |
$host = wfUtils::reverseLookup($IP);
|
26 |
if(! $host){
|
27 |
+
$db->queryWrite("insert into $table (IP, patternSig, status, lastUpdate, PTR) values (%s, UNHEX(MD5('%s')), '%s', unix_timestamp(), '%s') ON DUPLICATE KEY UPDATE status='%s', lastUpdate=unix_timestamp(), PTR='%s'", $IPn, $hostPattern, 'noPTR', '', 'noPTR', '');
|
28 |
return false;
|
29 |
}
|
30 |
if(preg_match($hostPattern, $host)){
|
37 |
}
|
38 |
}
|
39 |
if($addrsMatch){
|
40 |
+
$db->queryWrite("insert into $table (IP, patternSig, status, lastUpdate, PTR) values (%s, UNHEX(MD5('%s')), '%s', unix_timestamp(), '%s') ON DUPLICATE KEY UPDATE status='%s', lastUpdate=unix_timestamp(), PTR='%s'", $IPn, $hostPattern, 'verified', $host, 'verified', $host);
|
41 |
return true;
|
42 |
} else {
|
43 |
+
$db->queryWrite("insert into $table (IP, patternSig, status, lastUpdate, PTR) values (%s, UNHEX(MD5('%s')), '%s', unix_timestamp(), '%s') ON DUPLICATE KEY UPDATE status='%s', lastUpdate=unix_timestamp(), PTR='%s'", $IPn, $hostPattern, 'fwdFail', $host, 'fwdFail', $host);
|
44 |
return false;
|
45 |
}
|
46 |
} else {
|
47 |
+
$db->queryWrite("insert into $table (IP, patternSig, status, lastUpdate, PTR) values (%s, UNHEX(MD5('%s')), '%s', unix_timestamp(), '%s') ON DUPLICATE KEY UPDATE status='%s', lastUpdate=unix_timestamp(), PTR='%s'", $IPn, $hostPattern, 'badPTR', $host, 'badPTR', $host);
|
48 |
return false;
|
49 |
}
|
50 |
}
|
lib/wfDB.php
CHANGED
@@ -6,182 +6,56 @@ class wfDB {
|
|
6 |
private $dbpassword = false;
|
7 |
private $dbname = false;
|
8 |
private $dbuser = false;
|
9 |
-
private $createNewHandle = false;
|
10 |
public $errorMsg = false;
|
11 |
-
public function __construct(
|
12 |
-
$this->createNewHandle = $createNewHandle;
|
13 |
-
if($dbhost && $dbuser && $dbpassword && $dbname){
|
14 |
-
$this->dbhost = $dbhost;
|
15 |
-
$this->dbuser = $dbuser;
|
16 |
-
$this->dbpassword = $dbpassword;
|
17 |
-
$this->dbname = $dbname;
|
18 |
-
} else {
|
19 |
-
global $wpdb;
|
20 |
-
if(! $wpdb){
|
21 |
-
self::criticalError("The WordPress variable wpdb is not defined. Wordfence can't function without this being defined as it is in all standard WordPress installs.");
|
22 |
-
return;
|
23 |
-
}
|
24 |
-
$sources = array(
|
25 |
-
array('dbhost', 'DB_HOST'),
|
26 |
-
array('dbuser', 'DB_USER'),
|
27 |
-
array('dbpassword', 'DB_PASSWORD'),
|
28 |
-
array('dbname', 'DB_NAME')
|
29 |
-
);
|
30 |
-
foreach($sources as $src){
|
31 |
-
$prop = $src[0];
|
32 |
-
if(isset($wpdb->$prop)){
|
33 |
-
$this->$prop = $wpdb->$prop;
|
34 |
-
} else if(defined($src[1])){
|
35 |
-
$this->$prop = constant($src[1]);
|
36 |
-
} else {
|
37 |
-
self::criticalError("Wordfence DB connect error. wpdb.$prop is not set and " . $src[1] . " is not defined.");
|
38 |
-
return;
|
39 |
-
}
|
40 |
-
}
|
41 |
-
}
|
42 |
-
$this->connectHandle();
|
43 |
}
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
if( (! $this->createNewHandle) && isset(self::$dbhCache[$handleKey]) && mysql_ping(self::$dbhCache[$handleKey]) ){
|
49 |
-
$this->dbh = self::$dbhCache[$handleKey];
|
50 |
} else {
|
51 |
-
|
52 |
-
if(isset(self::$dbhCache[$handleKey]) && mysql_ping(self::$dbhCache[$handleKey])){
|
53 |
-
mysql_close(self::$dbhCache[$handleKey]);
|
54 |
-
unset(self::$dbhCache[$handleKey]);
|
55 |
-
}
|
56 |
-
$dbh = mysql_connect($this->dbhost, $this->dbuser, $this->dbpassword, true );
|
57 |
-
mysql_select_db($this->dbname, $dbh);
|
58 |
-
if($this->createNewHandle){
|
59 |
-
$this->dbh = $dbh;
|
60 |
-
} else {
|
61 |
-
self::$dbhCache[$handleKey] = $dbh;
|
62 |
-
$this->dbh = self::$dbhCache[$handleKey];
|
63 |
-
}
|
64 |
-
$this->query("SET NAMES 'utf8'");
|
65 |
-
$this->queryIgnoreError("SET GLOBAL max_allowed_packet=256*1024*1024");
|
66 |
-
//$this->queryIgnoreError("SET GLOBAL wait_timeout=28800");
|
67 |
-
$this->queryIgnoreError("SET @@wait_timeout=30800"); //Changing to session setting bc user may not have super privilege
|
68 |
}
|
69 |
}
|
70 |
-
public function
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
}
|
75 |
-
public function querySingleRec(){
|
76 |
-
$this->reconnect();
|
77 |
-
$this->errorMsg = false;
|
78 |
-
$args = func_get_args();
|
79 |
-
if(sizeof($args) == 1){
|
80 |
-
$query = $args[0];
|
81 |
-
} else if(sizeof($args) > 1){
|
82 |
-
$query = call_user_func_array('sprintf', $args);
|
83 |
} else {
|
84 |
-
$
|
85 |
-
}
|
86 |
-
$res = mysql_query($query, $this->dbh);
|
87 |
-
$this->handleError();
|
88 |
-
return mysql_fetch_assoc($res); //returns false if no rows found
|
89 |
-
}
|
90 |
-
public function handleError($err = false){
|
91 |
-
if(! $err){
|
92 |
-
$err = mysql_error();
|
93 |
-
}
|
94 |
-
if($err){
|
95 |
-
$trace=debug_backtrace();
|
96 |
-
$first=array_shift($trace);
|
97 |
-
$caller=array_shift($trace);
|
98 |
-
$msg = "Wordfence DB error in " . $caller['file'] . " line " . $caller['line'] . ": $err";
|
99 |
-
global $wpdb;
|
100 |
-
$statusTable = $wpdb->base_prefix . 'wfStatus';
|
101 |
-
$this->reconnect(); //Putting reconnect here so it doesn't mess with the mysql_error() call
|
102 |
-
mysql_query(sprintf("insert into " . $statusTable . " (ctime, level, type, msg) values (%s, %d, '%s', '%s')",
|
103 |
-
mysql_real_escape_string(sprintf('%.6f', microtime(true))),
|
104 |
-
mysql_real_escape_string(1),
|
105 |
-
mysql_real_escape_string('error'),
|
106 |
-
mysql_real_escape_string($msg)), $this->dbh);
|
107 |
-
//error_log($msg);
|
108 |
-
return;
|
109 |
}
|
110 |
}
|
111 |
-
public function
|
112 |
-
$
|
113 |
-
|
114 |
-
|
115 |
-
if(sizeof($args) == 1){
|
116 |
-
$query = $args[0];
|
117 |
-
} else if(sizeof($args) > 1){
|
118 |
-
for($i = 1; $i < sizeof($args); $i++){
|
119 |
-
$args[$i] = mysql_real_escape_string($args[$i]);
|
120 |
-
}
|
121 |
-
$query = call_user_func_array('sprintf', $args);
|
122 |
} else {
|
123 |
-
$
|
124 |
-
}
|
125 |
-
$res = mysql_query($query, $this->dbh);
|
126 |
-
$this->handleError();
|
127 |
-
if(! $res){
|
128 |
-
return false;
|
129 |
}
|
130 |
-
$row = mysql_fetch_array($res, MYSQL_NUM);
|
131 |
-
if(! is_array($row)){ return false; }
|
132 |
-
return $row[0];
|
133 |
}
|
134 |
-
public function
|
135 |
-
$
|
136 |
-
$
|
137 |
-
$args = func_get_args();
|
138 |
-
$isStatusQuery = false;
|
139 |
-
if(sizeof($args) == 1){
|
140 |
-
if(preg_match('/Wordfence DB error/i', $args[0])){
|
141 |
-
$isStatusQuery = true;
|
142 |
-
}
|
143 |
-
$res = mysql_query($args[0], $this->dbh);
|
144 |
-
} else if(sizeof($args) > 1){
|
145 |
-
for($i = 1; $i < sizeof($args); $i++){
|
146 |
-
if(preg_match('/Wordfence DB error/i', $args[$i])){
|
147 |
-
$isStatusQuery = true;
|
148 |
-
}
|
149 |
-
$args[$i] = mysql_real_escape_string($args[$i]);
|
150 |
-
}
|
151 |
-
$res = mysql_query(call_user_func_array('sprintf', $args), $this->dbh);
|
152 |
-
} else {
|
153 |
-
$this->handleError("No arguments passed to query()");
|
154 |
-
}
|
155 |
-
$this->handleError();
|
156 |
-
return $res;
|
157 |
}
|
158 |
-
public function
|
159 |
-
$
|
160 |
-
|
161 |
-
|
162 |
-
if(sizeof($args) == 1){
|
163 |
-
$res = mysql_query($args[0], $this->dbh);
|
164 |
-
} else if(sizeof($args) > 1){
|
165 |
-
for($i = 1; $i < sizeof($args); $i++){
|
166 |
-
$args[$i] = mysql_real_escape_string($args[$i]);
|
167 |
-
}
|
168 |
-
$res = mysql_query(call_user_func_array('sprintf', $args), $this->dbh);
|
169 |
} else {
|
170 |
-
$
|
171 |
}
|
172 |
-
return $res;
|
173 |
}
|
174 |
-
|
175 |
-
|
176 |
-
$
|
177 |
-
|
178 |
-
|
179 |
}
|
180 |
public function columnExists($table, $col){
|
181 |
global $wpdb; $prefix = $wpdb->base_prefix;
|
182 |
$table = $prefix . $table;
|
183 |
-
$q = $this->
|
184 |
-
|
185 |
if($row['Field'] == $col){
|
186 |
return true;
|
187 |
}
|
@@ -191,28 +65,24 @@ class wfDB {
|
|
191 |
public function dropColumn($table, $col){
|
192 |
global $wpdb; $prefix = $wpdb->base_prefix;
|
193 |
$table = $prefix . $table;
|
194 |
-
$this->
|
195 |
}
|
196 |
public function createKeyIfNotExists($table, $col, $keyName){
|
197 |
-
|
198 |
-
$table = $prefix . $table;
|
199 |
$exists = $this->querySingle("show tables like '$table'");
|
200 |
$keyFound = false;
|
201 |
if($exists){
|
202 |
-
$q = $this->
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
$keyFound = true;
|
207 |
-
}
|
208 |
}
|
209 |
}
|
210 |
}
|
211 |
if(! $keyFound){
|
212 |
-
$this->
|
213 |
}
|
214 |
}
|
215 |
-
public function getDBH(){ return $this->dbh; }
|
216 |
public function getMaxAllowedPacketBytes(){
|
217 |
$rec = $this->querySingleRec("show variables like 'max_allowed_packet'");
|
218 |
return $rec['Value'];
|
@@ -221,12 +91,13 @@ class wfDB {
|
|
221 |
global $wpdb;
|
222 |
return $wpdb->base_prefix;
|
223 |
}
|
224 |
-
public function getAffectedRows(){
|
225 |
-
return mysql_affected_rows($this->dbh);
|
226 |
-
}
|
227 |
public function truncate($table){ //Ensures everything is deleted if user is using MySQL >= 5.1.16 and does not have "drop" privileges
|
228 |
-
$this->
|
229 |
-
$this->
|
|
|
|
|
|
|
|
|
230 |
}
|
231 |
}
|
232 |
|
6 |
private $dbpassword = false;
|
7 |
private $dbname = false;
|
8 |
private $dbuser = false;
|
|
|
9 |
public $errorMsg = false;
|
10 |
+
public function __construct(){
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
11 |
}
|
12 |
+
public function querySingle(){
|
13 |
+
global $wpdb;
|
14 |
+
if(func_num_args() > 1){
|
15 |
+
return $wpdb->get_var(call_user_func_array(array($wpdb, 'prepare'), func_get_args()));
|
|
|
|
|
16 |
} else {
|
17 |
+
return $wpdb->get_var(func_get_arg(0));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
18 |
}
|
19 |
}
|
20 |
+
public function querySingleRec(){ //queryInSprintfFormat, arg1, arg2, ... :: Returns a single assoc-array or null if nothing found.
|
21 |
+
global $wpdb;
|
22 |
+
if(func_num_args() > 1){
|
23 |
+
return $wpdb->get_row(call_user_func_array(array($wpdb, 'prepare'), func_get_args()), ARRAY_A);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
24 |
} else {
|
25 |
+
return $wpdb->get_row(func_get_arg(0), ARRAY_A);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
26 |
}
|
27 |
}
|
28 |
+
public function queryWrite(){
|
29 |
+
global $wpdb;
|
30 |
+
if(func_num_args() > 1){
|
31 |
+
return $wpdb->query(call_user_func_array(array($wpdb, 'prepare'), func_get_args()));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
32 |
} else {
|
33 |
+
return $wpdb->query(func_get_arg(0));
|
|
|
|
|
|
|
|
|
|
|
34 |
}
|
|
|
|
|
|
|
35 |
}
|
36 |
+
public function flush(){ //Clear cache
|
37 |
+
global $wpdb;
|
38 |
+
$wpdb->flush();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
39 |
}
|
40 |
+
public function querySelect(){ //sprintfString, arguments :: always returns array() and will be empty if no results.
|
41 |
+
global $wpdb;
|
42 |
+
if(func_num_args() > 1){
|
43 |
+
return $wpdb->get_results(call_user_func_array(array($wpdb, 'prepare'), func_get_args()), ARRAY_A);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
44 |
} else {
|
45 |
+
return $wpdb->get_results(func_get_arg(0), ARRAY_A);
|
46 |
}
|
|
|
47 |
}
|
48 |
+
public function queryWriteIgnoreError(){ //sprintfString, arguments
|
49 |
+
global $wpdb;
|
50 |
+
$oldSuppress = $wpdb->suppress_errors(true);
|
51 |
+
call_user_func_array(array($this, 'queryWrite'), func_get_args());
|
52 |
+
$wpdb->suppress_errors($oldSuppress);
|
53 |
}
|
54 |
public function columnExists($table, $col){
|
55 |
global $wpdb; $prefix = $wpdb->base_prefix;
|
56 |
$table = $prefix . $table;
|
57 |
+
$q = $this->querySelect("desc $table");
|
58 |
+
foreach($q as $row){
|
59 |
if($row['Field'] == $col){
|
60 |
return true;
|
61 |
}
|
65 |
public function dropColumn($table, $col){
|
66 |
global $wpdb; $prefix = $wpdb->base_prefix;
|
67 |
$table = $prefix . $table;
|
68 |
+
$this->queryWrite("alter table $table drop column $col");
|
69 |
}
|
70 |
public function createKeyIfNotExists($table, $col, $keyName){
|
71 |
+
$table = $this->prefix() . $table;
|
|
|
72 |
$exists = $this->querySingle("show tables like '$table'");
|
73 |
$keyFound = false;
|
74 |
if($exists){
|
75 |
+
$q = $this->querySelect("show keys from $table");
|
76 |
+
foreach($q as $row){
|
77 |
+
if($row['Key_name'] == $keyName){
|
78 |
+
$keyFound = true;
|
|
|
|
|
79 |
}
|
80 |
}
|
81 |
}
|
82 |
if(! $keyFound){
|
83 |
+
$this->queryWrite("alter table $table add KEY $keyName($col)");
|
84 |
}
|
85 |
}
|
|
|
86 |
public function getMaxAllowedPacketBytes(){
|
87 |
$rec = $this->querySingleRec("show variables like 'max_allowed_packet'");
|
88 |
return $rec['Value'];
|
91 |
global $wpdb;
|
92 |
return $wpdb->base_prefix;
|
93 |
}
|
|
|
|
|
|
|
94 |
public function truncate($table){ //Ensures everything is deleted if user is using MySQL >= 5.1.16 and does not have "drop" privileges
|
95 |
+
$this->queryWrite("truncate table $table");
|
96 |
+
$this->queryWrite("delete from $table");
|
97 |
+
}
|
98 |
+
public function getLastError(){
|
99 |
+
global $wpdb;
|
100 |
+
return $wpdb->last_error;
|
101 |
}
|
102 |
}
|
103 |
|
lib/wfGeoIP.php
CHANGED
@@ -19,7 +19,7 @@
|
|
19 |
* License along with this library; if not, write to the Free Software
|
20 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
21 |
*/
|
22 |
-
|
23 |
define("GEOIP_COUNTRY_BEGIN", 16776960);
|
24 |
define("GEOIP_STATE_BEGIN_REV0", 16700000);
|
25 |
define("GEOIP_STATE_BEGIN_REV1", 16000000);
|
@@ -70,7 +70,7 @@ define("GEOIP_DOMAIN_EDITION_V6",24);
|
|
70 |
|
71 |
define("CITYCOMBINED_FIXED_RECORD", 7 );
|
72 |
|
73 |
-
class
|
74 |
var $flags;
|
75 |
var $filehandle;
|
76 |
var $memory_buffer;
|
@@ -377,7 +377,7 @@ function _setup_segments($gi){
|
|
377 |
}
|
378 |
|
379 |
function geoip_open($filename, $flags) {
|
380 |
-
$gi = new
|
381 |
$gi->flags = $flags;
|
382 |
if ($gi->flags & GEOIP_SHARED_MEMORY) {
|
383 |
$gi->shmid = @shmop_open (GEOIP_SHM_KEY, "a", 0, 0);
|
@@ -709,5 +709,5 @@ function getdnsattributes ($l,$ip){
|
|
709 |
$str = substr( $str, 1, -1 );
|
710 |
return $str;
|
711 |
}
|
712 |
-
|
713 |
?>
|
19 |
* License along with this library; if not, write to the Free Software
|
20 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
21 |
*/
|
22 |
+
if(! class_exists('wfGeoIP')){
|
23 |
define("GEOIP_COUNTRY_BEGIN", 16776960);
|
24 |
define("GEOIP_STATE_BEGIN_REV0", 16700000);
|
25 |
define("GEOIP_STATE_BEGIN_REV1", 16000000);
|
70 |
|
71 |
define("CITYCOMBINED_FIXED_RECORD", 7 );
|
72 |
|
73 |
+
class wfGeoIP {
|
74 |
var $flags;
|
75 |
var $filehandle;
|
76 |
var $memory_buffer;
|
377 |
}
|
378 |
|
379 |
function geoip_open($filename, $flags) {
|
380 |
+
$gi = new wfGeoIP;
|
381 |
$gi->flags = $flags;
|
382 |
if ($gi->flags & GEOIP_SHARED_MEMORY) {
|
383 |
$gi->shmid = @shmop_open (GEOIP_SHM_KEY, "a", 0, 0);
|
709 |
$str = substr( $str, 1, -1 );
|
710 |
return $str;
|
711 |
}
|
712 |
+
}
|
713 |
?>
|
lib/wfIssues.php
CHANGED
@@ -53,7 +53,7 @@ class wfIssues {
|
|
53 |
'tmplData' => $templateData
|
54 |
);
|
55 |
|
56 |
-
$this->getDB()->
|
57 |
'new',
|
58 |
$type,
|
59 |
$severity,
|
@@ -66,13 +66,13 @@ class wfIssues {
|
|
66 |
return true;
|
67 |
}
|
68 |
public function deleteIgnored(){
|
69 |
-
$this->getDB()->
|
70 |
}
|
71 |
public function deleteNew(){
|
72 |
-
$this->getDB()->
|
73 |
}
|
74 |
public function ignoreAllNew(){
|
75 |
-
$this->getDB()->
|
76 |
}
|
77 |
public function emailNewIssues(){
|
78 |
$level = wfConfig::getAlertLevel();
|
@@ -124,14 +124,14 @@ class wfIssues {
|
|
124 |
wp_mail(implode(',', $emails), $subject, $content);
|
125 |
}
|
126 |
public function deleteIssue($id){
|
127 |
-
$this->getDB()->
|
128 |
}
|
129 |
public function updateIssue($id, $status){ //ignoreC, ignoreP, delete or new
|
130 |
$currentStatus = $this->getDB()->querySingle("select status from " . $this->issuesTable . " where id=%d", $id);
|
131 |
if($status == 'delete'){
|
132 |
-
$this->getDB()->
|
133 |
} else if($status == 'ignoreC' || $status == 'ignoreP' || $status == 'new'){
|
134 |
-
$this->getDB()->
|
135 |
}
|
136 |
}
|
137 |
public function getIssueByID($id){
|
@@ -145,8 +145,8 @@ class wfIssues {
|
|
145 |
'new' => array(),
|
146 |
'ignored' => array()
|
147 |
);
|
148 |
-
$q1 = $this->getDB()->
|
149 |
-
|
150 |
$i['data'] = unserialize($i['data']);
|
151 |
$i['timeAgo'] = wfUtils::makeTimeAgo(time() - $i['time']);
|
152 |
if($i['status'] == 'new'){
|
53 |
'tmplData' => $templateData
|
54 |
);
|
55 |
|
56 |
+
$this->getDB()->queryWrite("insert into " . $this->issuesTable . " (time, status, type, severity, ignoreP, ignoreC, shortMsg, longMsg, data) values (unix_timestamp(), '%s', '%s', %d, '%s', '%s', '%s', '%s', '%s')",
|
57 |
'new',
|
58 |
$type,
|
59 |
$severity,
|
66 |
return true;
|
67 |
}
|
68 |
public function deleteIgnored(){
|
69 |
+
$this->getDB()->queryWrite("delete from " . $this->issuesTable . " where status='ignoreP' or status='ignoreC'");
|
70 |
}
|
71 |
public function deleteNew(){
|
72 |
+
$this->getDB()->queryWrite("delete from " . $this->issuesTable . " where status='new'");
|
73 |
}
|
74 |
public function ignoreAllNew(){
|
75 |
+
$this->getDB()->queryWrite("update " . $this->issuesTable . " set status='ignoreC' where status='new'");
|
76 |
}
|
77 |
public function emailNewIssues(){
|
78 |
$level = wfConfig::getAlertLevel();
|
124 |
wp_mail(implode(',', $emails), $subject, $content);
|
125 |
}
|
126 |
public function deleteIssue($id){
|
127 |
+
$this->getDB()->queryWrite("delete from " . $this->issuesTable . " where id=%d", $id);
|
128 |
}
|
129 |
public function updateIssue($id, $status){ //ignoreC, ignoreP, delete or new
|
130 |
$currentStatus = $this->getDB()->querySingle("select status from " . $this->issuesTable . " where id=%d", $id);
|
131 |
if($status == 'delete'){
|
132 |
+
$this->getDB()->queryWrite("delete from " . $this->issuesTable . " where id=%d", $id);
|
133 |
} else if($status == 'ignoreC' || $status == 'ignoreP' || $status == 'new'){
|
134 |
+
$this->getDB()->queryWrite("update " . $this->issuesTable . " set status='%s' where id=%d", $status, $id);
|
135 |
}
|
136 |
}
|
137 |
public function getIssueByID($id){
|
145 |
'new' => array(),
|
146 |
'ignored' => array()
|
147 |
);
|
148 |
+
$q1 = $this->getDB()->querySelect("select * from " . $this->issuesTable . " order by time desc");
|
149 |
+
foreach($q1 as $i){
|
150 |
$i['data'] = unserialize($i['data']);
|
151 |
$i['timeAgo'] = wfUtils::makeTimeAgo(time() - $i['time']);
|
152 |
if($i['status'] == 'new'){
|
lib/wfLog.php
CHANGED
@@ -30,7 +30,7 @@ class wfLog {
|
|
30 |
if($user){
|
31 |
$userID = $user->ID;
|
32 |
}
|
33 |
-
$this->getDB()->
|
34 |
sprintf('%.6f', microtime(true)),
|
35 |
$fail,
|
36 |
$action,
|
@@ -66,13 +66,13 @@ class wfLog {
|
|
66 |
wordfence::status(1, 'error', "Invalid type to logLeechAndBlock(): $type");
|
67 |
return;
|
68 |
}
|
69 |
-
$this->getDB()->
|
70 |
$hitsPerMinute = $this->getDB()->querySingle("select @wfcurrenthits");
|
71 |
//end block moved into "is fw enabled" section
|
72 |
|
73 |
//New range and UA pattern blocking:
|
74 |
-
$r1 = $this->getDB()->
|
75 |
-
|
76 |
if($blockRec['blockType'] == 'IU'){
|
77 |
$ipRangeBlocked = false;
|
78 |
$uaPatternBlocked = false;
|
@@ -106,7 +106,7 @@ class wfLog {
|
|
106 |
}
|
107 |
}
|
108 |
if($rangeBlockReason){
|
109 |
-
$this->getDB()->
|
110 |
$this->do503(3600, $rangeBlockReason);
|
111 |
}
|
112 |
}
|
@@ -126,16 +126,16 @@ class wfLog {
|
|
126 |
if($type == '404'){
|
127 |
global $wpdb; $p = $wpdb->base_prefix;
|
128 |
if(wfConfig::get('other_WFNet')){
|
129 |
-
$this->getDB()->
|
130 |
}
|
131 |
$pat = wfConfig::get('vulnRegex');
|
132 |
if($pat){
|
133 |
$URL = wfUtils::getRequestedURL();
|
134 |
if(preg_match($pat, $URL)){
|
135 |
-
$this->getDB()->
|
136 |
if(wfConfig::get('maxScanHits') != 'DISABLED'){
|
137 |
if( empty($_SERVER['HTTP_REFERER'] )){
|
138 |
-
$this->getDB()->
|
139 |
$BL_hitsPerMinute = $this->getDB()->querySingle("select @wfblcurrenthits");
|
140 |
if($BL_hitsPerMinute > wfConfig::get('maxScanHits')){
|
141 |
$this->takeBlockingAction('maxScanHits', "Exceeded the maximum number of 404 requests per minute for a known security vulnerability.");
|
@@ -200,25 +200,24 @@ class wfLog {
|
|
200 |
return false;
|
201 |
}
|
202 |
public function unblockAllIPs(){
|
203 |
-
$this->getDB()->
|
204 |
}
|
205 |
public function unlockAllIPs(){
|
206 |
-
$this->getDB()->
|
207 |
}
|
208 |
public function unblockIP($IP){
|
209 |
-
$this->getDB()->
|
210 |
}
|
211 |
public function unblockRange($id){
|
212 |
-
$this->getDB()->
|
213 |
}
|
214 |
public function blockRange($blockType, $range, $reason){
|
215 |
-
$this->getDB()->
|
216 |
return true;
|
217 |
}
|
218 |
public function getRanges(){
|
219 |
-
$
|
220 |
-
$results
|
221 |
-
while($elem = mysql_fetch_assoc($res)){
|
222 |
if($elem['blockType'] != 'IU'){ continue; } //We only use IU type for now, but have this for future different block types.
|
223 |
$elem['ctimeAgo'] = wfUtils::makeTimeAgo($elem['ctimeAgo']);
|
224 |
if($elem['lastBlocked'] > 0){
|
@@ -239,7 +238,6 @@ class wfLog {
|
|
239 |
} else {
|
240 |
$elem['browserPattern'] = 'Allow all browsers';
|
241 |
}
|
242 |
-
array_push($results, $elem);
|
243 |
}
|
244 |
return $results;
|
245 |
}
|
@@ -248,7 +246,7 @@ class wfLog {
|
|
248 |
$wfsn = $wfsn ? 1 : 0;
|
249 |
if($permanent){
|
250 |
//Insert permanent=1 or update existing perm or non-per block to be permanent
|
251 |
-
$this->getDB()->
|
252 |
wfUtils::inet_aton($IP),
|
253 |
$reason,
|
254 |
$wfsn,
|
@@ -259,7 +257,7 @@ class wfLog {
|
|
259 |
);
|
260 |
} else {
|
261 |
//insert perm=0 but don't update and make perm blocks non-perm.
|
262 |
-
$this->getDB()->
|
263 |
wfUtils::inet_aton($IP),
|
264 |
$reason,
|
265 |
$wfsn,
|
@@ -272,7 +270,7 @@ class wfLog {
|
|
272 |
}
|
273 |
public function lockOutIP($IP, $reason){
|
274 |
if($this->isWhitelisted($IP)){ return false; }
|
275 |
-
$this->getDB()->
|
276 |
wfUtils::inet_aton($IP),
|
277 |
$reason,
|
278 |
$reason
|
@@ -280,23 +278,21 @@ class wfLog {
|
|
280 |
return true;
|
281 |
}
|
282 |
public function unlockOutIP($IP){
|
283 |
-
$this->getDB()->
|
284 |
}
|
285 |
public function isIPLockedOut($IP){
|
286 |
if($this->getDB()->querySingle("select IP from " . $this->lockOutTable . " where IP=%s and blockedTime + %s > unix_timestamp()", wfUtils::inet_aton($IP), wfConfig::get('loginSec_lockoutMins') * 60)){
|
287 |
-
$this->getDB()->
|
288 |
return true;
|
289 |
} else {
|
290 |
return false;
|
291 |
}
|
292 |
}
|
293 |
public function getThrottledIPs(){
|
294 |
-
$
|
295 |
-
$results
|
296 |
-
while($elem = mysql_fetch_assoc($res)){
|
297 |
$elem['startTimeAgo'] = wfUtils::makeTimeAgo($elem['startTimeAgo']);
|
298 |
$elem['endTimeAgo'] = wfUtils::makeTimeAgo($elem['endTimeAgo']);
|
299 |
-
array_push($results, $elem);
|
300 |
}
|
301 |
$this->resolveIPs($results);
|
302 |
foreach($results as &$elem){
|
@@ -305,12 +301,10 @@ class wfLog {
|
|
305 |
return $results;
|
306 |
}
|
307 |
public function getLockedOutIPs(){
|
308 |
-
$
|
309 |
-
$results
|
310 |
-
while($elem = mysql_fetch_assoc($res)){
|
311 |
$elem['lastAttemptAgo'] = $elem['lastAttempt'] ? wfUtils::makeTimeAgo($elem['lastAttemptAgo']) : '';
|
312 |
$elem['blockedForAgo'] = wfUtils::makeTimeAgo($elem['blockedFor']);
|
313 |
-
array_push($results, $elem);
|
314 |
}
|
315 |
$this->resolveIPs($results);
|
316 |
foreach($results as &$elem){
|
@@ -319,9 +313,8 @@ class wfLog {
|
|
319 |
return $results;
|
320 |
}
|
321 |
public function getBlockedIPs(){
|
322 |
-
$
|
323 |
-
$results
|
324 |
-
while($elem = mysql_fetch_assoc($res)){
|
325 |
$lastHitAgo = 0;
|
326 |
$totalHits = 0;
|
327 |
$serverTime = $this->getDB()->querySingle("select unix_timestamp()");
|
@@ -343,7 +336,6 @@ class wfLog {
|
|
343 |
$elem['lastHitAgo'] = $lastHitAgo ? wfUtils::makeTimeAgo($lastHitAgo) : '';
|
344 |
$elem['lastAttemptAgo'] = $elem['lastAttempt'] ? wfUtils::makeTimeAgo($elem['lastAttemptAgo']) : '';
|
345 |
$elem['blockedForAgo'] = wfUtils::makeTimeAgo($elem['blockedFor']);
|
346 |
-
array_push($results, $elem);
|
347 |
}
|
348 |
$this->resolveIPs($results);
|
349 |
foreach($results as &$elem){
|
@@ -361,11 +353,7 @@ class wfLog {
|
|
361 |
wordfence::status(1, 'error', "Invalid type to getLeechers(): $type");
|
362 |
return false;
|
363 |
}
|
364 |
-
$
|
365 |
-
$results = array();
|
366 |
-
while($elem = mysql_fetch_assoc($res)){
|
367 |
-
array_push($results, $elem);
|
368 |
-
}
|
369 |
$this->resolveIPs($results);
|
370 |
foreach($results as &$elem){
|
371 |
$elem['timeAgo'] = wfUtils::makeTimeAgo($this->getDB()->querySingle("select unix_timestamp() - (eMin * 60) from $table where IP=%s", $elem['IP']));
|
@@ -383,7 +371,7 @@ class wfLog {
|
|
383 |
$headers[$matches[1]] = $v;
|
384 |
}
|
385 |
}
|
386 |
-
$this->getDB()->
|
387 |
sprintf('%.6f', microtime(true)),
|
388 |
(is_404() ? 1 : 0),
|
389 |
(wfCrawl::isGoogleCrawler() ? 1 : 0),
|
@@ -400,7 +388,10 @@ class wfLog {
|
|
400 |
$serverTime = $this->getDB()->querySingle("select unix_timestamp()");
|
401 |
$IPSQL = "";
|
402 |
if($IP){
|
403 |
-
$IPSQL = " and IP=INET_ATON(
|
|
|
|
|
|
|
404 |
}
|
405 |
if($hitType == 'hits'){
|
406 |
if($type == 'hit'){
|
@@ -420,26 +411,17 @@ class wfLog {
|
|
420 |
wordfence::status(1, 'error', "Invalid log type to wfLog: $type");
|
421 |
return false;
|
422 |
}
|
423 |
-
|
424 |
-
$
|
425 |
-
$afterTime,
|
426 |
-
$limit
|
427 |
-
);
|
428 |
|
429 |
} else if($hitType == 'logins'){
|
430 |
-
$
|
431 |
-
|
432 |
-
$limit
|
433 |
-
);
|
434 |
|
435 |
} else {
|
436 |
wordfence::status(1, 'error', "getHits got invalid hitType: $hitType");
|
437 |
return false;
|
438 |
}
|
439 |
-
$results = array();
|
440 |
-
while($res = mysql_fetch_assoc($r1)){
|
441 |
-
array_push($results, $res);
|
442 |
-
}
|
443 |
$this->resolveIPs($results);
|
444 |
$ourURL = parse_url(site_url());
|
445 |
$ourHost = strtolower($ourURL['host']);
|
@@ -626,7 +608,7 @@ class wfLog {
|
|
626 |
|
627 |
$IP = wfUtils::inet_aton(wfUtils::getIP());
|
628 |
if($rec = $this->getDB()->querySingleRec("select blockedTime, reason from " . $this->blocksTable . " where IP=%s and (permanent=1 OR (blockedTime + %s > unix_timestamp()))", $IP, wfConfig::get('blockedTime'))){
|
629 |
-
$this->getDB()->
|
630 |
$now = $this->getDB()->querySingle("select unix_timestamp()");
|
631 |
$secsToGo = ($rec['blockedTime'] + wfConfig::get('blockedTime')) - $now;
|
632 |
$this->do503($secsToGo, $rec['reason']);
|
@@ -667,7 +649,7 @@ class wfLog {
|
|
667 |
$secsToGo = wfConfig::get('blockedTime');
|
668 |
} else if($action == 'throttle'){
|
669 |
$IP = wfUtils::inet_aton(wfUtils::getIP());
|
670 |
-
$this->getDB()->
|
671 |
wordfence::status(2, 'info', "Throttling IP $IP. $reason");
|
672 |
$secsToGo = 60;
|
673 |
}
|
@@ -729,7 +711,7 @@ class wfLog {
|
|
729 |
}
|
730 |
public function addStatus($level, $type, $msg){
|
731 |
//$msg = '[' . sprintf('%.2f', memory_get_usage(true) / (1024 * 1024)) . '] ' . $msg;
|
732 |
-
$this->getDB()->
|
733 |
}
|
734 |
public function getStatusEvents($lastCtime){
|
735 |
if($lastCtime < 1){
|
@@ -738,25 +720,21 @@ class wfLog {
|
|
738 |
$lastCtime = 0;
|
739 |
}
|
740 |
}
|
741 |
-
$
|
742 |
-
$results = array();
|
743 |
$lastTime = false;
|
744 |
$timeOffset = 3600 * get_option('gmt_offset');
|
745 |
-
|
746 |
//$rec['timeAgo'] = wfUtils::makeTimeAgo(time() - $rec['ctime']);
|
747 |
$rec['date'] = date('M d H:i:s', $rec['ctime'] + $timeOffset);
|
748 |
-
array_push($results, $rec);
|
749 |
}
|
750 |
return $results;
|
751 |
}
|
752 |
public function getSummaryEvents(){
|
753 |
-
$
|
754 |
-
$results = array();
|
755 |
$lastTime = false;
|
756 |
$timeOffset = 3600 * get_option('gmt_offset');
|
757 |
-
|
758 |
$rec['date'] = date('M d H:i:s', $rec['ctime'] + $timeOffset);
|
759 |
-
array_push($results, $rec);
|
760 |
if(strpos($rec['msg'], 'SUM_PREP:') === 0){
|
761 |
break;
|
762 |
}
|
30 |
if($user){
|
31 |
$userID = $user->ID;
|
32 |
}
|
33 |
+
$this->getDB()->queryWrite("insert into " . $this->loginsTable . " (ctime, fail, action, username, userID, IP, UA) values (%f, %d, '%s', '%s', %s, %s, '%s')",
|
34 |
sprintf('%.6f', microtime(true)),
|
35 |
$fail,
|
36 |
$action,
|
66 |
wordfence::status(1, 'error', "Invalid type to logLeechAndBlock(): $type");
|
67 |
return;
|
68 |
}
|
69 |
+
$this->getDB()->queryWrite("insert into $table (eMin, IP, hits) values (floor(unix_timestamp() / 60), %s, 1) ON DUPLICATE KEY update hits = IF(@wfcurrenthits := hits + 1, hits + 1, hits + 1)", wfUtils::inet_aton($IP));
|
70 |
$hitsPerMinute = $this->getDB()->querySingle("select @wfcurrenthits");
|
71 |
//end block moved into "is fw enabled" section
|
72 |
|
73 |
//New range and UA pattern blocking:
|
74 |
+
$r1 = $this->getDB()->querySelect("select id, blockType, blockString from " . $this->ipRangesTable);
|
75 |
+
foreach($r1 as $blockRec){
|
76 |
if($blockRec['blockType'] == 'IU'){
|
77 |
$ipRangeBlocked = false;
|
78 |
$uaPatternBlocked = false;
|
106 |
}
|
107 |
}
|
108 |
if($rangeBlockReason){
|
109 |
+
$this->getDB()->queryWrite("update " . $this->ipRangesTable . " set totalBlocked = totalBlocked + 1, lastBlocked = unix_timestamp() where id=%d", $blockRec['id']);
|
110 |
$this->do503(3600, $rangeBlockReason);
|
111 |
}
|
112 |
}
|
126 |
if($type == '404'){
|
127 |
global $wpdb; $p = $wpdb->base_prefix;
|
128 |
if(wfConfig::get('other_WFNet')){
|
129 |
+
$this->getDB()->queryWrite("insert IGNORE into $p"."wfNet404s (sig, ctime, URI) values (UNHEX(MD5('%s')), unix_timestamp(), '%s')", $_SERVER['REQUEST_URI'], $_SERVER['REQUEST_URI']);
|
130 |
}
|
131 |
$pat = wfConfig::get('vulnRegex');
|
132 |
if($pat){
|
133 |
$URL = wfUtils::getRequestedURL();
|
134 |
if(preg_match($pat, $URL)){
|
135 |
+
$this->getDB()->queryWrite("insert IGNORE into $p"."wfVulnScanners (IP, ctime, hits) values (INET_ATON('%s'), unix_timestamp(), 1) ON DUPLICATE KEY UPDATE ctime = unix_timestamp, hits = hits + 1", $IP);
|
136 |
if(wfConfig::get('maxScanHits') != 'DISABLED'){
|
137 |
if( empty($_SERVER['HTTP_REFERER'] )){
|
138 |
+
$this->getDB()->queryWrite("insert into " . $this->badLeechersTable . " (eMin, IP, hits) values (floor(unix_timestamp() / 60), %s, 1) ON DUPLICATE KEY update hits = IF(@wfblcurrenthits := hits + 1, hits + 1, hits + 1)", $IPnum);
|
139 |
$BL_hitsPerMinute = $this->getDB()->querySingle("select @wfblcurrenthits");
|
140 |
if($BL_hitsPerMinute > wfConfig::get('maxScanHits')){
|
141 |
$this->takeBlockingAction('maxScanHits', "Exceeded the maximum number of 404 requests per minute for a known security vulnerability.");
|
200 |
return false;
|
201 |
}
|
202 |
public function unblockAllIPs(){
|
203 |
+
$this->getDB()->queryWrite("delete from " . $this->blocksTable);
|
204 |
}
|
205 |
public function unlockAllIPs(){
|
206 |
+
$this->getDB()->queryWrite("delete from " . $this->lockOutTable);
|
207 |
}
|
208 |
public function unblockIP($IP){
|
209 |
+
$this->getDB()->queryWrite("delete from " . $this->blocksTable . " where IP=%s", wfUtils::inet_aton($IP));
|
210 |
}
|
211 |
public function unblockRange($id){
|
212 |
+
$this->getDB()->queryWrite("delete from " . $this->ipRangesTable . " where id=%d", $id);
|
213 |
}
|
214 |
public function blockRange($blockType, $range, $reason){
|
215 |
+
$this->getDB()->queryWrite("insert IGNORE into " . $this->ipRangesTable . " (blockType, blockString, ctime, reason, totalBlocked, lastBlocked) values ('%s', '%s', unix_timestamp(), '%s', 0, 0)", $blockType, $range, $reason);
|
216 |
return true;
|
217 |
}
|
218 |
public function getRanges(){
|
219 |
+
$results = $this->getDB()->querySelect("select id, blockType, blockString, unix_timestamp() - ctime as ctimeAgo, reason, totalBlocked, unix_timestamp() - lastBlocked as lastBlockedAgo, lastBlocked from " . $this->ipRangesTable . " order by ctime desc");
|
220 |
+
foreach($results as &$elem){
|
|
|
221 |
if($elem['blockType'] != 'IU'){ continue; } //We only use IU type for now, but have this for future different block types.
|
222 |
$elem['ctimeAgo'] = wfUtils::makeTimeAgo($elem['ctimeAgo']);
|
223 |
if($elem['lastBlocked'] > 0){
|
238 |
} else {
|
239 |
$elem['browserPattern'] = 'Allow all browsers';
|
240 |
}
|
|
|
241 |
}
|
242 |
return $results;
|
243 |
}
|
246 |
$wfsn = $wfsn ? 1 : 0;
|
247 |
if($permanent){
|
248 |
//Insert permanent=1 or update existing perm or non-per block to be permanent
|
249 |
+
$this->getDB()->queryWrite("insert into " . $this->blocksTable . " (IP, blockedTime, reason, wfsn, permanent) values (%s, unix_timestamp(), '%s', %d, %d) ON DUPLICATE KEY update blockedTime=unix_timestamp(), reason='%s', wfsn=%d, permanent=%d",
|
250 |
wfUtils::inet_aton($IP),
|
251 |
$reason,
|
252 |
$wfsn,
|
257 |
);
|
258 |
} else {
|
259 |
//insert perm=0 but don't update and make perm blocks non-perm.
|
260 |
+
$this->getDB()->queryWrite("insert into " . $this->blocksTable . " (IP, blockedTime, reason, wfsn, permanent) values (%s, unix_timestamp(), '%s', %d, %d) ON DUPLICATE KEY update blockedTime=unix_timestamp(), reason='%s', wfsn=%d",
|
261 |
wfUtils::inet_aton($IP),
|
262 |
$reason,
|
263 |
$wfsn,
|
270 |
}
|
271 |
public function lockOutIP($IP, $reason){
|
272 |
if($this->isWhitelisted($IP)){ return false; }
|
273 |
+
$this->getDB()->queryWrite("insert into " . $this->lockOutTable . " (IP, blockedTime, reason) values(%s, unix_timestamp(), '%s') ON DUPLICATE KEY update blockedTime=unix_timestamp(), reason='%s'",
|
274 |
wfUtils::inet_aton($IP),
|
275 |
$reason,
|
276 |
$reason
|
278 |
return true;
|
279 |
}
|
280 |
public function unlockOutIP($IP){
|
281 |
+
$this->getDB()->queryWrite("delete from " . $this->lockOutTable . " where IP=%s", wfUtils::inet_aton($IP));
|
282 |
}
|
283 |
public function isIPLockedOut($IP){
|
284 |
if($this->getDB()->querySingle("select IP from " . $this->lockOutTable . " where IP=%s and blockedTime + %s > unix_timestamp()", wfUtils::inet_aton($IP), wfConfig::get('loginSec_lockoutMins') * 60)){
|
285 |
+
$this->getDB()->queryWrite("update " . $this->lockOutTable . " set blockedHits = blockedHits + 1, lastAttempt = unix_timestamp() where IP=%s", wfUtils::inet_aton($IP));
|
286 |
return true;
|
287 |
} else {
|
288 |
return false;
|
289 |
}
|
290 |
}
|
291 |
public function getThrottledIPs(){
|
292 |
+
$results = $this->getDB()->querySelect("select IP, startTime, endTime, timesThrottled, lastReason, unix_timestamp() - startTime as startTimeAgo, unix_timestamp() - endTime as endTimeAgo from " . $this->throttleTable . " order by endTime desc limit 50");
|
293 |
+
foreach($results as &$elem){
|
|
|
294 |
$elem['startTimeAgo'] = wfUtils::makeTimeAgo($elem['startTimeAgo']);
|
295 |
$elem['endTimeAgo'] = wfUtils::makeTimeAgo($elem['endTimeAgo']);
|
|
|
296 |
}
|
297 |
$this->resolveIPs($results);
|
298 |
foreach($results as &$elem){
|
301 |
return $results;
|
302 |
}
|
303 |
public function getLockedOutIPs(){
|
304 |
+
$results = $this->getDB()->querySelect("select IP, unix_timestamp() - blockedTime as createdAgo, reason, unix_timestamp() - lastAttempt as lastAttemptAgo, lastAttempt, blockedHits, (blockedTime + %s) - unix_timestamp() as blockedFor from " . $this->lockOutTable . " where blockedTime + %s > unix_timestamp() order by blockedTime desc", wfConfig::get('loginSec_lockoutMins'), wfConfig::get('loginSec_lockoutMins'));
|
305 |
+
foreach($results as &$elem){
|
|
|
306 |
$elem['lastAttemptAgo'] = $elem['lastAttempt'] ? wfUtils::makeTimeAgo($elem['lastAttemptAgo']) : '';
|
307 |
$elem['blockedForAgo'] = wfUtils::makeTimeAgo($elem['blockedFor']);
|
|
|
308 |
}
|
309 |
$this->resolveIPs($results);
|
310 |
foreach($results as &$elem){
|
313 |
return $results;
|
314 |
}
|
315 |
public function getBlockedIPs(){
|
316 |
+
$results = $this->getDB()->querySelect("select IP, unix_timestamp() - blockedTime as createdAgo, reason, unix_timestamp() - lastAttempt as lastAttemptAgo, lastAttempt, blockedHits, (blockedTime + %s) - unix_timestamp() as blockedFor, permanent from " . $this->blocksTable . " where (permanent=1 OR (blockedTime + %s > unix_timestamp())) order by blockedTime desc", wfConfig::get('blockedTime'), wfConfig::get('blockedTime'));
|
317 |
+
foreach($results as &$elem){
|
|
|
318 |
$lastHitAgo = 0;
|
319 |
$totalHits = 0;
|
320 |
$serverTime = $this->getDB()->querySingle("select unix_timestamp()");
|
336 |
$elem['lastHitAgo'] = $lastHitAgo ? wfUtils::makeTimeAgo($lastHitAgo) : '';
|
337 |
$elem['lastAttemptAgo'] = $elem['lastAttempt'] ? wfUtils::makeTimeAgo($elem['lastAttemptAgo']) : '';
|
338 |
$elem['blockedForAgo'] = wfUtils::makeTimeAgo($elem['blockedFor']);
|
|
|
339 |
}
|
340 |
$this->resolveIPs($results);
|
341 |
foreach($results as &$elem){
|
353 |
wordfence::status(1, 'error', "Invalid type to getLeechers(): $type");
|
354 |
return false;
|
355 |
}
|
356 |
+
$results = $this->getDB()->querySelect("select IP, sum(hits) as totalHits from $table where eMin > ((unix_timestamp() - 86400) / 60) group by IP order by totalHits desc limit 20");
|
|
|
|
|
|
|
|
|
357 |
$this->resolveIPs($results);
|
358 |
foreach($results as &$elem){
|
359 |
$elem['timeAgo'] = wfUtils::makeTimeAgo($this->getDB()->querySingle("select unix_timestamp() - (eMin * 60) from $table where IP=%s", $elem['IP']));
|
371 |
$headers[$matches[1]] = $v;
|
372 |
}
|
373 |
}
|
374 |
+
$this->getDB()->queryWrite("insert into " . $this->hitsTable . " (ctime, is404, isGoogle, IP, userID, newVisit, URL, referer, UA) values (%f, %d, %d, %s, %s, %d, '%s', '%s', '%s')",
|
375 |
sprintf('%.6f', microtime(true)),
|
376 |
(is_404() ? 1 : 0),
|
377 |
(wfCrawl::isGoogleCrawler() ? 1 : 0),
|
388 |
$serverTime = $this->getDB()->querySingle("select unix_timestamp()");
|
389 |
$IPSQL = "";
|
390 |
if($IP){
|
391 |
+
$IPSQL = " and IP=INET_ATON(%s) ";
|
392 |
+
$sqlArgs = array($afterTime, $IP, $limit);
|
393 |
+
} else {
|
394 |
+
$sqlArgs = array($afterTime, $limit);
|
395 |
}
|
396 |
if($hitType == 'hits'){
|
397 |
if($type == 'hit'){
|
411 |
wordfence::status(1, 'error', "Invalid log type to wfLog: $type");
|
412 |
return false;
|
413 |
}
|
414 |
+
array_unshift($sqlArgs, "select * from " . $this->hitsTable . " where ctime > %f $IPSQL $typeSQL order by ctime desc limit %d");
|
415 |
+
$results = call_user_func_array(array($this->getDB(), 'querySelect'), $sqlArgs);
|
|
|
|
|
|
|
416 |
|
417 |
} else if($hitType == 'logins'){
|
418 |
+
array_unshift($sqlArgs, "select * from " . $this->loginsTable . " where ctime > %f $IPSQL order by ctime desc limit %d");
|
419 |
+
$results = call_user_func_array(array($this->getDB(), 'querySelect'), $sqlArgs );
|
|
|
|
|
420 |
|
421 |
} else {
|
422 |
wordfence::status(1, 'error', "getHits got invalid hitType: $hitType");
|
423 |
return false;
|
424 |
}
|
|
|
|
|
|
|
|
|
425 |
$this->resolveIPs($results);
|
426 |
$ourURL = parse_url(site_url());
|
427 |
$ourHost = strtolower($ourURL['host']);
|
608 |
|
609 |
$IP = wfUtils::inet_aton(wfUtils::getIP());
|
610 |
if($rec = $this->getDB()->querySingleRec("select blockedTime, reason from " . $this->blocksTable . " where IP=%s and (permanent=1 OR (blockedTime + %s > unix_timestamp()))", $IP, wfConfig::get('blockedTime'))){
|
611 |
+
$this->getDB()->queryWrite("update " . $this->blocksTable . " set lastAttempt=unix_timestamp(), blockedHits = blockedHits + 1 where IP=%s", $IP);
|
612 |
$now = $this->getDB()->querySingle("select unix_timestamp()");
|
613 |
$secsToGo = ($rec['blockedTime'] + wfConfig::get('blockedTime')) - $now;
|
614 |
$this->do503($secsToGo, $rec['reason']);
|
649 |
$secsToGo = wfConfig::get('blockedTime');
|
650 |
} else if($action == 'throttle'){
|
651 |
$IP = wfUtils::inet_aton(wfUtils::getIP());
|
652 |
+
$this->getDB()->queryWrite("insert into " . $this->throttleTable . " (IP, startTime, endTime, timesThrottled, lastReason) values (%s, unix_timestamp(), unix_timestamp(), 1, '%s') ON DUPLICATE KEY UPDATE endTime=unix_timestamp(), timesThrottled = timesThrottled + 1, lastReason='%s'", $IP, $reason, $reason);
|
653 |
wordfence::status(2, 'info', "Throttling IP $IP. $reason");
|
654 |
$secsToGo = 60;
|
655 |
}
|
711 |
}
|
712 |
public function addStatus($level, $type, $msg){
|
713 |
//$msg = '[' . sprintf('%.2f', memory_get_usage(true) / (1024 * 1024)) . '] ' . $msg;
|
714 |
+
$this->getDB()->queryWrite("insert into " . $this->statusTable . " (ctime, level, type, msg) values (%s, %d, '%s', '%s')", sprintf('%.6f', microtime(true)), $level, $type, $msg);
|
715 |
}
|
716 |
public function getStatusEvents($lastCtime){
|
717 |
if($lastCtime < 1){
|
720 |
$lastCtime = 0;
|
721 |
}
|
722 |
}
|
723 |
+
$results = $this->getDB()->querySelect("select ctime, level, type, msg from " . $this->statusTable . " where ctime > %f order by ctime asc", $lastCtime);
|
|
|
724 |
$lastTime = false;
|
725 |
$timeOffset = 3600 * get_option('gmt_offset');
|
726 |
+
foreach($results as &$rec){
|
727 |
//$rec['timeAgo'] = wfUtils::makeTimeAgo(time() - $rec['ctime']);
|
728 |
$rec['date'] = date('M d H:i:s', $rec['ctime'] + $timeOffset);
|
|
|
729 |
}
|
730 |
return $results;
|
731 |
}
|
732 |
public function getSummaryEvents(){
|
733 |
+
$results = $this->getDB()->querySelect("select ctime, level, type, msg from " . $this->statusTable . " where level = 10 order by ctime desc limit 100");
|
|
|
734 |
$lastTime = false;
|
735 |
$timeOffset = 3600 * get_option('gmt_offset');
|
736 |
+
foreach($results as &$rec){
|
737 |
$rec['date'] = date('M d H:i:s', $rec['ctime'] + $timeOffset);
|
|
|
738 |
if(strpos($rec['msg'], 'SUM_PREP:') === 0){
|
739 |
break;
|
740 |
}
|
lib/wfScanEngine.php
CHANGED
@@ -267,8 +267,8 @@ class wfScanEngine {
|
|
267 |
$wfdb = new wfDB();
|
268 |
$this->hoover = new wordfenceURLHoover($this->apiKey, $this->wp_version);
|
269 |
foreach($blogsToScan as $blog){
|
270 |
-
$q1 = $wfdb->
|
271 |
-
|
272 |
$this->scanQueue[] = array($blog, $idRow['ID']);
|
273 |
}
|
274 |
}
|
@@ -375,16 +375,8 @@ class wfScanEngine {
|
|
375 |
$blogsToScan = $this->getBlogsToScan('comments');
|
376 |
$wfdb = new wfDB();
|
377 |
foreach($blogsToScan as $blog){
|
378 |
-
$q1 = $wfdb->
|
379 |
-
|
380 |
-
wordfence::statusEndErr();
|
381 |
-
return;
|
382 |
-
}
|
383 |
-
if(! (mysql_num_rows($q1) > 0)){
|
384 |
-
continue;
|
385 |
-
}
|
386 |
-
|
387 |
-
while($idRow = mysql_fetch_assoc($q1)){
|
388 |
$this->scanQueue[] = array($blog, $idRow['comment_ID']);
|
389 |
}
|
390 |
}
|
@@ -506,8 +498,8 @@ class wfScanEngine {
|
|
506 |
$prefix = $wpdb->base_prefix;
|
507 |
$blogsToScan = array();
|
508 |
if(is_multisite()){
|
509 |
-
$q1 = $wfdb->
|
510 |
-
|
511 |
$row['isMultisite'] = true;
|
512 |
if($row['blog_id'] == 1){
|
513 |
$row['table'] = $prefix . $table;
|
@@ -547,10 +539,10 @@ class wfScanEngine {
|
|
547 |
$this->statusIDX['passwds'] = wordfence::statusStart('Scanning for weak passwords');
|
548 |
global $wpdb;
|
549 |
$wfdb = new wfDB();
|
550 |
-
$res1 = $wfdb->
|
551 |
$counter = 0;
|
552 |
-
|
553 |
-
$this->userPasswdQueue .= pack('N', $rec[
|
554 |
$counter++;
|
555 |
}
|
556 |
wordfence::status(2, 'info', "Starting password strength check on $counter users.");
|
267 |
$wfdb = new wfDB();
|
268 |
$this->hoover = new wordfenceURLHoover($this->apiKey, $this->wp_version);
|
269 |
foreach($blogsToScan as $blog){
|
270 |
+
$q1 = $wfdb->querySelect("select ID from " . $blog['table'] . " where post_type IN ('page', 'post') and post_status = 'publish'");
|
271 |
+
foreach($q1 as $idRow){
|
272 |
$this->scanQueue[] = array($blog, $idRow['ID']);
|
273 |
}
|
274 |
}
|
375 |
$blogsToScan = $this->getBlogsToScan('comments');
|
376 |
$wfdb = new wfDB();
|
377 |
foreach($blogsToScan as $blog){
|
378 |
+
$q1 = $wfdb->querySelect("select comment_ID from " . $blog['table'] . " where comment_approved=1");
|
379 |
+
foreach($q1 as $idRow){
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
380 |
$this->scanQueue[] = array($blog, $idRow['comment_ID']);
|
381 |
}
|
382 |
}
|
498 |
$prefix = $wpdb->base_prefix;
|
499 |
$blogsToScan = array();
|
500 |
if(is_multisite()){
|
501 |
+
$q1 = $wfdb->querySelect("select blog_id, domain, path from $prefix"."blogs where deleted=0 order by blog_id asc");
|
502 |
+
foreach($q1 as $row){
|
503 |
$row['isMultisite'] = true;
|
504 |
if($row['blog_id'] == 1){
|
505 |
$row['table'] = $prefix . $table;
|
539 |
$this->statusIDX['passwds'] = wordfence::statusStart('Scanning for weak passwords');
|
540 |
global $wpdb;
|
541 |
$wfdb = new wfDB();
|
542 |
+
$res1 = $wfdb->querySelect("select ID from " . $wpdb->users);
|
543 |
$counter = 0;
|
544 |
+
foreach($res1 as $rec){
|
545 |
+
$this->userPasswdQueue .= pack('N', $rec['ID']);
|
546 |
$counter++;
|
547 |
}
|
548 |
wordfence::status(2, 'info', "Starting password strength check on $counter users.");
|
lib/wfSchema.php
CHANGED
@@ -163,30 +163,31 @@ class wfSchema {
|
|
163 |
private $db = false;
|
164 |
private $prefix = 'wp_';
|
165 |
public function __construct($dbhost = false, $dbuser = false, $dbpassword = false, $dbname = false){
|
|
|
166 |
if($dbhost){ //for testing
|
167 |
$this->db = new wfDB(false, $dbhost, $dbuser, $dbpassword, $dbname);
|
168 |
$this->prefix = 'wp_';
|
169 |
} else {
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
}
|
175 |
public function dropAll(){
|
176 |
foreach($this->tables as $table => $def){
|
177 |
-
$this->db->
|
178 |
}
|
179 |
}
|
180 |
public function createAll(){
|
181 |
foreach($this->tables as $table => $def){
|
182 |
-
$this->db->
|
183 |
}
|
184 |
}
|
185 |
public function create($table){
|
186 |
-
$this->db->
|
187 |
}
|
188 |
public function drop($table){
|
189 |
-
$this->db->
|
190 |
}
|
191 |
}
|
192 |
?>
|
163 |
private $db = false;
|
164 |
private $prefix = 'wp_';
|
165 |
public function __construct($dbhost = false, $dbuser = false, $dbpassword = false, $dbname = false){
|
166 |
+
/*
|
167 |
if($dbhost){ //for testing
|
168 |
$this->db = new wfDB(false, $dbhost, $dbuser, $dbpassword, $dbname);
|
169 |
$this->prefix = 'wp_';
|
170 |
} else {
|
171 |
+
*/
|
172 |
+
global $wpdb;
|
173 |
+
$this->db = new wfDB();
|
174 |
+
$this->prefix = $wpdb->base_prefix;
|
175 |
}
|
176 |
public function dropAll(){
|
177 |
foreach($this->tables as $table => $def){
|
178 |
+
$this->db->queryWrite("drop table if exists " . $this->prefix . $table);
|
179 |
}
|
180 |
}
|
181 |
public function createAll(){
|
182 |
foreach($this->tables as $table => $def){
|
183 |
+
$this->db->queryWrite("create table IF NOT EXISTS " . $this->prefix . $table . " " . $def);
|
184 |
}
|
185 |
}
|
186 |
public function create($table){
|
187 |
+
$this->db->queryWrite("create table IF NOT EXISTS " . $this->prefix . $table . " " . $this->tables[$table]);
|
188 |
}
|
189 |
public function drop($table){
|
190 |
+
$this->db->queryWrite("drop table if exists " . $this->prefix . $table);
|
191 |
}
|
192 |
}
|
193 |
?>
|
lib/wfUtils.php
CHANGED
@@ -330,20 +330,18 @@ class wfUtils {
|
|
330 |
$locsTable = $wpdb->base_prefix . 'wfLocs';
|
331 |
$IPLocs = array();
|
332 |
foreach($IPs as $IP){
|
333 |
-
$
|
334 |
-
if($
|
335 |
-
if($row
|
336 |
-
|
337 |
-
|
|
|
|
|
338 |
} else {
|
339 |
-
if($
|
340 |
-
$
|
341 |
-
} else {
|
342 |
-
if(! $isInt){
|
343 |
-
$row['IP'] = self::inet_ntoa($row['IP']);
|
344 |
-
}
|
345 |
-
$IPLocs[$IP] = $row;
|
346 |
}
|
|
|
347 |
}
|
348 |
}
|
349 |
}
|
@@ -360,10 +358,10 @@ class wfUtils {
|
|
360 |
if(is_array($freshIPs)){
|
361 |
foreach($freshIPs as $IP => $value){
|
362 |
if($value == 'failed'){
|
363 |
-
$db->
|
364 |
$IPLocs[$IP] = false;
|
365 |
} else {
|
366 |
-
$db->
|
367 |
($isInt ? $IP : self::inet_aton($IP)),
|
368 |
$value[3], //city
|
369 |
$value[2], //region
|
@@ -405,7 +403,7 @@ class wfUtils {
|
|
405 |
} else {
|
406 |
$host = $host[0]['target'];
|
407 |
}
|
408 |
-
$db->
|
409 |
}
|
410 |
if($host == 'NONE'){
|
411 |
return '';
|
330 |
$locsTable = $wpdb->base_prefix . 'wfLocs';
|
331 |
$IPLocs = array();
|
332 |
foreach($IPs as $IP){
|
333 |
+
$row = $db->querySingleRec("select IP, ctime, failed, city, region, countryName, countryCode, lat, lon, unix_timestamp() - ctime as age from " . $locsTable . " where IP=%s", ($isInt ? $IP : self::inet_aton($IP)) );
|
334 |
+
if($row){
|
335 |
+
if($row['age'] > WORDFENCE_MAX_IPLOC_AGE){
|
336 |
+
$db->queryWrite("delete from " . $locsTable . " where IP=%s", $row['IP']);
|
337 |
+
} else {
|
338 |
+
if($row['failed'] == 1){
|
339 |
+
$IPLocs[$IP] = false;
|
340 |
} else {
|
341 |
+
if(! $isInt){
|
342 |
+
$row['IP'] = self::inet_ntoa($row['IP']);
|
|
|
|
|
|
|
|
|
|
|
343 |
}
|
344 |
+
$IPLocs[$IP] = $row;
|
345 |
}
|
346 |
}
|
347 |
}
|
358 |
if(is_array($freshIPs)){
|
359 |
foreach($freshIPs as $IP => $value){
|
360 |
if($value == 'failed'){
|
361 |
+
$db->queryWrite("insert IGNORE into " . $locsTable . " (IP, ctime, failed) values (%s, unix_timestamp(), 1)", ($isInt ? $IP : self::inet_aton($IP)) );
|
362 |
$IPLocs[$IP] = false;
|
363 |
} else {
|
364 |
+
$db->queryWrite("insert IGNORE into " . $locsTable . " (IP, ctime, failed, city, region, countryName, countryCode, lat, lon) values (%s, unix_timestamp(), 0, '%s', '%s', '%s', '%s', %s, %s)",
|
365 |
($isInt ? $IP : self::inet_aton($IP)),
|
366 |
$value[3], //city
|
367 |
$value[2], //region
|
403 |
} else {
|
404 |
$host = $host[0]['target'];
|
405 |
}
|
406 |
+
$db->queryWrite("insert into " . $reverseTable . " (IP, host, lastUpdate) values (%s, '%s', unix_timestamp()) ON DUPLICATE KEY UPDATE host='%s', lastUpdate=unix_timestamp()", $IPn, $host, $host);
|
407 |
}
|
408 |
if($host == 'NONE'){
|
409 |
return '';
|
lib/wordfenceClass.php
CHANGED
@@ -57,9 +57,9 @@ class wordfence {
|
|
57 |
|
58 |
if(wfConfig::get('other_WFNet')){
|
59 |
$wfdb = new wfDB();
|
60 |
-
$q1 = $wfdb->
|
61 |
$URIs = array();
|
62 |
-
|
63 |
array_push($URIs, $rec['URI']);
|
64 |
}
|
65 |
$wfdb->truncate($p . "wfNet404s");
|
@@ -71,16 +71,16 @@ class wordfence {
|
|
71 |
}
|
72 |
}
|
73 |
|
74 |
-
$q2 = $wfdb->
|
75 |
$scanCont = "";
|
76 |
-
|
77 |
$scanCont .= pack('N', ip2long($rec['IP']));
|
78 |
}
|
79 |
$wfdb->truncate($p . "wfVulnScanners");
|
80 |
|
81 |
-
$q3 = $wfdb->
|
82 |
$lockCont = "";
|
83 |
-
|
84 |
$lockCont .= pack('N', ip2long($rec['IP']));
|
85 |
}
|
86 |
if(strlen($lockCont) > 0 || strlen($scanCont) > 0){
|
@@ -90,7 +90,7 @@ class wordfence {
|
|
90 |
if($resp['code'] == 200){
|
91 |
$len = strlen($resp['data']);
|
92 |
$reason = "WFSN: Blocked by Wordfence Security Network";
|
93 |
-
$wfdb->
|
94 |
if($len > 0 && $len % 4 == 0){
|
95 |
for($i = 0; $i < $len; $i += 4){
|
96 |
list($ipLong) = array_values(unpack('N', substr($resp['data'], $i, 4)));
|
@@ -122,42 +122,42 @@ class wordfence {
|
|
122 |
wordfence::status(4, 'error', "Could not fetch vulnerability patterns in scheduled job: " . $e->getMessage());
|
123 |
}
|
124 |
|
125 |
-
$wfdb->
|
126 |
$wfdb->truncate($p . "wfBadLeechers"); //only uses date that's less than 1 minute old
|
127 |
-
$wfdb->
|
128 |
-
$wfdb->
|
129 |
|
130 |
$count = $wfdb->querySingle("select count(*) as cnt from $p"."wfHits");
|
131 |
if($count > 20000){
|
132 |
-
$wfdb->
|
133 |
}
|
134 |
$maxRows = 1000; //affects stuff further down too
|
135 |
foreach(array('wfLeechers', 'wfScanners') as $table){
|
136 |
//This is time based per IP so shouldn't get too big
|
137 |
-
$wfdb->
|
138 |
}
|
139 |
-
$wfdb->
|
140 |
$count2 = $wfdb->querySingle("select count(*) as cnt from $p"."wfLogins");
|
141 |
if($count2 > 20000){
|
142 |
$wfdb->truncate($p . "wfLogins"); //in case of Dos
|
143 |
} else if($count2 > $maxRows){
|
144 |
-
$wfdb->
|
145 |
}
|
146 |
-
$wfdb->
|
147 |
$count3 = $wfdb->querySingle("select count(*) as cnt from $p"."wfThrottleLog");
|
148 |
if($count3 > 20000){
|
149 |
$wfdb->truncate($p . "wfThrottleLog"); //in case of DoS
|
150 |
} else if($count3 > $maxRows){
|
151 |
-
$wfdb->
|
152 |
}
|
153 |
$count4 = $wfdb->querySingle("select count(*) as cnt from $p"."wfStatus");
|
154 |
if($count4 > 100000){
|
155 |
$wfdb->truncate($p . "wfStatus");
|
156 |
} else if($count4 > 1000){ //max status events we keep. This determines how much gets emailed to us when users sends us a debug report.
|
157 |
-
$wfdb->
|
158 |
$count5 = $wfdb->querySingle("select count(*) as cnt from $p"."wfStatus where level=10");
|
159 |
if($count5 > 100){
|
160 |
-
$wfdb->
|
161 |
}
|
162 |
}
|
163 |
|
@@ -169,13 +169,14 @@ class wordfence {
|
|
169 |
//Remove old legacy cron job if exists
|
170 |
wp_clear_scheduled_hook('wordfence_scheduled_scan');
|
171 |
|
172 |
-
//Install new schedule. If schedule config is blank it will install the default 'auto' schedule.
|
173 |
-
wordfence::scheduleScans();
|
174 |
|
175 |
$schema = new wfSchema();
|
176 |
$schema->createAll(); //if not exists
|
177 |
wfConfig::setDefaults(); //If not set
|
178 |
-
|
|
|
|
|
|
|
179 |
if(! wfConfig::get('apiKey')){
|
180 |
$api = new wfAPI('', wfUtils::getWPVersion());
|
181 |
try {
|
@@ -201,7 +202,7 @@ class wordfence {
|
|
201 |
$prefix = $wpdb->base_prefix;
|
202 |
$count = $db->querySingle("select count(*) as cnt from $prefix"."wfHits");
|
203 |
if($count > 20000){
|
204 |
-
$db->
|
205 |
}
|
206 |
$db->dropColumn('wfHits', 'HTTPHeaders');
|
207 |
}
|
@@ -215,19 +216,19 @@ class wordfence {
|
|
215 |
|
216 |
global $wpdb;
|
217 |
$prefix = $wpdb->base_prefix;
|
218 |
-
$db->
|
219 |
-
$db->
|
220 |
-
$db->
|
221 |
//3.1.2 to 3.1.4
|
222 |
-
$db->
|
223 |
//3.2.1 to 3.2.2
|
224 |
-
$db->
|
225 |
-
$db->
|
226 |
-
$db->
|
227 |
|
228 |
$optScanEnabled = $db->querySingle("select val from $prefix"."wfConfig where name='scansEnabled_options'");
|
229 |
if($optScanEnabled != '0' && $optScanEnabled != '1'){
|
230 |
-
$db->
|
231 |
}
|
232 |
|
233 |
//Must be the final line
|
@@ -305,7 +306,7 @@ class wordfence {
|
|
305 |
if(! preg_match('/^\d+$/', $hid)){ exit(); }
|
306 |
$db = new wfDB();
|
307 |
global $wpdb; $p = $wpdb->base_prefix;
|
308 |
-
$db->
|
309 |
if(! headers_sent()){ //suppress content-type warning in chrome
|
310 |
header('Content-type: image/gif');
|
311 |
}
|
@@ -439,12 +440,14 @@ class wordfence {
|
|
439 |
if($_GET['func'] == 'unlockMyIP'){
|
440 |
$wfLog->unblockIP(wfUtils::getIP());
|
441 |
$wfLog->unlockOutIP(wfUtils::getIP());
|
|
|
442 |
header('Location: ' . wp_login_url());
|
443 |
exit();
|
444 |
} else if($_GET['func'] == 'unlockAllIPs'){
|
445 |
wordfence::status(1, 'info', "Request received via unlock email link to unblock all IP's.");
|
446 |
$wfLog->unblockAllIPs();
|
447 |
$wfLog->unlockAllIPs();
|
|
|
448 |
header('Location: ' . wp_login_url());
|
449 |
exit();
|
450 |
} else if($_GET['func'] == 'disableRules'){
|
@@ -453,6 +456,7 @@ class wordfence {
|
|
453 |
wordfence::status(1, 'info', "Request received via unlock email link to unblock all IP's via disabling firewall rules.");
|
454 |
$wfLog->unblockAllIPs();
|
455 |
$wfLog->unlockAllIPs();
|
|
|
456 |
wfConfig::set('cbl_countries', ''); //unblock all countries
|
457 |
header('Location: ' . wp_login_url());
|
458 |
exit();
|
@@ -705,9 +709,9 @@ class wordfence {
|
|
705 |
$wfdb = new wfDB();
|
706 |
global $wpdb;
|
707 |
$p = $wpdb->base_prefix;
|
708 |
-
$q = $wfdb->
|
709 |
$timeOffset = 3600 * get_option('gmt_offset');
|
710 |
-
|
711 |
if($r['type'] == 'error'){
|
712 |
$content .= "\n";
|
713 |
}
|
@@ -828,7 +832,7 @@ class wordfence {
|
|
828 |
$wfdb = new wfDB();
|
829 |
global $wpdb;
|
830 |
$p = $wpdb->base_prefix;
|
831 |
-
$wfdb->
|
832 |
}
|
833 |
if($opts['howGetIPs'] != wfConfig::get('howGetIPs', '')){
|
834 |
$reload = 'reload';
|
@@ -1446,6 +1450,7 @@ class wordfence {
|
|
1446 |
}
|
1447 |
$warningAdded = true;
|
1448 |
}
|
|
|
1449 |
if(is_plugin_active('w3-total-cache/w3-total-cache.php') && wfConfig::get('liveTrafficEnabled')){
|
1450 |
wfConfig::set('liveTrafficEnabled', 0);
|
1451 |
if(wfUtils::isAdminPageMU()){
|
@@ -1462,6 +1467,7 @@ class wordfence {
|
|
1462 |
add_action('admin_notices', 'wordfence::liveTrafficSuperCacheWarning');
|
1463 |
}
|
1464 |
}
|
|
|
1465 |
|
1466 |
add_submenu_page("Wordfence", "Scan", "Scan", "activate_plugins", "Wordfence", 'wordfence::menu_scan');
|
1467 |
add_menu_page('Wordfence', 'Wordfence', 'activate_plugins', 'Wordfence', 'wordfence::menu_scan', wfUtils::getBaseURL() . 'images/wordfence-logo-16x16.png');
|
57 |
|
58 |
if(wfConfig::get('other_WFNet')){
|
59 |
$wfdb = new wfDB();
|
60 |
+
$q1 = $wfdb->querySelect("select URI from $p"."wfNet404s where ctime > unix_timestamp() - 3600 limit 1000");
|
61 |
$URIs = array();
|
62 |
+
foreach($q1 as $rec){
|
63 |
array_push($URIs, $rec['URI']);
|
64 |
}
|
65 |
$wfdb->truncate($p . "wfNet404s");
|
71 |
}
|
72 |
}
|
73 |
|
74 |
+
$q2 = $wfdb->querySelect("select INET_NTOA(IP) as IP from $p"."wfVulnScanners where ctime > unix_timestamp() - 3600");
|
75 |
$scanCont = "";
|
76 |
+
foreach($q2 as $rec){
|
77 |
$scanCont .= pack('N', ip2long($rec['IP']));
|
78 |
}
|
79 |
$wfdb->truncate($p . "wfVulnScanners");
|
80 |
|
81 |
+
$q3 = $wfdb->querySelect("select INET_NTOA(IP) as IP from $p"."wfLockedOut where blockedTime > unix_timestamp() - 3600");
|
82 |
$lockCont = "";
|
83 |
+
foreach($q3 as $rec){
|
84 |
$lockCont .= pack('N', ip2long($rec['IP']));
|
85 |
}
|
86 |
if(strlen($lockCont) > 0 || strlen($scanCont) > 0){
|
90 |
if($resp['code'] == 200){
|
91 |
$len = strlen($resp['data']);
|
92 |
$reason = "WFSN: Blocked by Wordfence Security Network";
|
93 |
+
$wfdb->queryWrite("delete from $p"."wfBlocks where wfsn=1 and permanent=0");
|
94 |
if($len > 0 && $len % 4 == 0){
|
95 |
for($i = 0; $i < $len; $i += 4){
|
96 |
list($ipLong) = array_values(unpack('N', substr($resp['data'], $i, 4)));
|
122 |
wordfence::status(4, 'error', "Could not fetch vulnerability patterns in scheduled job: " . $e->getMessage());
|
123 |
}
|
124 |
|
125 |
+
$wfdb->queryWrite("delete from $p"."wfLocs where ctime < unix_timestamp() - %d", WORDFENCE_MAX_IPLOC_AGE);
|
126 |
$wfdb->truncate($p . "wfBadLeechers"); //only uses date that's less than 1 minute old
|
127 |
+
$wfdb->queryWrite("delete from $p"."wfBlocks where (blockedTime + %s < unix_timestamp()) and permanent=0", wfConfig::get('blockedTime'));
|
128 |
+
$wfdb->queryWrite("delete from $p"."wfCrawlers where lastUpdate < unix_timestamp() - (86400 * 7)");
|
129 |
|
130 |
$count = $wfdb->querySingle("select count(*) as cnt from $p"."wfHits");
|
131 |
if($count > 20000){
|
132 |
+
$wfdb->queryWrite("delete from $p"."wfHits order by id asc limit " . ($count - 20000));
|
133 |
}
|
134 |
$maxRows = 1000; //affects stuff further down too
|
135 |
foreach(array('wfLeechers', 'wfScanners') as $table){
|
136 |
//This is time based per IP so shouldn't get too big
|
137 |
+
$wfdb->queryWrite("delete from $p"."$table where eMin < ((unix_timestamp() - (86400 * 2)) / 60)");
|
138 |
}
|
139 |
+
$wfdb->queryWrite("delete from $p"."wfLockedOut where blockedTime + %s < unix_timestamp()", wfConfig::get('loginSec_lockoutMins') * 60);
|
140 |
$count2 = $wfdb->querySingle("select count(*) as cnt from $p"."wfLogins");
|
141 |
if($count2 > 20000){
|
142 |
$wfdb->truncate($p . "wfLogins"); //in case of Dos
|
143 |
} else if($count2 > $maxRows){
|
144 |
+
$wfdb->queryWrite("delete from $p"."wfLogins order by ctime asc limit %d", ($count2 - $maxRows));
|
145 |
}
|
146 |
+
$wfdb->queryWrite("delete from $p"."wfReverseCache where unix_timestamp() - lastUpdate > 86400");
|
147 |
$count3 = $wfdb->querySingle("select count(*) as cnt from $p"."wfThrottleLog");
|
148 |
if($count3 > 20000){
|
149 |
$wfdb->truncate($p . "wfThrottleLog"); //in case of DoS
|
150 |
} else if($count3 > $maxRows){
|
151 |
+
$wfdb->queryWrite("delete from $p"."wfThrottleLog order by endTime asc limit %d", ($count3 - $maxRows));
|
152 |
}
|
153 |
$count4 = $wfdb->querySingle("select count(*) as cnt from $p"."wfStatus");
|
154 |
if($count4 > 100000){
|
155 |
$wfdb->truncate($p . "wfStatus");
|
156 |
} else if($count4 > 1000){ //max status events we keep. This determines how much gets emailed to us when users sends us a debug report.
|
157 |
+
$wfdb->queryWrite("delete from $p"."wfStatus where level != 10 order by ctime asc limit %d", ($count4 - 1000));
|
158 |
$count5 = $wfdb->querySingle("select count(*) as cnt from $p"."wfStatus where level=10");
|
159 |
if($count5 > 100){
|
160 |
+
$wfdb->queryWrite("delete from $p"."wfStatus where level = 10 order by ctime asc limit %d", ($count5 - 100) );
|
161 |
}
|
162 |
}
|
163 |
|
169 |
//Remove old legacy cron job if exists
|
170 |
wp_clear_scheduled_hook('wordfence_scheduled_scan');
|
171 |
|
|
|
|
|
172 |
|
173 |
$schema = new wfSchema();
|
174 |
$schema->createAll(); //if not exists
|
175 |
wfConfig::setDefaults(); //If not set
|
176 |
+
|
177 |
+
//Install new schedule. If schedule config is blank it will install the default 'auto' schedule.
|
178 |
+
wordfence::scheduleScans();
|
179 |
+
|
180 |
if(! wfConfig::get('apiKey')){
|
181 |
$api = new wfAPI('', wfUtils::getWPVersion());
|
182 |
try {
|
202 |
$prefix = $wpdb->base_prefix;
|
203 |
$count = $db->querySingle("select count(*) as cnt from $prefix"."wfHits");
|
204 |
if($count > 20000){
|
205 |
+
$db->queryWrite("delete from $prefix"."wfHits order by id asc limit " . ($count - 20000));
|
206 |
}
|
207 |
$db->dropColumn('wfHits', 'HTTPHeaders');
|
208 |
}
|
216 |
|
217 |
global $wpdb;
|
218 |
$prefix = $wpdb->base_prefix;
|
219 |
+
$db->queryWriteIgnoreError("alter table $prefix"."wfConfig modify column val longblob");
|
220 |
+
$db->queryWriteIgnoreError("alter table $prefix"."wfBlocks add column permanent tinyint UNSIGNED default 0");
|
221 |
+
$db->queryWriteIgnoreError("alter table $prefix"."wfStatus modify column msg varchar(1000) NOT NULL");
|
222 |
//3.1.2 to 3.1.4
|
223 |
+
$db->queryWriteIgnoreError("alter table $prefix"."wfBlocks modify column blockedTime bigint signed NOT NULL");
|
224 |
//3.2.1 to 3.2.2
|
225 |
+
$db->queryWriteIgnoreError("alter table $prefix"."wfLockedOut modify column blockedTime bigint signed NOT NULL");
|
226 |
+
$db->queryWriteIgnoreError("drop table if exists $prefix"."wfFileQueue");
|
227 |
+
$db->queryWriteIgnoreError("drop table if exists $prefix"."wfFileChanges");
|
228 |
|
229 |
$optScanEnabled = $db->querySingle("select val from $prefix"."wfConfig where name='scansEnabled_options'");
|
230 |
if($optScanEnabled != '0' && $optScanEnabled != '1'){
|
231 |
+
$db->queryWrite("update $prefix"."wfConfig set val='1' where name='scansEnabled_options'");
|
232 |
}
|
233 |
|
234 |
//Must be the final line
|
306 |
if(! preg_match('/^\d+$/', $hid)){ exit(); }
|
307 |
$db = new wfDB();
|
308 |
global $wpdb; $p = $wpdb->base_prefix;
|
309 |
+
$db->queryWrite("update LOW_PRIORITY $p"."wfHits set jsRun=1 where id=%d", $hid);
|
310 |
if(! headers_sent()){ //suppress content-type warning in chrome
|
311 |
header('Content-type: image/gif');
|
312 |
}
|
440 |
if($_GET['func'] == 'unlockMyIP'){
|
441 |
$wfLog->unblockIP(wfUtils::getIP());
|
442 |
$wfLog->unlockOutIP(wfUtils::getIP());
|
443 |
+
delete_transient('wflginfl_' . wfUtils::inet_aton(wfUtils::getIP())); //Reset login failure counter
|
444 |
header('Location: ' . wp_login_url());
|
445 |
exit();
|
446 |
} else if($_GET['func'] == 'unlockAllIPs'){
|
447 |
wordfence::status(1, 'info', "Request received via unlock email link to unblock all IP's.");
|
448 |
$wfLog->unblockAllIPs();
|
449 |
$wfLog->unlockAllIPs();
|
450 |
+
delete_transient('wflginfl_' . wfUtils::inet_aton(wfUtils::getIP())); //Reset login failure counter
|
451 |
header('Location: ' . wp_login_url());
|
452 |
exit();
|
453 |
} else if($_GET['func'] == 'disableRules'){
|
456 |
wordfence::status(1, 'info', "Request received via unlock email link to unblock all IP's via disabling firewall rules.");
|
457 |
$wfLog->unblockAllIPs();
|
458 |
$wfLog->unlockAllIPs();
|
459 |
+
delete_transient('wflginfl_' . wfUtils::inet_aton(wfUtils::getIP())); //Reset login failure counter
|
460 |
wfConfig::set('cbl_countries', ''); //unblock all countries
|
461 |
header('Location: ' . wp_login_url());
|
462 |
exit();
|
709 |
$wfdb = new wfDB();
|
710 |
global $wpdb;
|
711 |
$p = $wpdb->base_prefix;
|
712 |
+
$q = $wfdb->querySelect("select ctime, level, type, msg from $p"."wfStatus order by ctime desc limit 10000");
|
713 |
$timeOffset = 3600 * get_option('gmt_offset');
|
714 |
+
foreach($q as $r){
|
715 |
if($r['type'] == 'error'){
|
716 |
$content .= "\n";
|
717 |
}
|
832 |
$wfdb = new wfDB();
|
833 |
global $wpdb;
|
834 |
$p = $wpdb->base_prefix;
|
835 |
+
$wfdb->queryWrite("delete from $p"."wfBlocks where wfsn=1 and permanent=0");
|
836 |
}
|
837 |
if($opts['howGetIPs'] != wfConfig::get('howGetIPs', '')){
|
838 |
$reload = 'reload';
|
1450 |
}
|
1451 |
$warningAdded = true;
|
1452 |
}
|
1453 |
+
/*
|
1454 |
if(is_plugin_active('w3-total-cache/w3-total-cache.php') && wfConfig::get('liveTrafficEnabled')){
|
1455 |
wfConfig::set('liveTrafficEnabled', 0);
|
1456 |
if(wfUtils::isAdminPageMU()){
|
1467 |
add_action('admin_notices', 'wordfence::liveTrafficSuperCacheWarning');
|
1468 |
}
|
1469 |
}
|
1470 |
+
*/
|
1471 |
|
1472 |
add_submenu_page("Wordfence", "Scan", "Scan", "activate_plugins", "Wordfence", 'wordfence::menu_scan');
|
1473 |
add_menu_page('Wordfence', 'Wordfence', 'activate_plugins', 'Wordfence', 'wordfence::menu_scan', wfUtils::getBaseURL() . 'images/wordfence-logo-16x16.png');
|
lib/wordfenceHash.php
CHANGED
@@ -49,8 +49,8 @@ class wordfenceHash {
|
|
49 |
$this->db = new wfDB();
|
50 |
|
51 |
//Doing a delete for now. Later we can optimize this to only scan modified files.
|
52 |
-
//$this->db->
|
53 |
-
$this->db->
|
54 |
$fetchCoreHashesStatus = wordfence::statusStart("Fetching core, theme and plugin file signatures from Wordfence");
|
55 |
$dataArr = $engine->api->binCall('get_known_files', json_encode(array(
|
56 |
'plugins' => $plugins,
|
@@ -313,7 +313,7 @@ class wordfenceHash {
|
|
313 |
// knownFile means that the file is both part of core or a known plugin or theme AND that we recognize the file's hash.
|
314 |
// we could split this into files who's path we recognize and file's who's path we recognize AND who have a valid sig.
|
315 |
// But because we want to scan files who's sig we don't recognize, regardless of known path or not, we only need one "knownFile" field.
|
316 |
-
$this->db->
|
317 |
|
318 |
//Now that we know we can open the file, lets update stats
|
319 |
if(preg_match('/\.(?:js|html|htm|css)$/i', $realFile)){
|
49 |
$this->db = new wfDB();
|
50 |
|
51 |
//Doing a delete for now. Later we can optimize this to only scan modified files.
|
52 |
+
//$this->db->queryWrite("update " . $this->db->prefix() . "wfFileMods set oldMD5 = newMD5");
|
53 |
+
$this->db->queryWrite("delete from " . $this->db->prefix() . "wfFileMods");
|
54 |
$fetchCoreHashesStatus = wordfence::statusStart("Fetching core, theme and plugin file signatures from Wordfence");
|
55 |
$dataArr = $engine->api->binCall('get_known_files', json_encode(array(
|
56 |
'plugins' => $plugins,
|
313 |
// knownFile means that the file is both part of core or a known plugin or theme AND that we recognize the file's hash.
|
314 |
// we could split this into files who's path we recognize and file's who's path we recognize AND who have a valid sig.
|
315 |
// But because we want to scan files who's sig we don't recognize, regardless of known path or not, we only need one "knownFile" field.
|
316 |
+
$this->db->queryWrite("insert into " . $this->db->prefix() . "wfFileMods (filename, filenameMD5, knownFile, oldMD5, newMD5) values ('%s', unhex(md5('%s')), %d, '', unhex('%s')) ON DUPLICATE KEY UPDATE newMD5=unhex('%s'), knownFile=%d", $file, $file, $knownFile, $md5, $md5, $knownFile);
|
317 |
|
318 |
//Now that we know we can open the file, lets update stats
|
319 |
if(preg_match('/\.(?:js|html|htm|css)$/i', $realFile)){
|
lib/wordfenceScanner.php
CHANGED
@@ -50,9 +50,9 @@ class wordfenceScanner {
|
|
50 |
$this->lastStatusTime = microtime(true);
|
51 |
}
|
52 |
$db = new wfDB();
|
53 |
-
$res1 = $db->
|
54 |
-
|
55 |
-
$db->
|
56 |
$file = $rec1['filename'];
|
57 |
$fileSum = $rec1['newMD5'];
|
58 |
|
@@ -102,7 +102,7 @@ class wordfenceScanner {
|
|
102 |
break;
|
103 |
}
|
104 |
if($isPHP){
|
105 |
-
if(strpos($data, '
|
106 |
$this->addResult(array(
|
107 |
'type' => 'file',
|
108 |
'severity' => 1,
|
50 |
$this->lastStatusTime = microtime(true);
|
51 |
}
|
52 |
$db = new wfDB();
|
53 |
+
$res1 = $db->querySelect("select filename, filenameMD5, hex(newMD5) as newMD5 from " . $db->prefix() . "wfFileMods where oldMD5 != newMD5 and knownFile=0");
|
54 |
+
foreach($res1 as $rec1){
|
55 |
+
$db->queryWrite("update " . $db->prefix() . "wfFileMods set oldMD5 = newMD5 where filenameMD5='%s'", $rec1['filenameMD5']); //A way to mark as scanned so that if we come back from a sleep we don't rescan this one.
|
56 |
$file = $rec1['filename'];
|
57 |
$fileSum = $rec1['newMD5'];
|
58 |
|
102 |
break;
|
103 |
}
|
104 |
if($isPHP){
|
105 |
+
if(strpos($data, '$allowed'.'Sites') !== false && strpos($data, "define ('VER"."SION', '1.") !== false && strpos($data, "TimThum"."b script created by") !== false){
|
106 |
$this->addResult(array(
|
107 |
'type' => 'file',
|
108 |
'severity' => 1,
|
lib/wordfenceURLHoover.php
CHANGED
@@ -113,6 +113,7 @@ class wordfenceURLHoover {
|
|
113 |
if($this->useDB){
|
114 |
$sql = "insert into " . $this->table . " (owner, host, path, hostKey) values ";
|
115 |
while($elem = $this->hostsToAdd->shift()){
|
|
|
116 |
$sql .= sprintf("('%s', '%s', '%s', '%s'),",
|
117 |
mysql_real_escape_string($elem['owner']),
|
118 |
mysql_real_escape_string($elem['host']),
|
@@ -121,7 +122,7 @@ class wordfenceURLHoover {
|
|
121 |
);
|
122 |
}
|
123 |
$sql = rtrim($sql, ',');
|
124 |
-
$this->db->
|
125 |
} else {
|
126 |
while($elem = $this->hostsToAdd->shift()){
|
127 |
$this->hostKeys[] = $elem['hostKey'];
|
@@ -139,8 +140,8 @@ class wordfenceURLHoover {
|
|
139 |
$stime = microtime(true);
|
140 |
$allHostKeys = array();
|
141 |
if($this->useDB){
|
142 |
-
$q1 = $this->db->
|
143 |
-
|
144 |
array_push($allHostKeys, $hRec['hostKey']);
|
145 |
}
|
146 |
} else {
|
@@ -191,8 +192,8 @@ class wordfenceURLHoover {
|
|
191 |
//need to feed in all URL's from those id's where the hostkey matches a URL
|
192 |
foreach($badHostKeys as $badHostKey){
|
193 |
if($this->useDB){
|
194 |
-
$q1 = $this->db->
|
195 |
-
|
196 |
$url = 'http://' . $rec['host'] . $rec['path'];
|
197 |
if(! isset($urlsToCheck[$rec['owner']])){
|
198 |
$urlsToCheck[$rec['owner']] = array();
|
113 |
if($this->useDB){
|
114 |
$sql = "insert into " . $this->table . " (owner, host, path, hostKey) values ";
|
115 |
while($elem = $this->hostsToAdd->shift()){
|
116 |
+
//This may be an issue for hyperDB or other abstraction layers, but leaving it for now.
|
117 |
$sql .= sprintf("('%s', '%s', '%s', '%s'),",
|
118 |
mysql_real_escape_string($elem['owner']),
|
119 |
mysql_real_escape_string($elem['host']),
|
122 |
);
|
123 |
}
|
124 |
$sql = rtrim($sql, ',');
|
125 |
+
$this->db->queryWrite($sql);
|
126 |
} else {
|
127 |
while($elem = $this->hostsToAdd->shift()){
|
128 |
$this->hostKeys[] = $elem['hostKey'];
|
140 |
$stime = microtime(true);
|
141 |
$allHostKeys = array();
|
142 |
if($this->useDB){
|
143 |
+
$q1 = $this->db->querySelect("select distinct hostKey as hostKey from $this->table");
|
144 |
+
foreach($q1 as $hRec){
|
145 |
array_push($allHostKeys, $hRec['hostKey']);
|
146 |
}
|
147 |
} else {
|
192 |
//need to feed in all URL's from those id's where the hostkey matches a URL
|
193 |
foreach($badHostKeys as $badHostKey){
|
194 |
if($this->useDB){
|
195 |
+
$q1 = $this->db->querySelect("select owner, host, path from $this->table where hostKey='%s'", $badHostKey);
|
196 |
+
foreach($q1 as $rec){
|
197 |
$url = 'http://' . $rec['host'] . $rec['path'];
|
198 |
if(! isset($urlsToCheck[$rec['owner']])){
|
199 |
$urlsToCheck[$rec['owner']] = array();
|
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.5.1
|
6 |
-
Stable tag: 3.6.
|
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 |
|
@@ -155,6 +155,19 @@ or a theme, because often these have been updated to fix a security hole.
|
|
155 |
|
156 |
== Changelog ==
|
157 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
158 |
= 3.6.1 =
|
159 |
* Major new release that includes the much asked for IP Range blocking with ISP blocking ability and browser blocking.
|
160 |
* Added feature: WHOIS for IP's and Domains. Supports all registries and local rWhois
|
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.5.1
|
6 |
+
Stable tag: 3.6.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 |
|
155 |
|
156 |
== Changelog ==
|
157 |
|
158 |
+
=3.6.3 =
|
159 |
+
* Fixed 'max_user_connections' issue.
|
160 |
+
* Wordfence now uses WordPress's WPDB and this halves the number of DB connections Wordfence establishes to your DB.
|
161 |
+
* Wordfence is now HyperDB compatible.
|
162 |
+
* Advanced blocking i.e. Browser and IP Range blocking is now a free feature.
|
163 |
+
* We no longer disable Live Traffic if we detect a caching plugin. Based on user feedback, apparently live traffic actually works with those plugins.
|
164 |
+
* Fixed issue that causes site to crash if a conflicting GeoIP library is installed.
|
165 |
+
* Changed logHuman routine to do a LOW_PRIORITY MySQL update to speed things up.
|
166 |
+
* Login failure counter is now reset if you send yourself an unlock email so you're not locked out again after 1 failure.
|
167 |
+
* The free version of Wordfence is now supported with ads at the top of the admin pages. Please visit our sponsors and help keep Wordfence free!
|
168 |
+
* Fixed issue that may cause scans to not be scheduled using the default schedule for new users.
|
169 |
+
* There was no 3.6.2 release, in case you're wondering about the version skip.
|
170 |
+
|
171 |
= 3.6.1 =
|
172 |
* Major new release that includes the much asked for IP Range blocking with ISP blocking ability and browser blocking.
|
173 |
* Added feature: WHOIS for IP's and Domains. Supports all registries and local rWhois
|
wordfence.php
CHANGED
@@ -4,10 +4,10 @@ Plugin Name: Wordfence Security
|
|
4 |
Plugin URI: http://www.wordfence.com/
|
5 |
Description: Wordfence Security - Anti-virus and Firewall security plugin for WordPress
|
6 |
Author: Mark Maunder
|
7 |
-
Version: 3.6.
|
8 |
Author URI: http://www.wordfence.com/
|
9 |
*/
|
10 |
-
define('WORDFENCE_VERSION', '3.6.
|
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://www.wordfence.com/
|
5 |
Description: Wordfence Security - Anti-virus and Firewall security plugin for WordPress
|
6 |
Author: Mark Maunder
|
7 |
+
Version: 3.6.3
|
8 |
Author URI: http://www.wordfence.com/
|
9 |
*/
|
10 |
+
define('WORDFENCE_VERSION', '3.6.3');
|
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 |
}
|