Sucuri Security – Auditing, Malware Scanner and Security Hardening - Version 1.8.12

Version Description

This version adds support for the latest version of WordPress. Introduces new features and fixes some bugs reported by the WordPress community as well as bugs found by our automated testing system.

=

Download this release

Release Info

Developer yorman
Plugin Icon 128x128 Sucuri Security – Auditing, Malware Scanner and Security Hardening
Version 1.8.12
Comparing to
See all releases

Code changes from version 1.8.11 to 1.8.12

inc/css/styles.css CHANGED
@@ -46,7 +46,7 @@ body.sucuri-security_page_sucuriscan_hardening {
46
height: 30px;
47
line-height: normal;
48
}
49
- .sucuriscan-container input[type=text] {
50
margin: 0;
51
padding: 0 7px;
52
line-height: 28px;
@@ -62,6 +62,7 @@ body.sucuri-security_page_sucuriscan_hardening {
62
text-transform: uppercase;
63
line-height: 30px;
64
font-weight: 700;
65
}
66
.sucuriscan-container fieldset span {
67
line-height: 30px;
@@ -71,8 +72,8 @@ body.sucuri-security_page_sucuriscan_hardening {
71
.sucuriscan-container fieldset label,
72
.sucuriscan-container fieldset select,
73
.sucuriscan-container fieldset button,
74
- .sucuriscan-container fieldset input[type=text],
75
- .sucuriscan-container fieldset input[type=checkbox],
76
.wp-core-ui .sucuriscan-container fieldset .button,
77
.wp-core-ui .sucuriscan-container fieldset .button-primary,
78
.wp-core-ui .sucuriscan-container fieldset .button-secondary {
@@ -83,13 +84,13 @@ body.sucuri-security_page_sucuriscan_hardening {
83
.sucuriscan-container fieldset label {
84
margin-left: 0;
85
}
86
- .sucuriscan-container fieldset input[type=checkbox] {
87
margin-top: 7px;
88
margin-bottom: 7px;
89
}
90
.sucuriscan-container .sucuriscan-full-textarea {
91
width: 100%;
92
- min-height: 300px;
93
background: #efefef;
94
word-break: break-all;
95
padding: 20px;
@@ -898,8 +899,8 @@ body.sucuri-security_page_sucuriscan_hardening {
898
.rtl .sucuriscan-container fieldset label,
899
.rtl .sucuriscan-container fieldset select,
900
.rtl .sucuriscan-container fieldset button,
901
- .rtl .sucuriscan-container fieldset input[type=text],
902
- .rtl .sucuriscan-container fieldset input[type=checkbox],
903
.rtl .wp-core-ui .sucuriscan-container fieldset .button,
904
.rtl .wp-core-ui .sucuriscan-container fieldset .button-primary,
905
.rtl .wp-core-ui .sucuriscan-container fieldset .button-secondary {
46
height: 30px;
47
line-height: normal;
48
}
49
+ .sucuriscan-container input[type='text'] {
50
margin: 0;
51
padding: 0 7px;
52
line-height: 28px;
62
text-transform: uppercase;
63
line-height: 30px;
64
font-weight: 700;
65
+ cursor: initial;
66
}
67
.sucuriscan-container fieldset span {
68
line-height: 30px;
72
.sucuriscan-container fieldset label,
73
.sucuriscan-container fieldset select,
74
.sucuriscan-container fieldset button,
75
+ .sucuriscan-container fieldset input[type='text'],
76
+ .sucuriscan-container fieldset input[type='checkbox'],
77
.wp-core-ui .sucuriscan-container fieldset .button,
78
.wp-core-ui .sucuriscan-container fieldset .button-primary,
79
.wp-core-ui .sucuriscan-container fieldset .button-secondary {
84
.sucuriscan-container fieldset label {
85
margin-left: 0;
86
}
87
+ .sucuriscan-container fieldset input[type='checkbox'] {
88
margin-top: 7px;
89
margin-bottom: 7px;
90
}
91
.sucuriscan-container .sucuriscan-full-textarea {
92
width: 100%;
93
+ min-height: 400px;
94
background: #efefef;
95
word-break: break-all;
96
padding: 20px;
899
.rtl .sucuriscan-container fieldset label,
900
.rtl .sucuriscan-container fieldset select,
901
.rtl .sucuriscan-container fieldset button,
902
+ .rtl .sucuriscan-container fieldset input[type='text'],
903
+ .rtl .sucuriscan-container fieldset input[type='checkbox'],
904
.rtl .wp-core-ui .sucuriscan-container fieldset .button,
905
.rtl .wp-core-ui .sucuriscan-container fieldset .button-primary,
906
.rtl .wp-core-ui .sucuriscan-container fieldset .button-secondary {
inc/js/scripts.js CHANGED
@@ -1,29 +1,35 @@
1
/* global jQuery */
2
- /* jshint unused:false */
3
4
- function sucuriscanAlertClose (id) {
5
var element = document.getElementById('sucuriscan-alert-' + id);
6
element.parentNode.removeChild(element);
7
}
8
9
- jQuery(document).ready(function ($) {
10
- $('.sucuriscan-container').on('click', '.sucuriscan-modal-button', function (event) {
11
event.preventDefault();
12
var modalid = $(this).data('modalid');
13
$('div.' + modalid + '-modal').removeClass('sucuriscan-hidden');
14
});
15
16
- $('.sucuriscan-container').on('click', '.sucuriscan-overlay, .sucuriscan-modal-close', function (event) {
17
event.preventDefault();
18
$('.sucuriscan-overlay').addClass('sucuriscan-hidden');
19
$('.sucuriscan-modal').addClass('sucuriscan-hidden');
20
});
21
22
- $('.sucuriscan-container').on('click', '.sucuriscan-show-more', function (event) {
23
event.preventDefault();
24
var button = $(this);
25
var target = button.attr('data-target');
26
var status = button.attr('data-status');
27
if (status === 'more') {
28
button.attr('data-status', 'less');
29
$(target).removeClass('sucuriscan-hidden');
@@ -41,36 +47,44 @@ jQuery(document).ready(function ($) {
41
var activeState = 'sucuriscan-tab-active';
42
var locationHash = location.href.split('#')[1];
43
44
- $('.sucuriscan-container').on('click', '.sucuriscan-tabs-buttons a', function (event) {
45
event.preventDefault();
46
47
var button = $(this);
48
var uniqueid = button.attr('href').split('#')[1];
49
50
- if (uniqueid !== undefined) {
51
- var container = $('.sucuriscan-tabs-containers > #sucuriscan-tabs-' + uniqueid);
52
53
- if (container.length) {
54
- var rawurl = location.href.replace(location.hash, '');
55
- var newurl = rawurl + '#' + uniqueid;
56
57
- window.history.pushState({}, document.title, newurl);
58
59
- $('.sucuriscan-tabs-buttons a').removeClass(activeState);
60
- $('.sucuriscan-tabs-containers > div').addClass(hiddenState);
61
62
- button.addClass(activeState);
63
- container.addClass(visibleState);
64
- container.removeClass(hiddenState);
65
- }
66
- }
67
});
68
69
$('.sucuriscan-tabs-containers > div').addClass(hiddenState);
70
71
if (locationHash !== undefined) {
72
- $('.sucuriscan-tabs-buttons a').each(function (e, button) {
73
- if ($(button).attr('href').split('#')[1] === locationHash) {
74
$(button).trigger('click');
75
}
76
});
@@ -79,7 +93,7 @@ jQuery(document).ready(function ($) {
79
}
80
}
81
82
- $('.sucuriscan-container').on('mouseover', '.sucuriscan-tooltip', function (event) {
83
var element = $(this);
84
var content = element.attr('content');
85
@@ -88,7 +102,7 @@ jQuery(document).ready(function ($) {
88
}
89
90
/* create instance of tooltip container */
91
- var tooltip = $('<div>', { 'class': 'sucuriscan-tooltip-object' });
92
93
if (element.attr('tooltip-width')) {
94
var customWidth = element.attr('tooltip-width');
@@ -107,7 +121,6 @@ jQuery(document).ready(function ($) {
107
var tooltipHeight = tooltip.outerHeight();
108
tooltip.css('top', (tooltipHeight + arrowHeight) * -1);
109
110
- var positionLeft = 0;
111
var elementWidth = element.outerWidth();
112
var tooltipWidth = tooltip.outerWidth();
113
@@ -116,11 +129,31 @@ jQuery(document).ready(function ($) {
116
} else if (elementWidth > tooltipWidth) {
117
tooltip.css('left', (elementWidth - tooltipWidth) / 2);
118
} else if (elementWidth < tooltipWidth) {
119
- tooltip.css('left', ((tooltipWidth - elementWidth) / 2) * -1);
120
}
121
});
122
123
- $('.sucuriscan-container').on('mouseout', '.sucuriscan-tooltip', function (event) {
124
- $(this).find('.sucuriscan-tooltip-object').remove();
125
});
126
});
1
/* global jQuery */
2
3
+ /* jshint ignore:start */
4
+ function sucuriscanAlertClose(id) {
5
var element = document.getElementById('sucuriscan-alert-' + id);
6
element.parentNode.removeChild(element);
7
}
8
+ /* jshint ignore:end */
9
10
+ jQuery(document).ready(function($) {
11
+ $('.sucuriscan-container').on('click', '.sucuriscan-modal-button', function(event) {
12
event.preventDefault();
13
+
14
var modalid = $(this).data('modalid');
15
+
16
$('div.' + modalid + '-modal').removeClass('sucuriscan-hidden');
17
});
18
19
+ $('.sucuriscan-container').on('click', '.sucuriscan-overlay, .sucuriscan-modal-close', function(event) {
20
event.preventDefault();
21
+
22
$('.sucuriscan-overlay').addClass('sucuriscan-hidden');
23
$('.sucuriscan-modal').addClass('sucuriscan-hidden');
24
});
25
26
+ $('.sucuriscan-container').on('click', '.sucuriscan-show-more', function(event) {
27
event.preventDefault();
28
+
29
var button = $(this);
30
var target = button.attr('data-target');
31
var status = button.attr('data-status');
32
+
33
if (status === 'more') {
34
button.attr('data-status', 'less');
35
$(target).removeClass('sucuriscan-hidden');
47
var activeState = 'sucuriscan-tab-active';
48
var locationHash = location.href.split('#')[1];
49
50
+ $('.sucuriscan-container').on('click', '.sucuriscan-tabs-buttons a', function(event) {
51
event.preventDefault();
52
53
var button = $(this);
54
var uniqueid = button.attr('href').split('#')[1];
55
56
+ if (!uniqueid) {
57
+ return;
58
+ }
59
60
+ var container = $('.sucuriscan-tabs-containers > #sucuriscan-tabs-' + uniqueid);
61
62
+ if (!container.length) {
63
+ return;
64
+ }
65
66
+ var rawurl = location.href.replace(location.hash, '');
67
+ var newurl = rawurl + '#' + uniqueid;
68
69
+ window.history.pushState({}, document.title, newurl);
70
+
71
+ $('.sucuriscan-tabs-buttons a').removeClass(activeState);
72
+ $('.sucuriscan-tabs-containers > div').addClass(hiddenState);
73
+
74
+ button.addClass(activeState);
75
+ container.addClass(visibleState);
76
+ container.removeClass(hiddenState);
77
});
78
79
$('.sucuriscan-tabs-containers > div').addClass(hiddenState);
80
81
if (locationHash !== undefined) {
82
+ $('.sucuriscan-tabs-buttons a').each(function(e, button) {
83
+ var buttonHash = $(button)
84
+ .attr('href')
85
+ .split('#')[1];
86
+
87
+ if (buttonHash === locationHash) {
88
$(button).trigger('click');
89
}
90
});
93
}
94
}
95
96
+ $('.sucuriscan-container').on('mouseover', '.sucuriscan-tooltip', function() {
97
var element = $(this);
98
var content = element.attr('content');
99
102
}
103
104
/* create instance of tooltip container */
105
+ var tooltip = $('<div>', { class: 'sucuriscan-tooltip-object' });
106
107
if (element.attr('tooltip-width')) {
108
var customWidth = element.attr('tooltip-width');
121
var tooltipHeight = tooltip.outerHeight();
122
tooltip.css('top', (tooltipHeight + arrowHeight) * -1);
123
124
var elementWidth = element.outerWidth();
125
var tooltipWidth = tooltip.outerWidth();
126
129
} else if (elementWidth > tooltipWidth) {
130
tooltip.css('left', (elementWidth - tooltipWidth) / 2);
131
} else if (elementWidth < tooltipWidth) {
132
+ tooltip.css('left', (tooltipWidth - elementWidth) / 2 * -1);
133
}
134
});
135
136
+ $('.sucuriscan-container').on('mouseout', '.sucuriscan-tooltip', function() {
137
+ $(this)
138
+ .find('.sucuriscan-tooltip-object')
139
+ .remove();
140
+ });
141
+
142
+ $('.sucuriscan-container').on('click', 'button.sucuriscan-show-section', function(event) {
143
+ event.preventDefault();
144
+
145
+ var button = $(this);
146
+ var current = button.text();
147
+ var onText = button.attr('on');
148
+ var offText = button.attr('off');
149
+ var section = button.attr('section');
150
+
151
+ if (current === onText) {
152
+ $('#' + section).removeClass('sucuriscan-hidden');
153
+ button.html(offText);
154
+ } else {
155
+ $('#' + section).addClass('sucuriscan-hidden');
156
+ button.html(onText);
157
+ }
158
});
159
});
inc/tpl/lastlogins-failedlogins.html.tpl CHANGED
@@ -16,7 +16,6 @@
16
<input id="cb-select-all-1" type="checkbox">
17
</td>
18
<th class="manage-column">Username</th>
19
- <th class="manage-column">Password</th>
20
<th class="manage-column">IP Address</th>
21
<th class="manage-column">Date/Time</th>
22
<th class="manage-column" width="300">Web Browser</th>
@@ -27,13 +26,13 @@
27
%%%SUCURI.FailedLogins.List%%%
28
29
<tr class="sucuriscan-%%SUCURI.FailedLogins.NoItemsVisibility%%">
30
- <td colspan="6">
31
<em>no data available</em>
32
</td>
33
</tr>
34
35
<tr class="sucuriscan-%%SUCURI.FailedLogins.PaginationVisibility%%">
36
- <td colspan="6">
37
<ul class="sucuriscan-pagination">
38
%%%SUCURI.FailedLogins.PaginationLinks%%%
39
</ul>
16
<input id="cb-select-all-1" type="checkbox">
17
</td>
18
<th class="manage-column">Username</th>
19
<th class="manage-column">IP Address</th>
20
<th class="manage-column">Date/Time</th>
21
<th class="manage-column" width="300">Web Browser</th>
26
%%%SUCURI.FailedLogins.List%%%
27
28
<tr class="sucuriscan-%%SUCURI.FailedLogins.NoItemsVisibility%%">
29
+ <td colspan="5">
30
<em>no data available</em>
31
</td>
32
</tr>
33
34
<tr class="sucuriscan-%%SUCURI.FailedLogins.PaginationVisibility%%">
35
+ <td colspan="5">
36
<ul class="sucuriscan-pagination">
37
%%%SUCURI.FailedLogins.PaginationLinks%%%
38
</ul>
inc/tpl/lastlogins-failedlogins.snippet.tpl CHANGED
@@ -6,8 +6,6 @@
6
7
<td><span class="sucuriscan-monospace">%%SUCURI.FailedLogins.Username%%</span></td>
8
9
- <td><span class="sucuriscan-monospace">%%SUCURI.FailedLogins.Password%%</span></td>
10
-
11
<td><span class="sucuriscan-monospace">%%SUCURI.FailedLogins.RemoteAddr%%</span></td>
12
13
<td><em>%%SUCURI.FailedLogins.Datetime%%</em></td>
6
7
<td><span class="sucuriscan-monospace">%%SUCURI.FailedLogins.Username%%</span></td>
8
9
<td><span class="sucuriscan-monospace">%%SUCURI.FailedLogins.RemoteAddr%%</span></td>
10
11
<td><em>%%SUCURI.FailedLogins.Datetime%%</em></td>
inc/tpl/notification-pretty.html.tpl CHANGED
@@ -18,6 +18,7 @@
18
<p style="margin:0 0 10px 0">
19
Website: <a href="http://%%SUCURI.Website%%">%%SUCURI.Website%%</a><br>
20
IP Address: %%SUCURI.RemoteAddress%%<br>
21
Date/Time: %%SUCURI.Time%%<br>
22
%%SUCURI.User%%
23
</p>
18
<p style="margin:0 0 10px 0">
19
Website: <a href="http://%%SUCURI.Website%%">%%SUCURI.Website%%</a><br>
20
IP Address: %%SUCURI.RemoteAddress%%<br>
21
+ Reverse IP: %%SUCURI.ReverseAddress%%<br>
22
Date/Time: %%SUCURI.Time%%<br>
23
%%SUCURI.User%%
24
</p>
inc/tpl/notification-simple.html.tpl CHANGED
@@ -2,6 +2,7 @@
2
Event: %%SUCURI.Subject%%
3
Website: http://%%SUCURI.Website%%
4
IP Address: %%SUCURI.RemoteAddress%%
5
Date/Time: %%SUCURI.Time%%
6
%%SUCURI.User%%
7
2
Event: %%SUCURI.Subject%%
3
Website: http://%%SUCURI.Website%%
4
IP Address: %%SUCURI.RemoteAddress%%
5
+ Reverse IP: %%SUCURI.ReverseAddress%%
6
Date/Time: %%SUCURI.Time%%
7
%%SUCURI.User%%
8
inc/tpl/settings-alerts-ignore-posts.html.tpl CHANGED
@@ -22,29 +22,35 @@
22
23
<hr>
24
25
- <form action="%%SUCURI.URL.Settings%%#alerts" method="post">
26
- <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
27
- <input type="hidden" name="sucuriscan_ignorerule_action" value="batch" />
28
-
29
- <table class="wp-list-table widefat sucuriscan-table sucuriscan-settings-ignorerules">
30
- <thead>
31
- <tr>
32
- <td id="cb" class="manage-column column-cb check-column">
33
- <label class="screen-reader-text" for="cb-select-all-1">Select All</label>
34
- <input id="cb-select-all-1" type="checkbox">
35
- </td>
36
- <th class="manage-column">Post Type</th>
37
- <th class="manage-column">Post Type ID</th>
38
- <th class="manage-column">Ignored At (optional)</th>
39
- </tr>
40
- </thead>
41
-
42
- <tbody>
43
- %%%SUCURI.PostTypes.List%%%
44
- </tbody>
45
- </table>
46
-
47
- <button type="submit" class="button button-primary">Submit</button>
48
- </form>
49
</div>
50
</div>
22
23
<hr>
24
25
+ <button class="button button-primary sucuriscan-show-section" section="sucuriscan-ignorerules" on="Show Post-Types Table" off="Hide Post-Types Table">Show Post-Types Table</button>
26
+
27
+ <div class="sucuriscan-hidden" id="sucuriscan-ignorerules">
28
+ <hr>
29
+
30
+ <form action="%%SUCURI.URL.Settings%%#alerts" method="post">
31
+ <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
32
+ <input type="hidden" name="sucuriscan_ignorerule_action" value="batch" />
33
+
34
+ <table class="wp-list-table widefat sucuriscan-table sucuriscan-settings-ignorerules">
35
+ <thead>
36
+ <tr>
37
+ <td id="cb" class="manage-column column-cb check-column">
38
+ <label class="screen-reader-text" for="cb-select-all-1">Select All</label>
39
+ <input id="cb-select-all-1" type="checkbox">
40
+ </td>
41
+ <th class="manage-column">Post Type</th>
42
+ <th class="manage-column">Post Type ID</th>
43
+ <th class="manage-column">Ignored At (optional)</th>
44
+ </tr>
45
+ </thead>
46
+
47
+ <tbody>
48
+ %%%SUCURI.PostTypes.List%%%
49
+ </tbody>
50
+ </table>
51
+
52
+ <button type="submit" class="button button-primary">Submit</button>
53
+ </form>
54
+ </div>
55
</div>
56
</div>
inc/tpl/settings-apiservice-status.html.tpl CHANGED
@@ -18,5 +18,13 @@
18
<button type="submit" class="button button-primary">%%SUCURI.ApiStatus.SwitchText%%</button>
19
</form>
20
</div>
21
</div>
22
</div>
18
<button type="submit" class="button button-primary">%%SUCURI.ApiStatus.SwitchText%%</button>
19
</form>
20
</div>
21
+
22
+ <p>
23
+ <strong>Are you a developer?</strong> You may be interested in our API. Feel free to use the URL shown below to access the latest 50 entries in your security log, change the value for the parameter <code>l=N</code> if you need more. Be aware that the API doesn't provides an offset parameter, so if you have the intension to query specific sections of the log you will need to wrap the HTTP request around your own cache mechanism. We <strong>DO NOT</strong> take feature requests for the API, this is a semi-private service tailored for the specific needs of the plugin and not intended to be used by 3rd-party apps, we may change the behavior of each API endpoint without previous notice, use it at your own risk.
24
+ </p>
25
+
26
+ <div class="sucuriscan-hstatus sucuriscan-hstatus-2 sucuriscan-monospace">
27
+ <span>curl -s "https://wordpress.sucuri.net/api/?k=%%SUCURI.ApiStatus.ApiKey%%&a=get_logs&l=50" | python -m json.tool</span>
28
+ </div>
29
</div>
30
</div>
readme.txt CHANGED
@@ -3,8 +3,8 @@ Contributors: dd@sucuri.net
3
Donate Link: https://sucuri.net/
4
Tags: malware, security, firewall, scan, spam, virus, sucuri, protection, WordPress Security, Login Security, Security Auditing, File Integrity, htaccess, phishing, backdoors, SQL Injection, RFI, LFI, XSS, CSRF, website firewall, Website Security, Performance Optimization, Zero Day, Software Vulnerability, Exploits, Hacks, Attackers, Bad Actors, Reverse Proxy, Two Factor Security, Two Factor Authentication, Security Logs, HeatBleed Vulnerability, Website Protection, Bash Vulnerability, RevSlider Vulnerability, MailPoet Vulnerability, Malware Prevention, Website Security, Website Firewall, Website AntiVirus, Security Response, Security Detection, Security Prevention
5
Requires at least: 3.6
6
- Tested up to: 4.8.0
7
- Stable tag: 1.8.11
8
9
The Sucuri WordPress Security plugin is a security toolset for security integrity monitoring, malware detection and security hardening.
10
@@ -181,11 +181,31 @@ No, it is not required. The Website Firewall runs in the cloud without the need
181
182
== Upgrade Notice ==
183
184
- = 1.8.11 =
185
This version adds support for the latest version of WordPress. Introduces new features and fixes some bugs reported by the WordPress community as well as bugs found by our automated testing system.
186
187
== Changelog ==
188
189
= 1.8.11 =
190
* Modify Sucuri firewall detection with regular expressions
191
* Modify option to force scanner to ignore directories
3
Donate Link: https://sucuri.net/
4
Tags: malware, security, firewall, scan, spam, virus, sucuri, protection, WordPress Security, Login Security, Security Auditing, File Integrity, htaccess, phishing, backdoors, SQL Injection, RFI, LFI, XSS, CSRF, website firewall, Website Security, Performance Optimization, Zero Day, Software Vulnerability, Exploits, Hacks, Attackers, Bad Actors, Reverse Proxy, Two Factor Security, Two Factor Authentication, Security Logs, HeatBleed Vulnerability, Website Protection, Bash Vulnerability, RevSlider Vulnerability, MailPoet Vulnerability, Malware Prevention, Website Security, Website Firewall, Website AntiVirus, Security Response, Security Detection, Security Prevention
5
Requires at least: 3.6
6
+ Tested up to: 4.9.4
7
+ Stable tag: 1.8.12
8
9
The Sucuri WordPress Security plugin is a security toolset for security integrity monitoring, malware detection and security hardening.
10
181
182
== Upgrade Notice ==
183
184
+ = 1.8.12 =
185
This version adds support for the latest version of WordPress. Introduces new features and fixes some bugs reported by the WordPress community as well as bugs found by our automated testing system.
186
187
== Changelog ==
188
189
+ = 1.8.12 =
190
+ * Fix invalid array when deselecting all security alerts
191
+ * Add language files to the list of ignored changes
192
+ * Modify internal response to the log file not found error
193
+ * Add option to force the firewall cache flush
194
+ * Fix unexpected exception when open_basedir is in place
195
+ * Add support to export and import trusted IP addresses
196
+ * Add link to the audit logs API endpoint for developers
197
+ * Add reverse ip address in all email alerts from visitor
198
+ * Remove API key from the settings that can be exported
199
+ * Modify code to make default plugin options filterable
200
+ * Add ability to store the settings in the object cache
201
+ * Add support for wp-cli and command to generate an API key
202
+ * Fix missing documentation tags in the command line library
203
+ * Fix format and coding standard in CSS and JavaScript files
204
+ * Add button to toggle the visibility of the post-types table
205
+ * Modify order of the added, modified, removed core files
206
+ * Fix relative file path when ABSPATH is point to root
207
+ * Add additional notifications for changes on users
208
+
209
= 1.8.11 =
210
* Modify Sucuri firewall detection with regular expressions
211
* Modify option to force scanner to ignore directories
src/api.lib.php CHANGED
@@ -284,12 +284,9 @@ class SucuriScanAPI extends SucuriScanOption
284
if (stripos($raw, 'log file not found') !== false) {
285
$key = SucuriScanOption::getOption(':api_key');
286
$msg .= '; this generally happens when you use an invalid API key,'
287
- . ' the key will be deleted to hide these warnings, if you want to'
288
- . ' recover it go to the settings page and follow the instructions'
289
- . ' in the "API Key" section: <code>' . SucuriScan::escape($key)
290
- . '</code>';
291
292
- SucuriScanOption::deleteOption(':api_key');
293
}
294
295
// Special response for invalid firewall API keys.
284
if (stripos($raw, 'log file not found') !== false) {
285
$key = SucuriScanOption::getOption(':api_key');
286
$msg .= '; this generally happens when you use an invalid API key,'
287
+ . ' or when the connection with the API service suddently closes.';
288
289
+ SucuriScanEvent::reportCriticalEvent($msg);
290
}
291
292
// Special response for invalid firewall API keys.
src/auditlogs.lib.php CHANGED
@@ -170,7 +170,6 @@ class SucuriScanAuditLogs
170
$outdata = (array) $auditlogs['output_data'];
171
$todaysDate = SucuriScan::datetime(null, 'M d, Y');
172
$iterator_start = ($pageNumber - 1) * $maxPerPage;
173
- $show_password = SucuriScanOption::isEnabled(':notify_failed_password');
174
$total_items = count($outdata);
175
176
usort($outdata, array('SucuriScanAuditLogs', 'sortByDate'));
@@ -186,7 +185,7 @@ class SucuriScanAuditLogs
186
187
$audit_log = (array) $outdata[$i];
188
189
- if (!$show_password && strpos($audit_log['message'], ";\x20password:")) {
190
$idx = strpos($audit_log['message'], ";\x20password:");
191
$audit_log['message'] = substr($audit_log['message'], 0, $idx);
192
}
170
$outdata = (array) $auditlogs['output_data'];
171
$todaysDate = SucuriScan::datetime(null, 'M d, Y');
172
$iterator_start = ($pageNumber - 1) * $maxPerPage;
173
$total_items = count($outdata);
174
175
usort($outdata, array('SucuriScanAuditLogs', 'sortByDate'));
185
186
$audit_log = (array) $outdata[$i];
187
188
+ if (strpos($audit_log['message'], ";\x20password:")) {
189
$idx = strpos($audit_log['message'], ";\x20password:");
190
$audit_log['message'] = substr($audit_log['message'], 0, $idx);
191
}
src/cli.lib.php ADDED
@@ -0,0 +1,93 @@
1
+ <?php
2
+
3
+ /**
4
+ * Code related to the cli.lib.php interface.
5
+ *
6
+ * PHP version 5
7
+ *
8
+ * @category Library
9
+ * @package Sucuri
10
+ * @subpackage SucuriScanCLI
11
+ * @author Daniel Cid <dcid@sucuri.net>
12
+ * @copyright 2010-2017 Sucuri Inc.
13
+ * @license https://www.gnu.org/licenses/gpl-2.0.txt GPL2
14
+ * @link https://wordpress.org/plugins/sucuri-scanner
15
+ */
16
+
17
+ if (!defined('SUCURISCAN_INIT') || SUCURISCAN_INIT !== true) {
18
+ if (!headers_sent()) {
19
+ /* Report invalid access if possible. */
20
+ header('HTTP/1.1 403 Forbidden');
21
+ }
22
+ exit(1);
23
+ }
24
+
25
+ /**
26
+ * Manage Sucuri API registration.
27
+ *
28
+ * @category Library
29
+ * @package Sucuri
30
+ * @subpackage SucuriScanner
31
+ * @author Daniel Cid <dcid@sucuri.net>
32
+ * @copyright 2010-2017 Sucuri Inc.
33
+ * @license https://www.gnu.org/licenses/gpl-2.0.txt GPL2
34
+ * @link https://wordpress.org/plugins/sucuri-scanner
35
+ */
36
+ class SucuriScanCLI extends WP_CLI_Command
37
+ {
38
+ /**
39
+ * Register and connect to the Sucuri API.
40
+ *
41
+ * ## OPTIONS
42
+ *
43
+ * [<api_key>]
44
+ * : Sucuri API key to register with.
45
+ *
46
+ * ## EXAMPLES
47
+ *
48
+ * # New registration
49
+ * wp sucuri register
50
+ * API key: 99e656abef7a123d1cffe73f91ba63702
51
+ * Success: The API key for your site was successfully generated and saved.
52
+ *
53
+ * # Existing key registration
54
+ * wp sucuri register 99e656abef7a123d1cffe73f91ba63702
55
+ * Success: The API key for your site was successfully saved.
56
+ *
57
+ * # Registration recovery
58
+ * wp sucuri register
59
+ * Warning: We already have an API key created for this site. It has been sent to the email admin@example.com for recovery.
60
+ *
61
+ * @param array $args Arguments from the command line interface.
62
+ * @return void
63
+ */
64
+ public function register($args)
65
+ {
66
+ list($api_key) = $args;
67
+
68
+ ob_start();
69
+ $registered = $api_key ? SucuriScanAPI::setPluginKey($api_key, true) : SucuriScanAPI::registerSite();
70
+ $output = ob_get_clean();
71
+
72
+ preg_match_all('/<p><b>SUCURI:<\/b>(.+)<\/p>/', $output, $matches);
73
+
74
+ $message = isset($matches[1][0]) ? trim(strip_tags($matches[1][0])) : 'An unknown error occurred during registration.';
75
+
76
+ if (! $registered) {
77
+ WP_CLI::error($message);
78
+ }
79
+
80
+ if ($registered && $api_key) {
81
+ WP_CLI::success('The API key for your site was successfully saved.');
82
+ return;
83
+ }
84
+
85
+ $api_key = SucuriScanAPI::getPluginKey();
86
+
87
+ WP_CLI::line("API key: $api_key");
88
+
89
+ WP_CLI::success($message);
90
+ }
91
+ }
92
+
93
+ WP_CLI::add_command('sucuri', 'SucuriScanCLI');
src/fileinfo.lib.php CHANGED
@@ -235,23 +235,27 @@ class SucuriScanFileInfo extends SucuriScan
235
continue;
236
}
237
238
- /* check only files */
239
- if ($fifo->isFile()
240
- && $filterby === 'file'
241
- && !$this->ignoreFile($filepath)
242
- && !$this->ignoreFolder($filepath)
243
- ) {
244
- $files[] = $filepath;
245
- continue;
246
- }
247
-
248
- /* check only directories */
249
- if ($fifo->isDir()
250
- && $filterby === 'directory'
251
- && !$this->ignoreFolder($filepath)
252
- ) {
253
- $files[] = $filepath;
254
- continue;
255
}
256
}
257
@@ -293,7 +297,13 @@ class SucuriScanFileInfo extends SucuriScan
293
$filesize = @filesize($filepath);
294
295
if ($as_array) {
296
- $basename = str_replace($abspath . '/', '', $filepath);
297
$signatures[$basename] = array(
298
'filepath' => $filepath,
299
'checksum' => $file_checksum,
235
continue;
236
}
237
238
+ try {
239
+ /* check only files */
240
+ if ($fifo->isFile()
241
+ && $filterby === 'file'
242
+ && !$this->ignoreFile($filepath)
243
+ && !$this->ignoreFolder($filepath)
244
+ ) {
245
+ $files[] = $filepath;
246
+ continue;
247
+ }
248
+
249
+ /* check only directories */
250
+ if ($fifo->isDir()
251
+ && $filterby === 'directory'
252
+ && !$this->ignoreFolder($filepath)
253
+ ) {
254
+ $files[] = $filepath;
255
+ continue;
256
+ }
257
+ } catch (RuntimeException $e) {
258
+ SucuriScanEvent::reportCriticalEvent($e->getMessage());
259
}
260
}
261
297
$filesize = @filesize($filepath);
298
299
if ($as_array) {
300
+ $basename = $filepath;
301
+
302
+ if (strlen($abspath . '/') > 1) {
303
+ /* convert absolute path into relative path */
304
+ $basename = str_replace($abspath . '/', '', $filepath);
305
+ }
306
+
307
$signatures[$basename] = array(
308
'filepath' => $filepath,
309
'checksum' => $file_checksum,
src/firewall.lib.php CHANGED
@@ -691,7 +691,7 @@ class SucuriScanFirewall extends SucuriScanAPI
691
692
$params['FirewallAutoClearCache'] = 'data-status="disabled"';
693
694
- if (SucuriScanOption::isEnabled(':auto_clear_cache')) {
695
$params['FirewallAutoClearCache'] = 'checked="checked"';
696
}
697
@@ -711,7 +711,7 @@ class SucuriScanFirewall extends SucuriScanAPI
711
*/
712
public static function clearCacheHook()
713
{
714
- if (SucuriScanOption::isEnabled(':auto_clear_cache')) {
715
ob_start();
716
self::clearCache();
717
$error = ob_get_clean();
@@ -776,4 +776,17 @@ class SucuriScanFirewall extends SucuriScanAPI
776
777
wp_send_json($response, 200);
778
}
779
}
691
692
$params['FirewallAutoClearCache'] = 'data-status="disabled"';
693
694
+ if (self::shouldAutoClearCache()) {
695
$params['FirewallAutoClearCache'] = 'checked="checked"';
696
}
697
711
*/
712
public static function clearCacheHook()
713
{
714
+ if (self::shouldAutoClearCache()) {
715
ob_start();
716
self::clearCache();
717
$error = ob_get_clean();
776
777
wp_send_json($response, 200);
778
}
779
+
780
+ /**
781
+ * Returns true if the plugin should flush the firewall cache.
782
+ *
783
+ * @return bool True if the plugin should flush the firewall cache.
784
+ */
785
+ private static function shouldAutoClearCache()
786
+ {
787
+ return (bool) (
788
+ defined('SUCURI_CLEAR_CACHE_ON_PUBLISH')
789
+ || SucuriScanOption::isEnabled(':auto_clear_cache')
790
+ );
791
+ }
792
}
src/hook.lib.php CHANGED
@@ -176,13 +176,7 @@ class SucuriScanHook extends SucuriScanEvent
176
$title = empty($title) ? 'Unknown' : sanitize_user($title, true);
177
$message = 'User authentication failed: ' . $title;
178
179
- /* send the submitted password along with the alert */
180
- if (SucuriScanOption::isEnabled(':notify_failed_password')) {
181
- $message .= '; password: ' . $password;
182
- sucuriscan_log_failed_login($title, $password);
183
- } else {
184
- sucuriscan_log_failed_login($title, '[hidden]');
185
- }
186
187
self::reportErrorEvent($message);
188
176
$title = empty($title) ? 'Unknown' : sanitize_user($title, true);
177
$message = 'User authentication failed: ' . $title;
178
179
+ sucuriscan_log_failed_login($title);
180
181
self::reportErrorEvent($message);
182
src/integrity.lib.php CHANGED
@@ -586,6 +586,10 @@ class SucuriScanIntegrity
586
}
587
}
588
589
return $output;
590
}
591
@@ -662,6 +666,8 @@ class SucuriScanIntegrity
662
'^wp-content\/(themes|plugins)\/.+',
663
'^google[0-9a-z]{16}\.html#x27;,
664
'^pinterest-[0-9a-z]{5}\.html#x27;,
665
'\.ico#x27;,
666
);
667
586
}
587
}
588
589
+ sort($output['added']);
590
+ sort($output['removed']);
591
+ sort($output['modified']);
592
+
593
return $output;
594
}
595
666
'^wp-content\/(themes|plugins)\/.+',
667
'^google[0-9a-z]{16}\.html#x27;,
668
'^pinterest-[0-9a-z]{5}\.html#x27;,
669
+ '^wp-content\/languages\/.+\.mo#x27;,
670
+ '^wp-content\/languages\/.+\.po#x27;,
671
'\.ico#x27;,
672
);
673
src/interface.lib.php CHANGED
@@ -67,7 +67,7 @@ class SucuriScanInterface
67
'sucuriscan1',
68
SUCURISCAN_URL . '/inc/css/styles.css',
69
array(/* empty */),
70
- '3eeb7af'
71
);
72
wp_enqueue_style('sucuriscan1');
73
@@ -75,7 +75,7 @@ class SucuriScanInterface
75
'sucuriscan1',
76
SUCURISCAN_URL . '/inc/js/scripts.js',
77
array(/* empty */),
78
- '81f6bb4'
79
);
80
wp_enqueue_script('sucuriscan1');
81
@@ -84,7 +84,7 @@ class SucuriScanInterface
84
'sucuriscan3',
85
SUCURISCAN_URL . '/inc/css/flags.min.css',
86
array(/* empty */),
87
- substr(md5(time()), 0, 7)
88
);
89
wp_enqueue_style('sucuriscan3');
90
}
67
'sucuriscan1',
68
SUCURISCAN_URL . '/inc/css/styles.css',
69
array(/* empty */),
70
+ SucuriScan::fileVersion('inc/css/styles.css')
71
);
72
wp_enqueue_style('sucuriscan1');
73
75
'sucuriscan1',
76
SUCURISCAN_URL . '/inc/js/scripts.js',
77
array(/* empty */),
78
+ SucuriScan::fileVersion('inc/js/scripts.js')
79
);
80
wp_enqueue_script('sucuriscan1');
81
84
'sucuriscan3',
85
SUCURISCAN_URL . '/inc/css/flags.min.css',
86
array(/* empty */),
87
+ SucuriScan::fileVersion('inc/css/flags.min.css')
88
);
89
wp_enqueue_style('sucuriscan3');
90
}
src/lastlogins-failed.php CHANGED
@@ -57,7 +57,6 @@ function sucuriscan_failed_logins_panel()
57
$max_failed_logins = SucuriScanOption::getOption(':maximum_failed_logins');
58
$notify_bruteforce_attack = SucuriScanOption::getOption(':notify_bruteforce_attack');
59
$failed_logins = sucuriscan_get_all_failed_logins($page_offset, $max_per_page);
60
- $show_password = SucuriScanOption::isEnabled(':notify_failed_password');
61
62
if ($failed_logins) {
63
$counter = 0;
@@ -70,21 +69,6 @@ function sucuriscan_failed_logins_panel()
70
continue;
71
}
72
73
- $wrong_user_password = 'hidden';
74
- $wrong_user_password_color = 'default';
75
-
76
- if (isset($login_data['user_password']) && !empty($login_data['user_password'])) {
77
- $wrong_user_password = $login_data['user_password'];
78
- $wrong_user_password_color = 'danger';
79
- } else {
80
- $wrong_user_password = 'empty';
81
- $wrong_user_password_color = 'info';
82
- }
83
-
84
- if (!$show_password) {
85
- $wrong_user_password = 'hidden';
86
- }
87
-
88
$template_variables['FailedLogins.List'] .= SucuriScanTemplate::getSnippet(
89
'lastlogins-failedlogins',
90
array(
@@ -92,8 +76,6 @@ function sucuriscan_failed_logins_panel()
92
'FailedLogins.Username' => $login_data['user_login'],
93
'FailedLogins.RemoteAddr' => $login_data['remote_addr'],
94
'FailedLogins.UserAgent' => $login_data['user_agent'],
95
- 'FailedLogins.Password' => $wrong_user_password,
96
- 'FailedLogins.PasswordColor' => $wrong_user_password_color,
97
'FailedLogins.Datetime' => SucuriScan::datetime($login_data['attempt_time']),
98
)
99
);
@@ -314,11 +296,10 @@ function sucuriscan_get_failed_logins($get_old_logs = false, $offset = 0, $limit
314
* this entry will contain the username, timestamp of the login attempt, remote
315
* address of the computer sending the request, and the user-agent.
316
*
317
- * @param string $user_login Information from the current failed login event.
318
- * @param string $wrong_password Wrong password used during the supposed attack.
319
- * @return bool Whether the information of the current failed login event was stored or not.
320
*/
321
- function sucuriscan_log_failed_login($user_login = '', $wrong_password = '')
322
{
323
$storage = sucuriscan_failed_logins_datastore_path();
324
@@ -329,7 +310,6 @@ function sucuriscan_log_failed_login($user_login = '', $wrong_password = '')
329
$login_data = json_encode(
330
array(
331
'user_login' => $user_login,
332
- 'user_password' => $wrong_password,
333
'attempt_time' => time(),
334
'remote_addr' => SucuriScan::getRemoteAddr(),
335
'user_agent' => SucuriScan::getUserAgent(),
57
$max_failed_logins = SucuriScanOption::getOption(':maximum_failed_logins');
58
$notify_bruteforce_attack = SucuriScanOption::getOption(':notify_bruteforce_attack');
59
$failed_logins = sucuriscan_get_all_failed_logins($page_offset, $max_per_page);
60
61
if ($failed_logins) {
62
$counter = 0;
69
continue;
70
}
71
72
$template_variables['FailedLogins.List'] .= SucuriScanTemplate::getSnippet(
73
'lastlogins-failedlogins',
74
array(
76
'FailedLogins.Username' => $login_data['user_login'],
77
'FailedLogins.RemoteAddr' => $login_data['remote_addr'],
78
'FailedLogins.UserAgent' => $login_data['user_agent'],
79
'FailedLogins.Datetime' => SucuriScan::datetime($login_data['attempt_time']),
80
)
81
);
296
* this entry will contain the username, timestamp of the login attempt, remote
297
* address of the computer sending the request, and the user-agent.
298
*
299
+ * @param string $user_login Information from the current failed login event.
300
+ * @return bool True if the information was saved, false otherwise.
301
*/
302
+ function sucuriscan_log_failed_login($user_login = '')
303
{
304
$storage = sucuriscan_failed_logins_datastore_path();
305
310
$login_data = json_encode(
311
array(
312
'user_login' => $user_login,
313
'attempt_time' => time(),
314
'remote_addr' => SucuriScan::getRemoteAddr(),
315
'user_agent' => SucuriScan::getUserAgent(),
src/mail.lib.php CHANGED
@@ -204,6 +204,7 @@ class SucuriScanMail extends SucuriScanOption
204
$params['Subject'] = $subject;
205
$params['Website'] = $website;
206
$params['RemoteAddress'] = self::getRemoteAddr();
207
$params['Message'] = $message;
208
$params['User'] = $display_name;
209
$params['Time'] = SucuriScan::datetime();
204
$params['Subject'] = $subject;
205
$params['Website'] = $website;
206
$params['RemoteAddress'] = self::getRemoteAddr();
207
+ $params['ReverseAddress'] = gethostbyaddr($params['RemoteAddress']);
208
$params['Message'] = $message;
209
$params['User'] = $display_name;
210
$params['Time'] = SucuriScan::datetime();
src/option.lib.php CHANGED
@@ -82,7 +82,6 @@ class SucuriScanOption extends SucuriScanRequest
82
'sucuriscan_notify_available_updates' => 'disabled',
83
'sucuriscan_notify_bruteforce_attack' => 'disabled',
84
'sucuriscan_notify_failed_login' => 'enabled',
85
- 'sucuriscan_notify_failed_password' => 'disabled',
86
'sucuriscan_notify_plugin_activated' => 'enabled',
87
'sucuriscan_notify_plugin_change' => 'enabled',
88
'sucuriscan_notify_plugin_deactivated' => 'disabled',
@@ -115,7 +114,7 @@ class SucuriScanOption extends SucuriScanRequest
115
'sucuriscan_use_wpmail' => 'enabled',
116
);
117
118
- return $defaults;
119
}
120
121
/**
@@ -179,6 +178,12 @@ class SucuriScanOption extends SucuriScanRequest
179
*/
180
public static function getAllOptions()
181
{
182
$options = array();
183
$fpath = self::optionsFilePath();
184
@@ -198,6 +203,8 @@ class SucuriScanOption extends SucuriScanRequest
198
}
199
}
200
201
return $options;
202
}
203
@@ -209,6 +216,8 @@ class SucuriScanOption extends SucuriScanRequest
209
*/
210
public static function writeNewOptions($options = array())
211
{
212
$fpath = self::optionsFilePath();
213
$content = "<?php exit(0); ?>\n";
214
$content .= @json_encode($options) . "\n";
82
'sucuriscan_notify_available_updates' => 'disabled',
83
'sucuriscan_notify_bruteforce_attack' => 'disabled',
84
'sucuriscan_notify_failed_login' => 'enabled',
85
'sucuriscan_notify_plugin_activated' => 'enabled',
86
'sucuriscan_notify_plugin_change' => 'enabled',
87
'sucuriscan_notify_plugin_deactivated' => 'disabled',
114
'sucuriscan_use_wpmail' => 'enabled',
115
);
116
117
+ return (array) apply_filters('sucuriscan_option_defaults', $defaults);
118
}
119
120
/**
178
*/
179
public static function getAllOptions()
180
{
181
+ $options = wp_cache_get('alloptions', SUCURISCAN, WP_DEBUG);
182
+
183
+ if ($options && is_array($options)) {
184
+ return $options;
185
+ }
186
+
187
$options = array();
188
$fpath = self::optionsFilePath();
189
203
}
204
}
205
206
+ wp_cache_set('alloptions', $options, SUCURISCAN);
207
+
208
return $options;
209
}
210
216
*/
217
public static function writeNewOptions($options = array())
218
{
219
+ wp_cache_delete('alloptions', SUCURISCAN);
220
+
221
$fpath = self::optionsFilePath();
222
$content = "<?php exit(0); ?>\n";
223
$content .= @json_encode($options) . "\n";
src/settings-alerts.php CHANGED
@@ -139,8 +139,8 @@ function sucuriscan_settings_alerts_trustedips()
139
if ($trust_ip) {
140
if (SucuriScan::isValidIP($trust_ip) || SucuriScan::isValidCIDR($trust_ip)) {
141
$ip_info = SucuriScan::getIPInfo($trust_ip);
142
- $ip_info['added_at'] = time();
143
$cache_key = md5($ip_info['remote_addr']);
144
145
if ($cache->exists($cache_key)) {
146
SucuriScanInterface::error('The IP specified address was already added.');
@@ -405,7 +405,6 @@ function sucuriscan_settings_alerts_events($nonce)
405
'sucuriscan_notify_user_registration' => 'user:' . 'Receive email alerts for new user registration',
406
'sucuriscan_notify_success_login' => 'user:' . 'Receive email alerts for successful login attempts',
407
'sucuriscan_notify_failed_login' => 'user:' . 'Receive email alerts for failed login attempts <em>(you may receive tons of emails)</em>',
408
- 'sucuriscan_notify_failed_password' => 'user:' . 'Receive email alerts for failed login attempts including the submitted password',
409
'sucuriscan_notify_bruteforce_attack' => 'user:' . 'Receive email alerts for password guessing attacks <em>(summary of failed logins per hour)</em>',
410
'sucuriscan_notify_post_publication' => 'setting:' . 'Receive email alerts for changes in the post status <em>(configure from Ignore Posts Changes)</em>',
411
'sucuriscan_notify_website_updated' => 'setting:' . 'Receive email alerts when the WordPress version is updated',
@@ -441,7 +440,6 @@ function sucuriscan_settings_alerts_events($nonce)
441
$params['Alerts.NoAlertsVisibility'] = 'visible';
442
unset($notify_options['sucuriscan_notify_success_login']);
443
unset($notify_options['sucuriscan_notify_failed_login']);
444
- unset($notify_options['sucuriscan_notify_failed_password']);
445
}
446
447
// Process form submission to change the alert settings.
@@ -450,11 +448,6 @@ function sucuriscan_settings_alerts_events($nonce)
450
if (SucuriScanRequest::post(':save_alert_events') !== false) {
451
$ucounter = 0;
452
453
- /* disable password tracker for failed logins as well */
454
- if (SucuriScanRequest::post(':notify_failed_login') === '0') {
455
- $_POST['sucuriscan_notify_failed_password'] = '0';
456
- }
457
-
458
foreach ($notify_options as $alert_type => $alert_label) {
459
$option_value = SucuriScanRequest::post($alert_type, '(1|0)');
460
@@ -545,7 +538,7 @@ function sucuriscan_settings_alerts_ignore_posts()
545
// Ignore a new event for email alerts.
546
$action = SucuriScanRequest::post(':ignorerule_action');
547
$ignore_rule = SucuriScanRequest::post(':ignorerule');
548
- $selected_types = SucuriScanRequest::post(':posttypes', '_array');
549
550
if ($action === 'add') {
551
if (!preg_match('/^[a-z_\-]+#x2F;', $ignore_rule)) {
@@ -567,7 +560,7 @@ function sucuriscan_settings_alerts_ignore_posts()
567
$timestamp = time();
568
569
foreach ($post_types as $post_type) {
570
- if (!in_array($post_type, $selected_types)) {
571
$ignored_events[$post_type] = $timestamp;
572
}
573
}
139
if ($trust_ip) {
140
if (SucuriScan::isValidIP($trust_ip) || SucuriScan::isValidCIDR($trust_ip)) {
141
$ip_info = SucuriScan::getIPInfo($trust_ip);
142
$cache_key = md5($ip_info['remote_addr']);
143
+ $ip_info['added_at'] = time();
144
145
if ($cache->exists($cache_key)) {
146
SucuriScanInterface::error('The IP specified address was already added.');
405
'sucuriscan_notify_user_registration' => 'user:' . 'Receive email alerts for new user registration',
406
'sucuriscan_notify_success_login' => 'user:' . 'Receive email alerts for successful login attempts',
407
'sucuriscan_notify_failed_login' => 'user:' . 'Receive email alerts for failed login attempts <em>(you may receive tons of emails)</em>',
408
'sucuriscan_notify_bruteforce_attack' => 'user:' . 'Receive email alerts for password guessing attacks <em>(summary of failed logins per hour)</em>',
409
'sucuriscan_notify_post_publication' => 'setting:' . 'Receive email alerts for changes in the post status <em>(configure from Ignore Posts Changes)</em>',
410
'sucuriscan_notify_website_updated' => 'setting:' . 'Receive email alerts when the WordPress version is updated',
440
$params['Alerts.NoAlertsVisibility'] = 'visible';
441
unset($notify_options['sucuriscan_notify_success_login']);
442
unset($notify_options['sucuriscan_notify_failed_login']);
443
}
444
445
// Process form submission to change the alert settings.
448
if (SucuriScanRequest::post(':save_alert_events') !== false) {
449
$ucounter = 0;
450
451
foreach ($notify_options as $alert_type => $alert_label) {
452
$option_value = SucuriScanRequest::post($alert_type, '(1|0)');
453
538
// Ignore a new event for email alerts.
539
$action = SucuriScanRequest::post(':ignorerule_action');
540
$ignore_rule = SucuriScanRequest::post(':ignorerule');
541
+ $selected = SucuriScanRequest::post(':posttypes', '_array');
542
543
if ($action === 'add') {
544
if (!preg_match('/^[a-z_\-]+#x2F;', $ignore_rule)) {
560
$timestamp = time();
561
562
foreach ($post_types as $post_type) {
563
+ if (is_array($selected) && !in_array($post_type, $selected)) {
564
$ignored_events[$post_type] = $timestamp;
565
}
566
}
src/settings-apiservice.php CHANGED
@@ -39,6 +39,7 @@ function sucuriscan_settings_apiservice_status($nonce)
39
$params['ApiStatus.WarningVisibility'] = 'visible';
40
$params['ApiStatus.ErrorVisibility'] = 'hidden';
41
$params['ApiStatus.ServiceURL'] = SUCURISCAN_API_URL;
42
43
if ($nonce) {
44
// Enable or disable the API service communication.
@@ -66,6 +67,9 @@ function sucuriscan_settings_apiservice_status($nonce)
66
$params['ApiStatus.ErrorVisibility'] = 'visible';
67
}
68
69
return SucuriScanTemplate::getSection('settings-apiservice-status', $params);
70
}
71
39
$params['ApiStatus.WarningVisibility'] = 'visible';
40
$params['ApiStatus.ErrorVisibility'] = 'hidden';
41
$params['ApiStatus.ServiceURL'] = SUCURISCAN_API_URL;
42
+ $params['ApiStatus.ApiKey'] = '';
43
44
if ($nonce) {
45
// Enable or disable the API service communication.
67
$params['ApiStatus.ErrorVisibility'] = 'visible';
68
}
69
70
+ $api_key = SucuriScanAPI::getPluginKey();
71
+ $params['ApiStatus.ApiKey'] = $api_key ? $api_key : 'NONE';
72
+
73
return SucuriScanTemplate::getSection('settings-apiservice-status', $params);
74
}
75
src/settings-general.php CHANGED
@@ -476,7 +476,6 @@ function sucuriscan_settings_general_importexport($nonce)
476
$params = array();
477
$allowed = array(
478
':addr_header',
479
- ':api_key',
480
':api_protocol',
481
':api_service',
482
':cloudproxy_apikey',
@@ -549,6 +548,26 @@ function sucuriscan_settings_general_importexport($nonce)
549
$count++;
550
}
551
552
SucuriScanInterface::info(
553
sprintf(
554
'%d out of %d option have been successfully imported',
@@ -569,6 +588,14 @@ function sucuriscan_settings_general_importexport($nonce)
569
$settings[$option_name] = SucuriScanOption::getOption($option);
570
}
571
572
$params['Export'] = @json_encode($settings);
573
574
return SucuriScanTemplate::getSection('settings-general-importexport', $params);
476
$params = array();
477
$allowed = array(
478
':addr_header',
479
':api_protocol',
480
':api_service',
481
':cloudproxy_apikey',
548
$count++;
549
}
550
551
+ /* import trusted ip addresses */
552
+ if (array_key_exists('trusted_ips', $data) && is_array($data)) {
553
+ $cache = new SucuriScanCache('trustip');
554
+
555
+ foreach ($data['trusted_ips'] as $trustedIP) {
556
+ $trustedIP = str_replace('\/', '/', $trustedIP);
557
+ $trustedIP = str_replace('/32', '', $trustedIP);
558
+
559
+ if (SucuriScan::isValidIP($trustedIP) || SucuriScan::isValidCIDR($trustedIP)) {
560
+ $ipInfo = SucuriScan::getIPInfo($trustedIP);
561
+ $cacheKey = md5($ipInfo['remote_addr']);
562
+ $ipInfo['added_at'] = time();
563
+
564
+ if (!$cache->exists($cacheKey)) {
565
+ $cache->add($cacheKey, $ipInfo);
566
+ }
567
+ }
568
+ }
569
+ }
570
+
571
SucuriScanInterface::info(
572
sprintf(
573
'%d out of %d option have been successfully imported',
588
$settings[$option_name] = SucuriScanOption::getOption($option);
589
}
590
591
+ /* include the trusted IP address list */
592
+ $settings['trusted_ips'] = array();
593
+ $cache = new SucuriScanCache('trustip');
594
+ $trusted = $cache->getAll();
595
+ foreach ($trusted as $trustedIP) {
596
+ $settings['trusted_ips'][] = $trustedIP->cidr_format;
597
+ }
598
+
599
$params['Export'] = @json_encode($settings);
600
601
return SucuriScanTemplate::getSection('settings-general-importexport', $params);
src/sucuriscan.lib.php CHANGED
@@ -259,7 +259,10 @@ class SucuriScan
259
*/
260
public static function fixPath($path = '')
261
{
262
- return rtrim(str_replace(DIRECTORY_SEPARATOR, '/', $path), '/');
263
}
264
265
/**
@@ -770,15 +773,15 @@ class SucuriScan
770
*/
771
public static function isValidCIDR($remote_addr = '')
772
{
773
- $status = false;
774
775
if (preg_match('/^([0-9\.]{7,15})\/(8|16|24)#x2F;', $remote_addr, $match)) {
776
- if (self::isValidIP($match[1])) {
777
- $status = true;
778
- }
779
}
780
781
- return $status;
782
}
783
784
/**
@@ -906,4 +909,15 @@ class SucuriScan
906
{
907
return (bool) (stripos(@$_SERVER['SERVER_SOFTWARE'], 'Microsoft-IIS') !== false);
908
}
909
}
259
*/
260
public static function fixPath($path = '')
261
{
262
+ $new = str_replace(DIRECTORY_SEPARATOR, '/', $path);
263
+ $new = rtrim($new, '/'); /* purge right side. */
264
+
265
+ return empty($new) ? '/' : $new;
266
}
267
268
/**
773
*/
774
public static function isValidCIDR($remote_addr = '')
775
{
776
+ if (!is_string($remote_addr)) {
777
+ return false;
778
+ }
779
780
if (preg_match('/^([0-9\.]{7,15})\/(8|16|24)#x2F;', $remote_addr, $match)) {
781
+ return self::isValidIP($match[1]);
782
}
783
784
+ return false;
785
}
786
787
/**
909
{
910
return (bool) (stripos(@$_SERVER['SERVER_SOFTWARE'], 'Microsoft-IIS') !== false);
911
}
912
+
913
+ /**
914
+ * Returns the md5 hash representing the content of a file.
915
+ *
916
+ * @param string $file Relative path to the file.
917
+ * @return string Seven first characters in the hash of the file.
918
+ */
919
+ public static function fileVersion($file = '')
920
+ {
921
+ return substr(md5_file(SUCURISCAN_PLUGIN_PATH . '/' . $file), 0, 7);
922
+ }
923
}
sucuri.php CHANGED
@@ -6,7 +6,7 @@
6
* Plugin URI: https://wordpress.sucuri.net/
7
* Author URI: https://sucuri.net/
8
* Author: Sucuri Inc.
9
- * Version: 1.8.11
10
*
11
* PHP version 5
12
*
@@ -83,7 +83,7 @@ define('SUCURISCAN', 'sucuriscan');
83
/**
84
* Current version of the plugin's code.
85
*/
86
- define('SUCURISCAN_VERSION', '1.8.11');
87
88
/**
89
* The name of the folder where the plugin's files will be located.
@@ -232,6 +232,11 @@ require_once 'src/settings-webinfo.php';
232
/* Load global variables and triggers */
233
require_once 'src/globals.php';
234
235
/**
236
* Uninstalls the plugin, its settings and reverts the hardening.
237
*
6
* Plugin URI: https://wordpress.sucuri.net/
7
* Author URI: https://sucuri.net/
8
* Author: Sucuri Inc.
9
+ * Version: 1.8.12
10
*
11
* PHP version 5
12
*
83
/**
84
* Current version of the plugin's code.
85
*/
86
+ define('SUCURISCAN_VERSION', '1.8.12');
87
88
/**
89
* The name of the folder where the plugin's files will be located.
232
/* Load global variables and triggers */
233
require_once 'src/globals.php';
234
235
+ /* Load WP-CLI command */
236
+ if (defined('WP_CLI') && WP_CLI) {
237
+ include_once 'src/cli.lib.php';
238
+ }
239
+
240
/**
241
* Uninstalls the plugin, its settings and reverts the hardening.
242
*