Version Description
- Removed wfscan.php script and now using pseudo-ajax calls to fire off scans. Much more reliable.
- Removed visitor.php script and now using pseudo-ajax calls to log human visits.
- Added config option to allow admin to specify max execution time (advanced only!!).
- Fixed issue that caused API calls to fail on MultiSite installs.
- Fixed issue that caused comments to break on MultiSite installs under certain conditions.
- Fixed issue that caused incorrect domain to be shown in live traffic view on multi-site installs.
- Fixed issue where some proxies/firewalls send space delimited IP addresses in HTTP headers and Wordfence now handles that.
- Fixed issue that caused Wordfence to capture activation errors of other plugins.
- Geo IP database update to November 7th edition.
Download this release
Release Info
Developer | mmaunder |
Plugin | Wordfence Security – Firewall & Malware Scan |
Version | 3.4.1 |
Comparing to | |
See all releases |
Code changes from version 3.3.7 to 3.4.1
- js/admin.js +1 -1
- lib/GeoIP.dat +0 -0
- lib/menu_options.php +1 -0
- lib/wfAPI.php +6 -1
- lib/wfConfig.php +5 -5
- wfscan.php → lib/wfScan.php +1 -25
- lib/wfScanEngine.php +16 -85
- lib/wfUtils.php +15 -1
- lib/wordfenceClass.php +37 -7
- lib/wordfenceConstants.php +1 -1
- readme.txt +12 -1
- visitor.php +0 -33
- wordfence.php +5 -3
js/admin.js
CHANGED
@@ -932,7 +932,7 @@ window['wordfenceAdmin'] = {
|
|
932 |
}
|
933 |
}
|
934 |
for(var k in WFSLevels[level].otherParams){
|
935 |
-
if(! /^(?:apiKey|securityLevel|alertEmails|liveTraf_ignoreUsers|liveTraf_ignoreIPs|liveTraf_ignoreUA|liveTraf_hitsMaxSize|maxMem)$/.test(k)){
|
936 |
jQuery('#' + k).val(WFSLevels[level].otherParams[k]);
|
937 |
}
|
938 |
}
|
932 |
}
|
933 |
}
|
934 |
for(var k in WFSLevels[level].otherParams){
|
935 |
+
if(! /^(?:apiKey|securityLevel|alertEmails|liveTraf_ignoreUsers|liveTraf_ignoreIPs|liveTraf_ignoreUA|liveTraf_hitsMaxSize|maxMem|maxExecutionTime)$/.test(k)){
|
936 |
jQuery('#' + k).val(WFSLevels[level].otherParams[k]);
|
937 |
}
|
938 |
}
|
lib/GeoIP.dat
CHANGED
Binary file
|
lib/menu_options.php
CHANGED
@@ -220,6 +220,7 @@ var WFSLevels = <?php echo json_encode(wfConfig::$securityLevels); ?>;
|
|
220 |
<tr><th>Check password strength on profile update</th><td><input type="checkbox" id="other_pwStrengthOnUpdate" class="wfConfigElem" name="other_pwStrengthOnUpdate" value="1" <?php $w->cb('other_pwStrengthOnUpdate'); ?> /></td></tr>
|
221 |
<tr><th>Participate in the Wordfence Security Network</th><td><input type="checkbox" id="other_WFNet" class="wfConfigElem" name="other_WFNet" value="1" <?php $w->cb('other_WFNet'); ?> /></td></tr>
|
222 |
<tr><th>Maximum memory Wordfence can use</th><td><input type="text" id="maxMem" name="maxMem" value="<?php $w->f('maxMem'); ?>" size="4" />Megabytes</td></tr>
|
|
|
223 |
<tr><th>Enable debugging mode (increases database load)</th><td><input type="checkbox" id="debugOn" class="wfConfigElem" name="debugOn" value="1" <?php $w->cb('debugOn'); ?> /></td></tr>
|
224 |
<tr><th>Delete Wordfence tables and data on deactivation?</th><td><input type="checkbox" id="deleteTablesOnDeact" class="wfConfigElem" name="deleteTablesOnDeact" value="1" <?php $w->cb('deleteTablesOnDeact'); ?> /></td></tr>
|
225 |
<tr><th colspan="2"><a href="<?php echo wfUtils::siteURLRelative(); ?>?_wfsf=sysinfo&nonce=<?php echo wp_create_nonce('wp-ajax'); ?>" target="_blank">Click to view your system's configuration in a new window</a></th></tr>
|
220 |
<tr><th>Check password strength on profile update</th><td><input type="checkbox" id="other_pwStrengthOnUpdate" class="wfConfigElem" name="other_pwStrengthOnUpdate" value="1" <?php $w->cb('other_pwStrengthOnUpdate'); ?> /></td></tr>
|
221 |
<tr><th>Participate in the Wordfence Security Network</th><td><input type="checkbox" id="other_WFNet" class="wfConfigElem" name="other_WFNet" value="1" <?php $w->cb('other_WFNet'); ?> /></td></tr>
|
222 |
<tr><th>Maximum memory Wordfence can use</th><td><input type="text" id="maxMem" name="maxMem" value="<?php $w->f('maxMem'); ?>" size="4" />Megabytes</td></tr>
|
223 |
+
<tr><th>Maximum execution time for each scan stage</th><td><input type="text" id="maxExecutionTime" name="maxExecutionTime" value="<?php $w->f('maxExecutionTime'); ?>" size="4" />Blank for default. Must be greater than 10.</td></tr>
|
224 |
<tr><th>Enable debugging mode (increases database load)</th><td><input type="checkbox" id="debugOn" class="wfConfigElem" name="debugOn" value="1" <?php $w->cb('debugOn'); ?> /></td></tr>
|
225 |
<tr><th>Delete Wordfence tables and data on deactivation?</th><td><input type="checkbox" id="deleteTablesOnDeact" class="wfConfigElem" name="deleteTablesOnDeact" value="1" <?php $w->cb('deleteTablesOnDeact'); ?> /></td></tr>
|
226 |
<tr><th colspan="2"><a href="<?php echo wfUtils::siteURLRelative(); ?>?_wfsf=sysinfo&nonce=<?php echo wp_create_nonce('wp-ajax'); ?>" target="_blank">Click to view your system's configuration in a new window</a></th></tr>
|
lib/wfAPI.php
CHANGED
@@ -155,7 +155,12 @@ class wfAPI {
|
|
155 |
public function makeAPIQueryString(){
|
156 |
$siteurl = '';
|
157 |
if(function_exists('get_bloginfo')){
|
158 |
-
|
|
|
|
|
|
|
|
|
|
|
159 |
}
|
160 |
return self::buildQuery(array(
|
161 |
'v' => $this->wordpressVersion,
|
155 |
public function makeAPIQueryString(){
|
156 |
$siteurl = '';
|
157 |
if(function_exists('get_bloginfo')){
|
158 |
+
if(is_multisite()){
|
159 |
+
$siteurl = network_home_url();
|
160 |
+
$siteurl = rtrim($siteurl, '/'); //Because previously we used get_bloginfo and it returns http://example.com without a '/' char.
|
161 |
+
} else {
|
162 |
+
$siteurl = get_bloginfo('siteurl');
|
163 |
+
}
|
164 |
}
|
165 |
return self::buildQuery(array(
|
166 |
'v' => $this->wordpressVersion,
|
lib/wfConfig.php
CHANGED
@@ -48,7 +48,7 @@ class wfConfig {
|
|
48 |
),
|
49 |
"otherParams" => array(
|
50 |
'securityLevel' => '0',
|
51 |
-
"alertEmails" => "", "liveTraf_ignoreUsers" => "", "liveTraf_ignoreIPs" => "", "liveTraf_ignoreUA" => "", "apiKey" => "", "maxMem" => '256', 'whitelisted' => '',
|
52 |
"neverBlockBG" => "neverBlockVerified",
|
53 |
"loginSec_countFailMins" => "5",
|
54 |
"loginSec_lockoutMins" => "5",
|
@@ -111,7 +111,7 @@ class wfConfig {
|
|
111 |
),
|
112 |
"otherParams" => array(
|
113 |
'securityLevel' => '1',
|
114 |
-
"alertEmails" => "", "liveTraf_ignoreUsers" => "", "liveTraf_ignoreIPs" => "", "liveTraf_ignoreUA" => "", "apiKey" => "", "maxMem" => '256', 'whitelisted' => '',
|
115 |
"neverBlockBG" => "neverBlockVerified",
|
116 |
"loginSec_countFailMins" => "5",
|
117 |
"loginSec_lockoutMins" => "5",
|
@@ -174,7 +174,7 @@ class wfConfig {
|
|
174 |
),
|
175 |
"otherParams" => array(
|
176 |
'securityLevel' => '2',
|
177 |
-
"alertEmails" => "", "liveTraf_ignoreUsers" => "", "liveTraf_ignoreIPs" => "", "liveTraf_ignoreUA" => "", "apiKey" => "", "maxMem" => '256', 'whitelisted' => '',
|
178 |
"neverBlockBG" => "neverBlockVerified",
|
179 |
"loginSec_countFailMins" => "240",
|
180 |
"loginSec_lockoutMins" => "240",
|
@@ -237,7 +237,7 @@ class wfConfig {
|
|
237 |
),
|
238 |
"otherParams" => array(
|
239 |
'securityLevel' => '3',
|
240 |
-
"alertEmails" => "", "liveTraf_ignoreUsers" => "", "liveTraf_ignoreIPs" => "", "liveTraf_ignoreUA" => "", "apiKey" => "", "maxMem" => '256', 'whitelisted' => '',
|
241 |
"neverBlockBG" => "neverBlockVerified",
|
242 |
"loginSec_countFailMins" => "1440",
|
243 |
"loginSec_lockoutMins" => "1440",
|
@@ -300,7 +300,7 @@ class wfConfig {
|
|
300 |
),
|
301 |
"otherParams" => array(
|
302 |
'securityLevel' => '4',
|
303 |
-
"alertEmails" => "", "liveTraf_ignoreUsers" => "", "liveTraf_ignoreIPs" => "", "liveTraf_ignoreUA" => "", "apiKey" => "", "maxMem" => '256', 'whitelisted' => '',
|
304 |
"neverBlockBG" => "neverBlockVerified",
|
305 |
"loginSec_countFailMins" => "1440",
|
306 |
"loginSec_lockoutMins" => "1440",
|
48 |
),
|
49 |
"otherParams" => array(
|
50 |
'securityLevel' => '0',
|
51 |
+
"alertEmails" => "", "liveTraf_ignoreUsers" => "", "liveTraf_ignoreIPs" => "", "liveTraf_ignoreUA" => "", "apiKey" => "", "maxMem" => '256', 'whitelisted' => '', 'maxExecutionTime' => '',
|
52 |
"neverBlockBG" => "neverBlockVerified",
|
53 |
"loginSec_countFailMins" => "5",
|
54 |
"loginSec_lockoutMins" => "5",
|
111 |
),
|
112 |
"otherParams" => array(
|
113 |
'securityLevel' => '1',
|
114 |
+
"alertEmails" => "", "liveTraf_ignoreUsers" => "", "liveTraf_ignoreIPs" => "", "liveTraf_ignoreUA" => "", "apiKey" => "", "maxMem" => '256', 'whitelisted' => '', 'maxExecutionTime' => '',
|
115 |
"neverBlockBG" => "neverBlockVerified",
|
116 |
"loginSec_countFailMins" => "5",
|
117 |
"loginSec_lockoutMins" => "5",
|
174 |
),
|
175 |
"otherParams" => array(
|
176 |
'securityLevel' => '2',
|
177 |
+
"alertEmails" => "", "liveTraf_ignoreUsers" => "", "liveTraf_ignoreIPs" => "", "liveTraf_ignoreUA" => "", "apiKey" => "", "maxMem" => '256', 'whitelisted' => '', 'maxExecutionTime' => '',
|
178 |
"neverBlockBG" => "neverBlockVerified",
|
179 |
"loginSec_countFailMins" => "240",
|
180 |
"loginSec_lockoutMins" => "240",
|
237 |
),
|
238 |
"otherParams" => array(
|
239 |
'securityLevel' => '3',
|
240 |
+
"alertEmails" => "", "liveTraf_ignoreUsers" => "", "liveTraf_ignoreIPs" => "", "liveTraf_ignoreUA" => "", "apiKey" => "", "maxMem" => '256', 'whitelisted' => '', 'maxExecutionTime' => '',
|
241 |
"neverBlockBG" => "neverBlockVerified",
|
242 |
"loginSec_countFailMins" => "1440",
|
243 |
"loginSec_lockoutMins" => "1440",
|
300 |
),
|
301 |
"otherParams" => array(
|
302 |
'securityLevel' => '4',
|
303 |
+
"alertEmails" => "", "liveTraf_ignoreUsers" => "", "liveTraf_ignoreIPs" => "", "liveTraf_ignoreUA" => "", "apiKey" => "", "maxMem" => '256', 'whitelisted' => '', 'maxExecutionTime' => '',
|
304 |
"neverBlockBG" => "neverBlockVerified",
|
305 |
"loginSec_countFailMins" => "1440",
|
306 |
"loginSec_lockoutMins" => "1440",
|
wfscan.php → lib/wfScan.php
RENAMED
@@ -1,26 +1,4 @@
|
|
1 |
<?php
|
2 |
-
/* Don't remove this line. WFSOURCEVISIBLE */
|
3 |
-
define('WORDFENCE_VERSIONONLY_MODE', true); //So that we can include wordfence.php and get the version constant
|
4 |
-
ignore_user_abort(true);
|
5 |
-
$wordfence_wp_version = false;
|
6 |
-
if ( !defined('ABSPATH') ) {
|
7 |
-
/** Set up WordPress environment */
|
8 |
-
if($_SERVER['SCRIPT_FILENAME']){
|
9 |
-
$wfBaseDir = preg_replace('/[^\/]+\/[^\/]+\/[^\/]+\/wfscan\.php$/', '', $_SERVER['SCRIPT_FILENAME']);
|
10 |
-
require_once($wfBaseDir . 'wp-load.php');
|
11 |
-
global $wp_version;
|
12 |
-
global $wordfence_wp_version;
|
13 |
-
require($wfBaseDir . 'wp-includes/version.php');
|
14 |
-
$wordfence_wp_version = $wp_version;
|
15 |
-
} else {
|
16 |
-
require_once('../../../wp-load.php');
|
17 |
-
require_once('../../../wp-includes/version.php');
|
18 |
-
}
|
19 |
-
}
|
20 |
-
require_once('wordfence.php');
|
21 |
-
require_once('lib/wordfenceConstants.php');
|
22 |
-
require_once('lib/wfScanEngine.php');
|
23 |
-
|
24 |
class wfScan {
|
25 |
public static $debugMode = false;
|
26 |
public static $errorHandlingOn = true;
|
@@ -43,7 +21,7 @@ class wfScan {
|
|
43 |
self::status(4, 'info', "Scan engine received request.");
|
44 |
self::status(4, 'info', "Checking cronkey");
|
45 |
if(! $_GET['cronKey']){
|
46 |
-
self::status(4, 'error', "Wordfence
|
47 |
echo "If you see this message it means Wordfence is working correctly. You should not access this URL directly. It is part of the Wordfence security plugin and is designed for internal use only.";
|
48 |
exit();
|
49 |
}
|
@@ -65,7 +43,6 @@ class wfScan {
|
|
65 |
}
|
66 |
/* --------- end cronkey check ---------- */
|
67 |
|
68 |
-
wfUtils::iniSet('max_execution_time', 1800); //30 mins
|
69 |
self::status(4, 'info', "Becoming admin for scan");
|
70 |
self::becomeAdmin();
|
71 |
self::status(4, 'info', "Done become admin");
|
@@ -217,5 +194,4 @@ class wfScan {
|
|
217 |
wordfence::status($level, $type, $msg);
|
218 |
}
|
219 |
}
|
220 |
-
wfScan::wfScanMain();
|
221 |
?>
|
1 |
<?php
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
class wfScan {
|
3 |
public static $debugMode = false;
|
4 |
public static $errorHandlingOn = true;
|
21 |
self::status(4, 'info', "Scan engine received request.");
|
22 |
self::status(4, 'info', "Checking cronkey");
|
23 |
if(! $_GET['cronKey']){
|
24 |
+
self::status(4, 'error', "Wordfence scan script accessed directly, or WF did not receive a cronkey.");
|
25 |
echo "If you see this message it means Wordfence is working correctly. You should not access this URL directly. It is part of the Wordfence security plugin and is designed for internal use only.";
|
26 |
exit();
|
27 |
}
|
43 |
}
|
44 |
/* --------- end cronkey check ---------- */
|
45 |
|
|
|
46 |
self::status(4, 'info', "Becoming admin for scan");
|
47 |
self::becomeAdmin();
|
48 |
self::status(4, 'info', "Done become admin");
|
194 |
wordfence::status($level, $type, $msg);
|
195 |
}
|
196 |
}
|
|
|
197 |
?>
|
lib/wfScanEngine.php
CHANGED
@@ -21,7 +21,7 @@ class wfScanEngine {
|
|
21 |
private $apiKey = false;
|
22 |
private $startTime = 0;
|
23 |
private $scanStep = 0;
|
24 |
-
public $maxExecTime =
|
25 |
private $publicScanEnabled = false;
|
26 |
private $fileContentsResults = false;
|
27 |
private $scanner = false;
|
@@ -41,6 +41,7 @@ class wfScanEngine {
|
|
41 |
}
|
42 |
public function __construct(){
|
43 |
$this->startTime = time();
|
|
|
44 |
$this->i = new wfIssues();
|
45 |
$this->i->deleteNew();
|
46 |
$this->cycleStartTime = time();
|
@@ -851,72 +852,6 @@ class wfScanEngine {
|
|
851 |
throw new Exception("Scan was killed on administrator request.");
|
852 |
}
|
853 |
}
|
854 |
-
private static function getOwnHostname(){
|
855 |
-
if(preg_match('/https?:\/\/([^\/]+)/i', site_url(), $matches)){
|
856 |
-
$host = $matches[1];
|
857 |
-
} else {
|
858 |
-
wordfence::status(2, 'error', "Warning: Could not extract hostname from site URL: " . site_url());
|
859 |
-
$host = site_url();
|
860 |
-
}
|
861 |
-
return $host;
|
862 |
-
}
|
863 |
-
private static function tryCronURL(){
|
864 |
-
if(! wfConfig::get('cronTestID')){
|
865 |
-
wfConfig::set('cronTestID', wfUtils::bigRandomHex());
|
866 |
-
}
|
867 |
-
$URL = wfConfig::get('cronURL');
|
868 |
-
$sendHeader = wfConfig::get('cronSendHeader');
|
869 |
-
$opts = array(
|
870 |
-
'timeout' => 30, //Long timeout here which is fine because it should return immediately if there are no delays.
|
871 |
-
'blocking' => true,
|
872 |
-
'sslverify' => false
|
873 |
-
);
|
874 |
-
if($sendHeader){
|
875 |
-
$host = self::getOwnHostname();
|
876 |
-
$opts['headers'] = array( 'Host' => $host);
|
877 |
-
}
|
878 |
-
$testURL = $URL . '?test=1';
|
879 |
-
wordfence::status(4, 'info', "Testing cron URL: $testURL");
|
880 |
-
$result = wp_remote_post($testURL, $opts);
|
881 |
-
if( is_array($result) && isset($result['body']) && preg_match('/WFCRONTESTOK:' . wfConfig::get('cronTestID') . '/', $result['body'])){
|
882 |
-
wordfence::status(4, 'info', "Cron URL test success with: $testURL");
|
883 |
-
return true;
|
884 |
-
} else {
|
885 |
-
wordfence::status(4, 'info', "Cron URL test fail with: $testURL");
|
886 |
-
self::$cronTestFailedURLs[] = $testURL;
|
887 |
-
}
|
888 |
-
return false;
|
889 |
-
}
|
890 |
-
private static function detectCronURL(){
|
891 |
-
$URL = wfConfig::get('cronURL');
|
892 |
-
if($URL){
|
893 |
-
if(self::tryCronURL()){
|
894 |
-
return true;
|
895 |
-
}
|
896 |
-
}
|
897 |
-
|
898 |
-
$host = self::getOwnHostname();
|
899 |
-
$URLS = array();
|
900 |
-
$URLS[] = array(false, plugins_url('wordfence/wfscan.php'));
|
901 |
-
$URLS[] = array(true, preg_replace('/^https?:\/\/[^\/]+/i', 'http://127.0.0.1', $URLS[0][1]));
|
902 |
-
$URLS[] = array(true, preg_replace('/^https?:\/\/[^\/]+/i', 'https://127.0.0.1', $URLS[0][1]));
|
903 |
-
$withHostInsecure = 'http://' . $host . '/wp-content/plugins/wordfence/wfscan.php';
|
904 |
-
$withHostSecure = 'https://' . $host . '/wp-content/plugins/wordfence/wfscan.php';
|
905 |
-
if($URLS[0][1] != $withHostInsecure){
|
906 |
-
$URLS[] = array(false, $withHostInsecure);
|
907 |
-
}
|
908 |
-
if($URLS[0][1] != $withHostSecure){
|
909 |
-
$URLS[] = array(false, $withHostSecure);
|
910 |
-
}
|
911 |
-
foreach($URLS as $elem){
|
912 |
-
wfConfig::set('cronSendHeader', $elem[0] ? 1 : 0);
|
913 |
-
wfConfig::set('cronURL', $elem[1]);
|
914 |
-
if(self::tryCronURL()){
|
915 |
-
return true;
|
916 |
-
}
|
917 |
-
}
|
918 |
-
return false;
|
919 |
-
}
|
920 |
public static function startScan($isFork = false){
|
921 |
if(! $isFork){ //beginning of scan
|
922 |
wfConfig::set('wfKillRequested', 0);
|
@@ -924,31 +859,17 @@ class wfScanEngine {
|
|
924 |
if(wfUtils::isScanRunning()){
|
925 |
return "A scan is already running. Use the kill link if you would like to terminate the current scan.";
|
926 |
}
|
927 |
-
if(! self::detectCronURL()){
|
928 |
-
$msg = 'We could not determine how this WordPress server connects to itself. Please read <a href="http://www.wordfence.com/docs/wordfence-server-cant-connect-to-itself-error/" target="_blank">the documentation we provide on this page</a> which may help with this error. For your info, this machine\'s hostname is: ' . self::getOwnHostname();
|
929 |
-
$msg .= "<br /><br />We tried the following URLs:<ul>";
|
930 |
-
foreach(self::$cronTestFailedURLs as $URL){
|
931 |
-
$msg .= '<li><a href="' . $URL . '" target="_blank">' . $URL . '</a></li>';
|
932 |
-
}
|
933 |
-
$msg .= '</ul>';
|
934 |
-
return $msg;
|
935 |
-
}
|
936 |
}
|
937 |
|
938 |
$cronKey = wfUtils::bigRandomHex();
|
939 |
wfConfig::set('currentCronKey', time() . ',' . $cronKey);
|
940 |
-
$cronURL =
|
|
|
941 |
wordfence::status(4, 'info', "Starting cron at URL $cronURL");
|
942 |
$headers = array();
|
943 |
-
if(wfConfig::get('cronSendHeader')){
|
944 |
-
$headers['Host'] = self::getOwnHostname();
|
945 |
-
}
|
946 |
wordfence::status(4, 'info', "Starting wp_remote_post");
|
947 |
-
|
948 |
-
|
949 |
-
} else {
|
950 |
-
$timeout = 3; //3 seconds if we're kicking off the scan so that the Ajax call returns quickly and UI isn't too slow
|
951 |
-
}
|
952 |
$result = wp_remote_post( $cronURL, array(
|
953 |
'timeout' => $timeout, //Must be less than max execution time or more than 2 HTTP children will be occupied by scan
|
954 |
'blocking' => true, //Non-blocking seems to block anyway, so we use blocking
|
@@ -961,6 +882,16 @@ class wfScanEngine {
|
|
961 |
public function processResponse($result){
|
962 |
return false;
|
963 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
964 |
}
|
965 |
|
966 |
?>
|
21 |
private $apiKey = false;
|
22 |
private $startTime = 0;
|
23 |
private $scanStep = 0;
|
24 |
+
public $maxExecTime = false; //If more than $maxExecTime has elapsed since last check, fork a new scan process and continue
|
25 |
private $publicScanEnabled = false;
|
26 |
private $fileContentsResults = false;
|
27 |
private $scanner = false;
|
41 |
}
|
42 |
public function __construct(){
|
43 |
$this->startTime = time();
|
44 |
+
$this->maxExecTime = self::getMaxExecutionTime() / 2;
|
45 |
$this->i = new wfIssues();
|
46 |
$this->i->deleteNew();
|
47 |
$this->cycleStartTime = time();
|
852 |
throw new Exception("Scan was killed on administrator request.");
|
853 |
}
|
854 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
855 |
public static function startScan($isFork = false){
|
856 |
if(! $isFork){ //beginning of scan
|
857 |
wfConfig::set('wfKillRequested', 0);
|
859 |
if(wfUtils::isScanRunning()){
|
860 |
return "A scan is already running. Use the kill link if you would like to terminate the current scan.";
|
861 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
862 |
}
|
863 |
|
864 |
$cronKey = wfUtils::bigRandomHex();
|
865 |
wfConfig::set('currentCronKey', time() . ',' . $cronKey);
|
866 |
+
$cronURL = admin_url('admin-ajax.php');
|
867 |
+
$cronURL .= '?action=wordfence_doScan&isFork=' . ($isFork ? '1' : '0') . '&cronKey=' . $cronKey;
|
868 |
wordfence::status(4, 'info', "Starting cron at URL $cronURL");
|
869 |
$headers = array();
|
|
|
|
|
|
|
870 |
wordfence::status(4, 'info', "Starting wp_remote_post");
|
871 |
+
$timeout = self::getMaxExecutionTime() - 2; //2 seconds shorter than max execution time which ensures that only 2 HTTP processes are ever occupied
|
872 |
+
|
|
|
|
|
|
|
873 |
$result = wp_remote_post( $cronURL, array(
|
874 |
'timeout' => $timeout, //Must be less than max execution time or more than 2 HTTP children will be occupied by scan
|
875 |
'blocking' => true, //Non-blocking seems to block anyway, so we use blocking
|
882 |
public function processResponse($result){
|
883 |
return false;
|
884 |
}
|
885 |
+
public static function getMaxExecutionTime(){
|
886 |
+
$maxExecutionTime = wfConfig::get('maxExecutionTime');
|
887 |
+
if(! is_numeric($maxExecutionTime)){
|
888 |
+
$maxExecutionTime = @ini_get('max_execution_time');
|
889 |
+
}
|
890 |
+
if(! is_numeric($maxExecutionTime)){
|
891 |
+
$maxExecutionTime = 15;
|
892 |
+
}
|
893 |
+
return $maxExecutionTime;
|
894 |
+
}
|
895 |
}
|
896 |
|
897 |
?>
|
lib/wfUtils.php
CHANGED
@@ -96,6 +96,15 @@ class wfUtils {
|
|
96 |
break;
|
97 |
}
|
98 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
99 |
}
|
100 |
if(preg_match('/:\d+$/', $IP)){
|
101 |
$IP = preg_replace('/:\d+$/', '', $IP);
|
@@ -136,7 +145,12 @@ class wfUtils {
|
|
136 |
return false;
|
137 |
}
|
138 |
public static function getRequestedURL(){
|
139 |
-
|
|
|
|
|
|
|
|
|
|
|
140 |
}
|
141 |
|
142 |
public static function editUserLink($userID){
|
96 |
break;
|
97 |
}
|
98 |
}
|
99 |
+
} else if(preg_match('/(\d+)\.(\d+)\.(\d+)\.(\d+)\s+(\d+)\.(\d+)\.(\d+)\.(\d+)/', $IP)){
|
100 |
+
$parts = explode(' ', $IP); //Some users have "unknown 100.100.100.100" for example so we take the first thing that looks like an IP.
|
101 |
+
foreach($parts as $part){
|
102 |
+
if(preg_match('/(\d+)\.(\d+)\.(\d+)\.(\d+)/', $part)){
|
103 |
+
$IP = trim($part);
|
104 |
+
break;
|
105 |
+
}
|
106 |
+
}
|
107 |
+
|
108 |
}
|
109 |
if(preg_match('/:\d+$/', $IP)){
|
110 |
$IP = preg_replace('/:\d+$/', '', $IP);
|
145 |
return false;
|
146 |
}
|
147 |
public static function getRequestedURL(){
|
148 |
+
if(isset($_SERVER['HTTP_HOST']) && $_SERVER['HTTP_HOST']){
|
149 |
+
$host = $_SERVER['HTTP_HOST'];
|
150 |
+
} else {
|
151 |
+
$host = $_SERVER['SERVER_NAME'];
|
152 |
+
}
|
153 |
+
return (@$_SERVER['HTTPS'] ? 'https' : 'http') . '://' . $host . $_SERVER['REQUEST_URI'];
|
154 |
}
|
155 |
|
156 |
public static function editUserLink($userID){
|
lib/wordfenceClass.php
CHANGED
@@ -217,9 +217,6 @@ class wordfence {
|
|
217 |
wfConfig::set('alertEmailMsgCount', 0);
|
218 |
}
|
219 |
|
220 |
-
@chmod(dirname(__FILE__) . '/../wfscan.php', 0755);
|
221 |
-
@chmod(dirname(__FILE__) . '/../visitor.php', 0755);
|
222 |
-
|
223 |
global $wpdb;
|
224 |
$prefix = $wpdb->base_prefix;
|
225 |
$db->queryIgnoreError("alter table $prefix"."wfConfig modify column val longblob");
|
@@ -244,6 +241,13 @@ class wordfence {
|
|
244 |
global $blog_id;
|
245 |
if($blog_id == 1 && get_option('wordfenceActivated') != 1){ return; } //Because the plugin is active once installed, even before it's network activated, for site 1 (WordPress team, why?!)
|
246 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
247 |
add_action('wordfence_start_scheduled_scan', 'wordfence::wordfenceStartScheduledScan');
|
248 |
add_action('wordfence_daily_cron', 'wordfence::dailyCron');
|
249 |
add_action('wordfence_hourly_cron', 'wordfence::hourlyCron');
|
@@ -279,6 +283,27 @@ class wordfence {
|
|
279 |
}
|
280 |
}
|
281 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
282 |
public static function ajaxReceiver(){
|
283 |
if(! wfUtils::isAdmin()){
|
284 |
die(json_encode(array('errorMsg' => "You appear to have logged out or you are not an admin. Please sign-out and sign-in again.")));
|
@@ -1132,7 +1157,6 @@ class wordfence {
|
|
1132 |
}
|
1133 |
private static function wfFunc_testtime(){
|
1134 |
header('Content-Type: text/plain');
|
1135 |
-
wfUtils::iniSet('max_execution_time', 1800); //30 mins
|
1136 |
@error_reporting(E_ALL);
|
1137 |
wfUtils::iniSet('display_errors','On');
|
1138 |
set_error_handler('wordfence::memtest_error_handler', E_ALL);
|
@@ -1188,7 +1212,9 @@ class wordfence {
|
|
1188 |
exit();
|
1189 |
}
|
1190 |
public static function wp_head(){
|
1191 |
-
|
|
|
|
|
1192 |
}
|
1193 |
public static function shutdownAction(){
|
1194 |
}
|
@@ -1427,8 +1453,12 @@ class wordfence {
|
|
1427 |
|
1428 |
if(($approved == 1 || $approved == 0) && wfConfig::get('other_scanComments')){
|
1429 |
$wf = new wfScanEngine();
|
1430 |
-
|
1431 |
-
|
|
|
|
|
|
|
|
|
1432 |
}
|
1433 |
}
|
1434 |
return $approved;
|
217 |
wfConfig::set('alertEmailMsgCount', 0);
|
218 |
}
|
219 |
|
|
|
|
|
|
|
220 |
global $wpdb;
|
221 |
$prefix = $wpdb->base_prefix;
|
222 |
$db->queryIgnoreError("alter table $prefix"."wfConfig modify column val longblob");
|
241 |
global $blog_id;
|
242 |
if($blog_id == 1 && get_option('wordfenceActivated') != 1){ return; } //Because the plugin is active once installed, even before it's network activated, for site 1 (WordPress team, why?!)
|
243 |
}
|
244 |
+
//User may be logged in or not, so register both handlers
|
245 |
+
add_action('wp_ajax_nopriv_wordfence_logHuman', 'wordfence::ajax_logHuman_callback');
|
246 |
+
add_action('wp_ajax_wordfence_logHuman', 'wordfence::ajax_logHuman_callback');
|
247 |
+
add_action('wp_ajax_nopriv_wordfence_doScan', 'wordfence::ajax_doScan_callback');
|
248 |
+
add_action('wp_ajax_wordfence_doScan', 'wordfence::ajax_doScan_callback');
|
249 |
+
|
250 |
+
|
251 |
add_action('wordfence_start_scheduled_scan', 'wordfence::wordfenceStartScheduledScan');
|
252 |
add_action('wordfence_daily_cron', 'wordfence::dailyCron');
|
253 |
add_action('wordfence_hourly_cron', 'wordfence::hourlyCron');
|
283 |
}
|
284 |
}
|
285 |
}
|
286 |
+
public static function ajax_doScan_callback(){
|
287 |
+
ignore_user_abort(true);
|
288 |
+
$wordfence_wp_version = false;
|
289 |
+
require(ABSPATH . 'wp-includes/version.php');
|
290 |
+
$wordfence_wp_version = $wp_version;
|
291 |
+
require('wfScan.php');
|
292 |
+
wfScan::wfScanMain();
|
293 |
+
|
294 |
+
} //END doScan
|
295 |
+
public static function ajax_logHuman_callback(){
|
296 |
+
$hid = $_GET['hid'];
|
297 |
+
$hid = wfUtils::decrypt($hid);
|
298 |
+
if(! preg_match('/^\d+$/', $hid)){ exit(); }
|
299 |
+
$db = new wfDB();
|
300 |
+
global $wpdb; $p = $wpdb->base_prefix;
|
301 |
+
$db->query("update $p"."wfHits set jsRun=1 where id=%d", $hid);
|
302 |
+
if(! headers_sent()){ //suppress content-type warning in chrome
|
303 |
+
header('Content-type: image/gif');
|
304 |
+
}
|
305 |
+
die("");
|
306 |
+
}
|
307 |
public static function ajaxReceiver(){
|
308 |
if(! wfUtils::isAdmin()){
|
309 |
die(json_encode(array('errorMsg' => "You appear to have logged out or you are not an admin. Please sign-out and sign-in again.")));
|
1157 |
}
|
1158 |
private static function wfFunc_testtime(){
|
1159 |
header('Content-Type: text/plain');
|
|
|
1160 |
@error_reporting(E_ALL);
|
1161 |
wfUtils::iniSet('display_errors','On');
|
1162 |
set_error_handler('wordfence::memtest_error_handler', E_ALL);
|
1212 |
exit();
|
1213 |
}
|
1214 |
public static function wp_head(){
|
1215 |
+
$URL = admin_url('admin-ajax.php');
|
1216 |
+
$URL .= '?action=wordfence_logHuman&hid=' . wfUtils::encrypt(self::$hitID);
|
1217 |
+
echo '<script type="text/javascript">var src="' . $URL . '"; if(window.location.protocol == "https:"){ src = src.replace("http:", "https:"); } var wfHTImg = new Image(); wfHTImg.src=src;</script>';
|
1218 |
}
|
1219 |
public static function shutdownAction(){
|
1220 |
}
|
1453 |
|
1454 |
if(($approved == 1 || $approved == 0) && wfConfig::get('other_scanComments')){
|
1455 |
$wf = new wfScanEngine();
|
1456 |
+
try {
|
1457 |
+
if($wf->isBadComment($cData['comment_author'], $cData['comment_author_email'], $cData['comment_author_url'], $cData['comment_author_IP'], $cData['comment_content'])){
|
1458 |
+
return 'spam';
|
1459 |
+
}
|
1460 |
+
} catch(Exception $e){
|
1461 |
+
//This will most likely be an API exception because we can't contact the API, so we ignore it and let the normal comment mechanisms run.
|
1462 |
}
|
1463 |
}
|
1464 |
return $approved;
|
lib/wordfenceConstants.php
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
define('WORDFENCE_API_VERSION', '2.4');
|
3 |
define('WORDFENCE_API_URL_SEC', 'https://noc1.wordfence.com/');
|
4 |
define('WORDFENCE_API_URL_NONSEC', 'http://noc1.wordfence.com/');
|
5 |
-
define('WORDFENCE_MAX_SCAN_TIME',
|
6 |
define('WORDFENCE_TRANSIENTS_TIMEOUT', 3600); //how long are items cached in seconds e.g. files downloaded for diffing
|
7 |
define('WORDFENCE_MAX_IPLOC_AGE', 604800); //1 week
|
8 |
define('WORDFENCE_CRAWLER_VERIFY_CACHE_TIME', 604800);
|
2 |
define('WORDFENCE_API_VERSION', '2.4');
|
3 |
define('WORDFENCE_API_URL_SEC', 'https://noc1.wordfence.com/');
|
4 |
define('WORDFENCE_API_URL_NONSEC', 'http://noc1.wordfence.com/');
|
5 |
+
define('WORDFENCE_MAX_SCAN_TIME', 86400); //Increased this from 10 mins to 1 day because very big scans run for a long time. Users can use kill.
|
6 |
define('WORDFENCE_TRANSIENTS_TIMEOUT', 3600); //how long are items cached in seconds e.g. files downloaded for diffing
|
7 |
define('WORDFENCE_MAX_IPLOC_AGE', 604800); //1 week
|
8 |
define('WORDFENCE_CRAWLER_VERIFY_CACHE_TIME', 604800);
|
readme.txt
CHANGED
@@ -3,7 +3,7 @@ Contributors: mmaunder
|
|
3 |
Tags: wordpress, security, wordpress security, security plugin, secure, anti-virus, malware, firewall, antivirus, virus, google safe browsing, phishing, scrapers, hacking, wordfence, securty, secrity, secure
|
4 |
Requires at least: 3.3.1
|
5 |
Tested up to: 3.4.2
|
6 |
-
Stable tag: 3.
|
7 |
|
8 |
Wordfence Security is a free enterprise class security plugin that includes a firewall, virus scanning, real-time traffic with geolocation and more.
|
9 |
|
@@ -154,6 +154,17 @@ or a theme, because often these have been updated to fix a security hole.
|
|
154 |
|
155 |
== Changelog ==
|
156 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
157 |
= 3.3.7 =
|
158 |
* Upgrade immediately. Fixes possible XSS vulnerability in Wordfence "firewall unlock" form.
|
159 |
* Also added rate limiting to max of 10 requests per second to the unlock form.
|
3 |
Tags: wordpress, security, wordpress security, security plugin, secure, anti-virus, malware, firewall, antivirus, virus, google safe browsing, phishing, scrapers, hacking, wordfence, securty, secrity, secure
|
4 |
Requires at least: 3.3.1
|
5 |
Tested up to: 3.4.2
|
6 |
+
Stable tag: 3.4.1
|
7 |
|
8 |
Wordfence Security is a free enterprise class security plugin that includes a firewall, virus scanning, real-time traffic with geolocation and more.
|
9 |
|
154 |
|
155 |
== Changelog ==
|
156 |
|
157 |
+
= 3.4.1 =
|
158 |
+
* Removed wfscan.php script and now using pseudo-ajax calls to fire off scans. Much more reliable.
|
159 |
+
* Removed visitor.php script and now using pseudo-ajax calls to log human visits.
|
160 |
+
* Added config option to allow admin to specify max execution time (advanced only!!).
|
161 |
+
* Fixed issue that caused API calls to fail on MultiSite installs.
|
162 |
+
* Fixed issue that caused comments to break on MultiSite installs under certain conditions.
|
163 |
+
* Fixed issue that caused incorrect domain to be shown in live traffic view on multi-site installs.
|
164 |
+
* Fixed issue where some proxies/firewalls send space delimited IP addresses in HTTP headers and Wordfence now handles that.
|
165 |
+
* Fixed issue that caused Wordfence to capture activation errors of other plugins.
|
166 |
+
* Geo IP database update to November 7th edition.
|
167 |
+
|
168 |
= 3.3.7 =
|
169 |
* Upgrade immediately. Fixes possible XSS vulnerability in Wordfence "firewall unlock" form.
|
170 |
* Also added rate limiting to max of 10 requests per second to the unlock form.
|
visitor.php
DELETED
@@ -1,33 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
define('WORDFENCE_VERSIONONLY_MODE', true); //So that we can include wordfence.php and get the version constant
|
3 |
-
ignore_user_abort(true);
|
4 |
-
if ( !defined('ABSPATH') ) {
|
5 |
-
/** Set up WordPress environment */
|
6 |
-
if($_SERVER['SCRIPT_FILENAME']){
|
7 |
-
$wfBaseDir = preg_replace('/[^\/]+\/[^\/]+\/[^\/]+\/visitor\.php$/', '', $_SERVER['SCRIPT_FILENAME']);
|
8 |
-
require_once($wfBaseDir . 'wp-load.php');
|
9 |
-
global $wp_version;
|
10 |
-
global $wordfence_wp_version;
|
11 |
-
require($wfBaseDir . 'wp-includes/version.php');
|
12 |
-
$wordfence_wp_version = $wp_version;
|
13 |
-
} else {
|
14 |
-
require_once('../../../wp-load.php');
|
15 |
-
require_once('../../../wp-includes/version.php');
|
16 |
-
}
|
17 |
-
|
18 |
-
}
|
19 |
-
require_once('wordfence.php');
|
20 |
-
require_once('lib/wfUtils.php');
|
21 |
-
require_once('lib/wfDB.php');
|
22 |
-
function wfVisitor(){
|
23 |
-
$hid = $_GET['hid'];
|
24 |
-
$hid = wfUtils::decrypt($hid);
|
25 |
-
if(! preg_match('/^\d+$/', $hid)){ exit(); }
|
26 |
-
$db = new wfDB();
|
27 |
-
global $wpdb; $p = $wpdb->base_prefix;
|
28 |
-
$db->query("update $p"."wfHits set jsRun=1 where id=%d", $hid);
|
29 |
-
exit();
|
30 |
-
}
|
31 |
-
wfVisitor();
|
32 |
-
|
33 |
-
?>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
wordfence.php
CHANGED
@@ -4,11 +4,13 @@ Plugin Name: Wordfence Security
|
|
4 |
Plugin URI: http://wordfence.com/
|
5 |
Description: Wordfence Security - Anti-virus and Firewall security plugin for WordPress
|
6 |
Author: Mark Maunder
|
7 |
-
Version: 3.
|
8 |
Author URI: http://wordfence.com/
|
9 |
*/
|
10 |
-
define('WORDFENCE_VERSION', '3.
|
11 |
-
|
|
|
|
|
12 |
if(! defined('WORDFENCE_VERSIONONLY_MODE')){
|
13 |
if((int) @ini_get('memory_limit') < 64){
|
14 |
if(strpos(ini_get('disable_functions'), 'ini_set') === false){
|
4 |
Plugin URI: http://wordfence.com/
|
5 |
Description: Wordfence Security - Anti-virus and Firewall security plugin for WordPress
|
6 |
Author: Mark Maunder
|
7 |
+
Version: 3.4.1
|
8 |
Author URI: http://wordfence.com/
|
9 |
*/
|
10 |
+
define('WORDFENCE_VERSION', '3.4.1');
|
11 |
+
if(get_option('wordfenceActivated') != 1){
|
12 |
+
add_action('activated_plugin','wordfence_save_activation_error'); function wordfence_save_activation_error(){ update_option('wf_plugin_act_error', ob_get_contents()); }
|
13 |
+
}
|
14 |
if(! defined('WORDFENCE_VERSIONONLY_MODE')){
|
15 |
if((int) @ini_get('memory_limit') < 64){
|
16 |
if(strpos(ini_get('disable_functions'), 'ini_set') === false){
|