Wordfence Security – Firewall & Malware Scan - Version 3.6.3

Version Description

Download this release

Release Info

Developer mmaunder
Plugin Icon 128x128 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 CHANGED
@@ -40,7 +40,24 @@ div.wordfenceLive p {
40
  margin: 7px 5px 0 0;
41
  float: left;
42
  }
43
- .wordfence-lock-icon {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
- <div class="wordfence-lock-icon wordfence-icon32"><br /></div><h2 id="wfHeading">Live Site Activity</h2>
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
- <div class="wordfence-lock-icon wordfence-icon32"><br /></div><h2 id="wfHeading">Wordfence Blocked IP Addresses</h2>
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
- <div class="wordfence-lock-icon wordfence-icon32"><br /></div><h2 id="wfHeading">Wordfence Options</h2>
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
- <div class="wordfence-lock-icon wordfence-icon32"><br /></div><h2 id="wfHeading">Advanced Pattern Blocking</h2>
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
- <div class="wordfence-lock-icon wordfence-icon32"><br /></div><h2 id="wfHeading">Wordfence Scan</h2>
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
- <div class="wordfence-lock-icon wordfence-icon32"><br /></div><h2 id="wfHeading">WHOIS Facility: Look up the owner of an IP Address or Domain Name</h2>
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. &nbsp;&nbsp;&nbsp;<a href="http://www.bluehost.com/track/wordfence/wfplghead" target="_blank">&raquo;Visit Bluehost now&raquo;</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->query("select ctime, level, type, msg from $table order by ctime desc");
17
  $timeOffset = 3600 * get_option('gmt_offset');
18
- while($r = mysql_fetch_assoc($q)){
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'] . ']&nbsp;' . 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'] . ']&nbsp;' . htmlspecialchars($r['msg']) . "</div>\n";
21
  }
lib/wfConfig.php CHANGED
@@ -385,7 +385,7 @@ class wfConfig {
385
  return;
386
  }
387
 
388
- self::getDB()->query("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,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
- if(mysql_num_rows($res) > 0){
437
- $row = mysql_fetch_row($res);
438
- return unserialize($row[0]);
 
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 ultra-memory efficient. We don't make any copies of $val and don't use ON DUPLICATE KEY UPDATE
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
- $res = mysql_query("update " . self::table() . " set val='" . mysql_real_escape_string($serialized) . "' where name='" . mysql_real_escape_string($key) . "'", $dbh);
485
  } else {
486
- $res = mysql_query("insert IGNORE into " . self::table() . " (name, val) values ('" . mysql_real_escape_string($key) . "', '" . mysql_real_escape_string($serialized) . "')", $dbh);
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()->query("select name, val from " . self::table());
543
- while($row = mysql_fetch_assoc($q)){
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->query("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,14 +37,14 @@ class wfCrawl {
37
  }
38
  }
39
  if($addrsMatch){
40
- $db->query("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->query("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->query("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
  }
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($createNewHandle = false, $dbhost = false, $dbuser = false, $dbpassword = false, $dbname = false){
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
- private function connectHandle(){
45
- //We tried reusing wpdb but got disconnection errors from many users.
46
- $handleKey = md5($this->dbhost . $this->dbuser . $this->dbpassword . $this->dbname);
47
- //Use a cached handle if it exists and is still connected
48
- if( (! $this->createNewHandle) && isset(self::$dbhCache[$handleKey]) && mysql_ping(self::$dbhCache[$handleKey]) ){
49
- $this->dbh = self::$dbhCache[$handleKey];
50
  } else {
51
- //This close call is to deal with versions of mysql prior to 5.0.3 which auto-recommend when callig ping. So the conditional above may have reconnected this handle, so we disconnect it before reconnecting, if it's connected.
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 reconnect(){
71
- if((! $this->dbh) || (! mysql_ping($this->dbh)) ){
72
- $this->connectHandle();
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
- $this->handleError("No arguments passed to querySingle()");
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 querySingle(){
112
- $this->reconnect();
113
- $this->errorMsg = false;
114
- $args = func_get_args();
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
- $this->handleError("No arguments passed to querySingle()");
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 query(){ //sprintfString, arguments
135
- $this->reconnect();
136
- $this->errorMsg = false;
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 queryIgnoreError(){ //sprintfString, arguments
159
- $this->reconnect();
160
- $this->errorMsg = false;
161
- $args = func_get_args();
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
- $this->handleError("No arguments passed to query()");
171
  }
172
- return $res;
173
  }
174
-
175
- private static function criticalError($msg){
176
- $msg = "Wordfence critical database error: $msg";
177
- error_log($msg);
178
- return;
179
  }
180
  public function columnExists($table, $col){
181
  global $wpdb; $prefix = $wpdb->base_prefix;
182
  $table = $prefix . $table;
183
- $q = $this->query("desc $table");
184
- while($row = mysql_fetch_assoc($q)){
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->query("alter table $table drop column $col");
195
  }
196
  public function createKeyIfNotExists($table, $col, $keyName){
197
- global $wpdb; $prefix = $wpdb->base_prefix;
198
- $table = $prefix . $table;
199
  $exists = $this->querySingle("show tables like '$table'");
200
  $keyFound = false;
201
  if($exists){
202
- $q = $this->query("show keys from $table");
203
- if($q){
204
- while($row = mysql_fetch_assoc($q)){
205
- if($row['Key_name'] == $keyName){
206
- $keyFound = true;
207
- }
208
  }
209
  }
210
  }
211
  if(! $keyFound){
212
- $this->query("alter table $table add KEY $keyName($col)");
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->query("truncate table $table");
229
- $this->query("delete from $table");
 
 
 
 
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 GeoIP {
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 GeoIP;
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()->query("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,13 +66,13 @@ class wfIssues {
66
  return true;
67
  }
68
  public function deleteIgnored(){
69
- $this->getDB()->query("delete from " . $this->issuesTable . " where status='ignoreP' or status='ignoreC'");
70
  }
71
  public function deleteNew(){
72
- $this->getDB()->query("delete from " . $this->issuesTable . " where status='new'");
73
  }
74
  public function ignoreAllNew(){
75
- $this->getDB()->query("update " . $this->issuesTable . " set status='ignoreC' where status='new'");
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()->query("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()->query("delete from " . $this->issuesTable . " where id=%d", $id);
133
  } else if($status == 'ignoreC' || $status == 'ignoreP' || $status == 'new'){
134
- $this->getDB()->query("update " . $this->issuesTable . " set status='%s' where id=%d", $status, $id);
135
  }
136
  }
137
  public function getIssueByID($id){
@@ -145,8 +145,8 @@ class wfIssues {
145
  'new' => array(),
146
  'ignored' => array()
147
  );
148
- $q1 = $this->getDB()->query("select * from " . $this->issuesTable . " order by time desc");
149
- while($i = mysql_fetch_assoc($q1)){
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()->query("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,13 +66,13 @@ class wfLog {
66
  wordfence::status(1, 'error', "Invalid type to logLeechAndBlock(): $type");
67
  return;
68
  }
69
- $this->getDB()->query("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()->query("select id, blockType, blockString from " . $this->ipRangesTable);
75
- while($blockRec = mysql_fetch_assoc($r1)){
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()->query("update " . $this->ipRangesTable . " set totalBlocked = totalBlocked + 1, lastBlocked = unix_timestamp() where id=%d", $blockRec['id']);
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()->query("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()->query("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()->query("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,25 +200,24 @@ class wfLog {
200
  return false;
201
  }
202
  public function unblockAllIPs(){
203
- $this->getDB()->query("delete from " . $this->blocksTable);
204
  }
205
  public function unlockAllIPs(){
206
- $this->getDB()->query("delete from " . $this->lockOutTable);
207
  }
208
  public function unblockIP($IP){
209
- $this->getDB()->query("delete from " . $this->blocksTable . " where IP=%s", wfUtils::inet_aton($IP));
210
  }
211
  public function unblockRange($id){
212
- $this->getDB()->query("delete from " . $this->ipRangesTable . " where id=%d", $id);
213
  }
214
  public function blockRange($blockType, $range, $reason){
215
- $this->getDB()->query("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
- $res = $this->getDB()->query("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
- $results = array();
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()->query("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",
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()->query("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",
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()->query("insert into " . $this->lockOutTable . " (IP, blockedTime, reason) values(%s, unix_timestamp(), '%s') ON DUPLICATE KEY update blockedTime=unix_timestamp(), reason='%s'",
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()->query("delete from " . $this->lockOutTable . " where IP=%s", wfUtils::inet_aton($IP));
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()->query("update " . $this->lockOutTable . " set blockedHits = blockedHits + 1, lastAttempt = unix_timestamp() where IP=%s", wfUtils::inet_aton($IP));
288
  return true;
289
  } else {
290
  return false;
291
  }
292
  }
293
  public function getThrottledIPs(){
294
- $res = $this->getDB()->query("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");
295
- $results = array();
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
- $res = $this->getDB()->query("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'));
309
- $results = array();
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
- $res = $this->getDB()->query("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'));
323
- $results = array();
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
- $res = $this->getDB()->query("select IP, sum(hits) as totalHits from $table where eMin > ((unix_timestamp() - 86400) / 60) group by IP order by totalHits desc limit 20");
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()->query("insert into " . $this->hitsTable . " (ctime, is404, isGoogle, IP, userID, newVisit, URL, referer, UA) values (%f, %d, %d, %s, %s, %d, '%s', '%s', '%s')",
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('" . mysql_real_escape_string($IP) . "') ";
 
 
 
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
- $r1 = $this->getDB()->query("select * from " . $this->hitsTable . " where ctime > %f $IPSQL $typeSQL order by ctime desc limit %s",
425
- $afterTime,
426
- $limit
427
- );
428
 
429
  } else if($hitType == 'logins'){
430
- $r1 = $this->getDB()->query("select * from " . $this->loginsTable . " where ctime > %f $IPSQL order by ctime desc limit %s",
431
- $afterTime,
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()->query("update " . $this->blocksTable . " set lastAttempt=unix_timestamp(), blockedHits = blockedHits + 1 where IP=%s", $IP);
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()->query("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);
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()->query("insert into " . $this->statusTable . " (ctime, level, type, msg) values (%s, %d, '%s', '%s')", sprintf('%.6f', microtime(true)), $level, $type, $msg);
733
  }
734
  public function getStatusEvents($lastCtime){
735
  if($lastCtime < 1){
@@ -738,25 +720,21 @@ class wfLog {
738
  $lastCtime = 0;
739
  }
740
  }
741
- $res = $this->getDB()->query("select ctime, level, type, msg from " . $this->statusTable . " where ctime > %f order by ctime asc", $lastCtime);
742
- $results = array();
743
  $lastTime = false;
744
  $timeOffset = 3600 * get_option('gmt_offset');
745
- while($rec = mysql_fetch_assoc($res)){
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
- $res = $this->getDB()->query("select ctime, level, type, msg from " . $this->statusTable . " where level = 10 order by ctime desc limit 100");
754
- $results = array();
755
  $lastTime = false;
756
  $timeOffset = 3600 * get_option('gmt_offset');
757
- while($rec = mysql_fetch_assoc($res)){
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->query("select ID from " . $blog['table'] . " where post_type IN ('page', 'post') and post_status = 'publish'");
271
- while($idRow = mysql_fetch_assoc($q1)){
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->query("select comment_ID from " . $blog['table'] . " where comment_approved=1");
379
- if( ! $q1){
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->query("select blog_id, domain, path from $prefix"."blogs where deleted=0 order by blog_id asc");
510
- while($row = mysql_fetch_assoc($q1)){
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->query("select ID from " . $wpdb->users);
551
  $counter = 0;
552
- while($rec = mysql_fetch_row($res1)){
553
- $this->userPasswdQueue .= pack('N', $rec[0]);
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
- global $wpdb;
171
- $this->db = new wfDB();
172
- $this->prefix = $wpdb->base_prefix;
173
- }
174
  }
175
  public function dropAll(){
176
  foreach($this->tables as $table => $def){
177
- $this->db->query("drop table if exists " . $this->prefix . $table);
178
  }
179
  }
180
  public function createAll(){
181
  foreach($this->tables as $table => $def){
182
- $this->db->query("create table IF NOT EXISTS " . $this->prefix . $table . " " . $def);
183
  }
184
  }
185
  public function create($table){
186
- $this->db->query("create table IF NOT EXISTS " . $this->prefix . $table . " " . $this->tables[$table]);
187
  }
188
  public function drop($table){
189
- $this->db->query("drop table if exists " . $this->prefix . $table);
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
- $r1 = $db->query("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($r1){
335
- if($row = mysql_fetch_assoc($r1)){
336
- if($row['age'] > WORDFENCE_MAX_IPLOC_AGE){
337
- $db->query("delete from " . $locsTable . " where IP=%s", $row['IP']);
 
 
338
  } else {
339
- if($row['failed'] == 1){
340
- $IPLocs[$IP] = false;
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->query("insert IGNORE into " . $locsTable . " (IP, ctime, failed) values (%s, unix_timestamp(), 1)", ($isInt ? $IP : self::inet_aton($IP)) );
364
  $IPLocs[$IP] = false;
365
  } else {
366
- $db->query("insert IGNORE into " . $locsTable . " (IP, ctime, failed, city, region, countryName, countryCode, lat, lon) values (%s, unix_timestamp(), 0, '%s', '%s', '%s', '%s', %s, %s)",
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->query("insert into " . $reverseTable . " (IP, host, lastUpdate) values (%s, '%s', unix_timestamp()) ON DUPLICATE KEY UPDATE host='%s', lastUpdate=unix_timestamp()", $IPn, $host, $host);
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->query("select URI from $p"."wfNet404s where ctime > unix_timestamp() - 3600 limit 1000");
61
  $URIs = array();
62
- while($rec = mysql_fetch_assoc($q1)){
63
  array_push($URIs, $rec['URI']);
64
  }
65
  $wfdb->truncate($p . "wfNet404s");
@@ -71,16 +71,16 @@ class wordfence {
71
  }
72
  }
73
 
74
- $q2 = $wfdb->query("select INET_NTOA(IP) as IP from $p"."wfVulnScanners where ctime > unix_timestamp() - 3600");
75
  $scanCont = "";
76
- while($rec = mysql_fetch_assoc($q2)){
77
  $scanCont .= pack('N', ip2long($rec['IP']));
78
  }
79
  $wfdb->truncate($p . "wfVulnScanners");
80
 
81
- $q3 = $wfdb->query("select INET_NTOA(IP) as IP from $p"."wfLockedOut where blockedTime > unix_timestamp() - 3600");
82
  $lockCont = "";
83
- while($rec = mysql_fetch_assoc($q3)){
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->query("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,42 +122,42 @@ class wordfence {
122
  wordfence::status(4, 'error', "Could not fetch vulnerability patterns in scheduled job: " . $e->getMessage());
123
  }
124
 
125
- $wfdb->query("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->query("delete from $p"."wfBlocks where (blockedTime + %s < unix_timestamp()) and permanent=0", wfConfig::get('blockedTime'));
128
- $wfdb->query("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->query("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->query("delete from $p"."$table where eMin < ((unix_timestamp() - (86400 * 2)) / 60)");
138
  }
139
- $wfdb->query("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->query("delete from $p"."wfLogins order by ctime asc limit %d", ($count2 - $maxRows));
145
  }
146
- $wfdb->query("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->query("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->query("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->query("delete from $p"."wfStatus where level = 10 order by ctime asc limit %d", ($count5 - 100) );
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->query("delete from $prefix"."wfHits order by id asc limit " . ($count - 20000));
205
  }
206
  $db->dropColumn('wfHits', 'HTTPHeaders');
207
  }
@@ -215,19 +216,19 @@ class wordfence {
215
 
216
  global $wpdb;
217
  $prefix = $wpdb->base_prefix;
218
- $db->queryIgnoreError("alter table $prefix"."wfConfig modify column val longblob");
219
- $db->queryIgnoreError("alter table $prefix"."wfBlocks add column permanent tinyint UNSIGNED default 0");
220
- $db->queryIgnoreError("alter table $prefix"."wfStatus modify column msg varchar(1000) NOT NULL");
221
  //3.1.2 to 3.1.4
222
- $db->queryIgnoreError("alter table $prefix"."wfBlocks modify column blockedTime bigint signed NOT NULL");
223
  //3.2.1 to 3.2.2
224
- $db->queryIgnoreError("alter table $prefix"."wfLockedOut modify column blockedTime bigint signed NOT NULL");
225
- $db->queryIgnoreError("drop table if exists $prefix"."wfFileQueue");
226
- $db->queryIgnoreError("drop table if exists $prefix"."wfFileChanges");
227
 
228
  $optScanEnabled = $db->querySingle("select val from $prefix"."wfConfig where name='scansEnabled_options'");
229
  if($optScanEnabled != '0' && $optScanEnabled != '1'){
230
- $db->query("update $prefix"."wfConfig set val='1' where name='scansEnabled_options'");
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->query("update $p"."wfHits set jsRun=1 where id=%d", $hid);
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->query("select ctime, level, type, msg from $p"."wfStatus order by ctime desc limit 10000");
709
  $timeOffset = 3600 * get_option('gmt_offset');
710
- while($r = mysql_fetch_assoc($q)){
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->query("delete from $p"."wfBlocks where wfsn=1 and permanent=0");
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->query("update " . $this->db->prefix() . "wfFileMods set oldMD5 = newMD5");
53
- $this->db->query("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,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->query("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)){
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->query("select filename, filenameMD5, hex(newMD5) as newMD5 from " . $db->prefix() . "wfFileMods where oldMD5 != newMD5 and knownFile=0");
54
- while($rec1 = mysql_fetch_assoc($res1)){
55
- $db->query("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,7 +102,7 @@ class wordfenceScanner {
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,
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->query($sql);
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->query("select distinct hostKey as hostKey from $this->table");
143
- while($hRec = mysql_fetch_assoc($q1)){
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->query("select owner, host, path from $this->table where hostKey='%s'", $badHostKey);
195
- while($rec = mysql_fetch_assoc($q1)){
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.1
7
 
8
  Wordfence Security is a free enterprise class security plugin that includes a firewall, virus scanning, real-time traffic with geolocation and more.
9
 
@@ -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.1
8
  Author URI: http://www.wordfence.com/
9
  */
10
- define('WORDFENCE_VERSION', '3.6.1');
11
  if(get_option('wordfenceActivated') != 1){
12
  add_action('activated_plugin','wordfence_save_activation_error'); function wordfence_save_activation_error(){ update_option('wf_plugin_act_error', ob_get_contents()); }
13
  }
4
  Plugin URI: http://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
  }