Wordfence Security – Firewall & Malware Scan - Version 6.1.5

Version Description

  • Fix: WordPress language files no longer flagged as changed.
  • Improvement: Accept wildcards in "Immediately block IP's that access these URLs."
  • Fix: Fixed bug when multiple authors have published posts, /?author=N scans show an author archive page.
  • Fix: Fixed issue with IPv6 mapped IPv4 addresses not being treated as IPv4.
  • Improvement: Added WordPress version and various constants to Diagnostics report.
  • Fix: Fixed bug with Windows users unable to save Firewall config.
  • Improvement: Include option for IIS on Windows in Firewall config process, and recommend manual php.ini change only.
  • Fix: Made the 'administrator email address' admin notice dismissable.
Download this release

Release Info

Developer wfmatt
Plugin Icon 128x128 Wordfence Security – Firewall & Malware Scan
Version 6.1.5
Comparing to
See all releases

Code changes from version 6.1.4 to 6.1.5

css/main.css CHANGED
@@ -518,7 +518,7 @@ h3.wfConfigHeading {
518
.wfOnOffSwitch-checkbox:checked + .wfOnOffSwitch-label .wfOnOffSwitch-switch {
519
right: 0 !important ;
520
}
521
- #wordfenceConfigWarning {
522
clear: left;
523
margin-top: 5px;
524
}
518
.wfOnOffSwitch-checkbox:checked + .wfOnOffSwitch-label .wfOnOffSwitch-switch {
519
right: 0 !important ;
520
}
521
+ #wordfenceConfigWarning, #wordfenceAdminEmailWarning {
522
clear: left;
523
margin-top: 5px;
524
}
js/tourTip.js CHANGED
@@ -25,6 +25,14 @@ window['wordfenceExt'] = {
25
function(){ jQuery('#wordfenceAutoUpdateChoice').fadeOut(); }
26
);
27
},
28
removeFromCache: function(postID){
29
this.ajax('wordfence_removeFromCache', {
30
id: postID
25
function(){ jQuery('#wordfenceAutoUpdateChoice').fadeOut(); }
26
);
27
},
28
+ adminEmailChoice: function(choice) {
29
+ this.ajax('wordfence_adminEmailChoice', {
30
+ choice: choice
31
+ },
32
+ function(res){ jQuery('#wordfenceAdminEmailWarning').fadeOut(); },
33
+ function(){ jQuery('#wordfenceAdminEmailWarning').fadeOut(); }
34
+ );
35
+ },
36
removeFromCache: function(postID){
37
this.ajax('wordfence_removeFromCache', {
38
id: postID
lib/menu_diagnostic.php CHANGED
@@ -87,6 +87,96 @@ $w = new wfConfig();
87
</tr>
88
</tbody>
89
90
<tbody class="thead">
91
<tr>
92
<th colspan="<?php echo $cols ?>">WordPress Plugins</th>
87
</tr>
88
</tbody>
89
90
+ <tbody class="thead">
91
+ <tr>
92
+ <th colspan="<?php echo $cols ?>">WordPress</th>
93
+ </tr>
94
+ </tbody>
95
+ <tbody>
96
+ <?php
97
+ require(ABSPATH . 'wp-includes/version.php');
98
+ $postRevisions = (defined('WP_POST_REVISIONS') ? WP_POST_REVISIONS : true);
99
+ $wordPressValues = array(
100
+ 'WordPress Version' => array('description' => '', 'value' => $wp_version),
101
+ 'WP_DEBUG' => array('description' => 'WordPress debug mode', 'value' => (defined('WP_DEBUG') && WP_DEBUG ? 'On' : 'Off')),
102
+ 'WP_DEBUG_LOG' => array('description' => 'WordPress error logging override', 'value' => defined('WP_DEBUG_LOG') ? (WP_DEBUG_LOG ? 'Enabled' : 'Disabled') : '(not set)'),
103
+ 'WP_DEBUG_DISPLAY' => array('description' => 'WordPress error display override', 'value' => defined('WP_DEBUG_DISPLAY') ? (WP_DEBUG_LOG ? 'Enabled' : 'Disabled') : '(not set)'),
104
+ 'SCRIPT_DEBUG' => array('description' => 'WordPress script debug mode', 'value' => (defined('SCRIPT_DEBUG') && SCRIPT_DEBUG ? 'On' : 'Off')),
105
+ 'SAVEQUERIES' => array('description' => 'WordPress query debug mode', 'value' => (defined('SAVEQUERIES') && SAVEQUERIES ? 'On' : 'Off')),
106
+ 'DB_CHARSET' => 'Database character set',
107
+ 'DB_COLLATE' => 'Database collation',
108
+ 'WP_SITEURL' => 'Explicitly set site URL',
109
+ 'WP_HOME' => 'Explicitly set blog URL',
110
+ 'WP_CONTENT_DIR' => array('description' => '"wp-content" folder is in default location', 'value' => (realpath(WP_CONTENT_DIR) === realpath(ABSPATH . 'wp-content') ? 'Yes' : 'No')),
111
+ 'WP_CONTENT_URL' => 'URL to the "wp-content" folder',
112
+ 'WP_PLUGIN_DIR' => array('description' => '"plugins" folder is in default location', 'value' => (realpath(WP_PLUGIN_DIR) === realpath(ABSPATH . 'wp-content/plugins') ? 'Yes' : 'No')),
113
+ 'WP_LANG_DIR' => array('description' => '"languages" folder is in default location', 'value' => (realpath(WP_LANG_DIR) === realpath(ABSPATH . 'wp-content/languages') ? 'Yes' : 'No')),
114
+ 'WPLANG' => 'Language choice',
115
+ 'UPLOADS' => 'Custom upload folder location',
116
+ 'TEMPLATEPATH' => array('description' => 'Theme template folder override', 'value' => (defined('TEMPLATEPATH') && realpath(get_template_directory()) !== realpath(TEMPLATEPATH) ? 'Overridden' : '(not set)')),
117
+ 'STYLESHEETPATH' => array('description' => 'Theme stylesheet folder override', 'value' => (defined('STYLESHEETPATH') && realpath(get_stylesheet_directory()) !== realpath(STYLESHEETPATH) ? 'Overridden' : '(not set)')),
118
+ 'AUTOSAVE_INTERVAL' => 'Post editing automatic saving interval',
119
+ 'WP_POST_REVISIONS' => array('description' => 'Post revisions saved by WordPress', 'value' => is_numeric($postRevisions) ? $postRevisions : ($postRevisions ? 'Unlimited' : 'None')),
120
+ 'COOKIE_DOMAIN' => 'WordPress cookie domain',
121
+ 'COOKIEPATH' => 'WordPress cookie path',
122
+ 'SITECOOKIEPATH' => 'WordPress site cookie path',
123
+ 'ADMIN_COOKIE_PATH' => 'WordPress admin cookie path',
124
+ 'PLUGINS_COOKIE_PATH' => 'WordPress plugins cookie path',
125
+ 'WP_ALLOW_MULTISITE' => array('description' => 'Multisite/network ability enabled', 'value' => (defined('WP_ALLOW_MULTISITE') && WP_ALLOW_MULTISITE ? 'Yes' : 'No')),
126
+ 'NOBLOGREDIRECT' => 'URL redirected to if the visitor tries to access a nonexistent blog',
127
+ 'CONCATENATE_SCRIPTS' => array('description' => 'Concatenate JavaScript files', 'value' => (defined('CONCATENATE_SCRIPTS') && CONCATENATE_SCRIPTS ? 'Yes' : 'No')),
128
+ 'WP_MEMORY_LIMIT' => 'WordPress memory limit',
129
+ 'WP_MAX_MEMORY_LIMIT' => 'Administrative memory limit',
130
+ 'WP_CACHE' => array('description' => 'Built-in caching', 'value' => (defined('WP_CACHE') && WP_CACHE ? 'Enabled' : 'Disabled')),
131
+ 'CUSTOM_USER_TABLE' => array('description' => 'Custom "users" table', 'value' => (defined('CUSTOM_USER_TABLE') ? 'Set' : '(not set)')),
132
+ 'CUSTOM_USER_META_TABLE' => array('description' => 'Custom "usermeta" table', 'value' => (defined('CUSTOM_USER_META_TABLE') ? 'Set' : '(not set)')),
133
+ 'FS_CHMOD_DIR' => array('description' => 'Overridden permissions for a new folder', 'value' => defined('FS_CHMOD_DIR') ? decoct(FS_CHMOD_DIR) : '(not set)'),
134
+ 'FS_CHMOD_FILE' => array('description' => 'Overridden permissions for a new file', 'value' => defined('FS_CHMOD_FILE') ? decoct(FS_CHMOD_FILE) : '(not set)'),
135
+ 'ALTERNATE_WP_CRON' => array('description' => 'Alternate WP cron', 'value' => (defined('ALTERNATE_WP_CRON') && ALTERNATE_WP_CRON ? 'Enabled' : 'Disabled')),
136
+ 'DISABLE_WP_CRON' => array('description' => 'WP cron status', 'value' => (defined('DISABLE_WP_CRON') && DISABLE_WP_CRON ? 'Disabled' : 'Enabled')),
137
+ 'WP_CRON_LOCK_TIMEOUT' => 'Cron running frequency lock',
138
+ 'EMPTY_TRASH_DAYS' => array('description' => 'Interval the trash is automatically emptied at in days', 'value' => (EMPTY_TRASH_DAYS > 0 ? EMPTY_TRASH_DAYS : 'Never')),
139
+ 'WP_ALLOW_REPAIR' => array('description' => 'Automatic database repair', 'value' => (defined('WP_ALLOW_REPAIR') && WP_ALLOW_REPAIR ? 'Enabled' : 'Disabled')),
140
+ 'DO_NOT_UPGRADE_GLOBAL_TABLES' => array('description' => 'Do not upgrade global tables', 'value' => (defined('DO_NOT_UPGRADE_GLOBAL_TABLES') && DO_NOT_UPGRADE_GLOBAL_TABLES ? 'Yes' : 'No')),
141
+ 'DISALLOW_FILE_EDIT' => array('description' => 'Disallow plugin/theme editing', 'value' => (defined('DISALLOW_FILE_EDIT') && DISALLOW_FILE_EDIT ? 'Yes' : 'No')),
142
+ 'DISALLOW_FILE_MOD' => array('description' => 'Disallow plugin/theme update and installation', 'value' => (defined('DISALLOW_FILE_MOD') && DISALLOW_FILE_MOD ? 'Yes' : 'No')),
143
+ 'IMAGE_EDIT_OVERWRITE' => array('description' => 'Overwrite image edits when restoring the original', 'value' => (defined('IMAGE_EDIT_OVERWRITE') && IMAGE_EDIT_OVERWRITE ? 'Yes' : 'No')),
144
+ 'FORCE_SSL_ADMIN' => array('description' => 'Force SSL for administrative logins', 'value' => (defined('FORCE_SSL_ADMIN') && FORCE_SSL_ADMIN ? 'Yes' : 'No')),
145
+ 'WP_HTTP_BLOCK_EXTERNAL' => array('description' => 'Block external URL requests', 'value' => (defined('WP_HTTP_BLOCK_EXTERNAL') && WP_HTTP_BLOCK_EXTERNAL ? 'Yes' : 'No')),
146
+ 'WP_ACCESSIBLE_HOSTS' => 'Whitelisted hosts',
147
+ 'WP_AUTO_UPDATE_CORE' => array('description' => 'Automatic WP Core updates', 'value' => defined('WP_AUTO_UPDATE_CORE') ? (is_bool(WP_AUTO_UPDATE_CORE) ? (WP_AUTO_UPDATE_CORE ? 'Everything' : 'None') : WP_AUTO_UPDATE_CORE) : 'Default'),
148
+ );
149
+
150
+ foreach ($wordPressValues as $settingName => $settingData):
151
+ $escapedName = esc_html($settingName);
152
+ $escapedDescription = '';
153
+ $escapedValue = '(not set)';
154
+ if (is_array($settingData)) {
155
+ $escapedDescription = esc_html($settingData['description']);
156
+ if (isset($settingData['value'])) {
157
+ $escapedValue = esc_html($settingData['value']);
158
+ }
159
+ }
160
+ else {
161
+ $escapedDescription = esc_html($settingData);
162
+ if (defined($settingName)) {
163
+ $escapedValue = esc_html(constant($settingName));
164
+ }
165
+ }
166
+ ?>
167
+ <tr>
168
+ <td><strong><?php echo $escapedName ?></strong></td>
169
+ <td><?php echo $escapedDescription ?></td>
170
+ <td><?php echo $escapedValue ?></td>
171
+ </tr>
172
+ <?php endforeach ?>
173
+ </tbody>
174
+ <tbody class="empty-row">
175
+ <tr>
176
+ <td colspan="<?php echo $cols ?>"></td>
177
+ </tr>
178
+ </tbody>
179
+
180
<tbody class="thead">
181
<tr>
182
<th colspan="<?php echo $cols ?>">WordPress Plugins</th>
lib/menu_options.php CHANGED
@@ -885,11 +885,10 @@ $w = new wfConfig();
885
value="<?php $w->f( 'bannedURLs' ); ?>" size="40"/></td>
886
</tr>
887
<tr>
888
- <th colspan="2" style="color: #999;">Separate multiple URL's with commas. If you see an attacker
889
- repeatedly probing your site for a known vulnerability you can use this to immediately block
890
- them.<br/>
891
- All URL's must start with a '/' without quotes and must be relative. e.g. /badURLone/,
892
- /bannedPage.html, /dont-access/this/URL/
893
<br/><br/></th>
894
</tr>
895
885
value="<?php $w->f( 'bannedURLs' ); ?>" size="40"/></td>
886
</tr>
887
<tr>
888
+ <th colspan="2" style="color: #999;">Separate multiple URL's with commas. Asterisks are wildcards,
889
+ but use with care. If you see an attacker repeatedly probing your site for a known vulnerability
890
+ you can use this to immediately block them. All URL's must start with a '/' without quotes and
891
+ must be relative. e.g. /badURLone/, /bannedPage.html, /dont-access/this/URL/, /starts/with-*
892
<br/><br/></th>
893
</tr>
894
lib/wfCache.php CHANGED
@@ -513,7 +513,7 @@ class wfCache {
513
$excludedURLs = "";
514
if(wfConfig::get('bannedURLs', false)){
515
foreach(explode(',', wfConfig::get('bannedURLs', false)) as $URL){
516
- $excludedURLs .= "RewriteCond %{REQUEST_URI} !^" . self::regexSpaceFix(preg_quote(trim($URL))) . "$\n\t";
517
}
518
}
519
513
$excludedURLs = "";
514
if(wfConfig::get('bannedURLs', false)){
515
foreach(explode(',', wfConfig::get('bannedURLs', false)) as $URL){
516
+ $excludedURLs .= "RewriteCond %{REQUEST_URI} !" . wfUtils::patternToRegex($URL, '', '') . "\n\t";
517
}
518
}
519
lib/wfUtils.php CHANGED
@@ -8,7 +8,8 @@ class wfUtils {
8
private static $lastDisplayErrors = false;
9
public static function patternToRegex($pattern, $mod = 'i', $sep = '/') {
10
$pattern = preg_quote(trim($pattern), $sep);
11
- return $sep . str_replace("\\*", '.*', $pattern) . $sep . $mod;
12
}
13
public static function makeTimeAgo($secs, $noSeconds = false) {
14
if($secs < 1){
@@ -274,8 +275,8 @@ class wfUtils {
274
}
275
276
// IPv4 mapped IPv6
277
- if (preg_match('/^((?:0{1,4}(?::|)){0,5})(::)?ffff:((?:\d{1,3}(?:\.|$)){4})#x2F;i', $ip, $matches)) {
278
- $octets = explode('.', $matches[3]);
279
return "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff" . chr($octets[0]) . chr($octets[1]) . chr($octets[2]) . chr($octets[3]);
280
}
281
@@ -512,6 +513,10 @@ class wfUtils {
512
$j = preg_replace('/:\d+#x2F;', '', $j); //Strip off port
513
}
514
if (self::isValidIP($j)) {
515
if (self::isPrivateAddress($j)) {
516
$privates[] = array($j, $var);
517
} else {
@@ -530,6 +535,10 @@ class wfUtils {
530
$j = preg_replace('/:\d+#x2F;', '', $j); //Strip off port
531
}
532
if(self::isValidIP($j)){
533
if(self::isPrivateAddress($j)){
534
$privates[] = array($j, $var);
535
} else {
@@ -547,6 +556,10 @@ class wfUtils {
547
$item = preg_replace('/:\d+#x2F;', '', $item); //Strip off port
548
}
549
if(self::isValidIP($item)){
550
if(self::isPrivateAddress($item)){
551
$privates[] = array($item, $var);
552
} else {
@@ -560,6 +573,15 @@ class wfUtils {
560
return false;
561
}
562
}
563
public static function extractHostname($str){
564
if(preg_match('/https?:\/\/([a-zA-Z0-9\.\-]+)(?:\/|$)/i', $str, $matches)){
565
return strtolower($matches[1]);
8
private static $lastDisplayErrors = false;
9
public static function patternToRegex($pattern, $mod = 'i', $sep = '/') {
10
$pattern = preg_quote(trim($pattern), $sep);
11
+ $pattern = str_replace(' ', '\s', $pattern);
12
+ return $sep . '^' . str_replace('\*', '.*', $pattern) . '#x27; . $sep . $mod;
13
}
14
public static function makeTimeAgo($secs, $noSeconds = false) {
15
if($secs < 1){
275
}
276
277
// IPv4 mapped IPv6
278
+ if (preg_match('/^(?:\:(?:\:0{1,4}){0,4}\:|(?:0{1,4}\:){5})ffff\:(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})#x2F;i', $ip, $matches)) {
279
+ $octets = explode('.', $matches[1]);
280
return "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff" . chr($octets[0]) . chr($octets[1]) . chr($octets[2]) . chr($octets[3]);
281
}
282
513
$j = preg_replace('/:\d+#x2F;', '', $j); //Strip off port
514
}
515
if (self::isValidIP($j)) {
516
+ if (self::isIPv6MappedIPv4($j)) {
517
+ $j = self::inet_ntop(self::inet_pton($j));
518
+ }
519
+
520
if (self::isPrivateAddress($j)) {
521
$privates[] = array($j, $var);
522
} else {
535
$j = preg_replace('/:\d+#x2F;', '', $j); //Strip off port
536
}
537
if(self::isValidIP($j)){
538
+ if (self::isIPv6MappedIPv4($j)) {
539
+ $j = self::inet_ntop(self::inet_pton($j));
540
+ }
541
+
542
if(self::isPrivateAddress($j)){
543
$privates[] = array($j, $var);
544
} else {
556
$item = preg_replace('/:\d+#x2F;', '', $item); //Strip off port
557
}
558
if(self::isValidIP($item)){
559
+ if (self::isIPv6MappedIPv4($item)) {
560
+ $item = self::inet_ntop(self::inet_pton($item));
561
+ }
562
+
563
if(self::isPrivateAddress($item)){
564
$privates[] = array($item, $var);
565
} else {
573
return false;
574
}
575
}
576
+
577
+ /**
578
+ * @param string $ip
579
+ * @return bool
580
+ */
581
+ public static function isIPv6MappedIPv4($ip) {
582
+ return preg_match('/^(?:\:(?:\:0{1,4}){0,4}\:|(?:0{1,4}\:){5})ffff\:\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}#x2F;i', $ip) > 0;
583
+ }
584
+
585
public static function extractHostname($str){
586
if(preg_match('/https?:\/\/([a-zA-Z0-9\.\-]+)(?:\/|$)/i', $str, $matches)){
587
return strtolower($matches[1]);
lib/wordfenceClass.php CHANGED
@@ -1100,7 +1100,7 @@ SQL
1100
if(wfConfig::get('bannedURLs', false)){
1101
$URLs = explode(',', wfConfig::get('bannedURLs'));
1102
foreach($URLs as $URL){
1103
- if($_SERVER['REQUEST_URI'] == trim($URL)){
1104
$wfLog->blockIP($IP, "Accessed a banned URL.");
1105
$wfLog->do503(3600, "Accessed a banned URL.");
1106
//exits
@@ -1773,6 +1773,15 @@ SQL
1773
}
1774
return array('ok' => 1);
1775
}
1776
public static function ajax_removeFromCache_callback(){
1777
$id = $_POST['id'];
1778
$link = get_permalink($id);
@@ -3469,7 +3478,7 @@ HTML;
3469
'activityLogUpdate', 'ticker', 'loadIssues', 'updateIssueStatus', 'deleteIssue', 'updateAllIssues',
3470
'reverseLookup', 'unlockOutIP', 'loadBlockRanges', 'unblockRange', 'blockIPUARange', 'whois', 'unblockIP',
3471
'blockIP', 'permBlockIP', 'loadStaticPanel', 'saveConfig', 'downloadHtaccess', 'checkFalconHtaccess',
3472
- 'updateConfig', 'saveCacheConfig', 'removeFromCache', 'autoUpdateChoice', 'saveCacheOptions', 'clearPageCache',
3473
'getCacheStats', 'clearAllBlocked', 'killScan', 'saveCountryBlocking', 'saveScanSchedule', 'tourClosed',
3474
'welcomeClosed', 'startTourAgain', 'downgradeLicense', 'addTwoFactor', 'twoFacActivate', 'twoFacDel',
3475
'loadTwoFactor', 'loadAvgSitePerf', 'sendTestEmail', 'addCacheExclusion', 'removeCacheExclusion',
@@ -3573,7 +3582,11 @@ HTML;
3573
echo '<div id="wordfenceConfigWarning" class="fade error"><p><strong>Wordfence could not get an API key from the Wordfence scanning servers when it activated.</strong> You can try to fix this by going to the Wordfence "options" page and hitting "Save Changes". This will cause Wordfence to retry fetching an API key for you. If you keep seeing this error it usually means your WordPress server can\'t connect to our scanning servers. You can try asking your WordPress host to allow your WordPress server to connect to noc1.wordfence.com.</p></div>';
3574
}
3575
public static function adminEmailWarning(){
3576
- echo '<div id="wordfenceConfigWarning" class="fade error"><p><strong>You have not set an administrator email address to receive alerts for Wordfence.</strong> Please <a href="' . self::getMyOptionsURL() . '">click here to go to the Wordfence Options Page</a> and set an email address where you will receive security alerts from this site.</p></div>';
3577
}
3578
public static function autoUpdateNotice(){
3579
echo '<div id="wordfenceAutoUpdateChoice" class="fade error"><p><strong>Do you want Wordfence to stay up-to-date automatically?</strong>&nbsp;&nbsp;&nbsp;<a href="#" onclick="wordfenceExt.autoUpdateChoice(\'yes\'); return false;">Yes, enable auto-update.</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href="#" onclick="wordfenceExt.autoUpdateChoice(\'no\'); return false;">No thanks.</a></p></div>';
@@ -3608,7 +3621,7 @@ HTML;
3608
}
3609
}
3610
if(! $warningAdded){
3611
- if(wfConfig::get('tourClosed') == '1' && (! wfConfig::get('alertEmails')) ){
3612
$warningAdded = true;
3613
if(wfUtils::isAdminPageMU()){
3614
add_action('network_admin_notices', 'wordfence::adminEmailWarning');
@@ -3864,7 +3877,7 @@ document.location.href=$adminURL;
3864
($serverInfo->isCGI() || $serverInfo->isFastCGI())),
3865
array("litespeed", 'LiteSpeed', $serverInfo->isLiteSpeed()),
3866
array("nginx", 'NGINX', $serverInfo->isNGINX()),
3867
- // array("iis", 'Windows (IIS)', $serverInfo->isIIS()),
3868
);
3869
$wafActionContent = '<p>To be as secure as possible, the Wordfence Web Application Firewall is designed
3870
to run via a PHP ini setting called <code>auto_prepend_file</code> in order to ensure it runs before any potentially
@@ -4467,7 +4480,10 @@ to your httpd.conf if using Apache, or find documentation on how to disable dire
4467
(isset($_POST['author']) && is_numeric(preg_replace('/[^0-9]/', '', $_POST['author'])))
4468
)
4469
) {
4470
- $query_vars['author'] = -1;
4471
}
4472
return $query_vars;
4473
}
@@ -5110,7 +5126,7 @@ LIMIT %d", $lastSendTime, $limit));
5110
if (WFWAF_AUTO_PREPEND && !WFWAF_SUBDIRECTORY_INSTALL) {
5111
echo '<div class="updated is-dismissible"><p>The installation was successful! Your site is protected to the fullest extent!</p></div>';
5112
} else {
5113
- echo '<div class="notice notice-error"><p>The changes have not yet taken effect. If you are using LiteSpeed
5114
as your web server or CGI/FastCGI interface, you may need to wait a few minutes for the changes to take effect since the
5115
configuration files are sometimes cached. You also may need to select a different server configuration in order to
5116
complete this step, but wait for a few minutes before trying. You can try refreshing this page. </p></div>';
@@ -5206,6 +5222,7 @@ class wfWAFAutoPrependHelper {
5206
case 'apache-suphp':
5207
case 'nginx':
5208
case 'litespeed':
5209
if (file_exists($userIniPath)) {
5210
$backups[] = $userIniPath;
5211
}
@@ -5357,6 +5374,7 @@ $userIniHtaccessDirectives
5357
case 'nginx':
5358
case 'apache-suphp':
5359
case 'litespeed':
5360
$autoPrependIni = sprintf("; Wordfence WAF
5361
auto_prepend_file = '%s'
5362
; END Wordfence WAF
1100
if(wfConfig::get('bannedURLs', false)){
1101
$URLs = explode(',', wfConfig::get('bannedURLs'));
1102
foreach($URLs as $URL){
1103
+ if(preg_match(wfUtils::patternToRegex($URL, ''), $_SERVER['REQUEST_URI'])){
1104
$wfLog->blockIP($IP, "Accessed a banned URL.");
1105
$wfLog->do503(3600, "Accessed a banned URL.");
1106
//exits
1773
}
1774
return array('ok' => 1);
1775
}
1776
+ public static function ajax_adminEmailChoice_callback() {
1777
+ $choice = $_POST['choice'];
1778
+ wfConfig::set('adminEmailChoice', '1');
1779
+ if ($choice == 'mine') {
1780
+ $email = wp_get_current_user()->user_email;
1781
+ wfConfig::set('alertEmails', $email);
1782
+ }
1783
+ return array('ok' => 1);
1784
+ }
1785
public static function ajax_removeFromCache_callback(){
1786
$id = $_POST['id'];
1787
$link = get_permalink($id);
3478
'activityLogUpdate', 'ticker', 'loadIssues', 'updateIssueStatus', 'deleteIssue', 'updateAllIssues',
3479
'reverseLookup', 'unlockOutIP', 'loadBlockRanges', 'unblockRange', 'blockIPUARange', 'whois', 'unblockIP',
3480
'blockIP', 'permBlockIP', 'loadStaticPanel', 'saveConfig', 'downloadHtaccess', 'checkFalconHtaccess',
3481
+ 'updateConfig', 'saveCacheConfig', 'removeFromCache', 'autoUpdateChoice', 'adminEmailChoice', 'saveCacheOptions', 'clearPageCache',
3482
'getCacheStats', 'clearAllBlocked', 'killScan', 'saveCountryBlocking', 'saveScanSchedule', 'tourClosed',
3483
'welcomeClosed', 'startTourAgain', 'downgradeLicense', 'addTwoFactor', 'twoFacActivate', 'twoFacDel',
3484
'loadTwoFactor', 'loadAvgSitePerf', 'sendTestEmail', 'addCacheExclusion', 'removeCacheExclusion',
3582
echo '<div id="wordfenceConfigWarning" class="fade error"><p><strong>Wordfence could not get an API key from the Wordfence scanning servers when it activated.</strong> You can try to fix this by going to the Wordfence "options" page and hitting "Save Changes". This will cause Wordfence to retry fetching an API key for you. If you keep seeing this error it usually means your WordPress server can\'t connect to our scanning servers. You can try asking your WordPress host to allow your WordPress server to connect to noc1.wordfence.com.</p></div>';
3583
}
3584
public static function adminEmailWarning(){
3585
+ $url = network_admin_url('admin.php?page=WordfenceSecOpt&wafAction=useMineForAdminEmailAlerts');
3586
+ $dismissURL = network_admin_url('admin.php?page=WordfenceSecOpt&wafAction=dismissAdminEmailNotice&nonce=' .
3587
+ rawurlencode(wp_create_nonce('wfDismissAdminEmailWarning')));
3588
+ echo '<div id="wordfenceAdminEmailWarning" class="fade error"><p><strong>You have not set an administrator email address to receive alerts for Wordfence.</strong> Please <a href="' . self::getMyOptionsURL() . '">click here to go to the Wordfence Options Page</a> and set an email address where you will receive security alerts from this site.</p><p><a class="button button-small" href="#" onclick="wordfenceExt.adminEmailChoice(\'mine\'); return false;"">Use My Email Address</a>
3589
+ <a class="button button-small wf-dismiss-link" href="#" onclick="wordfenceExt.adminEmailChoice(\'no\'); return false;">Dismiss</a></p></div>';
3590
}
3591
public static function autoUpdateNotice(){
3592
echo '<div id="wordfenceAutoUpdateChoice" class="fade error"><p><strong>Do you want Wordfence to stay up-to-date automatically?</strong>&nbsp;&nbsp;&nbsp;<a href="#" onclick="wordfenceExt.autoUpdateChoice(\'yes\'); return false;">Yes, enable auto-update.</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href="#" onclick="wordfenceExt.autoUpdateChoice(\'no\'); return false;">No thanks.</a></p></div>';
3621
}
3622
}
3623
if(! $warningAdded){
3624
+ if(wfConfig::get('tourClosed') == '1' && (!wfConfig::get('alertEmails') && (!wfConfig::get('adminEmailChoice')))){
3625
$warningAdded = true;
3626
if(wfUtils::isAdminPageMU()){
3627
add_action('network_admin_notices', 'wordfence::adminEmailWarning');
3877
($serverInfo->isCGI() || $serverInfo->isFastCGI())),
3878
array("litespeed", 'LiteSpeed', $serverInfo->isLiteSpeed()),
3879
array("nginx", 'NGINX', $serverInfo->isNGINX()),
3880
+ array("iis", 'Windows (IIS)', $serverInfo->isIIS()),
3881
);
3882
$wafActionContent = '<p>To be as secure as possible, the Wordfence Web Application Firewall is designed
3883
to run via a PHP ini setting called <code>auto_prepend_file</code> in order to ensure it runs before any potentially
4480
(isset($_POST['author']) && is_numeric(preg_replace('/[^0-9]/', '', $_POST['author'])))
4481
)
4482
) {
4483
+ status_header(404);
4484
+ nocache_headers();
4485
+ include(get_404_template());
4486
+ exit;
4487
}
4488
return $query_vars;
4489
}
5126
if (WFWAF_AUTO_PREPEND && !WFWAF_SUBDIRECTORY_INSTALL) {
5127
echo '<div class="updated is-dismissible"><p>The installation was successful! Your site is protected to the fullest extent!</p></div>';
5128
} else {
5129
+ echo '<div class="notice notice-error"><p>The changes have not yet taken effect. If you are using LiteSpeed or IIS
5130
as your web server or CGI/FastCGI interface, you may need to wait a few minutes for the changes to take effect since the
5131
configuration files are sometimes cached. You also may need to select a different server configuration in order to
5132
complete this step, but wait for a few minutes before trying. You can try refreshing this page. </p></div>';
5222
case 'apache-suphp':
5223
case 'nginx':
5224
case 'litespeed':
5225
+ case 'iis':
5226
if (file_exists($userIniPath)) {
5227
$backups[] = $userIniPath;
5228
}
5374
case 'nginx':
5375
case 'apache-suphp':
5376
case 'litespeed':
5377
+ case 'iis':
5378
$autoPrependIni = sprintf("; Wordfence WAF
5379
auto_prepend_file = '%s'
5380
; END Wordfence WAF
lib/wordfenceHash.php CHANGED
@@ -199,12 +199,11 @@ class wordfenceHash {
199
//exits
200
}
201
202
- $exclude = WordfenceScanner::getExcludeFilePattern();
203
if ($exclude && preg_match($exclude, $realFile)) {
204
return;
205
}
206
207
-
208
//Put this after the fork, that way we will at least scan one more file after we fork if it takes us more than 10 seconds to search for the stoppedOnFile
209
if($this->stoppedOnFile && $file != $this->stoppedOnFile){
210
return;
@@ -230,99 +229,125 @@ class wordfenceHash {
230
if($this->malwareEnabled && $this->isMalwarePrefix($md5)){
231
$this->possibleMalware[] = array($file, $md5);
232
}
233
- if(isset($this->knownFiles['core'][$file])){
234
- if(strtoupper($this->knownFiles['core'][$file]) == $shac){
235
- $knownFile = 1;
236
- } else {
237
- if($this->coreEnabled){
238
- $localFile = ABSPATH . '/' . preg_replace('/^[\.\/]+/', '', $file);
239
- $fileContents = @file_get_contents($localFile);
240
- if($fileContents && (! preg_match('/<\?' . 'php[\r\n\s\t]*\/\/[\r\n\s\t]*Silence is golden\.[\r\n\s\t]*(?:\?>)?[\r\n\s\t]*#x2F;s', $fileContents))){ //<?php
241
- if(! $this->isSafeFile($shac)){
242
243
- $this->haveIssues['core'] = true;
244
- $this->engine->addIssue(
245
- 'file',
246
- 1,
247
- 'coreModified' . $file . $md5,
248
- 'coreModified' . $file,
249
- 'WordPress core file modified: ' . $file,
250
- "This WordPress core file has been modified and differs from the original file distributed with this version of WordPress.",
251
- array(
252
- 'file' => $file,
253
- 'cType' => 'core',
254
- 'canDiff' => true,
255
- 'canFix' => true,
256
- 'canDelete' => false
257
)
258
);
259
}
260
}
261
}
262
- }
263
- } else if(isset($this->knownFiles['plugins'][$file])){
264
- if(in_array($shac, $this->knownFiles['plugins'][$file])){
265
- $knownFile = 1;
266
- } else {
267
- if($this->pluginsEnabled){
268
- if(! $this->isSafeFile($shac)){
269
- $itemName = $this->knownFiles['plugins'][$file][0];
270
- $itemVersion = $this->knownFiles['plugins'][$file][1];
271
- $cKey = $this->knownFiles['plugins'][$file][2];
272
- $this->haveIssues['plugins'] = true;
273
- $this->engine->addIssue(
274
- 'file',
275
- 2,
276
- 'modifiedplugin' . $file . $md5,
277
- 'modifiedplugin' . $file,
278
- 'Modified plugin file: ' . $file,
279
- "This file belongs to plugin \"$itemName\" version \"$itemVersion\" and has been modified from the file that is distributed by WordPress.org for this version. Please use the link to see how the file has changed. If you have modified this file yourself, you can safely ignore this warning. If you see a lot of changed files in a plugin that have been made by the author, then try uninstalling and reinstalling the plugin to force an upgrade. Doing this is a workaround for plugin authors who don't manage their code correctly. [See our FAQ on www.wordfence.com for more info]",
280
- array(
281
- 'file' => $file,
282
- 'cType' => 'plugin',
283
- 'canDiff' => true,
284
- 'canFix' => true,
285
- 'canDelete' => false,
286
- 'cName' => $itemName,
287
- 'cVersion' => $itemVersion,
288
- 'cKey' => $cKey
289
)
290
);
291
}
292
- }
293
294
- }
295
- } else if(isset($this->knownFiles['themes'][$file])){
296
- if(in_array($shac, $this->knownFiles['themes'][$file])){
297
- $knownFile = 1;
298
- } else {
299
- if($this->themesEnabled){
300
- if(! $this->isSafeFile($shac)){
301
- $itemName = $this->knownFiles['themes'][$file][0];
302
- $itemVersion = $this->knownFiles['themes'][$file][1];
303
- $cKey = $this->knownFiles['themes'][$file][2];
304
- $this->haveIssues['themes'] = true;
305
- $this->engine->addIssue(
306
- 'file',
307
- 2,
308
- 'modifiedtheme' . $file . $md5,
309
- 'modifiedtheme' . $file,
310
- 'Modified theme file: ' . $file,
311
- "This file belongs to theme \"$itemName\" version \"$itemVersion\" and has been modified from the original distribution. It is common for site owners to modify their theme files, so if you have modified this file yourself you can safely ignore this warning.",
312
- array(
313
- 'file' => $file,
314
- 'cType' => 'theme',
315
- 'canDiff' => true,
316
- 'canFix' => true,
317
- 'canDelete' => false,
318
- 'cName' => $itemName,
319
- 'cVersion' => $itemVersion,
320
- 'cKey' => $cKey
321
)
322
);
323
}
324
- }
325
326
}
327
}
328
// knownFile means that the file is both part of core or a known plugin or theme AND that we recognize the file's hash.
199
//exits
200
}
201
202
+ $exclude = wordfenceScanner::getExcludeFilePattern(wordfenceScanner::EXCLUSION_PATTERNS_USER);
203
if ($exclude && preg_match($exclude, $realFile)) {
204
return;
205
}
206
207
//Put this after the fork, that way we will at least scan one more file after we fork if it takes us more than 10 seconds to search for the stoppedOnFile
208
if($this->stoppedOnFile && $file != $this->stoppedOnFile){
209
return;
229
if($this->malwareEnabled && $this->isMalwarePrefix($md5)){
230
$this->possibleMalware[] = array($file, $md5);
231
}
232
+
233
+ $knownFileExclude = wordfenceScanner::getExcludeFilePattern(wordfenceScanner::EXCLUSION_PATTERNS_KNOWN_FILES);
234
+ $allowKnownFileScan = true;
235
+ if ($knownFileExclude) {
236
+ $allowKnownFileScan = !preg_match($knownFileExclude, $realFile);
237
+ }
238
+
239
+ if ($allowKnownFileScan)
240
+ {
241
+ if (isset($this->knownFiles['core'][$file]))
242
+ {
243
+ if (strtoupper($this->knownFiles['core'][$file]) == $shac)
244
+ {
245
+ $knownFile = 1;
246
+ } else
247
+ {
248
+ if ($this->coreEnabled)
249
+ {
250
+ $localFile = ABSPATH . '/' . preg_replace('/^[\.\/]+/', '', $file);
251
+ $fileContents = @file_get_contents($localFile);
252
+ if ($fileContents && (!preg_match('/<\?' . 'php[\r\n\s\t]*\/\/[\r\n\s\t]*Silence is golden\.[\r\n\s\t]*(?:\?>)?[\r\n\s\t]*#x2F;s', $fileContents)))
253
+ { //<?php
254
+ if (!$this->isSafeFile($shac))
255
+ {
256
257
+ $this->haveIssues['core'] = true;
258
+ $this->engine->addIssue(
259
+ 'file',
260
+ 1,
261
+ 'coreModified' . $file . $md5,
262
+ 'coreModified' . $file,
263
+ 'WordPress core file modified: ' . $file,
264
+ "This WordPress core file has been modified and differs from the original file distributed with this version of WordPress.",
265
+ array(
266
+ 'file' => $file,
267
+ 'cType' => 'core',
268
+ 'canDiff' => true,
269
+ 'canFix' => true,
270
+ 'canDelete' => false
271
)
272
);
273
+ }
274
}
275
}
276
}
277
+ } else if (isset($this->knownFiles['plugins'][$file]))
278
+ {
279
+ if (in_array($shac, $this->knownFiles['plugins'][$file]))
280
+ {
281
+ $knownFile = 1;
282
+ } else
283
+ {
284
+ if ($this->pluginsEnabled)
285
+ {
286
+ if (!$this->isSafeFile($shac))
287
+ {
288
+ $itemName = $this->knownFiles['plugins'][$file][0];
289
+ $itemVersion = $this->knownFiles['plugins'][$file][1];
290
+ $cKey = $this->knownFiles['plugins'][$file][2];
291
+ $this->haveIssues['plugins'] = true;
292
+ $this->engine->addIssue(
293
+ 'file',
294
+ 2,
295
+ 'modifiedplugin' . $file . $md5,
296
+ 'modifiedplugin' . $file,
297
+ 'Modified plugin file: ' . $file,
298
+ "This file belongs to plugin \"$itemName\" version \"$itemVersion\" and has been modified from the file that is distributed by WordPress.org for this version. Please use the link to see how the file has changed. If you have modified this file yourself, you can safely ignore this warning. If you see a lot of changed files in a plugin that have been made by the author, then try uninstalling and reinstalling the plugin to force an upgrade. Doing this is a workaround for plugin authors who don't manage their code correctly. [See our FAQ on www.wordfence.com for more info]",
299
+ array(
300
+ 'file' => $file,
301
+ 'cType' => 'plugin',
302
+ 'canDiff' => true,
303
+ 'canFix' => true,
304
+ 'canDelete' => false,
305
+ 'cName' => $itemName,
306
+ 'cVersion' => $itemVersion,
307
+ 'cKey' => $cKey
308
)
309
);
310
+ }
311
}
312
313
+ }
314
+ } else if (isset($this->knownFiles['themes'][$file]))
315
+ {
316
+ if (in_array($shac, $this->knownFiles['themes'][$file]))
317
+ {
318
+ $knownFile = 1;
319
+ } else
320
+ {
321
+ if ($this->themesEnabled)
322
+ {
323
+ if (!$this->isSafeFile($shac))
324
+ {
325
+ $itemName = $this->knownFiles['themes'][$file][0];
326
+ $itemVersion = $this->knownFiles['themes'][$file][1];
327
+ $cKey = $this->knownFiles['themes'][$file][2];
328
+ $this->haveIssues['themes'] = true;
329
+ $this->engine->addIssue(
330
+ 'file',
331
+ 2,
332
+ 'modifiedtheme' . $file . $md5,
333
+ 'modifiedtheme' . $file,
334
+ 'Modified theme file: ' . $file,
335
+ "This file belongs to theme \"$itemName\" version \"$itemVersion\" and has been modified from the original distribution. It is common for site owners to modify their theme files, so if you have modified this file yourself you can safely ignore this warning.",
336
+ array(
337
+ 'file' => $file,
338
+ 'cType' => 'theme',
339
+ 'canDiff' => true,
340
+ 'canFix' => true,
341
+ 'canDelete' => false,
342
+ 'cName' => $itemName,
343
+ 'cVersion' => $itemVersion,
344
+ 'cKey' => $cKey
345
)
346
);
347
+ }
348
}
349
350
+ }
351
}
352
}
353
// knownFile means that the file is both part of core or a known plugin or theme AND that we recognize the file's hash.
lib/wordfenceScanner.php CHANGED
@@ -3,6 +3,24 @@ require_once('wordfenceConstants.php');
3
require_once('wordfenceClass.php');
4
require_once('wordfenceURLHoover.php');
5
class wordfenceScanner {
6
//serialized:
7
protected $path = '';
8
protected $results = array();
@@ -14,7 +32,10 @@ class wordfenceScanner {
14
protected $lastStatusTime = false;
15
protected $patterns = "";
16
protected $api = false;
17
- protected static $excludePattern = NULL;
18
/** @var wfScanEngine */
19
protected $scanEngine;
20
@@ -87,29 +108,46 @@ class wordfenceScanner {
87
}
88
89
/**
90
- * Return regular expression to exclude files or false if
91
- * there is no pattern
92
*
93
- * @return string|boolean
94
*/
95
- public static function getExcludeFilePattern() {
96
- if (self::$excludePattern !== NULL) {
97
- return self::$excludePattern;
98
}
99
- if(wfConfig::get('scan_exclude', false)){
100
- $exParts = explode("\n", wfUtils::cleanupOneEntryPerLine(wfConfig::get('scan_exclude')));
101
foreach($exParts as &$exPart){
102
$exPart = preg_quote(trim($exPart), '/');
103
$exPart = preg_replace('/\\\\\*/', '.*', $exPart);
104
}
105
106
- self::$excludePattern = '/^(?:' . implode('|', array_filter($exParts)) . ')#x2F;i';
107
- self::$excludePattern = '/(?:' . implode('|', array_filter($exParts)) . ')#x2F;i';
108
- } else {
109
- self::$excludePattern = false;
110
}
111
112
- return self::$excludePattern;
113
}
114
115
/**
@@ -127,7 +165,7 @@ class wordfenceScanner {
127
}
128
$db = new wfDB();
129
$lastCount = 'whatever';
130
- $excludePattern = self::getExcludeFilePattern();
131
while(true){
132
$thisCount = $db->querySingle("select count(*) from " . $db->prefix() . "wfFileMods where oldMD5 != newMD5 and knownFile=0");
133
if($thisCount == $lastCount){
3
require_once('wordfenceClass.php');
4
require_once('wordfenceURLHoover.php');
5
class wordfenceScanner {
6
+ /*
7
+ * Mask to return all patterns in the exclusion list.
8
+ * @var int
9
+ */
10
+ const EXCLUSION_PATTERNS_ALL = PHP_INT_MAX;
11
+ /*
12
+ * Mask for patterns that the user has added.
13
+ */
14
+ const EXCLUSION_PATTERNS_USER = 0x1;
15
+ /*
16
+ * Mask for patterns that should be excluded from the known files scan.
17
+ */
18
+ const EXCLUSION_PATTERNS_KNOWN_FILES = 0x2;
19
+ /*
20
+ * Mask for patterns that should be excluded from the malware scan.
21
+ */
22
+ const EXCLUSION_PATTERNS_MALWARE = 0x4;
23
+
24
//serialized:
25
protected $path = '';
26
protected $results = array();
32
protected $lastStatusTime = false;
33
protected $patterns = "";
34
protected $api = false;
35
+ protected static $excludePatterns = array();
36
+ protected static $builtinExclusions = array(
37
+ array('pattern' => 'wp-includes/version.php', 'include' => self::EXCLUSION_PATTERNS_KNOWN_FILES), //Excluded from the known files scan because non-en_US installations will have extra content that fails the check, still in malware scan
38
+ );
39
/** @var wfScanEngine */
40
protected $scanEngine;
41
108
}
109
110
/**
111
+ * Return regular expression to exclude files or false if
112
+ * there is no pattern
113
*
114
+ * @param $whichPatterns int Bitmask indicating which patterns to include.
115
+ * @return string|boolean
116
*/
117
+ public static function getExcludeFilePattern($whichPatterns = self::EXCLUSION_PATTERNS_USER) {
118
+ if (isset(self::$excludePatterns[$whichPatterns])) {
119
+ return self::$excludePatterns[$whichPatterns];
120
}
121
+
122
+ $exParts = array();
123
+ if (($whichPatterns & self::EXCLUSION_PATTERNS_USER) > 0)
124
+ {
125
+ if (wfConfig::get('scan_exclude', false))
126
+ {
127
+ $exParts = explode("\n", wfUtils::cleanupOneEntryPerLine(wfConfig::get('scan_exclude')));
128
+ }
129
+ }
130
+
131
+ foreach (self::$builtinExclusions as $pattern) {
132
+ if (($pattern['include'] & $whichPatterns) > 0) {
133
+ $exParts[] = $pattern['pattern'];
134
+ }
135
+ }
136
+
137
+ if (!empty($exParts)) {
138
foreach($exParts as &$exPart){
139
$exPart = preg_quote(trim($exPart), '/');
140
$exPart = preg_replace('/\\\\\*/', '.*', $exPart);
141
}
142
143
+ //self::$excludePattern = '/^(?:' . implode('|', array_filter($exParts)) . ')#x2F;i';
144
+ self::$excludePatterns[$whichPatterns] = '/(?:' . implode('|', array_filter($exParts)) . ')#x2F;i';
145
+ }
146
+ else {
147
+ self::$excludePatterns[$whichPatterns]= false;
148
}
149
150
+ return self::$excludePatterns[$whichPatterns];
151
}
152
153
/**
165
}
166
$db = new wfDB();
167
$lastCount = 'whatever';
168
+ $excludePattern = self::getExcludeFilePattern(self::EXCLUSION_PATTERNS_USER & self::EXCLUSION_PATTERNS_MALWARE);
169
while(true){
170
$thisCount = $db->querySingle("select count(*) from " . $db->prefix() . "wfFileMods where oldMD5 != newMD5 and knownFile=0");
171
if($thisCount == $lastCount){
readme.txt CHANGED
@@ -2,8 +2,8 @@
2
Contributors: mmaunder
3
Tags: wordpress, security, web application firewall, waf, performance, speed, caching, cache, caching plugin, wordpress cache, wordpress caching, wordpress security, security plugin, secure, anti-virus, malware, firewall, antivirus, virus, google safe browsing, phishing, scrapers, hacking, wordfence, securty, secrity, secure, two factor, cellphone sign-in, cellphone signin, cellphone, twofactor, security, secure, htaccess, login, log, users, login alerts, lock, chmod, maintenance, plugin, private, privacy, protection, permissions, 503, base64, injection, code, encode, script, attack, hack, hackers, block, blocked, prevent, prevention, RFI, XSS, CRLF, CSRF, SQL Injection, vulnerability, website security, WordPress security, security log, logging, HTTP log, error log, login security, personal security, infrastructure security, firewall security, front-end security, web server security, proxy security, reverse proxy security, secure website, secure login, two factor security, two factor authentication, maximum login security, heartbleed, heart bleed, heartbleed vulnerability, openssl vulnerability, nginx, litespeed, php5-fpm, woocommerce support, woocommerce caching, IPv6, IP version 6
4
Requires at least: 3.9
5
- Tested up to: 4.5
6
- Stable tag: 6.1.4
7
8
The Wordfence WordPress security plugin provides free enterprise-class WordPress security, protecting your website from hacks and malware.
9
== Description ==
@@ -195,22 +195,32 @@ Designed for every skill level, [The WordPress Security Learning Center](https:/
195
196
== Changelog ==
197
198
= 6.1.4 =
199
- Fix: Fixed potential bug with 'stored data not found after a fork. Got type: boolean'.
200
- Improvement: Added bulk actions and filters to WAF whitelist table.
201
- Improvement: Added a check while in learning mode to verify the response is not 404 before whitelising.
202
- Fix: Added index to attackLogTime. wfHits trimmed on runInstall now.
203
- Fix: Fixed attack data sync for hosts that cannot use wp-cron.
204
- Improvement: Use wftest@wordfence.com as the Diagnostics page default email address.
205
- Improvement: When WFWAF_ENABLED is set to false to disable the firewall, show this on the Firewall page.
206
- Fix: Prevent warnings when $_SERVER is empty.
207
- Fix: Bug fix for illegal string offset.
208
- Fix: Hooked up multibyte string functions to binary safe equivalents.
209
- Fix: Hooked up reverse IP lookup in Live Traffic.
210
- Fix: Add the user the web server (or PHP) is currently running as to Diagnostics page.
211
- Improvement: Pause Live Traffic after scrolling past the first entry.
212
- Improvement: Move "Permanently block all temporarily blocked IP addresses" button to top of blocked IP list.
213
- Fix: Added JSON fallback for PHP installations that don't have JSON enabled.
214
215
= 6.1.3 =
216
* Improvement: Added dismiss button to the Wordfence WAF setup admin notice.
2
Contributors: mmaunder
3
Tags: wordpress, security, web application firewall, waf, performance, speed, caching, cache, caching plugin, wordpress cache, wordpress caching, wordpress security, security plugin, secure, anti-virus, malware, firewall, antivirus, virus, google safe browsing, phishing, scrapers, hacking, wordfence, securty, secrity, secure, two factor, cellphone sign-in, cellphone signin, cellphone, twofactor, security, secure, htaccess, login, log, users, login alerts, lock, chmod, maintenance, plugin, private, privacy, protection, permissions, 503, base64, injection, code, encode, script, attack, hack, hackers, block, blocked, prevent, prevention, RFI, XSS, CRLF, CSRF, SQL Injection, vulnerability, website security, WordPress security, security log, logging, HTTP log, error log, login security, personal security, infrastructure security, firewall security, front-end security, web server security, proxy security, reverse proxy security, secure website, secure login, two factor security, two factor authentication, maximum login security, heartbleed, heart bleed, heartbleed vulnerability, openssl vulnerability, nginx, litespeed, php5-fpm, woocommerce support, woocommerce caching, IPv6, IP version 6
4
Requires at least: 3.9
5
+ Tested up to: 4.5.1
6
+ Stable tag: 6.1.5
7
8
The Wordfence WordPress security plugin provides free enterprise-class WordPress security, protecting your website from hacks and malware.
9
== Description ==
195
196
== Changelog ==
197
198
+ = 6.1.5 =
199
+ * Fix: WordPress language files no longer flagged as changed.
200
+ * Improvement: Accept wildcards in "Immediately block IP's that access these URLs."
201
+ * Fix: Fixed bug when multiple authors have published posts, /?author=N scans show an author archive page.
202
+ * Fix: Fixed issue with IPv6 mapped IPv4 addresses not being treated as IPv4.
203
+ * Improvement: Added WordPress version and various constants to Diagnostics report.
204
+ * Fix: Fixed bug with Windows users unable to save Firewall config.
205
+ * Improvement: Include option for IIS on Windows in Firewall config process, and recommend manual php.ini change only.
206
+ * Fix: Made the 'administrator email address' admin notice dismissable.
207
+
208
= 6.1.4 =
209
+ * Fix: Fixed potential bug with 'stored data not found after a fork. Got type: boolean'.
210
+ * Improvement: Added bulk actions and filters to WAF whitelist table.
211
+ * Improvement: Added a check while in learning mode to verify the response is not 404 before whitelising.
212
+ * Fix: Added index to attackLogTime. wfHits trimmed on runInstall now.
213
+ * Fix: Fixed attack data sync for hosts that cannot use wp-cron.
214
+ * Improvement: Use wftest@wordfence.com as the Diagnostics page default email address.
215
+ * Improvement: When WFWAF_ENABLED is set to false to disable the firewall, show this on the Firewall page.
216
+ * Fix: Prevent warnings when $_SERVER is empty.
217
+ * Fix: Bug fix for illegal string offset.
218
+ * Fix: Hooked up multibyte string functions to binary safe equivalents.
219
+ * Fix: Hooked up reverse IP lookup in Live Traffic.
220
+ * Fix: Add the user the web server (or PHP) is currently running as to Diagnostics page.
221
+ * Improvement: Pause Live Traffic after scrolling past the first entry.
222
+ * Improvement: Move "Permanently block all temporarily blocked IP addresses" button to top of blocked IP list.
223
+ * Fix: Added JSON fallback for PHP installations that don't have JSON enabled.
224
225
= 6.1.3 =
226
* Improvement: Added dismiss button to the Wordfence WAF setup admin notice.
vendor/wordfence/wf-waf/src/init.php CHANGED
@@ -4,7 +4,7 @@ define('WFWAF_VERSION', '1.0.0');
4
define('WFWAF_PATH', dirname(__FILE__) . '/');
5
define('WFWAF_LIB_PATH', WFWAF_PATH . 'lib/');
6
define('WFWAF_VIEW_PATH', WFWAF_PATH . 'views/');
7
- define('WFWAF_API_URL_SEC', 'https://noc4.wordfence.com/v1.1/');
8
if (!defined('WFWAF_DEBUG')) {
9
define('WFWAF_DEBUG', false);
10
}
@@ -12,6 +12,8 @@ if (!defined('WFWAF_ENABLED')) {
12
define('WFWAF_ENABLED', true);
13
}
14
15
require_once WFWAF_LIB_PATH . 'waf.php';
16
require_once WFWAF_LIB_PATH . 'utils.php';
17
4
define('WFWAF_PATH', dirname(__FILE__) . '/');
5
define('WFWAF_LIB_PATH', WFWAF_PATH . 'lib/');
6
define('WFWAF_VIEW_PATH', WFWAF_PATH . 'views/');
7
+ define('WFWAF_API_URL_SEC', 'https://noc4.wordfence.com/v1.2/');
8
if (!defined('WFWAF_DEBUG')) {
9
define('WFWAF_DEBUG', false);
10
}
12
define('WFWAF_ENABLED', true);
13
}
14
15
+ define('WFWAF_IS_WINDOWS', strtoupper(substr(PHP_OS, 0, 3)) === 'WIN');
16
+
17
require_once WFWAF_LIB_PATH . 'waf.php';
18
require_once WFWAF_LIB_PATH . 'utils.php';
19
vendor/wordfence/wf-waf/src/lib/parser/lexer.php CHANGED
@@ -301,6 +301,18 @@ class wfWAFBaseParser {
301
$this->lexer = $lexer;
302
}
303
304
/**
305
* @param wfWAFLexerToken $token
306
* @param int $type
301
$this->lexer = $lexer;
302
}
303
304
+ /**
305
+ * @param wfWAFLexerToken $token
306
+ * @param mixed $type
307
+ * @return bool
308
+ */
309
+ protected function isTokenOfType($token, $type) {
310
+ if (is_array($type)) {
311
+ return $token && in_array($token->getType(), $type);
312
+ }
313
+ return $token && $token->getType() === $type;
314
+ }
315
+
316
/**
317
* @param wfWAFLexerToken $token
318
* @param int $type
vendor/wordfence/wf-waf/src/lib/parser/parser.php CHANGED
@@ -50,6 +50,7 @@ class wfWAFRuleParser extends wfWAFBaseParser {
50
$action->getCategory(),
51
$action->getScore(),
52
$action->getDescription(),
53
$action->getAction(),
54
$comparisonGroup
55
);
@@ -312,22 +313,38 @@ class wfWAFRuleParser extends wfWAFBaseParser {
312
$subject = array(
313
$globalToken->getValue() . '.' . $globalToken2->getValue(),
314
);
315
- while (true) {
316
- $dotToken = $this->expectNextToken();
317
- if ($dotToken->getType() !== wfWAFRuleLexer::T_DOT) {
318
- $this->index--;
319
- break;
320
- }
321
- $paramToken = $this->expectNextToken();
322
- $this->expectTokenTypeEquals($paramToken, wfWAFRuleLexer::T_IDENTIFIER);
323
- $subject[] = $paramToken->getValue();
324
}
325
if (count($subject) === 1) {
326
list($subject) = $subject;
327
}
328
return $subject;
329
}
330
331
/**
332
* @return wfWAFRuleParserURLParam
333
* @throws wfWAFParserSyntaxError
@@ -411,6 +428,17 @@ class wfWAFRuleParser extends wfWAFBaseParser {
411
return $value;
412
}
413
414
/**
415
* @param wfWAFLexerToken $token
416
* @return bool
@@ -441,6 +469,7 @@ class wfWAFRuleParserAction {
441
private $category;
442
private $score;
443
private $description;
444
private $action;
445
446
/**
@@ -529,6 +558,20 @@ class wfWAFRuleParserAction {
529
$this->description = $description;
530
}
531
532
/**
533
* @return mixed
534
*/
@@ -588,7 +631,9 @@ class wfWAFRuleParserURLParam {
588
* @return string
589
*/
590
public function renderRule($action) {
591
- return sprintf('%s(url=%s, param=%s%s)', $action, wfWAFRule::exportString($this->getUrl()), $this->renderParam($this->getParam()),
592
$this->getRules() ? ', rules=[' . join(', ', array_map('intval', $this->getRules())) . ']' : '');
593
}
594
@@ -597,7 +642,21 @@ class wfWAFRuleParserURLParam {
597
* @return mixed
598
*/
599
private function renderParam($param) {
600
- return str_replace(array('[', ']'), array('.', ''), $param);
601
}
602
603
/**
50
$action->getCategory(),
51
$action->getScore(),
52
$action->getDescription(),
53
+ $action->getWhitelist(),
54
$action->getAction(),
55
$comparisonGroup
56
);
313
$subject = array(
314
$globalToken->getValue() . '.' . $globalToken2->getValue(),
315
);
316
+ $savePoint = $this->index;
317
+ while (($property = $this->parsePropertyAccessor()) !== false) {
318
+ $subject[] = $property;
319
+ $savePoint = $this->index;
320
}
321
+ $this->index = $savePoint;
322
if (count($subject) === 1) {
323
list($subject) = $subject;
324
}
325
return $subject;
326
}
327
328
+ /**
329
+ * @return bool|mixed|string
330
+ * @throws wfWAFParserSyntaxError
331
+ */
332
+ private function parsePropertyAccessor() {
333
+ $savePoint = $this->index;
334
+ $nextToken = $this->nextToken();
335
+ if ($this->isTokenOfType($nextToken, wfWAFRuleLexer::T_DOT)) {
336
+ $property = $this->expectNextToken();
337
+ $this->expectTokenTypeEquals($property, wfWAFRuleLexer::T_IDENTIFIER);
338
+ return $property->getValue();
339
+ } else if ($this->isTokenOfType($nextToken, wfWAFRuleLexer::T_OPEN_BRACKET)) {
340
+ $property = $this->expectLiteral();
341
+ $this->expectTokenTypeEquals($this->expectNextToken(), wfWAFRuleLexer::T_CLOSE_BRACKET);
342
+ return $property;
343
+ }
344
+ $this->index = $savePoint;
345
+ return false;
346
+ }
347
+
348
/**
349
* @return wfWAFRuleParserURLParam
350
* @throws wfWAFParserSyntaxError
428
return $value;
429
}
430
431
+ /**
432
+ * @param wfWAFLexerToken $token
433
+ * @param string|array $value
434
+ * @return bool
435
+ */
436
+ private function isIdentifierWithValue($token, $value) {
437
+ return $token && $token->getType() === wfWAFRuleLexer::T_IDENTIFIER &&
438
+ (is_array($value) ? in_array($token->getLowerCaseValue(), array_map('strtolower', $value)) :
439
+ $token->getLowerCaseValue() === strtolower($value));
440
+ }
441
+
442
/**
443
* @param wfWAFLexerToken $token
444
* @return bool
469
private $category;
470
private $score;
471
private $description;
472
+ private $whitelist = 1;
473
private $action;
474
475
/**
558
$this->description = $description;
559
}
560
561
+ /**
562
+ * @return mixed
563
+ */
564
+ public function getWhitelist() {
565
+ return $this->whitelist;
566
+ }
567
+
568
+ /**
569
+ * @param mixed $whitelist
570
+ */
571
+ public function setWhitelist($whitelist) {
572
+ $this->whitelist = $whitelist;
573
+ }
574
+
575
/**
576
* @return mixed
577
*/
631
* @return string
632
*/
633
public function renderRule($action) {
634
+ return sprintf('%s(url=%s, param=%s%s)', $action,
635
+ wfWAFRule::exportString($this->getUrl()),
636
+ $this->renderParam($this->getParam()),
637
$this->getRules() ? ', rules=[' . join(', ', array_map('intval', $this->getRules())) . ']' : '');
638
}
639
642
* @return mixed
643
*/
644
private function renderParam($param) {
645
+ if (preg_match('/([a-zA-Z_][\\w_]*?\\.[a-zA-Z_][\\w_]*)(.*)/', $param, $matches)) {
646
+ list(, $global, $params) = $matches;
647
+ if (strlen($params) > 0) {
648
+ if (preg_match_all('/\\[([^\\]]*?)\\]/', $params, $matches)) {
649
+ $rendered = $global;
650
+ foreach ($matches[1] as $prop) {
651
+ $single = "'" . str_replace(array("'", '\\'), array("\\'", "\\\\"), $prop) . "'";
652
+ $double = '"' . str_replace(array('"', '\\'), array('\\"', "\\\\"), $prop) . '"';
653
+ $rendered .= sprintf('[%s]', strlen($single) <= strlen($double) ? $single : $double);
654
+ }
655
+ return $rendered;
656
+ }
657
+ }
658
+ }
659
+ return $param;
660
}
661
662
/**
vendor/wordfence/wf-waf/src/lib/parser/sqli.php CHANGED
@@ -2562,18 +2562,6 @@ class wfWAFSQLiParser extends wfWAFBaseParser {
2562
$token->getLowerCaseValue() === wfWAFUtils::strtolower($value));
2563
}
2564
2565
- /**
2566
- * @param wfWAFLexerToken $token
2567
- * @param mixed $type
2568
- * @return bool
2569
- */
2570
- private function isTokenOfType($token, $type) {
2571
- if (is_array($type)) {
2572
- return $token && in_array($token->getType(), $type);
2573
- }
2574
- return $token && $token->getType() === $type;
2575
- }
2576
-
2577
/**
2578
* @param wfWAFLexerToken $token
2579
* @return bool
2562
$token->getLowerCaseValue() === wfWAFUtils::strtolower($value));
2563
}
2564
2565
/**
2566
* @param wfWAFLexerToken $token
2567
* @return bool
vendor/wordfence/wf-waf/src/lib/rules.php CHANGED
@@ -25,6 +25,7 @@ class wfWAFRule implements wfWAFRuleInterface {
25
private $category;
26
private $score;
27
private $description;
28
private $action;
29
private $comparisonGroup;
30
/**
@@ -39,12 +40,32 @@ class wfWAFRule implements wfWAFRuleInterface {
39
* @param string $category
40
* @param int $score
41
* @param string $description
42
* @param string $action
43
* @param wfWAFRuleComparisonGroup $comparisonGroup
44
* @return wfWAFRule
45
*/
46
- public static function create($waf, $ruleID, $type, $category, $score, $description, $action, $comparisonGroup) {
47
- return new self($waf, $ruleID, $type, $category, $score, $description, $action, $comparisonGroup);
48
}
49
50
/**
@@ -62,16 +83,18 @@ class wfWAFRule implements wfWAFRuleInterface {
62
* @param string $category
63
* @param int $score
64
* @param string $description
65
* @param string $action
66
* @param wfWAFRuleComparisonGroup $comparisonGroup
67
*/
68
- public function __construct($waf, $ruleID, $type, $category, $score, $description, $action, $comparisonGroup) {
69
$this->setWAF($waf);
70
$this->setRuleID($ruleID);
71
$this->setType($type);
72
$this->setCategory($category);
73
$this->setScore($score);
74
$this->setDescription($description);
75
$this->setAction($action);
76
$this->setComparisonGroup($comparisonGroup);
77
}
@@ -80,12 +103,13 @@ class wfWAFRule implements wfWAFRuleInterface {
80
* @return string
81
*/
82
public function render() {
83
- return sprintf('%s::create($this, %d, %s, %s, %s, %s, %s, %s)', get_class($this),
84
$this->getRuleID(),
85
var_export($this->getType(), true),
86
var_export($this->getCategory(), true),
87
var_export($this->getScore(), true),
88
var_export($this->getDescription(), true),
89
var_export($this->getAction(), true),
90
$this->getComparisonGroup()->render()
91
);
@@ -106,7 +130,8 @@ RULE
106
$this->getRuleID() ? 'id=' . (int) $this->getRuleID() : '',
107
$this->getCategory() ? 'category=' . self::exportString($this->getCategory()) : '',
108
$this->getScore() > 0 ? 'score=' . (int) $this->getScore() : '',
109
- $this->getCategory() ? 'description=' . self::exportString($this->getDescription()) : '',
110
)))
111
);
112
}
@@ -140,6 +165,7 @@ RULE
140
'category' => $this->getCategory(),
141
'score' => $this->getScore(),
142
'description' => $this->getDescription(),
143
'action' => $this->getAction(),
144
);
145
}
@@ -214,6 +240,20 @@ RULE
214
$this->description = $description;
215
}
216
217
/**
218
* @return string
219
*/
@@ -415,6 +455,7 @@ class wfWAFRuleComparison implements wfWAFRuleInterface {
415
'lengthlessthan',
416
'currentuseris',
417
'currentuserisnot',
418
);
419
420
/**
@@ -653,6 +694,10 @@ class wfWAFRuleComparison implements wfWAFRuleInterface {
653
return !$this->currentUserIs($subject);
654
}
655
656
/**
657
* @return mixed
658
*/
25
private $category;
26
private $score;
27
private $description;
28
+ private $whitelist;
29
private $action;
30
private $comparisonGroup;
31
/**
40
* @param string $category
41
* @param int $score
42
* @param string $description
43
+ * @param int $whitelist
44
* @param string $action
45
* @param wfWAFRuleComparisonGroup $comparisonGroup
46
* @return wfWAFRule
47
*/
48
+ public static function create() {
49
+ $waf = func_get_arg(0);
50
+ $ruleID = func_get_arg(1);
51
+ $type = func_get_arg(2);
52
+ $category = func_get_arg(3);
53
+ $score = func_get_arg(4);
54
+ $description = func_get_arg(5);
55
+ $whitelist = 1;
56
+ $action = '';
57
+ $comparisonGroup = null;
58
+ //Compatibility with old compiled rules
59
+ if (func_num_args() == 8) { //Pre-whitelist flag
60
+ $action = func_get_arg(6);
61
+ $comparisonGroup = func_get_arg(7);
62
+ }
63
+ else if (func_num_args() == 9) { //Whitelist flag
64
+ $whitelist = func_get_arg(6);
65
+ $action = func_get_arg(7);
66
+ $comparisonGroup = func_get_arg(8);
67
+ }
68
+ return new self($waf, $ruleID, $type, $category, $score, $description, $whitelist, $action, $comparisonGroup);
69
}
70
71
/**
83
* @param string $category
84
* @param int $score
85
* @param string $description
86
+ * @param int $whitelist
87
* @param string $action
88
* @param wfWAFRuleComparisonGroup $comparisonGroup
89
*/
90
+ public function __construct($waf, $ruleID, $type, $category, $score, $description, $whitelist, $action, $comparisonGroup) {
91
$this->setWAF($waf);
92
$this->setRuleID($ruleID);
93
$this->setType($type);
94
$this->setCategory($category);
95
$this->setScore($score);
96
$this->setDescription($description);
97
+ $this->setWhitelist($whitelist);
98
$this->setAction($action);
99
$this->setComparisonGroup($comparisonGroup);
100
}
103
* @return string
104
*/
105
public function render() {
106
+ return sprintf('%s::create($this, %d, %s, %s, %s, %s, %d, %s, %s)', get_class($this),
107
$this->getRuleID(),
108
var_export($this->getType(), true),
109
var_export($this->getCategory(), true),
110
var_export($this->getScore(), true),
111
var_export($this->getDescription(), true),
112
+ var_export($this->getWhitelist(), true),
113
var_export($this->getAction(), true),
114
$this->getComparisonGroup()->render()
115
);
130
$this->getRuleID() ? 'id=' . (int) $this->getRuleID() : '',
131
$this->getCategory() ? 'category=' . self::exportString($this->getCategory()) : '',
132
$this->getScore() > 0 ? 'score=' . (int) $this->getScore() : '',
133
+ $this->getDescription() ? 'description=' . self::exportString($this->getDescription()) : '',
134
+ $this->getWhitelist() == 0 ? 'whitelist=0' : '',
135
)))
136
);
137
}
165
'category' => $this->getCategory(),
166
'score' => $this->getScore(),
167
'description' => $this->getDescription(),
168
+ 'whitelist' => $this->getWhitelist(),
169
'action' => $this->getAction(),
170
);
171
}
240
$this->description = $description;
241
}
242
243
+ /**
244
+ * @return int
245
+ */
246
+ public function getWhitelist() {
247
+ return $this->whitelist;
248
+ }
249
+
250
+ /**
251
+ * @param string $whitelist
252
+ */
253
+ public function setWhitelist($whitelist) {
254
+ $this->whitelist = $whitelist;
255
+ }
256
+
257
/**
258
* @return string
259
*/
455
'lengthlessthan',
456
'currentuseris',
457
'currentuserisnot',
458
+ 'md5equals',
459
);
460
461
/**
694
return !$this->currentUserIs($subject);
695
}
696
697
+ public function md5Equals($subject) {
698
+ return md5((string) $subject) === $this->getExpected();
699
+ }
700
+
701
/**
702
* @return mixed
703
*/
vendor/wordfence/wf-waf/src/lib/storage/file.php CHANGED
@@ -482,7 +482,17 @@ class wfWAFStorageFile implements wfWAFStorageInterface {
482
return;
483
}
484
485
- wfWAFStorageFile::atomicFilePutContents($this->getConfigFile(), self::LOG_FILE_HEADER . serialize($this->data));
486
}
487
488
/**
@@ -1051,7 +1061,11 @@ class wfWAFAttackDataStorageFileEngine {
1051
public function truncate() {
1052
$defaultHeader = $this->getDefaultHeader();
1053
$this->close();
1054
- wfWAFStorageFile::atomicFilePutContents($this->getFile(), $defaultHeader, 'attack');
1055
$this->header = array();
1056
$this->offsetTable = array();
1057
$this->open();
482
return;
483
}
484
485
+ if (WFWAF_IS_WINDOWS) {
486
+ self::lock($this->configFileHandle, LOCK_UN);
487
+ fclose($this->configFileHandle);
488
+ file_put_contents($this->getConfigFile(), self::LOG_FILE_HEADER . serialize($this->data), LOCK_EX);
489
+ } else {
490
+ wfWAFStorageFile::atomicFilePutContents($this->getConfigFile(), self::LOG_FILE_HEADER . serialize($this->data));
491
+ }
492
+
493
+ if (WFWAF_IS_WINDOWS) {
494
+ $this->configFileHandle = fopen($this->getConfigFile(), 'r+');
495
+ }
496
}
497
498
/**
1061
public function truncate() {
1062
$defaultHeader = $this->getDefaultHeader();
1063
$this->close();
1064
+ if (WFWAF_IS_WINDOWS) {
1065
+ file_put_contents($this->getFile(), $defaultHeader, LOCK_EX);
1066
+ } else {
1067
+ wfWAFStorageFile::atomicFilePutContents($this->getFile(), $defaultHeader, 'attack');
1068
+ }
1069
$this->header = array();
1070
$this->offsetTable = array();
1071
$this->open();
vendor/wordfence/wf-waf/src/lib/waf.php CHANGED
@@ -763,18 +763,20 @@ HTML
763
* @var wfWAFRuleComparisonFailure $failedComparison
764
*/
765
$rule = $failedRule['rule'];
766
- $failedComparison = $failedRule['failedComparison'];
767
768
- $data = array(
769
- 'timestamp' => time(),
770
- 'description' => 'Whitelisted while in Learning Mode.',
771
- 'ip' => $this->getRequest()->getIP(),
772
- );
773
- if (function_exists('get_current_user_id')) {
774
- $data['userID'] = get_current_user_id();
775
}
776
- $this->whitelistRuleForParam($this->getRequest()->getPath(), $failedComparison->getParamKey(),
777
- $rule->getRuleID(), $data);
778
}
779
}
780
}
763
* @var wfWAFRuleComparisonFailure $failedComparison
764
*/
765
$rule = $failedRule['rule'];
766
+ if ($rule->getWhitelist()) {
767
+ $failedComparison = $failedRule['failedComparison'];
768
769
+ $data = array(
770
+ 'timestamp' => time(),
771
+ 'description' => 'Whitelisted while in Learning Mode.',
772
+ 'ip' => $this->getRequest()->getIP(),
773
+ );
774
+ if (function_exists('get_current_user_id')) {
775
+ $data['userID'] = get_current_user_id();
776
+ }
777
+ $this->whitelistRuleForParam($this->getRequest()->getPath(), $failedComparison->getParamKey(),
778
+ $rule->getRuleID(), $data);
779
}
780
}
781
}
782
}
waf/bootstrap.php CHANGED
@@ -224,7 +224,15 @@ try {
224
225
if (!file_exists(wfWAF::getInstance()->getCompiledRulesFile()) || !filesize(wfWAF::getInstance()->getCompiledRulesFile())) {
226
try {
227
- wfWAF::getInstance()->updateRuleSet(file_get_contents(WFWAF_PATH . 'baseRules.rules'), false);
228
} catch (wfWAFBuildRulesException $e) {
229
// Log this somewhere
230
error_log($e->getMessage());
224
225
if (!file_exists(wfWAF::getInstance()->getCompiledRulesFile()) || !filesize(wfWAF::getInstance()->getCompiledRulesFile())) {
226
try {
227
+ if (is_writable(wfWAF::getInstance()->getCompiledRulesFile()) &&
228
+ wfWAF::getInstance()->getStorageEngine()->getConfig('apiKey') !== null &&
229
+ wfWAF::getInstance()->getStorageEngine()->getConfig('createInitialRulesDelay') < time()
230
+ ) {
231
+ $event = new wfWAFCronFetchRulesEvent(time() - 60);
232
+ $event->setWaf(wfWAF::getInstance());
233
+ $event->fire();
234
+ wfWAF::getInstance()->getStorageEngine()->setConfig('createInitialRulesDelay', time() + (5 * 60));
235
+ }
236
} catch (wfWAFBuildRulesException $e) {
237
// Log this somewhere
238
error_log($e->getMessage());
wordfence.php CHANGED
@@ -4,14 +4,14 @@ Plugin Name: Wordfence Security
4
Plugin URI: http://www.wordfence.com/
5
Description: Wordfence Security - Anti-virus, Firewall and High Speed Cache
6
Author: Wordfence
7
- Version: 6.1.4
8
Author URI: http://www.wordfence.com/
9
Network: true
10
*/
11
if(defined('WP_INSTALLING') && WP_INSTALLING){
12
return;
13
}
14
- define('WORDFENCE_VERSION', '6.1.4');
15
define('WORDFENCE_BASENAME', function_exists('plugin_basename') ? plugin_basename(__FILE__) :
16
basename(dirname(__FILE__)) . '/' . basename(__FILE__));
17
4
Plugin URI: http://www.wordfence.com/
5
Description: Wordfence Security - Anti-virus, Firewall and High Speed Cache
6
Author: Wordfence
7
+ Version: 6.1.5
8
Author URI: http://www.wordfence.com/
9
Network: true
10
*/
11
if(defined('WP_INSTALLING') && WP_INSTALLING){
12
return;
13
}
14
+ define('WORDFENCE_VERSION', '6.1.5');
15
define('WORDFENCE_BASENAME', function_exists('plugin_basename') ? plugin_basename(__FILE__) :
16
basename(dirname(__FILE__)) . '/' . basename(__FILE__));
17