Version Description
- Improvement: Optimized the malware signature scan to reduce memory usage.
- Improvement: Optimized the overall scan to make fewer network calls.
- Improvement: Running an update now automatically dismisses the corresponding scan issue if present.
- Improvement: Added a time limit to the live activity status so only current messages are shown.
- Improvement: WAF configuration files are now excluded by default from the recently modified files list in the activity report.
- Improvement: Background pausing for live activity and traffic may now be disabled.
- Improvement: Added additional WAF support to allow us to more easily address false positives.
- Improvement: Blocking pages presented by Wordfence now indicate the source and contain information to help diagnose caching problems.
- Fix: All external URLs in the tour are now https.
- Fix: Corrected a typo in the unlock email template.
- Fix: Fixed the target of a label on the options page.
Download this release
Release Info
Developer | wfryan |
Plugin | Wordfence Security – Firewall & Malware Scan |
Version | 6.3.6 |
Comparing to | |
See all releases |
Code changes from version 6.3.5 to 6.3.6
- js/admin.js +2 -2
- js/tourTip.js +1 -1
- lib/dashboard.php +0 -1
- lib/live_activity.php +2 -0
- lib/menu_activity.php +4 -4
- lib/menu_options.php +5 -5
- lib/menu_scan.php +2 -0
- lib/menu_scan_options.php +0 -4
- lib/wf503.php +1 -1
- lib/wfAPI.php +15 -1
- lib/wfConfig.php +3 -3
- lib/wfIssues.php +114 -28
- lib/wfScanEngine.php +14 -23
- lib/wfSchema.php +25 -11
- lib/wfUtils.php +21 -0
- lib/wordfenceClass.php +35 -19
- lib/wordfenceHash.php +169 -52
- lib/wordfenceScanner.php +141 -87
- readme.txt +24 -12
- vendor/wordfence/wf-waf/src/init.php +1 -1
- vendor/wordfence/wf-waf/src/lib/parser/parser.php +52 -4
- vendor/wordfence/wf-waf/src/lib/request.php +6 -6
- vendor/wordfence/wf-waf/src/lib/storage/file.php +7 -3
- vendor/wordfence/wf-waf/src/lib/utils.php +21 -0
- vendor/wordfence/wf-waf/src/lib/waf.php +25 -10
- vendor/wordfence/wf-waf/src/views/403-blacklist.php +2 -0
- vendor/wordfence/wf-waf/src/views/403-roadblock.php +2 -0
- vendor/wordfence/wf-waf/src/views/403.php +2 -0
- vendor/wordfence/wf-waf/src/views/503-lockout.php +1 -1
- vendor/wordfence/wf-waf/src/views/503.php +1 -1
- views/reports/activity-report-email-inline.php +2 -0
- wordfence.php +2 -2
js/admin.js
CHANGED
@@ -511,7 +511,7 @@
|
|
511 |
}, parseInt(WordfenceAdminVars.actUpdateInterval));
|
512 |
},
|
513 |
updateActivityLog: function() {
|
514 |
-
if (this.activityLogUpdatePending || !this.windowHasFocus()) {
|
515 |
if (!jQuery('body').hasClass('wordfenceLiveActivityPaused') && !this.activityLogUpdatePending) {
|
516 |
jQuery('body').addClass('wordfenceLiveActivityPaused');
|
517 |
}
|
@@ -700,7 +700,7 @@
|
|
700 |
}
|
701 |
},
|
702 |
updateTicker: function(forceUpdate) {
|
703 |
-
if ((!forceUpdate) && (this.tickerUpdatePending || !this.windowHasFocus())) {
|
704 |
if (!jQuery('body').hasClass('wordfenceLiveActivityPaused') && !this.tickerUpdatePending) {
|
705 |
jQuery('body').addClass('wordfenceLiveActivityPaused');
|
706 |
}
|
511 |
}, parseInt(WordfenceAdminVars.actUpdateInterval));
|
512 |
},
|
513 |
updateActivityLog: function() {
|
514 |
+
if (this.activityLogUpdatePending || (!this.windowHasFocus() && WordfenceAdminVars.allowsPausing == '1')) {
|
515 |
if (!jQuery('body').hasClass('wordfenceLiveActivityPaused') && !this.activityLogUpdatePending) {
|
516 |
jQuery('body').addClass('wordfenceLiveActivityPaused');
|
517 |
}
|
700 |
}
|
701 |
},
|
702 |
updateTicker: function(forceUpdate) {
|
703 |
+
if ((!forceUpdate) && (this.tickerUpdatePending || (!this.windowHasFocus() && WordfenceAdminVars.allowsPausing == '1'))) {
|
704 |
if (!jQuery('body').hasClass('wordfenceLiveActivityPaused') && !this.tickerUpdatePending) {
|
705 |
jQuery('body').addClass('wordfenceLiveActivityPaused');
|
706 |
}
|
js/tourTip.js
CHANGED
@@ -143,7 +143,7 @@ window['wordfenceTour'] = {
|
|
143 |
|
144 |
jQuery(function(){
|
145 |
if(WordfenceAdminVars.tourClosed != '1' && WordfenceAdminVars.welcomeClosed != '1'){
|
146 |
-
var formHTML = '<div style="padding: 0 5px 0 15px;" id="wordfenceEmailDiv"><form target="_new" style="display: inline;" method="post" class="af-form-wrapper" action="
|
147 |
var elem = '#toplevel_page_Wordfence';
|
148 |
jQuery(elem).pointer({
|
149 |
close: function(){},
|
143 |
|
144 |
jQuery(function(){
|
145 |
if(WordfenceAdminVars.tourClosed != '1' && WordfenceAdminVars.welcomeClosed != '1'){
|
146 |
+
var formHTML = '<div style="padding: 0 5px 0 15px;" id="wordfenceEmailDiv"><form target="_new" style="display: inline;" method="post" class="af-form-wrapper" action="https://www.aweber.com/scripts/addlead.pl" ><div style="display: none;"><input type="hidden" name="meta_web_form_id" value="1428034071" /><input type="hidden" name="meta_split_id" value="" /><input type="hidden" name="listname" value="wordfence" /><input type="hidden" name="redirect" value="https://www.aweber.com/thankyou-coi.htm?m=text" id="redirect_ae9f0882518768f447c80ea8f3b7afde" /><input type="hidden" name="meta_adtracking" value="widgetForm" /><input type="hidden" name="meta_message" value="1" /><input type="hidden" name="meta_required" value="email" /><input type="hidden" name="meta_tooltip" value="" /></div><input class="text" id="wfListEmail" type="text" name="email" value="Enter your email" tabindex="500" onclick="wordfenceTour.wfClearEmailField(); return false;" /><input name="submit" type="submit" value="Get Alerted" tabindex="501" onclick="var evt = event || window.event; try { return wordfenceTour.processEmailClick(evt); } catch(err){ evt.returnValue = false; evt.preventDefault(); }" /><div style="display: none;"><img src="https://forms.aweber.com/form/displays.htm?id=jCxMHAzMLAzsjA==" alt="" /></div><div style="padding: 5px; font-size: 10px;"><input type="checkbox" id="wfJoinListCheck" value="1" checked /><span style="font-size: 10px;">Also join our WordPress Security email list to receive WordPress Security Alerts and Wordfence news.</span></div></form></div>';
|
147 |
var elem = '#toplevel_page_Wordfence';
|
148 |
jQuery(elem).pointer({
|
149 |
close: function(){},
|
lib/dashboard.php
CHANGED
@@ -27,7 +27,6 @@
|
|
27 |
<?php if(wfConfig::get('scheduledScansEnabled')){ ?>
|
28 |
<?php if(wfConfig::get('scheduledScansEnabled')){ ?><tr><td style="padding-right: 20px;">Security Scans Enabled:</td><td style="color: #0F0;">✔</td></tr> <?php } ?>
|
29 |
<?php if(wfConfig::get('scansEnabled_public')){ ?><tr><td style="padding-right: 20px;">Scan public facing site:</td><td style="color: #0F0;">✔</td></tr> <?php } ?>
|
30 |
-
<?php if(wfConfig::get('scansEnabled_heartbleed')){ ?><tr><td style="padding-right: 20px;">Scan for HeartBleed Vulnerability:</td><td style="color: #0F0;">✔</td></tr> <?php } ?>
|
31 |
<?php if(wfConfig::get('scansEnabled_core')){ ?><tr><td style="padding-right: 20px;">Scan Core Files:</td><td style="color: #0F0;">✔</td></tr> <?php } ?>
|
32 |
<?php if(wfConfig::get('scansEnabled_themes')){ ?><tr><td style="padding-right: 20px;">Scan Themes:</td><td style="color: #0F0;">✔</td></tr> <?php } ?>
|
33 |
<?php if(wfConfig::get('scansEnabled_plugins')){ ?><tr><td style="padding-right: 20px;">Scan Plugins:</td><td style="color: #0F0;">✔</td></tr> <?php } ?>
|
27 |
<?php if(wfConfig::get('scheduledScansEnabled')){ ?>
|
28 |
<?php if(wfConfig::get('scheduledScansEnabled')){ ?><tr><td style="padding-right: 20px;">Security Scans Enabled:</td><td style="color: #0F0;">✔</td></tr> <?php } ?>
|
29 |
<?php if(wfConfig::get('scansEnabled_public')){ ?><tr><td style="padding-right: 20px;">Scan public facing site:</td><td style="color: #0F0;">✔</td></tr> <?php } ?>
|
|
|
30 |
<?php if(wfConfig::get('scansEnabled_core')){ ?><tr><td style="padding-right: 20px;">Scan Core Files:</td><td style="color: #0F0;">✔</td></tr> <?php } ?>
|
31 |
<?php if(wfConfig::get('scansEnabled_themes')){ ?><tr><td style="padding-right: 20px;">Scan Themes:</td><td style="color: #0F0;">✔</td></tr> <?php } ?>
|
32 |
<?php if(wfConfig::get('scansEnabled_plugins')){ ?><tr><td style="padding-right: 20px;">Scan Plugins:</td><td style="color: #0F0;">✔</td></tr> <?php } ?>
|
lib/live_activity.php
CHANGED
@@ -4,6 +4,8 @@
|
|
4 |
<div class="wf-live-activity-title">Wordfence Live Activity:</div>
|
5 |
<div class="wf-live-activity-message"></div>
|
6 |
</div>
|
|
|
7 |
<div class="wf-live-activity-state"><p>Live Updates Paused — Click inside window to resume</p></div>
|
|
|
8 |
</div>
|
9 |
</div>
|
4 |
<div class="wf-live-activity-title">Wordfence Live Activity:</div>
|
5 |
<div class="wf-live-activity-message"></div>
|
6 |
</div>
|
7 |
+
<?php if (wfConfig::get('liveActivityPauseEnabled')): ?>
|
8 |
<div class="wf-live-activity-state"><p>Live Updates Paused — Click inside window to resume</p></div>
|
9 |
+
<?php endif; ?>
|
10 |
</div>
|
11 |
</div>
|
lib/menu_activity.php
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
-
<?php if (wfConfig::liveTrafficEnabled()): ?>
|
2 |
<div id="wfLiveTrafficOverlayAnchor"></div>
|
3 |
<div id="wfLiveTrafficDisabledMessage">
|
4 |
<h2>Live Updates Paused<br /><small>Click inside window to resume</small></h2>
|
@@ -194,13 +194,13 @@
|
|
194 |
<div id="wf-lt-listings" data-bind="foreach: listings">
|
195 |
<div data-bind="attr: { id: ('wfActEvent_' + id()), 'class': cssClasses }">
|
196 |
<div>
|
197 |
-
<span data-bind="if: action() != 'loginOK' && user()">
|
198 |
<span data-bind="html: user.avatar" class="wfAvatar"></span>
|
199 |
<a data-bind="attr: { href: user.editLink }, text: user().display_name"
|
200 |
target="_blank"></a>
|
201 |
</span>
|
202 |
<span data-bind="if: loc()">
|
203 |
-
<span data-bind="if: action() != 'loginOK' && user()"> in</span>
|
204 |
<img data-bind="attr: { src: '<?php echo wfUtils::getBaseURL() . 'images/flags/'; ?>' + loc().countryCode.toLowerCase() + '.png',
|
205 |
alt: loc().countryName, title: loc().countryName }" width="16"
|
206 |
height="11"
|
@@ -211,7 +211,7 @@
|
|
211 |
</span>
|
212 |
<span data-bind="if: !loc()">
|
213 |
<span
|
214 |
-
data-bind="text: action() != 'loginOK' && user() ? 'at an' : 'An'"></span> unknown location at IP <a
|
215 |
data-bind="text: IP, attr: { href: WFAD.makeIPTrafLink(IP()) }"
|
216 |
target="_blank"></a>
|
217 |
</span>
|
1 |
+
<?php if (wfConfig::liveTrafficEnabled() && wfConfig::get('liveActivityPauseEnabled')): ?>
|
2 |
<div id="wfLiveTrafficOverlayAnchor"></div>
|
3 |
<div id="wfLiveTrafficDisabledMessage">
|
4 |
<h2>Live Updates Paused<br /><small>Click inside window to resume</small></h2>
|
194 |
<div id="wf-lt-listings" data-bind="foreach: listings">
|
195 |
<div data-bind="attr: { id: ('wfActEvent_' + id()), 'class': cssClasses }">
|
196 |
<div>
|
197 |
+
<span data-bind="if: action() != 'loginOK' && action() != 'loginFailValidUsername' && action() != 'loginFailInvalidUsername' && user()">
|
198 |
<span data-bind="html: user.avatar" class="wfAvatar"></span>
|
199 |
<a data-bind="attr: { href: user.editLink }, text: user().display_name"
|
200 |
target="_blank"></a>
|
201 |
</span>
|
202 |
<span data-bind="if: loc()">
|
203 |
+
<span data-bind="if: action() != 'loginOK' && action() != 'loginFailValidUsername' && action() != 'loginFailInvalidUsername' && user()"> in</span>
|
204 |
<img data-bind="attr: { src: '<?php echo wfUtils::getBaseURL() . 'images/flags/'; ?>' + loc().countryCode.toLowerCase() + '.png',
|
205 |
alt: loc().countryName, title: loc().countryName }" width="16"
|
206 |
height="11"
|
211 |
</span>
|
212 |
<span data-bind="if: !loc()">
|
213 |
<span
|
214 |
+
data-bind="text: action() != 'loginOK' && action() != 'loginFailValidUsername' && action() != 'loginFailInvalidUsername' && user() ? 'at an' : 'An'"></span> unknown location at IP <a
|
215 |
data-bind="text: IP, attr: { href: WFAD.makeIPTrafLink(IP()) }"
|
216 |
target="_blank"></a>
|
217 |
</span>
|
lib/menu_options.php
CHANGED
@@ -400,10 +400,6 @@ $w = new wfConfig();
|
|
400 |
'id' => 'scansEnabled_checkHowGetIPs',
|
401 |
'label' => 'Scan for misconfigured How does Wordfence get IPs <a href="http://docs.wordfence.com/en/Wordfence_options#Scan_for_misconfigured_How_does_Wordfence_get_IPs" target="_blank" class="wfhelp"></a>',
|
402 |
),
|
403 |
-
array(
|
404 |
-
'id' => 'scansEnabled_heartbleed',
|
405 |
-
'label' => 'Scan for the HeartBleed vulnerability <a href="http://docs.wordfence.com/en/Wordfence_options#Scan_for_the_HeartBleed_vulnerability" target="_blank" class="wfhelp"></a>',
|
406 |
-
),
|
407 |
array(
|
408 |
'id' => 'scansEnabled_checkReadableConfig',
|
409 |
'label' => 'Scan for publicly accessible configuration, backup, or log files <a href="http://docs.wordfence.com/en/Wordfence_options#Configuration_Readable" target="_blank" class="wfhelp"></a>',
|
@@ -648,7 +644,7 @@ $w = new wfConfig();
|
|
648 |
<div class="wfMarker" id="wfMarkerLoginSecurity"></div>
|
649 |
<h3>Login Security Options <a href="http://docs.wordfence.com/en/Wordfence_options#Login_Security_Options" target="_blank" class="wfhelp"></a></h3>
|
650 |
<div class="wf-form-group">
|
651 |
-
<label for="
|
652 |
<div class="wf-col-sm-7">
|
653 |
<select class="wf-form-control" id="loginSec_strongPasswds" name="loginSec_strongPasswds">
|
654 |
<option value="">Do not force users to use strong passwords</option>
|
@@ -939,6 +935,10 @@ $w = new wfConfig();
|
|
939 |
</div>
|
940 |
<?php
|
941 |
$options = array( //Contents should already be HTML-escaped as needed
|
|
|
|
|
|
|
|
|
942 |
array(
|
943 |
'id' => 'deleteTablesOnDeact',
|
944 |
'label' => 'Delete Wordfence tables and data on deactivation <a href="http://docs.wordfence.com/en/Wordfence_options#Delete_Wordfence_tables_and_data_on_deactivation.3F" target="_blank" class="wfhelp"></a>',
|
400 |
'id' => 'scansEnabled_checkHowGetIPs',
|
401 |
'label' => 'Scan for misconfigured How does Wordfence get IPs <a href="http://docs.wordfence.com/en/Wordfence_options#Scan_for_misconfigured_How_does_Wordfence_get_IPs" target="_blank" class="wfhelp"></a>',
|
402 |
),
|
|
|
|
|
|
|
|
|
403 |
array(
|
404 |
'id' => 'scansEnabled_checkReadableConfig',
|
405 |
'label' => 'Scan for publicly accessible configuration, backup, or log files <a href="http://docs.wordfence.com/en/Wordfence_options#Configuration_Readable" target="_blank" class="wfhelp"></a>',
|
644 |
<div class="wfMarker" id="wfMarkerLoginSecurity"></div>
|
645 |
<h3>Login Security Options <a href="http://docs.wordfence.com/en/Wordfence_options#Login_Security_Options" target="_blank" class="wfhelp"></a></h3>
|
646 |
<div class="wf-form-group">
|
647 |
+
<label for="loginSec_strongPasswds" class="wf-col-sm-5 wf-control-label">Enforce strong passwords <a href="http://docs.wordfence.com/en/Wordfence_options#Enforce_strong_passwords.3F" target="_blank" class="wfhelp"></a></label>
|
648 |
<div class="wf-col-sm-7">
|
649 |
<select class="wf-form-control" id="loginSec_strongPasswds" name="loginSec_strongPasswds">
|
650 |
<option value="">Do not force users to use strong passwords</option>
|
935 |
</div>
|
936 |
<?php
|
937 |
$options = array( //Contents should already be HTML-escaped as needed
|
938 |
+
array(
|
939 |
+
'id' => 'liveActivityPauseEnabled',
|
940 |
+
'label' => 'Pause live updates when window loses focus <a href="http://docs.wordfence.com/en/Wordfence_options#Pause_live_updates_when_window_loses_focus" target="_blank" class="wfhelp"></a>',
|
941 |
+
),
|
942 |
array(
|
943 |
'id' => 'deleteTablesOnDeact',
|
944 |
'label' => 'Delete Wordfence tables and data on deactivation <a href="http://docs.wordfence.com/en/Wordfence_options#Delete_Wordfence_tables_and_data_on_deactivation.3F" target="_blank" class="wfhelp"></a>',
|
lib/menu_scan.php
CHANGED
@@ -1,10 +1,12 @@
|
|
1 |
<?php
|
2 |
$sigUpdateTime = wfConfig::get('signatureUpdateTime');
|
3 |
?>
|
|
|
4 |
<div id="wfLiveTrafficOverlayAnchor"></div>
|
5 |
<div id="wfLiveTrafficDisabledMessage">
|
6 |
<h2>Live Updates Paused<br /><small>Click inside window to resume</small></h2>
|
7 |
</div>
|
|
|
8 |
<div class="wrap wordfence">
|
9 |
<div class="wf-container-fluid">
|
10 |
|
1 |
<?php
|
2 |
$sigUpdateTime = wfConfig::get('signatureUpdateTime');
|
3 |
?>
|
4 |
+
<?php if (wfConfig::get('liveActivityPauseEnabled')): ?>
|
5 |
<div id="wfLiveTrafficOverlayAnchor"></div>
|
6 |
<div id="wfLiveTrafficDisabledMessage">
|
7 |
<h2>Live Updates Paused<br /><small>Click inside window to resume</small></h2>
|
8 |
</div>
|
9 |
+
<?php endif; ?>
|
10 |
<div class="wrap wordfence">
|
11 |
<div class="wf-container-fluid">
|
12 |
|
lib/menu_scan_options.php
CHANGED
@@ -15,10 +15,6 @@ $w = new wfConfig();
|
|
15 |
'id' => 'scansEnabled_checkHowGetIPs',
|
16 |
'label' => 'Scan for misconfigured How does Wordfence get IPs <a href="http://docs.wordfence.com/en/Wordfence_options#Scan_for_misconfigured_How_does_Wordfence_get_IPs" target="_blank" class="wfhelp"></a>',
|
17 |
),
|
18 |
-
array(
|
19 |
-
'id' => 'scansEnabled_heartbleed',
|
20 |
-
'label' => 'Scan for the HeartBleed vulnerability <a href="http://docs.wordfence.com/en/Wordfence_options#Scan_for_the_HeartBleed_vulnerability" target="_blank" class="wfhelp"></a>',
|
21 |
-
),
|
22 |
array(
|
23 |
'id' => 'scansEnabled_checkReadableConfig',
|
24 |
'label' => 'Scan for publicly accessible configuration, backup, or log files <a href="http://docs.wordfence.com/en/Wordfence_options#Configuration_Readable" target="_blank" class="wfhelp"></a>',
|
15 |
'id' => 'scansEnabled_checkHowGetIPs',
|
16 |
'label' => 'Scan for misconfigured How does Wordfence get IPs <a href="http://docs.wordfence.com/en/Wordfence_options#Scan_for_misconfigured_How_does_Wordfence_get_IPs" target="_blank" class="wfhelp"></a>',
|
17 |
),
|
|
|
|
|
|
|
|
|
18 |
array(
|
19 |
'id' => 'scansEnabled_checkReadableConfig',
|
20 |
'label' => 'Scan for publicly accessible configuration, backup, or log files <a href="http://docs.wordfence.com/en/Wordfence_options#Configuration_Readable" target="_blank" class="wfhelp"></a>',
|
lib/wf503.php
CHANGED
@@ -20,5 +20,5 @@ still benefit from the other security features that Wordfence provides.
|
|
20 |
<?php require('wfUnlockMsg.php'); ?>
|
21 |
|
22 |
</p>
|
23 |
-
<
|
24 |
</body></html>
|
20 |
<?php require('wfUnlockMsg.php'); ?>
|
21 |
|
22 |
</p>
|
23 |
+
<p style="color: #999999;margin-top: 2rem;"><em>Generated by Wordfence at <?php echo gmdate('D, j M Y G:i:s T', wfUtils::normalizedTime()); ?>.<br>Your computer's time: <script type="application/javascript">document.write(new Date().toUTCString());</script>.</em></p>
|
24 |
</body></html>
|
lib/wfAPI.php
CHANGED
@@ -98,13 +98,27 @@ class wfAPI {
|
|
98 |
$error_message = $response->get_error_message();
|
99 |
throw new Exception("There was an " . ($error_message ? '' : 'unknown ') . "error connecting to the the Wordfence scanning servers" . ($error_message ? ": $error_message" : '.'));
|
100 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
101 |
|
102 |
if (!empty($response['response']['code'])) {
|
103 |
$this->lastHTTPStatus = (int) $response['response']['code'];
|
104 |
}
|
105 |
|
106 |
if (200 != $this->lastHTTPStatus) {
|
107 |
-
throw new Exception("
|
108 |
}
|
109 |
|
110 |
$this->curlContent = wp_remote_retrieve_body($response);
|
98 |
$error_message = $response->get_error_message();
|
99 |
throw new Exception("There was an " . ($error_message ? '' : 'unknown ') . "error connecting to the the Wordfence scanning servers" . ($error_message ? ": $error_message" : '.'));
|
100 |
}
|
101 |
+
|
102 |
+
$dateHeader = @$response['headers']['date'];
|
103 |
+
if (!empty($dateHeader) && (time() - wfConfig::get('timeoffset_wf_updated', 0) > 3600)) {
|
104 |
+
if (function_exists('date_create_from_format')) {
|
105 |
+
$dt = DateTime::createFromFormat('D, j M Y G:i:s O', $dateHeader);
|
106 |
+
$timestamp = $dt->getTimestamp();
|
107 |
+
}
|
108 |
+
else {
|
109 |
+
$timestamp = strtotime($dateHeader);
|
110 |
+
}
|
111 |
+
$offset = $timestamp - time();
|
112 |
+
wfConfig::set('timeoffset_wf', $offset);
|
113 |
+
wfConfig::set('timeoffset_wf_updated', time());
|
114 |
+
}
|
115 |
|
116 |
if (!empty($response['response']['code'])) {
|
117 |
$this->lastHTTPStatus = (int) $response['response']['code'];
|
118 |
}
|
119 |
|
120 |
if (200 != $this->lastHTTPStatus) {
|
121 |
+
throw new Exception("The Wordfence scanning servers are currently unavailable. This may be for maintenance or a temporary outage. If this still occurs in an hour, please contact support. [$this->lastHTTPStatus]");
|
122 |
}
|
123 |
|
124 |
$this->curlContent = wp_remote_retrieve_body($response);
|
lib/wfConfig.php
CHANGED
@@ -35,7 +35,6 @@ class wfConfig {
|
|
35 |
"scheduledScansEnabled" => array('value' => true, 'autoload' => self::AUTOLOAD),
|
36 |
"lowResourceScansEnabled" => array('value' => false, 'autoload' => self::AUTOLOAD),
|
37 |
"scansEnabled_public" => array('value' => false, 'autoload' => self::AUTOLOAD),
|
38 |
-
"scansEnabled_heartbleed" => array('value' => true, 'autoload' => self::AUTOLOAD),
|
39 |
"scansEnabled_checkHowGetIPs" => array('value' => true, 'autoload' => self::AUTOLOAD),
|
40 |
"scansEnabled_core" => array('value' => true, 'autoload' => self::AUTOLOAD),
|
41 |
"scansEnabled_themes" => array('value' => false, 'autoload' => self::AUTOLOAD),
|
@@ -57,6 +56,7 @@ class wfConfig {
|
|
57 |
"scansEnabled_highSense" => array('value' => false, 'autoload' => self::AUTOLOAD),
|
58 |
"scansEnabled_oldVersions" => array('value' => true, 'autoload' => self::AUTOLOAD),
|
59 |
"scansEnabled_suspiciousAdminUsers" => array('value' => true, 'autoload' => self::AUTOLOAD),
|
|
|
60 |
"firewallEnabled" => array('value' => true, 'autoload' => self::AUTOLOAD),
|
61 |
"blockFakeBots" => array('value' => false, 'autoload' => self::AUTOLOAD),
|
62 |
"autoBlockScanners" => array('value' => true, 'autoload' => self::AUTOLOAD),
|
@@ -122,7 +122,7 @@ class wfConfig {
|
|
122 |
'maxScanHits_action' => "throttle",
|
123 |
'blockedTime' => "300",
|
124 |
'email_summary_interval' => 'weekly',
|
125 |
-
'email_summary_excluded_directories' => 'wp-content/cache,wp-content/
|
126 |
'allowed404s' => "/favicon.ico\n/apple-touch-icon*.png\n/*@2x.png\n/browserconfig.xml",
|
127 |
'wafAlertWhitelist' => '',
|
128 |
'wafAlertInterval' => 600,
|
@@ -130,7 +130,7 @@ class wfConfig {
|
|
130 |
'howGetIPs_trusted_proxies' => '',
|
131 |
)
|
132 |
);
|
133 |
-
public static $serializedOptions = array('lastAdminLogin', 'scanSched', 'emailedIssuesList', 'wf_summaryItems', 'adminUserList', 'twoFactorUsers', 'alertFreqTrack', 'wfStatusStartMsgs', 'vulnerabilities_plugin', 'vulnerabilities_theme', 'dashboardData');
|
134 |
public static function setDefaults() {
|
135 |
foreach (self::$defaultConfig['checkboxes'] as $key => $config) {
|
136 |
$val = $config['value'];
|
35 |
"scheduledScansEnabled" => array('value' => true, 'autoload' => self::AUTOLOAD),
|
36 |
"lowResourceScansEnabled" => array('value' => false, 'autoload' => self::AUTOLOAD),
|
37 |
"scansEnabled_public" => array('value' => false, 'autoload' => self::AUTOLOAD),
|
|
|
38 |
"scansEnabled_checkHowGetIPs" => array('value' => true, 'autoload' => self::AUTOLOAD),
|
39 |
"scansEnabled_core" => array('value' => true, 'autoload' => self::AUTOLOAD),
|
40 |
"scansEnabled_themes" => array('value' => false, 'autoload' => self::AUTOLOAD),
|
56 |
"scansEnabled_highSense" => array('value' => false, 'autoload' => self::AUTOLOAD),
|
57 |
"scansEnabled_oldVersions" => array('value' => true, 'autoload' => self::AUTOLOAD),
|
58 |
"scansEnabled_suspiciousAdminUsers" => array('value' => true, 'autoload' => self::AUTOLOAD),
|
59 |
+
"liveActivityPauseEnabled" => array('value' => true, 'autoload' => self::AUTOLOAD),
|
60 |
"firewallEnabled" => array('value' => true, 'autoload' => self::AUTOLOAD),
|
61 |
"blockFakeBots" => array('value' => false, 'autoload' => self::AUTOLOAD),
|
62 |
"autoBlockScanners" => array('value' => true, 'autoload' => self::AUTOLOAD),
|
122 |
'maxScanHits_action' => "throttle",
|
123 |
'blockedTime' => "300",
|
124 |
'email_summary_interval' => 'weekly',
|
125 |
+
'email_summary_excluded_directories' => 'wp-content/cache,wp-content/wflogs',
|
126 |
'allowed404s' => "/favicon.ico\n/apple-touch-icon*.png\n/*@2x.png\n/browserconfig.xml",
|
127 |
'wafAlertWhitelist' => '',
|
128 |
'wafAlertInterval' => 600,
|
130 |
'howGetIPs_trusted_proxies' => '',
|
131 |
)
|
132 |
);
|
133 |
+
public static $serializedOptions = array('lastAdminLogin', 'scanSched', 'emailedIssuesList', 'wf_summaryItems', 'adminUserList', 'twoFactorUsers', 'alertFreqTrack', 'wfStatusStartMsgs', 'vulnerabilities_plugin', 'vulnerabilities_theme', 'dashboardData', 'malwarePrefixes');
|
134 |
public static function setDefaults() {
|
135 |
foreach (self::$defaultConfig['checkboxes'] as $key => $config) {
|
136 |
$val = $config['value'];
|
lib/wfIssues.php
CHANGED
@@ -6,33 +6,49 @@ class wfIssues {
|
|
6 |
//Properties that are serialized on sleep:
|
7 |
private $updateCalled = false;
|
8 |
private $issuesTable = '';
|
|
|
9 |
private $maxIssues = 0;
|
10 |
private $newIssues = array();
|
11 |
public $totalIssues = 0;
|
12 |
public $totalCriticalIssues = 0;
|
13 |
public $totalWarningIssues = 0;
|
14 |
public function __sleep(){ //Same order here as vars above
|
15 |
-
return array('updateCalled', 'issuesTable', 'maxIssues', 'newIssues', 'totalIssues', 'totalCriticalIssues', 'totalWarningIssues');
|
16 |
}
|
17 |
public function __construct(){
|
18 |
global $wpdb;
|
19 |
$this->issuesTable = $wpdb->base_prefix . 'wfIssues';
|
|
|
20 |
$this->maxIssues = wfConfig::get('scan_maxIssues', 0);
|
21 |
}
|
22 |
public function __wakeup(){
|
23 |
$this->db = new wfDB();
|
24 |
}
|
25 |
-
public function addIssue($type, $severity,
|
26 |
-
|
|
|
|
|
|
|
|
|
|
|
27 |
$ignoreP, /* some piece of data used for md5 for permanent ignores */
|
28 |
$ignoreC, /* some piece of data used for md5 for ignoring until something changes */
|
29 |
-
$shortMsg, $longMsg, $templateData
|
30 |
){
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
36 |
if($rec){
|
37 |
if($rec['status'] == 'new' && ($rec['ignoreC'] == $ignoreC || $rec['ignoreP'] == $ignoreP)){
|
38 |
if($type != 'file' && $type != 'database'){ //Filter out duplicate new issues but not infected files because we want to see all infections even if file contents are identical
|
@@ -43,27 +59,30 @@ class wfIssues {
|
|
43 |
if($rec['status'] == 'ignoreC' && $rec['ignoreC'] == $ignoreC){ return false; }
|
44 |
if($rec['status'] == 'ignoreP' && $rec['ignoreP'] == $ignoreP){ return false; }
|
45 |
}
|
46 |
-
|
47 |
-
if($
|
48 |
-
$
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
$this->
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
|
|
|
|
|
|
64 |
}
|
65 |
|
66 |
-
$this->getDB()->queryWrite("insert into
|
67 |
'new',
|
68 |
$type,
|
69 |
$severity,
|
@@ -212,9 +231,76 @@ class wfIssues {
|
|
212 |
}
|
213 |
return $ret; //array of lists of issues by status
|
214 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
215 |
public function getIssueCount() {
|
216 |
return (int) $this->getDB()->querySingle("select COUNT(*) from " . $this->issuesTable . " WHERE status = 'new'");
|
217 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
218 |
public function updateSummaryItem($key, $val){
|
219 |
$arr = wfConfig::get_ser('wf_summaryItems', array());
|
220 |
$arr[$key] = $val;
|
6 |
//Properties that are serialized on sleep:
|
7 |
private $updateCalled = false;
|
8 |
private $issuesTable = '';
|
9 |
+
private $pendingIssuesTable = '';
|
10 |
private $maxIssues = 0;
|
11 |
private $newIssues = array();
|
12 |
public $totalIssues = 0;
|
13 |
public $totalCriticalIssues = 0;
|
14 |
public $totalWarningIssues = 0;
|
15 |
public function __sleep(){ //Same order here as vars above
|
16 |
+
return array('updateCalled', 'issuesTable', 'pendingIssuesTable', 'maxIssues', 'newIssues', 'totalIssues', 'totalCriticalIssues', 'totalWarningIssues');
|
17 |
}
|
18 |
public function __construct(){
|
19 |
global $wpdb;
|
20 |
$this->issuesTable = $wpdb->base_prefix . 'wfIssues';
|
21 |
+
$this->pendingIssuesTable = $wpdb->base_prefix . 'wfPendingIssues';
|
22 |
$this->maxIssues = wfConfig::get('scan_maxIssues', 0);
|
23 |
}
|
24 |
public function __wakeup(){
|
25 |
$this->db = new wfDB();
|
26 |
}
|
27 |
+
public function addIssue($type, $severity, $ignoreP, $ignoreC, $shortMsg, $longMsg, $templateData, $alreadyHashed = false) {
|
28 |
+
$this->_addIssue('issue', $type, $severity, $ignoreP, $ignoreC, $shortMsg, $longMsg, $templateData, $alreadyHashed);
|
29 |
+
}
|
30 |
+
public function addPendingIssue($type, $severity, $ignoreP, $ignoreC, $shortMsg, $longMsg, $templateData) {
|
31 |
+
$this->_addIssue('pending', $type, $severity, $ignoreP, $ignoreC, $shortMsg, $longMsg, $templateData);
|
32 |
+
}
|
33 |
+
private function _addIssue($group, $type, $severity,
|
34 |
$ignoreP, /* some piece of data used for md5 for permanent ignores */
|
35 |
$ignoreC, /* some piece of data used for md5 for ignoring until something changes */
|
36 |
+
$shortMsg, $longMsg, $templateData, $alreadyHashed = false
|
37 |
){
|
38 |
+
|
39 |
+
if ($group == 'pending') {
|
40 |
+
$table = $this->pendingIssuesTable;
|
41 |
+
}
|
42 |
+
else {
|
43 |
+
$table = $this->issuesTable;
|
44 |
+
}
|
45 |
+
|
46 |
+
if (!$alreadyHashed) {
|
47 |
+
$ignoreP = md5($ignoreP);
|
48 |
+
$ignoreC = md5($ignoreC);
|
49 |
+
}
|
50 |
+
|
51 |
+
$rec = $this->getDB()->querySingleRec("select status, ignoreP, ignoreC from {$this->issuesTable} where (ignoreP = '%s' OR ignoreC = '%s')", $ignoreP, $ignoreC);
|
52 |
if($rec){
|
53 |
if($rec['status'] == 'new' && ($rec['ignoreC'] == $ignoreC || $rec['ignoreP'] == $ignoreP)){
|
54 |
if($type != 'file' && $type != 'database'){ //Filter out duplicate new issues but not infected files because we want to see all infections even if file contents are identical
|
59 |
if($rec['status'] == 'ignoreC' && $rec['ignoreC'] == $ignoreC){ return false; }
|
60 |
if($rec['status'] == 'ignoreP' && $rec['ignoreP'] == $ignoreP){ return false; }
|
61 |
}
|
62 |
+
|
63 |
+
if ($group != 'pending') {
|
64 |
+
if ($severity == 1) {
|
65 |
+
$this->totalCriticalIssues++;
|
66 |
+
}
|
67 |
+
else if ($severity == 2) {
|
68 |
+
$this->totalWarningIssues++;
|
69 |
+
}
|
70 |
+
$this->totalIssues++;
|
71 |
+
if (empty($this->maxIssues) || $this->totalIssues <= $this->maxIssues)
|
72 |
+
{
|
73 |
+
$this->newIssues[] = array(
|
74 |
+
'type' => $type,
|
75 |
+
'severity' => $severity,
|
76 |
+
'ignoreP' => $ignoreP,
|
77 |
+
'ignoreC' => $ignoreC,
|
78 |
+
'shortMsg' => $shortMsg,
|
79 |
+
'longMsg' => $longMsg,
|
80 |
+
'tmplData' => $templateData
|
81 |
+
);
|
82 |
+
}
|
83 |
}
|
84 |
|
85 |
+
$this->getDB()->queryWrite("insert into {$table} (time, status, type, severity, ignoreP, ignoreC, shortMsg, longMsg, data) values (unix_timestamp(), '%s', '%s', %d, '%s', '%s', '%s', '%s', '%s')",
|
86 |
'new',
|
87 |
$type,
|
88 |
$severity,
|
231 |
}
|
232 |
return $ret; //array of lists of issues by status
|
233 |
}
|
234 |
+
public function getPendingIssues($offset = 0, $limit = 100){
|
235 |
+
/** @var wpdb $wpdb */
|
236 |
+
global $wpdb;
|
237 |
+
$issues = $this->getDB()->querySelect("SELECT * FROM {$this->pendingIssuesTable} ORDER BY id ASC LIMIT %d,%d", $offset, $limit);
|
238 |
+
foreach($issues as &$i){
|
239 |
+
$i['data'] = unserialize($i['data']);
|
240 |
+
}
|
241 |
+
return $issues;
|
242 |
+
}
|
243 |
public function getIssueCount() {
|
244 |
return (int) $this->getDB()->querySingle("select COUNT(*) from " . $this->issuesTable . " WHERE status = 'new'");
|
245 |
}
|
246 |
+
public function getPendingIssueCount() {
|
247 |
+
return (int) $this->getDB()->querySingle("select COUNT(*) from " . $this->pendingIssuesTable . " WHERE status = 'new'");
|
248 |
+
}
|
249 |
+
public function reconcileUpgradeIssues($report = null, $useCachedValued = false) {
|
250 |
+
if ($report === null) {
|
251 |
+
$report = new wfActivityReport();
|
252 |
+
}
|
253 |
+
|
254 |
+
$updatesNeeded = $report->getUpdatesNeeded($useCachedValued);
|
255 |
+
if ($updatesNeeded) {
|
256 |
+
if (!$updatesNeeded['core']) {
|
257 |
+
$this->getDB()->queryWrite("DELETE FROM {$this->issuesTable} WHERE status = 'new' AND type = 'wfUpgrade'");
|
258 |
+
}
|
259 |
+
|
260 |
+
if ($updatesNeeded['plugins']) {
|
261 |
+
$upgradeNames = array();
|
262 |
+
foreach ($updatesNeeded['plugins'] as $p) {
|
263 |
+
$name = $p['Name'];
|
264 |
+
$upgradeNames[$name] = 1;
|
265 |
+
}
|
266 |
+
$upgradeIssues = $this->getDB()->querySelect("SELECT * FROM {$this->issuesTable} WHERE status = 'new' AND type = 'wfPluginUpgrade'");
|
267 |
+
foreach ($upgradeIssues as $issue) {
|
268 |
+
$data = unserialize($issue['data']);
|
269 |
+
$name = $data['Name'];
|
270 |
+
if (!isset($upgradeNames[$name])) { //Some plugins don't have a slug associated with them, so we anchor on the name
|
271 |
+
$this->deleteIssue($issue['id']);
|
272 |
+
}
|
273 |
+
}
|
274 |
+
}
|
275 |
+
else {
|
276 |
+
$this->getDB()->queryWrite("DELETE FROM {$this->issuesTable} WHERE status = 'new' AND type = 'wfPluginUpgrade'");
|
277 |
+
}
|
278 |
+
|
279 |
+
if ($updatesNeeded['themes']) {
|
280 |
+
$upgradeNames = array();
|
281 |
+
foreach ($updatesNeeded['themes'] as $t) {
|
282 |
+
$name = $t['Name'];
|
283 |
+
$upgradeNames[$name] = 1;
|
284 |
+
}
|
285 |
+
$upgradeIssues = $this->getDB()->querySelect("SELECT * FROM {$this->issuesTable} WHERE status = 'new' AND type = 'wfThemeUpgrade'");
|
286 |
+
foreach ($upgradeIssues as $issue) {
|
287 |
+
$data = unserialize($issue['data']);
|
288 |
+
$name = $data['Name'];
|
289 |
+
if (!isset($upgradeNames[$name])) { //Some themes don't have a slug associated with them, so we anchor on the name
|
290 |
+
$this->deleteIssue($issue['id']);
|
291 |
+
}
|
292 |
+
}
|
293 |
+
}
|
294 |
+
else {
|
295 |
+
$this->getDB()->queryWrite("DELETE FROM {$this->issuesTable} WHERE status = 'new' AND type = 'wfThemeUpgrade'");
|
296 |
+
}
|
297 |
+
}
|
298 |
+
else {
|
299 |
+
$this->getDB()->queryWrite("DELETE FROM {$this->issuesTable} WHERE status = 'new' AND (type = 'wfUpgrade' OR type = 'wfPluginUpgrade' OR type = 'wfThemeUpgrade')");
|
300 |
+
}
|
301 |
+
|
302 |
+
wfScanEngine::refreshScanNotification($this);
|
303 |
+
}
|
304 |
public function updateSummaryItem($key, $val){
|
305 |
$arr = wfConfig::get_ser('wf_summaryItems', array());
|
306 |
$arr[$key] = $val;
|
lib/wfScanEngine.php
CHANGED
@@ -122,7 +122,6 @@ class wfScanEngine {
|
|
122 |
$this->jobList[] = 'checkSpamvertized';
|
123 |
$this->jobList[] = 'checkSpamIP';
|
124 |
$this->jobList[] = 'checkGSB';
|
125 |
-
$this->jobList[] = 'heartbleed';
|
126 |
$this->jobList[] = 'checkHowGetIPs_init';
|
127 |
$this->jobList[] = 'checkHowGetIPs_main';
|
128 |
$this->jobList[] = 'knownFiles_init';
|
@@ -278,24 +277,6 @@ class wfScanEngine {
|
|
278 |
public function getCurrentJob(){
|
279 |
return $this->jobList[0];
|
280 |
}
|
281 |
-
private function scan_heartbleed(){
|
282 |
-
if(wfConfig::get('scansEnabled_heartbleed')){
|
283 |
-
$this->statusIDX['heartbleed'] = wordfence::statusStart("Scanning your site for the HeartBleed vulnerability");
|
284 |
-
$result = $this->api->call('scan_heartbleed', array(), array(
|
285 |
-
'siteURL' => site_url()
|
286 |
-
));
|
287 |
-
$haveIssues = false;
|
288 |
-
if($result['haveIssues'] && is_array($result['issues']) ){
|
289 |
-
foreach($result['issues'] as $issue){
|
290 |
-
$this->addIssue($issue['type'], $issue['level'], $issue['ignoreP'], $issue['ignoreC'], $issue['shortMsg'], $issue['longMsg'], $issue['data']);
|
291 |
-
$haveIssues = true;
|
292 |
-
}
|
293 |
-
}
|
294 |
-
wordfence::statusEnd($this->statusIDX['heartbleed'], $haveIssues);
|
295 |
-
} else {
|
296 |
-
wordfence::statusDisabled("Skipping HeartBleed scan");
|
297 |
-
}
|
298 |
-
}
|
299 |
private function scan_publicSite(){
|
300 |
if(wfConfig::get('isPaid')){
|
301 |
if(wfConfig::get('scansEnabled_public')){
|
@@ -594,7 +575,7 @@ class wfScanEngine {
|
|
594 |
}
|
595 |
private function scan_knownFiles_init(){
|
596 |
$this->status(1, 'info', "Contacting Wordfence to initiate scan");
|
597 |
-
$this->api->call('log_scan', array(), array());
|
598 |
$baseWPStuff = array( '.htaccess', 'index.php', 'license.txt', 'readme.html', 'wp-activate.php', 'wp-admin', 'wp-app.php', 'wp-blog-header.php', 'wp-comments-post.php', 'wp-config-sample.php', 'wp-content', 'wp-cron.php', 'wp-includes', 'wp-links-opml.php', 'wp-load.php', 'wp-login.php', 'wp-mail.php', 'wp-pass.php', 'wp-register.php', 'wp-settings.php', 'wp-signup.php', 'wp-trackback.php', 'xmlrpc.php');
|
599 |
$baseContents = scandir(ABSPATH);
|
600 |
if(! is_array($baseContents)){
|
@@ -627,7 +608,8 @@ class wfScanEngine {
|
|
627 |
$this->status(2, 'info', "Found " . sizeof($knownFilesThemes) . " themes");
|
628 |
$this->i->updateSummaryItem('totalThemes', sizeof($knownFilesThemes));
|
629 |
|
630 |
-
$
|
|
|
631 |
}
|
632 |
private function scan_knownFiles_main(){
|
633 |
$this->hasher->run($this); //Include this so we can call addIssue and ->api->
|
@@ -1337,8 +1319,17 @@ class wfScanEngine {
|
|
1337 |
public function status($level, $type, $msg){
|
1338 |
wordfence::status($level, $type, $msg);
|
1339 |
}
|
1340 |
-
public function addIssue($type, $severity, $ignoreP, $ignoreC, $shortMsg, $longMsg, $templateData){
|
1341 |
-
return $this->i->addIssue($type, $severity, $ignoreP, $ignoreC, $shortMsg, $longMsg, $templateData);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1342 |
}
|
1343 |
public static function requestKill(){
|
1344 |
wfConfig::set('wfKillRequested', time(), wfConfig::DONT_AUTOLOAD);
|
122 |
$this->jobList[] = 'checkSpamvertized';
|
123 |
$this->jobList[] = 'checkSpamIP';
|
124 |
$this->jobList[] = 'checkGSB';
|
|
|
125 |
$this->jobList[] = 'checkHowGetIPs_init';
|
126 |
$this->jobList[] = 'checkHowGetIPs_main';
|
127 |
$this->jobList[] = 'knownFiles_init';
|
277 |
public function getCurrentJob(){
|
278 |
return $this->jobList[0];
|
279 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
280 |
private function scan_publicSite(){
|
281 |
if(wfConfig::get('isPaid')){
|
282 |
if(wfConfig::get('scansEnabled_public')){
|
575 |
}
|
576 |
private function scan_knownFiles_init(){
|
577 |
$this->status(1, 'info', "Contacting Wordfence to initiate scan");
|
578 |
+
$response = $this->api->call('log_scan', array(), array());
|
579 |
$baseWPStuff = array( '.htaccess', 'index.php', 'license.txt', 'readme.html', 'wp-activate.php', 'wp-admin', 'wp-app.php', 'wp-blog-header.php', 'wp-comments-post.php', 'wp-config-sample.php', 'wp-content', 'wp-cron.php', 'wp-includes', 'wp-links-opml.php', 'wp-load.php', 'wp-login.php', 'wp-mail.php', 'wp-pass.php', 'wp-register.php', 'wp-settings.php', 'wp-signup.php', 'wp-trackback.php', 'xmlrpc.php');
|
580 |
$baseContents = scandir(ABSPATH);
|
581 |
if(! is_array($baseContents)){
|
608 |
$this->status(2, 'info', "Found " . sizeof($knownFilesThemes) . " themes");
|
609 |
$this->i->updateSummaryItem('totalThemes', sizeof($knownFilesThemes));
|
610 |
|
611 |
+
$malwarePrefixesHash = (isset($response['malwarePrefixes']) ? wfUtils::hex2bin($response['malwarePrefixes']) : '');
|
612 |
+
$this->hasher = new wordfenceHash(strlen(ABSPATH), ABSPATH, $includeInKnownFilesScan, $knownFilesThemes, $knownFilesPlugins, $this, $malwarePrefixesHash);
|
613 |
}
|
614 |
private function scan_knownFiles_main(){
|
615 |
$this->hasher->run($this); //Include this so we can call addIssue and ->api->
|
1319 |
public function status($level, $type, $msg){
|
1320 |
wordfence::status($level, $type, $msg);
|
1321 |
}
|
1322 |
+
public function addIssue($type, $severity, $ignoreP, $ignoreC, $shortMsg, $longMsg, $templateData, $alreadyHashed = false) {
|
1323 |
+
return $this->i->addIssue($type, $severity, $ignoreP, $ignoreC, $shortMsg, $longMsg, $templateData, $alreadyHashed);
|
1324 |
+
}
|
1325 |
+
public function addPendingIssue($type, $severity, $ignoreP, $ignoreC, $shortMsg, $longMsg, $templateData){
|
1326 |
+
return $this->i->addPendingIssue($type, $severity, $ignoreP, $ignoreC, $shortMsg, $longMsg, $templateData);
|
1327 |
+
}
|
1328 |
+
public function getPendingIssueCount() {
|
1329 |
+
return $this->i->getPendingIssueCount();
|
1330 |
+
}
|
1331 |
+
public function getPendingIssues($offset = 0, $limit = 100) {
|
1332 |
+
return $this->i->getPendingIssues($offset, $limit);
|
1333 |
}
|
1334 |
public static function requestKill(){
|
1335 |
wfConfig::set('wfKillRequested', time(), wfConfig::DONT_AUTOLOAD);
|
lib/wfSchema.php
CHANGED
@@ -58,17 +58,31 @@ class wfSchema {
|
|
58 |
KEY k2(IP, ctime)
|
59 |
) default charset=latin1",
|
60 |
"wfIssues" => "(
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
72 |
"wfLeechers" => "(
|
73 |
eMin int UNSIGNED NOT NULL,
|
74 |
IP int UNSIGNED NOT NULL,
|
58 |
KEY k2(IP, ctime)
|
59 |
) default charset=latin1",
|
60 |
"wfIssues" => "(
|
61 |
+
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
62 |
+
`time` int(10) unsigned NOT NULL,
|
63 |
+
`status` varchar(10) NOT NULL,
|
64 |
+
`type` varchar(20) NOT NULL,
|
65 |
+
`severity` tinyint(3) unsigned NOT NULL,
|
66 |
+
`ignoreP` char(32) NOT NULL,
|
67 |
+
`ignoreC` char(32) NOT NULL,
|
68 |
+
`shortMsg` varchar(255) NOT NULL,
|
69 |
+
`longMsg` text,
|
70 |
+
`data` text,
|
71 |
+
PRIMARY KEY (`id`)
|
72 |
+
) DEFAULT CHARSET=utf8",
|
73 |
+
"wfPendingIssues" => "(
|
74 |
+
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
75 |
+
`time` int(10) unsigned NOT NULL,
|
76 |
+
`status` varchar(10) NOT NULL,
|
77 |
+
`type` varchar(20) NOT NULL,
|
78 |
+
`severity` tinyint(3) unsigned NOT NULL,
|
79 |
+
`ignoreP` char(32) NOT NULL,
|
80 |
+
`ignoreC` char(32) NOT NULL,
|
81 |
+
`shortMsg` varchar(255) NOT NULL,
|
82 |
+
`longMsg` text,
|
83 |
+
`data` text,
|
84 |
+
PRIMARY KEY (`id`)
|
85 |
+
) DEFAULT CHARSET=utf8",
|
86 |
"wfLeechers" => "(
|
87 |
eMin int UNSIGNED NOT NULL,
|
88 |
IP int UNSIGNED NOT NULL,
|
lib/wfUtils.php
CHANGED
@@ -1775,6 +1775,12 @@ class wfUtils {
|
|
1775 |
return 'unknown';
|
1776 |
}
|
1777 |
|
|
|
|
|
|
|
|
|
|
|
|
|
1778 |
/**
|
1779 |
* Identical to the same functions in wfWAFUtils.
|
1780 |
*
|
@@ -1930,6 +1936,21 @@ class wfUtils {
|
|
1930 |
$args = func_get_args();
|
1931 |
return self::callMBSafeStrFunction('strrpos', $args);
|
1932 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1933 |
}
|
1934 |
|
1935 |
// GeoIP lib uses these as well
|
1775 |
return 'unknown';
|
1776 |
}
|
1777 |
|
1778 |
+
public static function hex2bin($string) { //Polyfill for PHP < 5.4
|
1779 |
+
if (!is_string($string)) { return false; }
|
1780 |
+
if (strlen($string) % 2 == 1) { return false; }
|
1781 |
+
return pack('H*', $string);
|
1782 |
+
}
|
1783 |
+
|
1784 |
/**
|
1785 |
* Identical to the same functions in wfWAFUtils.
|
1786 |
*
|
1936 |
$args = func_get_args();
|
1937 |
return self::callMBSafeStrFunction('strrpos', $args);
|
1938 |
}
|
1939 |
+
|
1940 |
+
/**
|
1941 |
+
* Returns the current timestamp, adjusted as needed to get close to what we consider a true timestamp. We use this
|
1942 |
+
* because a significant number of servers are using a drastically incorrect time.
|
1943 |
+
*
|
1944 |
+
* @return int
|
1945 |
+
*/
|
1946 |
+
public static function normalizedTime() {
|
1947 |
+
$offset = wfConfig::get('timeoffset_ntp', false);
|
1948 |
+
if ($offset === false) {
|
1949 |
+
$offset = wfConfig::get('timeoffset_wf', false);
|
1950 |
+
if ($offset === false) { $offset = 0; }
|
1951 |
+
}
|
1952 |
+
return time() + $offset;
|
1953 |
+
}
|
1954 |
}
|
1955 |
|
1956 |
// GeoIP lib uses these as well
|
lib/wordfenceClass.php
CHANGED
@@ -121,19 +121,7 @@ class wordfence {
|
|
121 |
$wfdb = new wfDB();
|
122 |
|
123 |
if(wfConfig::get('other_WFNet')){
|
124 |
-
$q1 = $wfdb->querySelect("select URI from $p"."wfNet404s where ctime > unix_timestamp() - 3600 limit 1000");
|
125 |
-
$URIs = array();
|
126 |
-
foreach($q1 as $rec){
|
127 |
-
$URIs[] = $rec['URI'];
|
128 |
-
}
|
129 |
$wfdb->truncate($p . "wfNet404s");
|
130 |
-
if(sizeof($URIs) > 0){
|
131 |
-
try {
|
132 |
-
$api->call('send_net_404s', array(), array( 'URIs' => json_encode($URIs) ));
|
133 |
-
} catch(Exception $e){
|
134 |
-
//Ignore
|
135 |
-
}
|
136 |
-
}
|
137 |
|
138 |
$q2 = $wfdb->querySelect("select IP from $p"."wfVulnScanners where ctime > unix_timestamp() - 3600");
|
139 |
$scanCont = "";
|
@@ -361,6 +349,9 @@ class wordfence {
|
|
361 |
}
|
362 |
}
|
363 |
|
|
|
|
|
|
|
364 |
wp_schedule_single_event(time(), 'wordfence_completeCoreUpdateNotification');
|
365 |
}
|
366 |
public static function _completeCoreUpdateNotification() {
|
@@ -481,11 +472,6 @@ SQL
|
|
481 |
$db->queryWrite("update $prefix"."wfConfig set val='1' where name='scansEnabled_options'");
|
482 |
}
|
483 |
|
484 |
-
$optScanEnabled = $db->querySingle("select val from $prefix"."wfConfig where name='scansEnabled_heartbleed'");
|
485 |
-
if($optScanEnabled != '0' && $optScanEnabled != '1'){ //Enable heartbleed if no value is set.
|
486 |
-
wfConfig::set('scansEnabled_heartbleed', 1);
|
487 |
-
}
|
488 |
-
|
489 |
// IPv6 schema changes for 6.0.1
|
490 |
$tables_with_ips = array(
|
491 |
'wfCrawlers',
|
@@ -692,6 +678,28 @@ SQL
|
|
692 |
$wpdb->query("ALTER TABLE {$blockedIPLogTable} ADD PRIMARY KEY (IP, unixday, blockType)");
|
693 |
}
|
694 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
695 |
//Check the How does Wordfence get IPs setting
|
696 |
wfUtils::requestDetectProxyCallback();
|
697 |
|
@@ -1230,7 +1238,7 @@ SQL
|
|
1230 |
));
|
1231 |
wp_mail($email, "Unlock email requested", $content, "Content-Type: text/html");
|
1232 |
}
|
1233 |
-
echo "<html><body><h1>Your request was received</h1><p>We received a request to email \"" . wp_kses($email, array()) . "\" instructions to unlock their access. If that is the email address of a site administrator or someone on the Wordfence alert list,
|
1234 |
exit();
|
1235 |
} else if($wfFunc == 'unlockAccess'){
|
1236 |
if (!preg_match('/^(?:(?:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){7})|(?:(?!(?:.*[a-f0-9](?::|$)){7,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?)))|(?:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){5}:)|(?:(?!(?:.*[a-f0-9]:){5,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3}:)?))?(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))(?:\.(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))){3}))$/i', get_transient('wfunlock_' . $_GET['key']))) {
|
@@ -1300,6 +1308,13 @@ SQL
|
|
1300 |
$waf->getStorageEngine()->setConfig($key, $value);
|
1301 |
}
|
1302 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1303 |
if (class_exists('wfWAFIPBlocksController')) {
|
1304 |
wfWAFIPBlocksController::synchronizeConfigSettings();
|
1305 |
}
|
@@ -3547,7 +3562,7 @@ HTACCESS;
|
|
3547 |
$jsonData = array(
|
3548 |
'serverTime' => $serverTime,
|
3549 |
'serverMicrotime' => microtime(true),
|
3550 |
-
'msg' => wp_kses_data( (string) $wfdb->querySingle("
|
3551 |
);
|
3552 |
$events = array();
|
3553 |
$alsoGet = $_POST['alsoGet'];
|
@@ -4841,6 +4856,7 @@ HTML;
|
|
4841 |
'cacheType' => wfConfig::get('cacheType'),
|
4842 |
'liveTrafficEnabled' => wfConfig::liveTrafficEnabled(),
|
4843 |
'scanIssuesPerPage' => WORDFENCE_SCAN_ISSUES_PER_PAGE,
|
|
|
4844 |
));
|
4845 |
}
|
4846 |
public static function activation_warning(){
|
121 |
$wfdb = new wfDB();
|
122 |
|
123 |
if(wfConfig::get('other_WFNet')){
|
|
|
|
|
|
|
|
|
|
|
124 |
$wfdb->truncate($p . "wfNet404s");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
125 |
|
126 |
$q2 = $wfdb->querySelect("select IP from $p"."wfVulnScanners where ctime > unix_timestamp() - 3600");
|
127 |
$scanCont = "";
|
349 |
}
|
350 |
}
|
351 |
|
352 |
+
$i = new wfIssues();
|
353 |
+
$i->reconcileUpgradeIssues($report, true);
|
354 |
+
|
355 |
wp_schedule_single_event(time(), 'wordfence_completeCoreUpdateNotification');
|
356 |
}
|
357 |
public static function _completeCoreUpdateNotification() {
|
472 |
$db->queryWrite("update $prefix"."wfConfig set val='1' where name='scansEnabled_options'");
|
473 |
}
|
474 |
|
|
|
|
|
|
|
|
|
|
|
475 |
// IPv6 schema changes for 6.0.1
|
476 |
$tables_with_ips = array(
|
477 |
'wfCrawlers',
|
678 |
$wpdb->query("ALTER TABLE {$blockedIPLogTable} ADD PRIMARY KEY (IP, unixday, blockType)");
|
679 |
}
|
680 |
|
681 |
+
//6.3.6
|
682 |
+
if (!wfConfig::get('migration636_email_summary_excluded_directories')) {
|
683 |
+
$excluded_directories = explode(',', (string) wfConfig::get('email_summary_excluded_directories'));
|
684 |
+
$key = array_search('wp-content/plugins/wordfence/tmp', $excluded_directories); if ($key !== false) { unset($excluded_directories[$key]); }
|
685 |
+
$key = array_search('wp-content/wflogs', $excluded_directories); if ($key === false) { $excluded_directories[] = 'wp-content/wflogs'; }
|
686 |
+
wfConfig::set('email_summary_excluded_directories', implode(',', $excluded_directories));
|
687 |
+
wfConfig::set('migration636_email_summary_excluded_directories', 1, wfConfig::DONT_AUTOLOAD);
|
688 |
+
}
|
689 |
+
|
690 |
+
$fileModsTable = wfDB::networkPrefix() . 'wfFileMods';
|
691 |
+
$hasSHAC = $wpdb->get_col($wpdb->prepare(<<<SQL
|
692 |
+
SELECT * FROM information_schema.COLUMNS
|
693 |
+
WHERE TABLE_SCHEMA=DATABASE()
|
694 |
+
AND COLUMN_NAME='SHAC'
|
695 |
+
AND TABLE_NAME=%s
|
696 |
+
SQL
|
697 |
+
, $fileModsTable));
|
698 |
+
if (!$hasSHAC) {
|
699 |
+
$wpdb->query("ALTER TABLE {$fileModsTable} ADD COLUMN `SHAC` BINARY(32) NOT NULL DEFAULT '' AFTER `newMD5`");
|
700 |
+
$wpdb->query("ALTER TABLE {$fileModsTable} ADD COLUMN `isSafeFile` VARCHAR(1) NOT NULL DEFAULT '?' AFTER `stoppedOnPosition`");
|
701 |
+
}
|
702 |
+
|
703 |
//Check the How does Wordfence get IPs setting
|
704 |
wfUtils::requestDetectProxyCallback();
|
705 |
|
1238 |
));
|
1239 |
wp_mail($email, "Unlock email requested", $content, "Content-Type: text/html");
|
1240 |
}
|
1241 |
+
echo "<html><body><h1>Your request was received</h1><p>We received a request to email \"" . wp_kses($email, array()) . "\" instructions to unlock their access. If that is the email address of a site administrator or someone on the Wordfence alert list, they have been emailed instructions on how to regain access to this system. The instructions we sent will expire 30 minutes from now.</body></html>";
|
1242 |
exit();
|
1243 |
} else if($wfFunc == 'unlockAccess'){
|
1244 |
if (!preg_match('/^(?:(?:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){7})|(?:(?!(?:.*[a-f0-9](?::|$)){7,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?)))|(?:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){5}:)|(?:(?!(?:.*[a-f0-9]:){5,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3}:)?))?(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))(?:\.(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))){3}))$/i', get_transient('wfunlock_' . $_GET['key']))) {
|
1308 |
$waf->getStorageEngine()->setConfig($key, $value);
|
1309 |
}
|
1310 |
|
1311 |
+
if (wfConfig::get('timeoffset_wf') !== false) {
|
1312 |
+
$waf->getStorageEngine()->setConfig('timeoffset_wf', wfConfig::get('timeoffset_wf'));
|
1313 |
+
}
|
1314 |
+
else {
|
1315 |
+
$waf->getStorageEngine()->unsetConfig('timeoffset_wf');
|
1316 |
+
}
|
1317 |
+
|
1318 |
if (class_exists('wfWAFIPBlocksController')) {
|
1319 |
wfWAFIPBlocksController::synchronizeConfigSettings();
|
1320 |
}
|
3562 |
$jsonData = array(
|
3563 |
'serverTime' => $serverTime,
|
3564 |
'serverMicrotime' => microtime(true),
|
3565 |
+
'msg' => wp_kses_data( (string) $wfdb->querySingle("SELECT msg FROM {$p}wfStatus WHERE level < 3 AND ctime > (UNIX_TIMESTAMP() - 3600) ORDER BY ctime DESC LIMIT 1"))
|
3566 |
);
|
3567 |
$events = array();
|
3568 |
$alsoGet = $_POST['alsoGet'];
|
4856 |
'cacheType' => wfConfig::get('cacheType'),
|
4857 |
'liveTrafficEnabled' => wfConfig::liveTrafficEnabled(),
|
4858 |
'scanIssuesPerPage' => WORDFENCE_SCAN_ISSUES_PER_PAGE,
|
4859 |
+
'allowsPausing' => wfConfig::get('liveActivityPauseEnabled'),
|
4860 |
));
|
4861 |
}
|
4862 |
public static function activation_warning(){
|
lib/wordfenceHash.php
CHANGED
@@ -41,7 +41,7 @@ class wordfenceHash {
|
|
41 |
* @param wfScanEngine $engine
|
42 |
* @throws Exception
|
43 |
*/
|
44 |
-
public function __construct($striplen, $path, $only, $themes, $plugins, $engine){
|
45 |
$this->striplen = $striplen;
|
46 |
$this->path = $path;
|
47 |
$this->only = $only;
|
@@ -71,6 +71,7 @@ class wordfenceHash {
|
|
71 |
//$this->db->queryWrite("update " . $this->db->prefix() . "wfFileMods set oldMD5 = newMD5");
|
72 |
$this->db->truncate($this->db->prefix() . "wfFileMods");
|
73 |
$this->db->truncate($this->db->prefix() . "wfKnownFileList");
|
|
|
74 |
$fetchCoreHashesStatus = wordfence::statusStart("Fetching core, theme and plugin file signatures from Wordfence");
|
75 |
try {
|
76 |
$this->knownFiles = $this->engine->getKnownFilesLoader()
|
@@ -80,21 +81,32 @@ class wordfenceHash {
|
|
80 |
throw $e;
|
81 |
}
|
82 |
wordfence::statusEnd($fetchCoreHashesStatus, false, true);
|
83 |
-
if($this->malwareEnabled){
|
84 |
$malwarePrefixStatus = wordfence::statusStart("Fetching list of known malware files from Wordfence");
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
}
|
90 |
-
if(strlen($malwareData) % 4 != 0){
|
91 |
-
wordfence::statusEndErr();
|
92 |
-
throw new Exception("Malware data received from Wordfence servers was not valid.");
|
93 |
}
|
94 |
-
|
95 |
-
|
96 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
97 |
}
|
|
|
|
|
98 |
wordfence::statusEnd($malwarePrefixStatus, false, true);
|
99 |
}
|
100 |
|
@@ -118,12 +130,18 @@ class wordfenceHash {
|
|
118 |
if($this->coreUnknownEnabled){ $this->status['coreUnknown'] = wordfence::statusStart("Scanning for unknown files in wp-admin and wp-includes"); } else { wordfence::statusDisabled("Skipping unknown core file scan"); }
|
119 |
}
|
120 |
public function __sleep(){
|
121 |
-
return array('striplen', 'totalFiles', 'totalDirs', 'totalData', 'stoppedOnFile', 'coreEnabled', 'pluginsEnabled', 'themesEnabled', 'malwareEnabled', 'coreUnknownEnabled', 'knownFiles', '
|
122 |
}
|
123 |
public function __wakeup(){
|
124 |
$this->db = new wfDB();
|
125 |
$this->startTime = microtime(true);
|
126 |
$this->totalForks++;
|
|
|
|
|
|
|
|
|
|
|
|
|
127 |
}
|
128 |
public function getSuspectedFiles() {
|
129 |
return array_keys($this->suspectedFiles);
|
@@ -164,6 +182,9 @@ class wordfenceHash {
|
|
164 |
$this->_checkForTimeout($file);
|
165 |
}
|
166 |
|
|
|
|
|
|
|
167 |
wordfence::status(2, 'info', "Analyzed " . $this->totalFiles . " files containing " . wfUtils::formatBytes($this->totalData) . " of data.");
|
168 |
if($this->coreEnabled){ wordfence::statusEnd($this->status['core'], $this->haveIssues['core']); }
|
169 |
if($this->themesEnabled){ wordfence::statusEnd($this->status['themes'], $this->haveIssues['themes']); }
|
@@ -409,28 +430,24 @@ class wordfenceHash {
|
|
409 |
{
|
410 |
$localFile = ABSPATH . '/' . preg_replace('/^[\.\/]+/', '', $file);
|
411 |
$fileContents = @file_get_contents($localFile);
|
412 |
-
if ($fileContents && (!preg_match('/<\?' . 'php[\r\n\s\t]*\/\/[\r\n\s\t]*Silence is golden\.[\r\n\s\t]*(?:\?>)?[\r\n\s\t]*$/s', $fileContents)))
|
413 |
-
|
414 |
-
|
415 |
-
|
416 |
-
|
417 |
-
|
418 |
-
$
|
419 |
-
|
420 |
-
|
421 |
-
|
422 |
-
'
|
423 |
-
'
|
424 |
-
|
425 |
-
|
426 |
-
|
427 |
-
|
428 |
-
|
429 |
-
|
430 |
-
'canDelete' => false
|
431 |
-
)
|
432 |
-
);
|
433 |
-
}
|
434 |
}
|
435 |
}
|
436 |
}
|
@@ -448,13 +465,12 @@ class wordfenceHash {
|
|
448 |
$shouldGenerateIssue = false;
|
449 |
}
|
450 |
|
451 |
-
if (
|
452 |
{
|
453 |
$itemName = $this->knownFiles['plugins'][$file][0];
|
454 |
$itemVersion = $this->knownFiles['plugins'][$file][1];
|
455 |
$cKey = $this->knownFiles['plugins'][$file][2];
|
456 |
-
$this->
|
457 |
-
$this->engine->addIssue(
|
458 |
'knownfile',
|
459 |
2,
|
460 |
'modifiedplugin' . $file . $md5,
|
@@ -469,7 +485,8 @@ class wordfenceHash {
|
|
469 |
'canDelete' => false,
|
470 |
'cName' => $itemName,
|
471 |
'cVersion' => $itemVersion,
|
472 |
-
'cKey' => $cKey
|
|
|
473 |
)
|
474 |
);
|
475 |
}
|
@@ -490,13 +507,12 @@ class wordfenceHash {
|
|
490 |
$shouldGenerateIssue = false;
|
491 |
}
|
492 |
|
493 |
-
if (
|
494 |
{
|
495 |
$itemName = $this->knownFiles['themes'][$file][0];
|
496 |
$itemVersion = $this->knownFiles['themes'][$file][1];
|
497 |
$cKey = $this->knownFiles['themes'][$file][2];
|
498 |
-
$this->
|
499 |
-
$this->engine->addIssue(
|
500 |
'knownfile',
|
501 |
2,
|
502 |
'modifiedtheme' . $file . $md5,
|
@@ -511,7 +527,8 @@ class wordfenceHash {
|
|
511 |
'canDelete' => false,
|
512 |
'cName' => $itemName,
|
513 |
'cVersion' => $itemVersion,
|
514 |
-
'cKey' => $cKey
|
|
|
515 |
)
|
516 |
);
|
517 |
}
|
@@ -536,7 +553,7 @@ class wordfenceHash {
|
|
536 |
'cType' => 'core',
|
537 |
'canDiff' => false,
|
538 |
'canFix' => false,
|
539 |
-
'canDelete' => true
|
540 |
)
|
541 |
);
|
542 |
}
|
@@ -544,9 +561,10 @@ class wordfenceHash {
|
|
544 |
}
|
545 |
}
|
546 |
// knownFile means that the file is both part of core or a known plugin or theme AND that we recognize the file's hash.
|
547 |
-
// we could split this into files
|
548 |
-
// But because we want to scan files
|
549 |
-
$
|
|
|
550 |
|
551 |
$this->totalFiles++;
|
552 |
$this->totalData += @filesize($realFile); //We already checked if file overflows int in the fileTooBig routine above
|
@@ -558,6 +576,61 @@ class wordfenceHash {
|
|
558 |
}
|
559 |
wfUtils::endProcessingFile();
|
560 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
561 |
public static function wfHash($file){
|
562 |
$fp = @fopen($file, "rb");
|
563 |
if (!$fp) {
|
@@ -639,13 +712,57 @@ class wordfenceHash {
|
|
639 |
return false;
|
640 |
}
|
641 |
private function isMalwarePrefix($hexMD5){
|
642 |
-
$
|
643 |
-
|
644 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
645 |
}
|
|
|
646 |
return false;
|
647 |
}
|
648 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
649 |
$result = $this->engine->api->call('is_safe_file', array(), array('shac' => strtoupper($shac)));
|
650 |
if(isset($result['isSafe']) && $result['isSafe'] == 1){
|
651 |
return true;
|
41 |
* @param wfScanEngine $engine
|
42 |
* @throws Exception
|
43 |
*/
|
44 |
+
public function __construct($striplen, $path, $only, $themes, $plugins, $engine, $malwarePrefixesHash){
|
45 |
$this->striplen = $striplen;
|
46 |
$this->path = $path;
|
47 |
$this->only = $only;
|
71 |
//$this->db->queryWrite("update " . $this->db->prefix() . "wfFileMods set oldMD5 = newMD5");
|
72 |
$this->db->truncate($this->db->prefix() . "wfFileMods");
|
73 |
$this->db->truncate($this->db->prefix() . "wfKnownFileList");
|
74 |
+
$this->db->truncate($this->db->prefix() . "wfPendingIssues");
|
75 |
$fetchCoreHashesStatus = wordfence::statusStart("Fetching core, theme and plugin file signatures from Wordfence");
|
76 |
try {
|
77 |
$this->knownFiles = $this->engine->getKnownFilesLoader()
|
81 |
throw $e;
|
82 |
}
|
83 |
wordfence::statusEnd($fetchCoreHashesStatus, false, true);
|
84 |
+
if ($this->malwareEnabled) {
|
85 |
$malwarePrefixStatus = wordfence::statusStart("Fetching list of known malware files from Wordfence");
|
86 |
+
|
87 |
+
$stored = wfConfig::get_ser('malwarePrefixes', array(), false);
|
88 |
+
if (is_array($stored) && isset($stored['hash']) && $stored['hash'] == $malwarePrefixesHash && isset($stored['prefixes']) && wfWAFUtils::strlen($stored['prefixes']) % 4 == 0) {
|
89 |
+
wordfence::status(4, 'info', "Using cached malware prefixes");
|
|
|
|
|
|
|
|
|
90 |
}
|
91 |
+
else {
|
92 |
+
wordfence::status(4, 'info', "Fetching fresh malware prefixes");
|
93 |
+
|
94 |
+
$malwareData = $engine->api->getStaticURL('/malwarePrefixes.bin');
|
95 |
+
if (!$malwareData) {
|
96 |
+
wordfence::statusEndErr();
|
97 |
+
throw new Exception("Could not fetch malware signatures from Wordfence servers.");
|
98 |
+
}
|
99 |
+
|
100 |
+
if (wfWAFUtils::strlen($malwareData) % 4 != 0) {
|
101 |
+
wordfence::statusEndErr();
|
102 |
+
throw new Exception("Malware data received from Wordfence servers was not valid.");
|
103 |
+
}
|
104 |
+
|
105 |
+
$stored = array('hash' => $malwarePrefixesHash, 'prefixes' => $malwareData);
|
106 |
+
wfConfig::set_ser('malwarePrefixes', $stored, true, wfConfig::DONT_AUTOLOAD);
|
107 |
}
|
108 |
+
|
109 |
+
$this->malwareData = $stored['prefixes'];
|
110 |
wordfence::statusEnd($malwarePrefixStatus, false, true);
|
111 |
}
|
112 |
|
130 |
if($this->coreUnknownEnabled){ $this->status['coreUnknown'] = wordfence::statusStart("Scanning for unknown files in wp-admin and wp-includes"); } else { wordfence::statusDisabled("Skipping unknown core file scan"); }
|
131 |
}
|
132 |
public function __sleep(){
|
133 |
+
return array('striplen', 'totalFiles', 'totalDirs', 'totalData', 'stoppedOnFile', 'coreEnabled', 'pluginsEnabled', 'themesEnabled', 'malwareEnabled', 'coreUnknownEnabled', 'knownFiles', 'haveIssues', 'status', 'possibleMalware', 'path', 'only', 'totalForks', 'alertedOnUnknownWordPressVersion', 'foldersProcessed', 'suspectedFiles', 'indexed', 'indexSize', 'currentIndex', 'foldersEntered');
|
134 |
}
|
135 |
public function __wakeup(){
|
136 |
$this->db = new wfDB();
|
137 |
$this->startTime = microtime(true);
|
138 |
$this->totalForks++;
|
139 |
+
|
140 |
+
$stored = wfConfig::get_ser('malwarePrefixes', array(), false);
|
141 |
+
if (!isset($stored['prefixes'])) {
|
142 |
+
$stored['prefixes'] = '';
|
143 |
+
}
|
144 |
+
$this->malwareData = $stored['prefixes'];
|
145 |
}
|
146 |
public function getSuspectedFiles() {
|
147 |
return array_keys($this->suspectedFiles);
|
182 |
$this->_checkForTimeout($file);
|
183 |
}
|
184 |
|
185 |
+
wordfence::status(4, 'info', "Processing pending issues");
|
186 |
+
$this->_processPendingIssues();
|
187 |
+
|
188 |
wordfence::status(2, 'info', "Analyzed " . $this->totalFiles . " files containing " . wfUtils::formatBytes($this->totalData) . " of data.");
|
189 |
if($this->coreEnabled){ wordfence::statusEnd($this->status['core'], $this->haveIssues['core']); }
|
190 |
if($this->themesEnabled){ wordfence::statusEnd($this->status['themes'], $this->haveIssues['themes']); }
|
430 |
{
|
431 |
$localFile = ABSPATH . '/' . preg_replace('/^[\.\/]+/', '', $file);
|
432 |
$fileContents = @file_get_contents($localFile);
|
433 |
+
if ($fileContents && (!preg_match('/<\?' . 'php[\r\n\s\t]*\/\/[\r\n\s\t]*Silence is golden\.[\r\n\s\t]*(?:\?>)?[\r\n\s\t]*$/s', $fileContents))) {
|
434 |
+
$this->haveIssues['core'] = true;
|
435 |
+
$this->engine->addPendingIssue(
|
436 |
+
'knownfile',
|
437 |
+
1,
|
438 |
+
'coreModified' . $file . $md5,
|
439 |
+
'coreModified' . $file,
|
440 |
+
'WordPress core file modified: ' . $file,
|
441 |
+
"This WordPress core file has been modified and differs from the original file distributed with this version of WordPress.",
|
442 |
+
array(
|
443 |
+
'file' => $file,
|
444 |
+
'cType' => 'core',
|
445 |
+
'canDiff' => true,
|
446 |
+
'canFix' => true,
|
447 |
+
'canDelete' => false,
|
448 |
+
'haveIssues' => 'core'
|
449 |
+
)
|
450 |
+
);
|
|
|
|
|
|
|
|
|
451 |
}
|
452 |
}
|
453 |
}
|
465 |
$shouldGenerateIssue = false;
|
466 |
}
|
467 |
|
468 |
+
if ($shouldGenerateIssue)
|
469 |
{
|
470 |
$itemName = $this->knownFiles['plugins'][$file][0];
|
471 |
$itemVersion = $this->knownFiles['plugins'][$file][1];
|
472 |
$cKey = $this->knownFiles['plugins'][$file][2];
|
473 |
+
$this->engine->addPendingIssue(
|
|
|
474 |
'knownfile',
|
475 |
2,
|
476 |
'modifiedplugin' . $file . $md5,
|
485 |
'canDelete' => false,
|
486 |
'cName' => $itemName,
|
487 |
'cVersion' => $itemVersion,
|
488 |
+
'cKey' => $cKey,
|
489 |
+
'haveIssues' => 'plugins'
|
490 |
)
|
491 |
);
|
492 |
}
|
507 |
$shouldGenerateIssue = false;
|
508 |
}
|
509 |
|
510 |
+
if ($shouldGenerateIssue)
|
511 |
{
|
512 |
$itemName = $this->knownFiles['themes'][$file][0];
|
513 |
$itemVersion = $this->knownFiles['themes'][$file][1];
|
514 |
$cKey = $this->knownFiles['themes'][$file][2];
|
515 |
+
$this->engine->addPendingIssue(
|
|
|
516 |
'knownfile',
|
517 |
2,
|
518 |
'modifiedtheme' . $file . $md5,
|
527 |
'canDelete' => false,
|
528 |
'cName' => $itemName,
|
529 |
'cVersion' => $itemVersion,
|
530 |
+
'cKey' => $cKey,
|
531 |
+
'haveIssues' => 'themes'
|
532 |
)
|
533 |
);
|
534 |
}
|
553 |
'cType' => 'core',
|
554 |
'canDiff' => false,
|
555 |
'canFix' => false,
|
556 |
+
'canDelete' => true,
|
557 |
)
|
558 |
);
|
559 |
}
|
561 |
}
|
562 |
}
|
563 |
// knownFile means that the file is both part of core or a known plugin or theme AND that we recognize the file's hash.
|
564 |
+
// we could split this into files whose path we recognize and file's whose path we recognize AND who have a valid sig.
|
565 |
+
// But because we want to scan files whose sig we don't recognize, regardless of known path or not, we only need one "knownFile" field.
|
566 |
+
$fileModsTable = $this->db->prefix() . 'wfFileMods';
|
567 |
+
$this->db->queryWrite("INSERT INTO {$fileModsTable} (filename, filenameMD5, knownFile, oldMD5, newMD5, SHAC) VALUES ('%s', UNHEX(MD5('%s')), %d, '', UNHEX('%s'), UNHEX('%s')) ON DUPLICATE KEY UPDATE newMD5 = UNHEX('%s'), SHAC = UNHEX('%s'), knownFile = %d", $file, $file, $knownFile, $md5, $shac, $md5, $shac, $knownFile);
|
568 |
|
569 |
$this->totalFiles++;
|
570 |
$this->totalData += @filesize($realFile); //We already checked if file overflows int in the fileTooBig routine above
|
576 |
}
|
577 |
wfUtils::endProcessingFile();
|
578 |
}
|
579 |
+
private function _processPendingIssues() {
|
580 |
+
$fileModsTable = $this->db->prefix() . 'wfFileMods';
|
581 |
+
|
582 |
+
$count = $this->engine->getPendingIssueCount();
|
583 |
+
$offset = 0;
|
584 |
+
while ($offset < $count) {
|
585 |
+
$issues = $this->engine->getPendingIssues($offset);
|
586 |
+
if (count($issues) == 0) {
|
587 |
+
break;
|
588 |
+
}
|
589 |
+
|
590 |
+
//Do a bulk check of is_safe_file
|
591 |
+
$hashesToCheck = array();
|
592 |
+
foreach ($issues as &$i) {
|
593 |
+
$shac = $this->db->querySingle("SELECT HEX(SHAC) FROM {$fileModsTable} WHERE filename = '%s' AND isSafeFile = '?'", $i['data']['file']);
|
594 |
+
$shac = strtoupper($shac);
|
595 |
+
$i['shac'] = null;
|
596 |
+
if ($shac !== null) {
|
597 |
+
$shac = strtoupper($shac);
|
598 |
+
$i['shac'] = $shac;
|
599 |
+
$hashesToCheck[] = $shac;
|
600 |
+
}
|
601 |
+
}
|
602 |
+
|
603 |
+
$safeFiles = array();
|
604 |
+
if (count($hashesToCheck) > 0) {
|
605 |
+
$safeFiles = $this->isSafeFile($hashesToCheck);
|
606 |
+
}
|
607 |
+
|
608 |
+
//Migrate non-safe file issues to official issues
|
609 |
+
foreach ($issues as &$i) {
|
610 |
+
if (!in_array($i['shac'], $safeFiles)) {
|
611 |
+
$haveIssuesType = $i['data']['haveIssues'];
|
612 |
+
$this->haveIssues[$haveIssuesType] = true;
|
613 |
+
$this->engine->addIssue(
|
614 |
+
$i['type'],
|
615 |
+
$i['severity'],
|
616 |
+
$i['ignoreP'],
|
617 |
+
$i['ignoreC'],
|
618 |
+
$i['shortMsg'],
|
619 |
+
$i['longMsg'],
|
620 |
+
$i['data'],
|
621 |
+
true //Prevent ignoreP and ignoreC from being hashed again
|
622 |
+
);
|
623 |
+
$this->db->queryWrite("UPDATE {$fileModsTable} SET isSafeFile = '0' WHERE SHAC = UNHEX('%s')", $i['shac']);
|
624 |
+
}
|
625 |
+
else {
|
626 |
+
$this->db->queryWrite("UPDATE {$fileModsTable} SET isSafeFile = '1' WHERE SHAC = UNHEX('%s')", $i['shac']);
|
627 |
+
}
|
628 |
+
}
|
629 |
+
|
630 |
+
$offset += count($issues);
|
631 |
+
$this->engine->checkForKill();
|
632 |
+
}
|
633 |
+
}
|
634 |
public static function wfHash($file){
|
635 |
$fp = @fopen($file, "rb");
|
636 |
if (!$fp) {
|
712 |
return false;
|
713 |
}
|
714 |
private function isMalwarePrefix($hexMD5){
|
715 |
+
$hasPrefix = $this->_prefixListContainsMD5($this->malwareData, wfUtils::hex2bin($hexMD5));
|
716 |
+
return $hasPrefix !== false;
|
717 |
+
}
|
718 |
+
|
719 |
+
/**
|
720 |
+
* @param $prefixList The prefix list to search, sorted as a binary string.
|
721 |
+
* @param $md5 The binary MD5 hash to search for.
|
722 |
+
* @return bool|int false if not found, otherwise the index in the list
|
723 |
+
*/
|
724 |
+
private function _prefixListContainsMD5($prefixList, $md5) {
|
725 |
+
$size = 4; //bytes
|
726 |
+
$p = substr($md5, 0, $size);
|
727 |
+
|
728 |
+
$count = ceil(wfWAFUtils::strlen($prefixList) / $size);
|
729 |
+
$low = 0;
|
730 |
+
$high = $count - 1;
|
731 |
+
|
732 |
+
while ($low <= $high) {
|
733 |
+
$mid = (int) (($high + $low) / 2);
|
734 |
+
$val = wfWAFUtils::substr($prefixList, $mid * $size, $size);
|
735 |
+
$cmp = strcmp($val, $p);
|
736 |
+
if ($cmp < 0) {
|
737 |
+
$low = $mid + 1;
|
738 |
+
}
|
739 |
+
else if ($cmp > 0) {
|
740 |
+
$high = $mid - 1;
|
741 |
+
}
|
742 |
+
else {
|
743 |
+
return $mid;
|
744 |
+
}
|
745 |
}
|
746 |
+
|
747 |
return false;
|
748 |
}
|
749 |
+
|
750 |
+
/**
|
751 |
+
* Queries the is_safe_file endpoint. If provided an array, it does a bulk check and returns an array containing the
|
752 |
+
* hashes that were marked as safe. If provided a string, it returns a boolean to indicate the safeness of the file.
|
753 |
+
*
|
754 |
+
* @param string|array $shac
|
755 |
+
* @return array|bool
|
756 |
+
*/
|
757 |
+
private function isSafeFile($shac) {
|
758 |
+
if (is_array($shac)) {
|
759 |
+
$result = $this->engine->api->call('is_safe_file', array(), array('multipleSHAC' => json_encode($shac)));
|
760 |
+
if (isset($result['isSafe'])) {
|
761 |
+
return $result['isSafe'];
|
762 |
+
}
|
763 |
+
return array();
|
764 |
+
}
|
765 |
+
|
766 |
$result = $this->engine->api->call('is_safe_file', array(), array('shac' => strtoupper($shac)));
|
767 |
if(isset($result['isSafe']) && $result['isSafe'] == 1){
|
768 |
return true;
|
lib/wordfenceScanner.php
CHANGED
@@ -301,21 +301,20 @@ class wordfenceScanner {
|
|
301 |
|
302 |
$treatAsBinary = ($isPHP || $isHTML || wfConfig::get('scansEnabled_scanImages'));
|
303 |
if ($treatAsBinary && wfUtils::strpos($data, '$allowed'.'Sites') !== false && wfUtils::strpos($data, "define ('VER"."SION', '1.") !== false && wfUtils::strpos($data, "TimThum"."b script created by") !== false) {
|
304 |
-
|
305 |
-
|
306 |
-
|
307 |
-
|
308 |
-
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
}
|
319 |
else {
|
320 |
$regexMatched = false;
|
321 |
foreach ($this->patterns['rules'] as $rule) {
|
@@ -336,28 +335,27 @@ class wordfenceScanner {
|
|
336 |
else if (($type == 'both' || $type == 'browser') && !$treatAsBinary) { continue; }
|
337 |
|
338 |
if (preg_match('/(' . $rule[2] . ')/i', $data, $matches, PREG_OFFSET_CAPTURE)) {
|
339 |
-
|
340 |
-
|
341 |
-
|
342 |
-
|
343 |
-
|
344 |
-
|
345 |
-
|
346 |
-
|
347 |
-
|
348 |
-
|
349 |
-
|
350 |
-
|
351 |
-
|
352 |
-
'
|
353 |
-
|
354 |
-
|
355 |
-
|
356 |
-
}
|
357 |
-
$regexMatched = true;
|
358 |
-
$this->scanEngine->recordMetric('malwareSignature', $rule[0], array('file' => $file, 'match' => $matchString, 'before' => $beforeString, 'after' => $afterString), false);
|
359 |
-
break;
|
360 |
}
|
|
|
|
|
|
|
361 |
}
|
362 |
|
363 |
if ($forkObj->shouldFork()) {
|
@@ -383,20 +381,19 @@ class wordfenceScanner {
|
|
383 |
}
|
384 |
}
|
385 |
if ($badStringFound) {
|
386 |
-
|
387 |
-
|
388 |
-
|
389 |
-
|
390 |
-
|
391 |
-
|
392 |
-
|
393 |
-
|
394 |
-
'
|
395 |
-
|
396 |
-
|
397 |
-
|
398 |
-
|
399 |
-
}
|
400 |
}
|
401 |
}
|
402 |
|
@@ -430,6 +427,7 @@ class wordfenceScanner {
|
|
430 |
$siteURL = get_site_url();
|
431 |
$siteHost = parse_url($siteURL, PHP_URL_HOST);
|
432 |
foreach($hooverResults as $file => $hresults){
|
|
|
433 |
$dataForFile = $this->dataForFile($file, $this->path . $file);
|
434 |
|
435 |
foreach($hresults as $result){
|
@@ -447,41 +445,54 @@ class wordfenceScanner {
|
|
447 |
}
|
448 |
|
449 |
if($result['badList'] == 'goog-malware-shavar'){
|
450 |
-
|
451 |
-
|
452 |
-
|
453 |
-
|
454 |
-
|
455 |
-
|
456 |
-
|
457 |
-
|
458 |
-
'
|
459 |
-
|
460 |
-
|
461 |
-
|
462 |
-
|
463 |
-
|
464 |
-
}
|
465 |
} else if($result['badList'] == 'googpub-phish-shavar'){
|
466 |
-
|
467 |
-
|
468 |
-
|
469 |
-
|
470 |
-
|
471 |
-
|
472 |
-
|
473 |
-
|
474 |
-
'
|
475 |
-
|
476 |
-
|
477 |
-
|
478 |
-
|
479 |
-
|
480 |
-
}
|
481 |
}
|
482 |
}
|
483 |
}
|
484 |
wfUtils::endProcessingFile();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
485 |
|
486 |
return $this->results;
|
487 |
}
|
@@ -502,13 +513,28 @@ class wordfenceScanner {
|
|
502 |
//We don't have a results for this file so append
|
503 |
$this->results[] = $result;
|
504 |
}
|
505 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
506 |
if(! $this->api){
|
507 |
$this->api = new wfAPI($this->apiKey, $this->wordpressVersion);
|
508 |
}
|
509 |
-
|
510 |
-
|
511 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
512 |
if(isset($result['isSafe']) && $result['isSafe'] == 1){
|
513 |
return true;
|
514 |
}
|
@@ -584,15 +610,19 @@ class wordfenceScanner {
|
|
584 |
* @property string $filename
|
585 |
* @property string $filenameMD5
|
586 |
* @property string $newMD5
|
|
|
587 |
* @property string $stoppedOnSignature
|
588 |
* @property string $stoppedOnPosition
|
|
|
589 |
*/
|
590 |
class wordfenceMalwareScanFile {
|
591 |
protected $_filename;
|
592 |
protected $_filenameMD5;
|
593 |
protected $_newMD5;
|
|
|
594 |
protected $_stoppedOnSignature;
|
595 |
protected $_stoppedOnPosition;
|
|
|
596 |
|
597 |
protected static function getDB() {
|
598 |
static $db = null;
|
@@ -609,20 +639,28 @@ class wordfenceMalwareScanFile {
|
|
609 |
|
610 |
public static function files($limit = 500) {
|
611 |
$db = self::getDB();
|
612 |
-
$result = $db->querySelect("SELECT filename, filenameMD5, HEX(newMD5) AS newMD5, stoppedOnSignature, stoppedOnPosition FROM " . wfDB::networkPrefix() . "wfFileMods WHERE oldMD5 != newMD5 AND knownFile = 0 limit %d", $limit);
|
613 |
$files = array();
|
614 |
foreach ($result as $row) {
|
615 |
-
$files[] = new wordfenceMalwareScanFile($row['filename'], $row['filenameMD5'], $row['newMD5'], $row['stoppedOnSignature'], $row['stoppedOnPosition']);
|
616 |
}
|
617 |
return $files;
|
618 |
}
|
619 |
|
620 |
-
public function
|
|
|
|
|
|
|
|
|
|
|
|
|
621 |
$this->_filename = $filename;
|
622 |
$this->_filenameMD5 = $filenameMD5;
|
623 |
$this->_newMD5 = $newMD5;
|
|
|
624 |
$this->_stoppedOnSignature = $stoppedOnSignature;
|
625 |
$this->_stoppedOnPosition = $stoppedOnPosition;
|
|
|
626 |
}
|
627 |
|
628 |
public function __get($key) {
|
@@ -633,10 +671,14 @@ class wordfenceMalwareScanFile {
|
|
633 |
return $this->_filenameMD5;
|
634 |
case 'newMD5':
|
635 |
return $this->_newMD5;
|
|
|
|
|
636 |
case 'stoppedOnSignature':
|
637 |
return $this->_stoppedOnSignature;
|
638 |
case 'stoppedOnPosition':
|
639 |
return $this->_stoppedOnPosition;
|
|
|
|
|
640 |
}
|
641 |
}
|
642 |
|
@@ -655,6 +697,18 @@ class wordfenceMalwareScanFile {
|
|
655 |
$db = self::getDB();
|
656 |
$db->queryWrite("UPDATE " . wfDB::networkPrefix() . "wfFileMods SET stoppedOnSignature = '%s', stoppedOnPosition = %d WHERE filenameMD5 = '%s'", $this->stoppedOnSignature, $this->stoppedOnPosition, $this->filenameMD5);
|
657 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
658 |
}
|
659 |
|
660 |
?>
|
301 |
|
302 |
$treatAsBinary = ($isPHP || $isHTML || wfConfig::get('scansEnabled_scanImages'));
|
303 |
if ($treatAsBinary && wfUtils::strpos($data, '$allowed'.'Sites') !== false && wfUtils::strpos($data, "define ('VER"."SION', '1.") !== false && wfUtils::strpos($data, "TimThum"."b script created by") !== false) {
|
304 |
+
$this->addResult(array(
|
305 |
+
'type' => 'file',
|
306 |
+
'severity' => 1,
|
307 |
+
'ignoreP' => $this->path . $file,
|
308 |
+
'ignoreC' => $fileSum,
|
309 |
+
'shortMsg' => "File is an old version of TimThumb which is vulnerable.",
|
310 |
+
'longMsg' => "This file appears to be an old version of the TimThumb script which makes your system vulnerable to attackers. Please upgrade the theme or plugin that uses this or remove it." . $extraMsg,
|
311 |
+
'data' => array_merge(array(
|
312 |
+
'file' => $file,
|
313 |
+
'shac' => $record->SHAC,
|
314 |
+
), $dataForFile),
|
315 |
+
));
|
316 |
+
break;
|
317 |
+
}
|
|
|
318 |
else {
|
319 |
$regexMatched = false;
|
320 |
foreach ($this->patterns['rules'] as $rule) {
|
335 |
else if (($type == 'both' || $type == 'browser') && !$treatAsBinary) { continue; }
|
336 |
|
337 |
if (preg_match('/(' . $rule[2] . ')/i', $data, $matches, PREG_OFFSET_CAPTURE)) {
|
338 |
+
$matchString = $matches[1][0];
|
339 |
+
$matchOffset = $matches[1][1];
|
340 |
+
$beforeString = wfWAFUtils::substr($data, max(0, $matchOffset - 100), $matchOffset - max(0, $matchOffset - 100));
|
341 |
+
$afterString = wfWAFUtils::substr($data, $matchOffset + strlen($matchString), 100);
|
342 |
+
if (!$logOnly) {
|
343 |
+
$this->addResult(array(
|
344 |
+
'type' => 'file',
|
345 |
+
'severity' => 1,
|
346 |
+
'ignoreP' => $this->path . $file,
|
347 |
+
'ignoreC' => $fileSum,
|
348 |
+
'shortMsg' => "File appears to be malicious: " . esc_html($file),
|
349 |
+
'longMsg' => "This file appears to be installed by a hacker to perform malicious activity. If you know about this file you can choose to ignore it to exclude it from future scans. The text we found in this file that matches a known malicious file is: <strong style=\"color: #F00;\" class=\"wf-split-word\">\"" . wfUtils::potentialBinaryStringToHTML((wfUtils::strlen($matchString) > 200 ? wfUtils::substr($matchString, 0, 200) . '...' : $matchString)) . "\"</strong>. The infection type is: <strong>" . esc_html($rule[3]) . '</strong>.' . $extraMsg,
|
350 |
+
'data' => array_merge(array(
|
351 |
+
'file' => $file,
|
352 |
+
'shac' => $record->SHAC,
|
353 |
+
), $dataForFile),
|
354 |
+
));
|
|
|
|
|
|
|
|
|
355 |
}
|
356 |
+
$regexMatched = true;
|
357 |
+
$this->scanEngine->recordMetric('malwareSignature', $rule[0], array('file' => $file, 'match' => $matchString, 'before' => $beforeString, 'after' => $afterString), false);
|
358 |
+
break;
|
359 |
}
|
360 |
|
361 |
if ($forkObj->shouldFork()) {
|
381 |
}
|
382 |
}
|
383 |
if ($badStringFound) {
|
384 |
+
$this->addResult(array(
|
385 |
+
'type' => 'file',
|
386 |
+
'severity' => 1,
|
387 |
+
'ignoreP' => $this->path . $file,
|
388 |
+
'ignoreC' => $fileSum,
|
389 |
+
'shortMsg' => "This file may contain malicious executable code: " . esc_html($this->path . $file),
|
390 |
+
'longMsg' => "This file is a PHP executable file and contains the word 'eval' (without quotes) and the word '<span class=\"wf-split-word\">" . esc_html($badStringFound) . "</span>' (without quotes). The eval() function along with an encoding function like the one mentioned are commonly used by hackers to hide their code. If you know about this file you can choose to ignore it to exclude it from future scans. This file was detected because you have enabled HIGH SENSITIVITY scanning. This option is more aggressive than the usual scans, and may cause false positives.",
|
391 |
+
'data' => array_merge(array(
|
392 |
+
'file' => $file,
|
393 |
+
'shac' => $record->SHAC,
|
394 |
+
), $dataForFile),
|
395 |
+
));
|
396 |
+
break;
|
|
|
397 |
}
|
398 |
}
|
399 |
|
427 |
$siteURL = get_site_url();
|
428 |
$siteHost = parse_url($siteURL, PHP_URL_HOST);
|
429 |
foreach($hooverResults as $file => $hresults){
|
430 |
+
$record = wordfenceMalwareScanFile::fileForPath($file);
|
431 |
$dataForFile = $this->dataForFile($file, $this->path . $file);
|
432 |
|
433 |
foreach($hresults as $result){
|
445 |
}
|
446 |
|
447 |
if($result['badList'] == 'goog-malware-shavar'){
|
448 |
+
$this->addResult(array(
|
449 |
+
'type' => 'file',
|
450 |
+
'severity' => 1,
|
451 |
+
'ignoreP' => $this->path . $file,
|
452 |
+
'ignoreC' => md5_file($this->path . $file),
|
453 |
+
'shortMsg' => "File contains suspected malware URL: " . esc_html($this->path . $file),
|
454 |
+
'longMsg' => "This file contains a suspected malware URL listed on Google's list of malware sites. Wordfence decodes " . esc_html($this->patterns['word3']) . " when scanning files so the URL may not be visible if you view this file. The URL is: " . esc_html($result['URL']) . " - More info available at <a href=\"http://safebrowsing.clients.google.com/safebrowsing/diagnostic?site=" . urlencode($result['URL']) . "&client=googlechrome&hl=en-US\" target=\"_blank\">Google Safe Browsing diagnostic page</a>.",
|
455 |
+
'data' => array_merge(array(
|
456 |
+
'file' => $file,
|
457 |
+
'shac' => $record->SHAC,
|
458 |
+
'badURL' => $result['URL'],
|
459 |
+
'gsb' => 'goog-malware-shavar'
|
460 |
+
), $dataForFile),
|
461 |
+
));
|
|
|
462 |
} else if($result['badList'] == 'googpub-phish-shavar'){
|
463 |
+
$this->addResult(array(
|
464 |
+
'type' => 'file',
|
465 |
+
'severity' => 1,
|
466 |
+
'ignoreP' => $this->path . $file,
|
467 |
+
'ignoreC' => md5_file($this->path . $file),
|
468 |
+
'shortMsg' => "File contains suspected phishing URL: " . esc_html($this->path . $file),
|
469 |
+
'longMsg' => "This file contains a URL that is a suspected phishing site that is currently listed on Google's list of known phishing sites. The URL is: " . esc_html($result['URL']),
|
470 |
+
'data' => array_merge(array(
|
471 |
+
'file' => $file,
|
472 |
+
'shac' => $record->SHAC,
|
473 |
+
'badURL' => $result['URL'],
|
474 |
+
'gsb' => 'googpub-phish-shavar'
|
475 |
+
), $dataForFile),
|
476 |
+
));
|
|
|
477 |
}
|
478 |
}
|
479 |
}
|
480 |
wfUtils::endProcessingFile();
|
481 |
+
|
482 |
+
wordfence::status(4, 'info', "Finalizing malware scan results");
|
483 |
+
$hashesToCheck = array();
|
484 |
+
foreach ($this->results as $r) {
|
485 |
+
$hashesToCheck[] = $r['data']['shac'];
|
486 |
+
}
|
487 |
+
|
488 |
+
if (count($hashesToCheck) > 0) {
|
489 |
+
$safeFiles = $this->isSafeFile($hashesToCheck);
|
490 |
+
foreach ($this->results as $index => $value) {
|
491 |
+
if (in_array($value['data']['shac'], $safeFiles)) {
|
492 |
+
unset($this->results[$index]);
|
493 |
+
}
|
494 |
+
}
|
495 |
+
}
|
496 |
|
497 |
return $this->results;
|
498 |
}
|
513 |
//We don't have a results for this file so append
|
514 |
$this->results[] = $result;
|
515 |
}
|
516 |
+
|
517 |
+
/**
|
518 |
+
* Queries the is_safe_file endpoint. If provided an array, it does a bulk check and returns an array containing the
|
519 |
+
* hashes that were marked as safe. If provided a string, it returns a boolean to indicate the safeness of the file.
|
520 |
+
*
|
521 |
+
* @param string|array $shac
|
522 |
+
* @return array|bool
|
523 |
+
*/
|
524 |
+
private function isSafeFile($shac) {
|
525 |
if(! $this->api){
|
526 |
$this->api = new wfAPI($this->apiKey, $this->wordpressVersion);
|
527 |
}
|
528 |
+
|
529 |
+
if (is_array($shac)) {
|
530 |
+
$result = $this->api->call('is_safe_file', array(), array('multipleSHAC' => json_encode($shac)));
|
531 |
+
if (isset($result['isSafe'])) {
|
532 |
+
return $result['isSafe'];
|
533 |
+
}
|
534 |
+
return array();
|
535 |
+
}
|
536 |
+
|
537 |
+
$result = $this->api->call('is_safe_file', array(), array('shac' => strtoupper($shac)));
|
538 |
if(isset($result['isSafe']) && $result['isSafe'] == 1){
|
539 |
return true;
|
540 |
}
|
610 |
* @property string $filename
|
611 |
* @property string $filenameMD5
|
612 |
* @property string $newMD5
|
613 |
+
* @property string $SHAC
|
614 |
* @property string $stoppedOnSignature
|
615 |
* @property string $stoppedOnPosition
|
616 |
+
* @property string $isSafeFile
|
617 |
*/
|
618 |
class wordfenceMalwareScanFile {
|
619 |
protected $_filename;
|
620 |
protected $_filenameMD5;
|
621 |
protected $_newMD5;
|
622 |
+
protected $_shac;
|
623 |
protected $_stoppedOnSignature;
|
624 |
protected $_stoppedOnPosition;
|
625 |
+
protected $_isSafeFile;
|
626 |
|
627 |
protected static function getDB() {
|
628 |
static $db = null;
|
639 |
|
640 |
public static function files($limit = 500) {
|
641 |
$db = self::getDB();
|
642 |
+
$result = $db->querySelect("SELECT filename, filenameMD5, HEX(newMD5) AS newMD5, HEX(SHAC) AS SHAC, stoppedOnSignature, stoppedOnPosition, isSafeFile FROM " . wfDB::networkPrefix() . "wfFileMods WHERE oldMD5 != newMD5 AND knownFile = 0 limit %d", $limit);
|
643 |
$files = array();
|
644 |
foreach ($result as $row) {
|
645 |
+
$files[] = new wordfenceMalwareScanFile($row['filename'], $row['filenameMD5'], $row['newMD5'], $row['SHAC'], $row['stoppedOnSignature'], $row['stoppedOnPosition'], $row['isSafeFile']);
|
646 |
}
|
647 |
return $files;
|
648 |
}
|
649 |
|
650 |
+
public static function fileForPath($file) {
|
651 |
+
$db = self::getDB();
|
652 |
+
$row = $db->querySingleRec("SELECT filename, filenameMD5, HEX(newMD5) AS newMD5, HEX(SHAC) AS SHAC, stoppedOnSignature, stoppedOnPosition, isSafeFile FROM " . wfDB::networkPrefix() . "wfFileMods WHERE filename = '%s'", $file);
|
653 |
+
return new wordfenceMalwareScanFile($row['filename'], $row['filenameMD5'], $row['newMD5'], $row['SHAC'], $row['stoppedOnSignature'], $row['stoppedOnPosition'], $row['isSafeFile']);
|
654 |
+
}
|
655 |
+
|
656 |
+
public function __construct($filename, $filenameMD5, $newMD5, $shac, $stoppedOnSignature, $stoppedOnPosition, $isSafeFile) {
|
657 |
$this->_filename = $filename;
|
658 |
$this->_filenameMD5 = $filenameMD5;
|
659 |
$this->_newMD5 = $newMD5;
|
660 |
+
$this->_shac = strtoupper($shac);
|
661 |
$this->_stoppedOnSignature = $stoppedOnSignature;
|
662 |
$this->_stoppedOnPosition = $stoppedOnPosition;
|
663 |
+
$this->_isSafeFile = $isSafeFile;
|
664 |
}
|
665 |
|
666 |
public function __get($key) {
|
671 |
return $this->_filenameMD5;
|
672 |
case 'newMD5':
|
673 |
return $this->_newMD5;
|
674 |
+
case 'SHAC':
|
675 |
+
return $this->_shac;
|
676 |
case 'stoppedOnSignature':
|
677 |
return $this->_stoppedOnSignature;
|
678 |
case 'stoppedOnPosition':
|
679 |
return $this->_stoppedOnPosition;
|
680 |
+
case 'isSafeFile':
|
681 |
+
return $this->_isSafeFile;
|
682 |
}
|
683 |
}
|
684 |
|
697 |
$db = self::getDB();
|
698 |
$db->queryWrite("UPDATE " . wfDB::networkPrefix() . "wfFileMods SET stoppedOnSignature = '%s', stoppedOnPosition = %d WHERE filenameMD5 = '%s'", $this->stoppedOnSignature, $this->stoppedOnPosition, $this->filenameMD5);
|
699 |
}
|
700 |
+
|
701 |
+
public function markSafe() {
|
702 |
+
$db = self::getDB();
|
703 |
+
$db->queryWrite("UPDATE " . wfDB::networkPrefix() . "wfFileMods SET isSafeFile = '1' WHERE filenameMD5 = '%s'", $this->filenameMD5);
|
704 |
+
$this->isSafeFile = '1';
|
705 |
+
}
|
706 |
+
|
707 |
+
public function markUnsafe() {
|
708 |
+
$db = self::getDB();
|
709 |
+
$db->queryWrite("UPDATE " . wfDB::networkPrefix() . "wfFileMods SET isSafeFile = '0' WHERE filenameMD5 = '%s'", $this->filenameMD5);
|
710 |
+
$this->isSafeFile = '0';
|
711 |
+
}
|
712 |
}
|
713 |
|
714 |
?>
|
readme.txt
CHANGED
@@ -3,7 +3,7 @@ Contributors: mmaunder
|
|
3 |
Tags: security, secure, security plugin, wordpress security, login security, firewall, malware, antivirus, web application firewall, block hackers, country blocking
|
4 |
Requires at least: 3.9
|
5 |
Tested up to: 4.7.3
|
6 |
-
Stable tag: 6.3.
|
7 |
|
8 |
Secure your website with the most comprehensive WordPress security plugin. Firewall, malware scan, blocking, live traffic, login security & more.
|
9 |
|
@@ -42,8 +42,7 @@ Wordfence Security is Multi-Site compatible and includes Cellphone Sign-in which
|
|
42 |
* Checks the strength of all user and admin passwords to enhance login security.
|
43 |
* Includes login security to lock out brute force hacks and to stop WordPress from revealing info that will compromise WordPress security.
|
44 |
|
45 |
-
= Security Scanning =
|
46 |
-
* Scans for the HeartBleed vulnerability - included in the free scan for all users.
|
47 |
* Scans core files, themes and plugins against WordPress.org repository versions to check their integrity. Verify security of your source.
|
48 |
* See how files have changed. Optionally repair changed files that are security threats.
|
49 |
* Scans for signatures of over 44,000 known malware variants that are known WordPress security threats.
|
@@ -151,16 +150,29 @@ Designed for every skill level, [The WordPress Security Learning Center](https:/
|
|
151 |
|
152 |
Secure your website with Wordfence.
|
153 |
|
154 |
-
1. The dashboard
|
155 |
-
2. The Web Application Firewall
|
156 |
-
3. The
|
157 |
-
4. The Live Traffic view
|
158 |
-
5.
|
159 |
-
6. The
|
160 |
-
7.
|
161 |
|
162 |
== Changelog ==
|
163 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
164 |
= 6.3.5 =
|
165 |
* Improvement: Sites can now specify a list of trusted proxies when using X-Forwarded-For for IP resolution.
|
166 |
* Improvement: Added options to customize which dashboard notifications are shown.
|
@@ -737,7 +749,7 @@ Secure your website with Wordfence.
|
|
737 |
* Fixed issue that caused litespeed users to receive multiple warnings about the noabort issue.
|
738 |
* Added detection for 5 new malware variants. Thanks to Dave M. and others for the samples. Keep them coming folks!
|
739 |
* Updated Wordfence server API to version 2.12.
|
740 |
-
* Added facility at bottom of Wordfence options page to send a test email from your WordPress
|
741 |
* Suppress LOCK_EX flock() warnings in falcon engine that were being generated by sites that use NFS and don't support flock() or reliable file locking.
|
742 |
* Updated to the October 2014 version of the Geo IP country DB. (newest edition)
|
743 |
|
@@ -1486,7 +1498,7 @@ Secure your website with Wordfence.
|
|
1486 |
* Added ability for admin's to unlock login and unblock their IP addresses if they're accidentally locked out by the firewall or login security. Uses two security tokens to prevent abuse.
|
1487 |
* Admins can now also disable firewall and login security from the unlock-me email, just in case of emergency.
|
1488 |
* Made advanced security options visible so you know they exist.
|
1489 |
-
* Fixed dns_get_record() function not existing bug on Windows
|
1490 |
* Increased login lockout defaults to be much higher which still protects against brute force hacks.
|
1491 |
* Removed CURLOPT_MAXREDIRS in curl to avoid safe mode warnings.
|
1492 |
* Fixed ability to view and diff files on blogs installed in subdirectories.
|
3 |
Tags: security, secure, security plugin, wordpress security, login security, firewall, malware, antivirus, web application firewall, block hackers, country blocking
|
4 |
Requires at least: 3.9
|
5 |
Tested up to: 4.7.3
|
6 |
+
Stable tag: 6.3.6
|
7 |
|
8 |
Secure your website with the most comprehensive WordPress security plugin. Firewall, malware scan, blocking, live traffic, login security & more.
|
9 |
|
42 |
* Checks the strength of all user and admin passwords to enhance login security.
|
43 |
* Includes login security to lock out brute force hacks and to stop WordPress from revealing info that will compromise WordPress security.
|
44 |
|
45 |
+
= Security Scanning =
|
|
|
46 |
* Scans core files, themes and plugins against WordPress.org repository versions to check their integrity. Verify security of your source.
|
47 |
* See how files have changed. Optionally repair changed files that are security threats.
|
48 |
* Scans for signatures of over 44,000 known malware variants that are known WordPress security threats.
|
150 |
|
151 |
Secure your website with Wordfence.
|
152 |
|
153 |
+
1. The dashboard gives you an overview of your site's security including notifications, attack statistics and Wordfence feature status.
|
154 |
+
2. The Web Application Firewall protects your site from common types of attacks and known security vulnerabilities.
|
155 |
+
3. The Wordfence Malware Scanner lets you know if your site has been compromised and alerts you to other security issues that need to be addressed.
|
156 |
+
4. The Wordfence Security Live Traffic view shows you real-time activity on your site including bot traffic and exploit attempts.
|
157 |
+
5. Block IPs that are known to be malicious, manage IPs that have been locked out and see recently throttled IPs that violated security rules.
|
158 |
+
6. The Wordfence Options page is where you manage high-level Wordfence features and upgrade your license to Premium.
|
159 |
+
7. The Advanced Options page allows technically-minded users fine-tune their security settings.
|
160 |
|
161 |
== Changelog ==
|
162 |
|
163 |
+
= 6.3.6 =
|
164 |
+
* Improvement: Optimized the malware signature scan to reduce memory usage.
|
165 |
+
* Improvement: Optimized the overall scan to make fewer network calls.
|
166 |
+
* Improvement: Running an update now automatically dismisses the corresponding scan issue if present.
|
167 |
+
* Improvement: Added a time limit to the live activity status so only current messages are shown.
|
168 |
+
* Improvement: WAF configuration files are now excluded by default from the recently modified files list in the activity report.
|
169 |
+
* Improvement: Background pausing for live activity and traffic may now be disabled.
|
170 |
+
* Improvement: Added additional WAF support to allow us to more easily address false positives.
|
171 |
+
* Improvement: Blocking pages presented by Wordfence now indicate the source and contain information to help diagnose caching problems.
|
172 |
+
* Fix: All external URLs in the tour are now https.
|
173 |
+
* Fix: Corrected a typo in the unlock email template.
|
174 |
+
* Fix: Fixed the target of a label on the options page.
|
175 |
+
|
176 |
= 6.3.5 =
|
177 |
* Improvement: Sites can now specify a list of trusted proxies when using X-Forwarded-For for IP resolution.
|
178 |
* Improvement: Added options to customize which dashboard notifications are shown.
|
749 |
* Fixed issue that caused litespeed users to receive multiple warnings about the noabort issue.
|
750 |
* Added detection for 5 new malware variants. Thanks to Dave M. and others for the samples. Keep them coming folks!
|
751 |
* Updated Wordfence server API to version 2.12.
|
752 |
+
* Added facility at bottom of Wordfence options page to send a test email from your WordPress system to check if email sending is working.
|
753 |
* Suppress LOCK_EX flock() warnings in falcon engine that were being generated by sites that use NFS and don't support flock() or reliable file locking.
|
754 |
* Updated to the October 2014 version of the Geo IP country DB. (newest edition)
|
755 |
|
1498 |
* Added ability for admin's to unlock login and unblock their IP addresses if they're accidentally locked out by the firewall or login security. Uses two security tokens to prevent abuse.
|
1499 |
* Admins can now also disable firewall and login security from the unlock-me email, just in case of emergency.
|
1500 |
* Made advanced security options visible so you know they exist.
|
1501 |
+
* Fixed dns_get_record() function not existing bug on Windows systems pre PHP 5.3.0. Was causing scans to hang.
|
1502 |
* Increased login lockout defaults to be much higher which still protects against brute force hacks.
|
1503 |
* Removed CURLOPT_MAXREDIRS in curl to avoid safe mode warnings.
|
1504 |
* Fixed ability to view and diff files on blogs installed in subdirectories.
|
vendor/wordfence/wf-waf/src/init.php
CHANGED
@@ -4,7 +4,7 @@ define('WFWAF_VERSION', '1.0.3');
|
|
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.
|
8 |
if (!defined('WFWAF_DEBUG')) {
|
9 |
define('WFWAF_DEBUG', false);
|
10 |
}
|
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.6/');
|
8 |
if (!defined('WFWAF_DEBUG')) {
|
9 |
define('WFWAF_DEBUG', false);
|
10 |
}
|
vendor/wordfence/wf-waf/src/lib/parser/parser.php
CHANGED
@@ -367,6 +367,14 @@ class wfWAFRuleParser extends wfWAFBaseParser {
|
|
367 |
} else if ($token->getValue() === 'rules') {
|
368 |
$rules = $this->expectLiteral();
|
369 |
$urlParam->setRules($rules);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
370 |
}
|
371 |
|
372 |
break;
|
@@ -601,6 +609,14 @@ class wfWAFRuleParserURLParam {
|
|
601 |
* @var null
|
602 |
*/
|
603 |
private $rules;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
604 |
|
605 |
/**
|
606 |
* @param string $param
|
@@ -617,24 +633,28 @@ class wfWAFRuleParserURLParam {
|
|
617 |
* @param string $param
|
618 |
* @param null $rules
|
619 |
*/
|
620 |
-
public function __construct($url = null, $param = null, $rules = null) {
|
621 |
$this->url = $url;
|
622 |
$this->param = $param;
|
623 |
$this->rules = $rules;
|
|
|
|
|
624 |
}
|
625 |
|
626 |
/**
|
627 |
* Return format:
|
628 |
-
* blacklistParam(url='/\/uploadify\.php$/i', param=request.fileNames.Filedata, rules=[3, 14])
|
629 |
*
|
630 |
* @param string $action
|
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 |
|
640 |
/**
|
@@ -700,6 +720,34 @@ class wfWAFRuleParserURLParam {
|
|
700 |
public function setRules($rules) {
|
701 |
$this->rules = $rules;
|
702 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
703 |
}
|
704 |
|
705 |
class wfWAFRuleParserSyntaxError extends wfWAFParserSyntaxError {
|
367 |
} else if ($token->getValue() === 'rules') {
|
368 |
$rules = $this->expectLiteral();
|
369 |
$urlParam->setRules($rules);
|
370 |
+
} else if ($token->getValue() === 'conditional') {
|
371 |
+
$this->expectTokenTypeEquals($this->expectNextToken(), wfWAFRuleLexer::T_OPEN_PARENTHESIS);
|
372 |
+
$conditional = $this->parseConditional();
|
373 |
+
$this->expectTokenTypeEquals($this->expectNextToken(), wfWAFRuleLexer::T_CLOSE_PARENTHESIS);
|
374 |
+
$urlParam->setConditional($conditional);
|
375 |
+
} else if ($token->getValue() === 'minVersion') {
|
376 |
+
$minVersion = $this->expectLiteral();
|
377 |
+
$urlParam->setMinVersion($minVersion);
|
378 |
}
|
379 |
|
380 |
break;
|
609 |
* @var null
|
610 |
*/
|
611 |
private $rules;
|
612 |
+
/**
|
613 |
+
* @var null
|
614 |
+
*/
|
615 |
+
private $conditional;
|
616 |
+
/**
|
617 |
+
* @var float
|
618 |
+
*/
|
619 |
+
private $minVersion;
|
620 |
|
621 |
/**
|
622 |
* @param string $param
|
633 |
* @param string $param
|
634 |
* @param null $rules
|
635 |
*/
|
636 |
+
public function __construct($url = null, $param = null, $rules = null, $conditional = null, $minVersion = null) {
|
637 |
$this->url = $url;
|
638 |
$this->param = $param;
|
639 |
$this->rules = $rules;
|
640 |
+
$this->conditional = $conditional;
|
641 |
+
$this->minVersion = $minVersion;
|
642 |
}
|
643 |
|
644 |
/**
|
645 |
* Return format:
|
646 |
+
* blacklistParam(url='/\/uploadify\.php$/i', param=request.fileNames.Filedata, rules=[3, 14], conditional=(match('1', request.body.field)))
|
647 |
*
|
648 |
* @param string $action
|
649 |
* @return string
|
650 |
*/
|
651 |
public function renderRule($action) {
|
652 |
+
return sprintf('%s(url=%s, param=%s%s%s)', $action,
|
653 |
wfWAFRule::exportString($this->getUrl()),
|
654 |
$this->renderParam($this->getParam()),
|
655 |
+
$this->getRules() ? ', rules=[' . join(', ', array_map('intval', $this->getRules())) . ']' : '',
|
656 |
+
$this->getConditional() ? ', conditional=(' . $this->getConditional()->renderRule() . ')' : '');
|
657 |
+
//minVersion not included in re-rendering
|
658 |
}
|
659 |
|
660 |
/**
|
720 |
public function setRules($rules) {
|
721 |
$this->rules = $rules;
|
722 |
}
|
723 |
+
|
724 |
+
/**
|
725 |
+
* @return null
|
726 |
+
*/
|
727 |
+
public function getConditional() {
|
728 |
+
return $this->conditional;
|
729 |
+
}
|
730 |
+
|
731 |
+
/**
|
732 |
+
* @param null $conditional
|
733 |
+
*/
|
734 |
+
public function setConditional($conditional) {
|
735 |
+
$this->conditional = $conditional;
|
736 |
+
}
|
737 |
+
|
738 |
+
/**
|
739 |
+
* @return float|null
|
740 |
+
*/
|
741 |
+
public function getMinVersion() {
|
742 |
+
return $this->minVersion;
|
743 |
+
}
|
744 |
+
|
745 |
+
/**
|
746 |
+
* @param float $minVersion
|
747 |
+
*/
|
748 |
+
public function setMinVersion($minVersion) {
|
749 |
+
$this->minVersion = $minVersion;
|
750 |
+
}
|
751 |
}
|
752 |
|
753 |
class wfWAFRuleParserSyntaxError extends wfWAFParserSyntaxError {
|
vendor/wordfence/wf-waf/src/lib/request.php
CHANGED
@@ -443,7 +443,7 @@ class wfWAFRequest implements wfWAFRequestInterface {
|
|
443 |
* @param string|null $baseKey The base key used when recursing.
|
444 |
* @return string
|
445 |
*/
|
446 |
-
public function getCookieString($cookies = null, $baseKey = null) {
|
447 |
if ($cookies == null) {
|
448 |
$cookies = $this->getCookies();
|
449 |
}
|
@@ -465,7 +465,7 @@ class wfWAFRequest implements wfWAFRequestInterface {
|
|
465 |
$cookieString .= $nestedCookies;
|
466 |
}
|
467 |
else {
|
468 |
-
if (strpos($resolvedName, 'wordpress_') === 0) {
|
469 |
$cookieValue = '<redacted>';
|
470 |
}
|
471 |
|
@@ -548,7 +548,7 @@ class wfWAFRequest implements wfWAFRequestInterface {
|
|
548 |
* @return string
|
549 |
*/
|
550 |
public function highlightFailedParams($failedParams = array(), $highlightParamFormat = '[param]%s[/param]',
|
551 |
-
$highlightMatchFormat = '[match]%s[/match]') {
|
552 |
$highlights = array();
|
553 |
|
554 |
// Cap at 47.5kb
|
@@ -622,7 +622,7 @@ class wfWAFRequest implements wfWAFRequestInterface {
|
|
622 |
switch (wfWAFUtils::strtolower($header)) {
|
623 |
case 'cookie':
|
624 |
// TODO: Hook up highlights to cookies
|
625 |
-
$request .= 'Cookie: ' . trim($this->getCookieString()) . "\n";
|
626 |
break;
|
627 |
|
628 |
case 'host':
|
@@ -632,7 +632,7 @@ class wfWAFRequest implements wfWAFRequestInterface {
|
|
632 |
case 'authorization':
|
633 |
$hasAuth = true;
|
634 |
if ($auth) {
|
635 |
-
$request .= 'Authorization: Basic ' . base64_encode($auth['user'] . ':' . $auth['password']) . "\n";
|
636 |
}
|
637 |
break;
|
638 |
|
@@ -644,7 +644,7 @@ class wfWAFRequest implements wfWAFRequestInterface {
|
|
644 |
}
|
645 |
|
646 |
if (!$hasAuth && $auth) {
|
647 |
-
$request .= 'Authorization: Basic ' . base64_encode($auth['user'] . ':' . $auth['password']) . "\n";
|
648 |
}
|
649 |
|
650 |
$body = $this->getBody();
|
443 |
* @param string|null $baseKey The base key used when recursing.
|
444 |
* @return string
|
445 |
*/
|
446 |
+
public function getCookieString($cookies = null, $baseKey = null, $preventRedaction = false) {
|
447 |
if ($cookies == null) {
|
448 |
$cookies = $this->getCookies();
|
449 |
}
|
465 |
$cookieString .= $nestedCookies;
|
466 |
}
|
467 |
else {
|
468 |
+
if (strpos($resolvedName, 'wordpress_') === 0 && !$preventRedaction) {
|
469 |
$cookieValue = '<redacted>';
|
470 |
}
|
471 |
|
548 |
* @return string
|
549 |
*/
|
550 |
public function highlightFailedParams($failedParams = array(), $highlightParamFormat = '[param]%s[/param]',
|
551 |
+
$highlightMatchFormat = '[match]%s[/match]', $preventRedaction = false) {
|
552 |
$highlights = array();
|
553 |
|
554 |
// Cap at 47.5kb
|
622 |
switch (wfWAFUtils::strtolower($header)) {
|
623 |
case 'cookie':
|
624 |
// TODO: Hook up highlights to cookies
|
625 |
+
$request .= 'Cookie: ' . trim($this->getCookieString(null, null, $preventRedaction)) . "\n";
|
626 |
break;
|
627 |
|
628 |
case 'host':
|
632 |
case 'authorization':
|
633 |
$hasAuth = true;
|
634 |
if ($auth) {
|
635 |
+
$request .= 'Authorization: Basic ' . ($preventRedaction ? base64_encode($auth['user'] . ':' . $auth['password']) : '<redacted>') . "\n";
|
636 |
}
|
637 |
break;
|
638 |
|
644 |
}
|
645 |
|
646 |
if (!$hasAuth && $auth) {
|
647 |
+
$request .= 'Authorization: Basic ' . ($preventRedaction ? base64_encode($auth['user'] . ':' . $auth['password']) : '<redacted>') . "\n";
|
648 |
}
|
649 |
|
650 |
$body = $this->getBody();
|
vendor/wordfence/wf-waf/src/lib/storage/file.php
CHANGED
@@ -3,6 +3,7 @@
|
|
3 |
class wfWAFStorageFile implements wfWAFStorageInterface {
|
4 |
|
5 |
const LOG_FILE_HEADER = "<?php exit('Access denied'); __halt_compiler(); ?>\n";
|
|
|
6 |
const IP_BLOCK_RECORD_SIZE = 24;
|
7 |
|
8 |
public static function atomicFilePutContents($file, $content, $prefix = 'config') {
|
@@ -349,7 +350,7 @@ class wfWAFStorageFile implements wfWAFStorageInterface {
|
|
349 |
|
350 |
$files = array(
|
351 |
array($this->getIPCacheFile(), 'ipCacheFileHandle', self::LOG_FILE_HEADER),
|
352 |
-
array($this->getConfigFile(), 'configFileHandle', self::LOG_FILE_HEADER . serialize($this->getDefaultConfiguration())),
|
353 |
);
|
354 |
foreach ($files as $file) {
|
355 |
list($filePath, $fileHandle, $defaultContents) = $file;
|
@@ -506,6 +507,9 @@ class wfWAFStorageFile implements wfWAFStorageInterface {
|
|
506 |
while (!feof($this->configFileHandle)) {
|
507 |
$serializedData .= fread($this->configFileHandle, 1024);
|
508 |
}
|
|
|
|
|
|
|
509 |
$this->data = @unserialize($serializedData);
|
510 |
|
511 |
if ($this->data === false) {
|
@@ -533,9 +537,9 @@ class wfWAFStorageFile implements wfWAFStorageInterface {
|
|
533 |
if (WFWAF_IS_WINDOWS) {
|
534 |
self::lock($this->configFileHandle, LOCK_UN);
|
535 |
fclose($this->configFileHandle);
|
536 |
-
file_put_contents($this->getConfigFile(), self::LOG_FILE_HEADER . serialize($this->data), LOCK_EX);
|
537 |
} else {
|
538 |
-
wfWAFStorageFile::atomicFilePutContents($this->getConfigFile(), self::LOG_FILE_HEADER . serialize($this->data));
|
539 |
}
|
540 |
|
541 |
if (WFWAF_IS_WINDOWS) {
|
3 |
class wfWAFStorageFile implements wfWAFStorageInterface {
|
4 |
|
5 |
const LOG_FILE_HEADER = "<?php exit('Access denied'); __halt_compiler(); ?>\n";
|
6 |
+
const LOG_INFO_HEADER = "******************************************************************\nThis file is used by the Wordfence Web Application Firewall. Read \nmore at https://docs.wordfence.com/en/Web_Application_Firewall_FAQ\n******************************************************************\n";
|
7 |
const IP_BLOCK_RECORD_SIZE = 24;
|
8 |
|
9 |
public static function atomicFilePutContents($file, $content, $prefix = 'config') {
|
350 |
|
351 |
$files = array(
|
352 |
array($this->getIPCacheFile(), 'ipCacheFileHandle', self::LOG_FILE_HEADER),
|
353 |
+
array($this->getConfigFile(), 'configFileHandle', self::LOG_FILE_HEADER . self::LOG_INFO_HEADER . serialize($this->getDefaultConfiguration())),
|
354 |
);
|
355 |
foreach ($files as $file) {
|
356 |
list($filePath, $fileHandle, $defaultContents) = $file;
|
507 |
while (!feof($this->configFileHandle)) {
|
508 |
$serializedData .= fread($this->configFileHandle, 1024);
|
509 |
}
|
510 |
+
if (wfWAFUtils::substr($serializedData, 0, 1) == '*') {
|
511 |
+
$serializedData = wfWAFUtils::substr($serializedData, wfWAFUtils::strlen(self::LOG_INFO_HEADER));
|
512 |
+
}
|
513 |
$this->data = @unserialize($serializedData);
|
514 |
|
515 |
if ($this->data === false) {
|
537 |
if (WFWAF_IS_WINDOWS) {
|
538 |
self::lock($this->configFileHandle, LOCK_UN);
|
539 |
fclose($this->configFileHandle);
|
540 |
+
file_put_contents($this->getConfigFile(), self::LOG_FILE_HEADER . self::LOG_INFO_HEADER . serialize($this->data), LOCK_EX);
|
541 |
} else {
|
542 |
+
wfWAFStorageFile::atomicFilePutContents($this->getConfigFile(), self::LOG_FILE_HEADER . self::LOG_INFO_HEADER . serialize($this->data));
|
543 |
}
|
544 |
|
545 |
if (WFWAF_IS_WINDOWS) {
|
vendor/wordfence/wf-waf/src/lib/utils.php
CHANGED
@@ -767,4 +767,25 @@ class wfWAFUtils {
|
|
767 |
}
|
768 |
return $data;
|
769 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
770 |
}
|
767 |
}
|
768 |
return $data;
|
769 |
}
|
770 |
+
|
771 |
+
/**
|
772 |
+
* Returns the current timestamp, adjusted as needed to get close to what we consider a true timestamp. We use this
|
773 |
+
* because a significant number of servers are using a drastically incorrect time.
|
774 |
+
*
|
775 |
+
* @return int
|
776 |
+
*/
|
777 |
+
public static function normalizedTime() {
|
778 |
+
$offset = 0;
|
779 |
+
try {
|
780 |
+
$offset = wfWAF::getInstance()->getStorageEngine()->getConfig('timeoffset_ntp', false);
|
781 |
+
if ($offset === false) {
|
782 |
+
$offset = wfWAF::getInstance()->getStorageEngine()->getConfig('timeoffset_wf', false);
|
783 |
+
if ($offset === false) { $offset = 0; }
|
784 |
+
}
|
785 |
+
}
|
786 |
+
catch (Exception $e) {
|
787 |
+
//Ignore
|
788 |
+
}
|
789 |
+
return time() + $offset;
|
790 |
+
}
|
791 |
}
|
vendor/wordfence/wf-waf/src/lib/waf.php
CHANGED
@@ -571,17 +571,26 @@ PHP
|
|
571 |
if (isset($rules[$key]) && is_array($rules[$key])) {
|
572 |
/** @var wfWAFRuleParserURLParam $urlParam */
|
573 |
foreach ($rules[$key] as $urlParam) {
|
574 |
-
if ($urlParam->
|
575 |
-
|
576 |
-
|
577 |
-
'
|
578 |
-
|
579 |
-
|
580 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
581 |
}
|
582 |
-
|
583 |
-
$exportedCode .= sprintf("\$this->{$key}[%s][] = %s;\n", var_export($urlParam->getParam(), true),
|
584 |
-
var_export($url, true));
|
585 |
}
|
586 |
$exportedCode .= "\n";
|
587 |
}
|
@@ -969,6 +978,9 @@ HTML
|
|
969 |
if (!in_array($ruleID, $urlRegex['rules'])) {
|
970 |
continue;
|
971 |
}
|
|
|
|
|
|
|
972 |
$urlRegex = $urlRegex['url'];
|
973 |
}
|
974 |
if (preg_match($urlRegex, $urlPath)) {
|
@@ -1103,6 +1115,9 @@ HTML
|
|
1103 |
if (!in_array($ruleID, $urlRegex['rules'])) {
|
1104 |
continue;
|
1105 |
}
|
|
|
|
|
|
|
1106 |
$urlRegex = $urlRegex['url'];
|
1107 |
}
|
1108 |
if (preg_match($urlRegex, $urlPath)) {
|
571 |
if (isset($rules[$key]) && is_array($rules[$key])) {
|
572 |
/** @var wfWAFRuleParserURLParam $urlParam */
|
573 |
foreach ($rules[$key] as $urlParam) {
|
574 |
+
if ($urlParam->getConditional()) {
|
575 |
+
|
576 |
+
$exportedCode .= sprintf("\$this->{$key}[%s][] = array(\n%s => %s,\n%s => %s,\n%s => %s\n);\n", var_export($urlParam->getParam(), true),
|
577 |
+
var_export('url', true), var_export($urlParam->getUrl(), true),
|
578 |
+
var_export('rules', true), var_export($urlParam->getRules(), true),
|
579 |
+
var_export('conditional', true), $urlParam->getConditional()->render());
|
580 |
+
}
|
581 |
+
else {
|
582 |
+
if ($urlParam->getRules()) {
|
583 |
+
$url = array(
|
584 |
+
'url' => $urlParam->getUrl(),
|
585 |
+
'rules' => $urlParam->getRules(),
|
586 |
+
);
|
587 |
+
} else {
|
588 |
+
$url = $urlParam->getUrl();
|
589 |
+
}
|
590 |
+
|
591 |
+
$exportedCode .= sprintf("\$this->{$key}[%s][] = %s;\n", var_export($urlParam->getParam(), true),
|
592 |
+
var_export($url, true));
|
593 |
}
|
|
|
|
|
|
|
594 |
}
|
595 |
$exportedCode .= "\n";
|
596 |
}
|
978 |
if (!in_array($ruleID, $urlRegex['rules'])) {
|
979 |
continue;
|
980 |
}
|
981 |
+
if (isset($urlRegex['conditional']) && !$urlRegex['conditional']->evaluate()) {
|
982 |
+
continue;
|
983 |
+
}
|
984 |
$urlRegex = $urlRegex['url'];
|
985 |
}
|
986 |
if (preg_match($urlRegex, $urlPath)) {
|
1115 |
if (!in_array($ruleID, $urlRegex['rules'])) {
|
1116 |
continue;
|
1117 |
}
|
1118 |
+
if (isset($urlRegex['conditional']) && !$urlRegex['conditional']->evaluate()) {
|
1119 |
+
continue;
|
1120 |
+
}
|
1121 |
$urlRegex = $urlRegex['url'];
|
1122 |
}
|
1123 |
if (preg_match($urlRegex, $urlPath)) {
|
vendor/wordfence/wf-waf/src/views/403-blacklist.php
CHANGED
@@ -209,5 +209,7 @@ $payload = "-----BEGIN REPORT-----\n" . implode("\n", str_split($message, 60)) .
|
|
209 |
|
210 |
<p><a href="#" id="reportButton" class="btn disabled" target="_blank">Report Problem</a></p>
|
211 |
|
|
|
|
|
212 |
</body>
|
213 |
</html>
|
209 |
|
210 |
<p><a href="#" id="reportButton" class="btn disabled" target="_blank">Report Problem</a></p>
|
211 |
|
212 |
+
<p style="color: #999999;margin-top: 2rem;"><em>Generated by Wordfence at <?php echo gmdate('D, j M Y G:i:s T', wfWAFUtils::normalizedTime()); ?>.<br>Your computer's time: <script type="application/javascript">document.write(new Date().toUTCString());</script>.</em></p>
|
213 |
+
|
214 |
</body>
|
215 |
</html>
|
vendor/wordfence/wf-waf/src/views/403-roadblock.php
CHANGED
@@ -113,5 +113,7 @@ foreach ($waf->getFailedRules() as $paramKey => $categories) {
|
|
113 |
|
114 |
<?php endif ?>
|
115 |
|
|
|
|
|
116 |
</body>
|
117 |
</html>
|
113 |
|
114 |
<?php endif ?>
|
115 |
|
116 |
+
<p style="color: #999999;margin-top: 2rem;"><em>Generated by Wordfence at <?php echo gmdate('D, j M Y G:i:s T', wfWAFUtils::normalizedTime()); ?>.<br>Your computer's time: <script type="application/javascript">document.write(new Date().toUTCString());</script>.</em></p>
|
117 |
+
|
118 |
</body>
|
119 |
</html>
|
vendor/wordfence/wf-waf/src/views/403.php
CHANGED
@@ -10,5 +10,7 @@
|
|
10 |
|
11 |
<p>A potentially unsafe operation has been detected in your request to this site.</p>
|
12 |
|
|
|
|
|
13 |
</body>
|
14 |
</html>
|
10 |
|
11 |
<p>A potentially unsafe operation has been detected in your request to this site.</p>
|
12 |
|
13 |
+
<p style="color: #999999;margin-top: 2rem;"><em>Generated by Wordfence at <?php echo gmdate('D, j M Y G:i:s T', wfWAFUtils::normalizedTime()); ?>.<br>Your computer's time: <script type="application/javascript">document.write(new Date().toUTCString());</script>.</em></p>
|
14 |
+
|
15 |
</body>
|
16 |
</html>
|
vendor/wordfence/wf-waf/src/views/503-lockout.php
CHANGED
@@ -28,7 +28,7 @@ if (!empty($homeURL) && !empty($nonce)) : ?>
|
|
28 |
</form>
|
29 |
<?php endif; ?>
|
30 |
</p>
|
31 |
-
<p style="
|
32 |
</body>
|
33 |
</html>
|
34 |
<?php exit(); ?>
|
28 |
</form>
|
29 |
<?php endif; ?>
|
30 |
</p>
|
31 |
+
<p style="color: #999999;margin-top: 2rem;"><em>Generated by Wordfence at <?php echo gmdate('D, j M Y G:i:s T', wfWAFUtils::normalizedTime()); ?>.<br>Your computer's time: <script type="application/javascript">document.write(new Date().toUTCString());</script>.</em></p>
|
32 |
</body>
|
33 |
</html>
|
34 |
<?php exit(); ?>
|
vendor/wordfence/wf-waf/src/views/503.php
CHANGED
@@ -31,5 +31,5 @@ If you are a site administrator and have been accidentally locked out, please en
|
|
31 |
<?php endif; ?>
|
32 |
<br /><br />
|
33 |
|
34 |
-
<
|
35 |
</body></html>
|
31 |
<?php endif; ?>
|
32 |
<br /><br />
|
33 |
|
34 |
+
<p style="color: #999999;margin-top: 2rem;"><em>Generated by Wordfence at <?php echo gmdate('D, j M Y G:i:s T', wfWAFUtils::normalizedTime()); ?>.<br>Your computer's time: <script type="application/javascript">document.write(new Date().toUTCString());</script>.</em></p>
|
35 |
</body></html>
|
views/reports/activity-report-email-inline.php
CHANGED
@@ -331,6 +331,8 @@ h6 a:visited { color: purple !important; }
|
|
331 |
</tbody>
|
332 |
</table>
|
333 |
|
|
|
|
|
334 |
<?php wfHelperString::cycle(); ?>
|
335 |
|
336 |
<h2 style="font-size: 20px; vertical-align: baseline; clear: both; color: #222 !important; margin: 20px 0 4px; padding: 0; border: 0;">Updates Needed</h2>
|
331 |
</tbody>
|
332 |
</table>
|
333 |
|
334 |
+
<div style="font-size: 12px; font-style: italic; vertical-align: baseline; clear: both; margin: 8px 0 4px; padding: 0; border: 0;">This list may include WordPress core/plugin/theme updates, error logs, cache files, and other normal changes.</div>
|
335 |
+
|
336 |
<?php wfHelperString::cycle(); ?>
|
337 |
|
338 |
<h2 style="font-size: 20px; vertical-align: baseline; clear: both; color: #222 !important; margin: 20px 0 4px; padding: 0; border: 0;">Updates Needed</h2>
|
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 Malware Scan
|
6 |
Author: Wordfence
|
7 |
-
Version: 6.3.
|
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.3.
|
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 Malware Scan
|
6 |
Author: Wordfence
|
7 |
+
Version: 6.3.6
|
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.3.6');
|
15 |
define('WORDFENCE_BASENAME', function_exists('plugin_basename') ? plugin_basename(__FILE__) :
|
16 |
basename(dirname(__FILE__)) . '/' . basename(__FILE__));
|
17 |
|