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

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.13
Comparing to
See all releases

Code changes from version 1.8.12 to 1.8.13

LICENSE CHANGED
@@ -1,12 +1,12 @@
1
- GNU GENERAL PUBLIC LICENSE
2
- Version 2, June 1991
3
 
4
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
5
- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
6
  Everyone is permitted to copy and distribute verbatim copies
7
  of this license document, but changing it is not allowed.
8
 
9
- Preamble
10
 
11
  The licenses for most software are designed to take away your
12
  freedom to share and change it. By contrast, the GNU General Public
@@ -15,7 +15,7 @@ software--to make sure the software is free for all its users. This
15
  General Public License applies to most of the Free Software
16
  Foundation's software and to any other program whose authors commit to
17
  using it. (Some other Free Software Foundation software is covered by
18
- the GNU Library General Public License instead.) You can apply it to
19
  your programs, too.
20
 
21
  When we speak of free software, we are referring to freedom, not
@@ -55,8 +55,8 @@ patent must be licensed for everyone's free use or not licensed at all.
55
 
56
  The precise terms and conditions for copying, distribution and
57
  modification follow.
58
-
59
- GNU GENERAL PUBLIC LICENSE
60
  TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61
 
62
  0. This License applies to any program or other work which contains
@@ -110,7 +110,7 @@ above, provided that you also meet all of these conditions:
110
  License. (Exception: if the Program itself is interactive but
111
  does not normally print such an announcement, your work based on
112
  the Program is not required to print an announcement.)
113
-
114
  These requirements apply to the modified work as a whole. If
115
  identifiable sections of that work are not derived from the Program,
116
  and can be reasonably considered independent and separate works in
@@ -168,7 +168,7 @@ access to copy from a designated place, then offering equivalent
168
  access to copy the source code from the same place counts as
169
  distribution of the source code, even though third parties are not
170
  compelled to copy the source along with the object code.
171
-
172
  4. You may not copy, modify, sublicense, or distribute the Program
173
  except as expressly provided under this License. Any attempt
174
  otherwise to copy, modify, sublicense or distribute the Program is
@@ -225,7 +225,7 @@ impose that choice.
225
 
226
  This section is intended to make thoroughly clear what is believed to
227
  be a consequence of the rest of this License.
228
-
229
  8. If the distribution and/or use of the Program is restricted in
230
  certain countries either by patents or by copyrighted interfaces, the
231
  original copyright holder who places the Program under this License
@@ -255,7 +255,7 @@ make exceptions for this. Our decision will be guided by the two goals
255
  of preserving the free status of all derivatives of our free software and
256
  of promoting the sharing and reuse of software generally.
257
 
258
- NO WARRANTY
259
 
260
  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261
  FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
@@ -277,9 +277,9 @@ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277
  PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278
  POSSIBILITY OF SUCH DAMAGES.
279
 
280
- END OF TERMS AND CONDITIONS
281
-
282
- How to Apply These Terms to Your New Programs
283
 
284
  If you develop a new program, and you want it to be of the greatest
285
  possible use to the public, the best way to achieve this is to make it
@@ -303,10 +303,9 @@ the "copyright" line and a pointer to where the full notice is found.
303
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304
  GNU General Public License for more details.
305
 
306
- You should have received a copy of the GNU General Public License
307
- along with this program; if not, write to the Free Software
308
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
309
-
310
 
311
  Also add information on how to contact you by electronic and paper mail.
312
 
@@ -336,5 +335,5 @@ necessary. Here is a sample; alter the names:
336
  This General Public License does not permit incorporating your program into
337
  proprietary programs. If your program is a subroutine library, you may
338
  consider it more useful to permit linking proprietary applications with the
339
- library. If this is what you want to do, use the GNU Library General
340
  Public License instead of this License.
1
+ GNU GENERAL PUBLIC LICENSE
2
+ Version 2, June 1991
3
 
4
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6
  Everyone is permitted to copy and distribute verbatim copies
7
  of this license document, but changing it is not allowed.
8
 
9
+ Preamble
10
 
11
  The licenses for most software are designed to take away your
12
  freedom to share and change it. By contrast, the GNU General Public
15
  General Public License applies to most of the Free Software
16
  Foundation's software and to any other program whose authors commit to
17
  using it. (Some other Free Software Foundation software is covered by
18
+ the GNU Lesser General Public License instead.) You can apply it to
19
  your programs, too.
20
 
21
  When we speak of free software, we are referring to freedom, not
55
 
56
  The precise terms and conditions for copying, distribution and
57
  modification follow.
58
+
59
+ GNU GENERAL PUBLIC LICENSE
60
  TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61
 
62
  0. This License applies to any program or other work which contains
110
  License. (Exception: if the Program itself is interactive but
111
  does not normally print such an announcement, your work based on
112
  the Program is not required to print an announcement.)
113
+
114
  These requirements apply to the modified work as a whole. If
115
  identifiable sections of that work are not derived from the Program,
116
  and can be reasonably considered independent and separate works in
168
  access to copy the source code from the same place counts as
169
  distribution of the source code, even though third parties are not
170
  compelled to copy the source along with the object code.
171
+
172
  4. You may not copy, modify, sublicense, or distribute the Program
173
  except as expressly provided under this License. Any attempt
174
  otherwise to copy, modify, sublicense or distribute the Program is
225
 
226
  This section is intended to make thoroughly clear what is believed to
227
  be a consequence of the rest of this License.
228
+
229
  8. If the distribution and/or use of the Program is restricted in
230
  certain countries either by patents or by copyrighted interfaces, the
231
  original copyright holder who places the Program under this License
255
  of preserving the free status of all derivatives of our free software and
256
  of promoting the sharing and reuse of software generally.
257
 
258
+ NO WARRANTY
259
 
260
  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261
  FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
277
  PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278
  POSSIBILITY OF SUCH DAMAGES.
279
 
280
+ END OF TERMS AND CONDITIONS
281
+
282
+ How to Apply These Terms to Your New Programs
283
 
284
  If you develop a new program, and you want it to be of the greatest
285
  possible use to the public, the best way to achieve this is to make it
303
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304
  GNU General Public License for more details.
305
 
306
+ You should have received a copy of the GNU General Public License along
307
+ with this program; if not, write to the Free Software Foundation, Inc.,
308
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
309
 
310
  Also add information on how to contact you by electronic and paper mail.
311
 
335
  This General Public License does not permit incorporating your program into
336
  proprietary programs. If your program is a subroutine library, you may
337
  consider it more useful to permit linking proprietary applications with the
338
+ library. If this is what you want to do, use the GNU Lesser General
339
  Public License instead of this License.
inc/tpl/base.html.tpl CHANGED
@@ -9,7 +9,7 @@
9
  <div class="sucuriscan-header sucuriscan-clearfix">
10
  <div class="sucuriscan-pull-left">
11
  <a href="https://sucuri.net/signup" target="_blank" title="Sucuri Security" class="sucuriscan-logo">
12
- <img src="%%SUCURI.SucuriURL%%/inc/images/pluginlogo.png" alt="Sucuri Inc." />
13
  </a>
14
  <span class="sucuriscan-subtitle">WP Plugin</span>
15
  <span class="sucuriscan-version">v%%SUCURI.PluginVersion%%</span>
9
  <div class="sucuriscan-header sucuriscan-clearfix">
10
  <div class="sucuriscan-pull-left">
11
  <a href="https://sucuri.net/signup" target="_blank" title="Sucuri Security" class="sucuriscan-logo">
12
+ <img src="%%SUCURI.PluginURL%%/inc/images/pluginlogo.png" alt="Sucuri Inc." />
13
  </a>
14
  <span class="sucuriscan-subtitle">WP Plugin</span>
15
  <span class="sucuriscan-version">v%%SUCURI.PluginVersion%%</span>
inc/tpl/firewall-auditlogs.snippet.tpl CHANGED
@@ -2,7 +2,7 @@
2
  <tr>
3
  <td class="sucuriscan-firewall-accesslog sucuriscan-monospace">
4
  <div class="sucuriscan-accesslog-origin">
5
- <img src="%%SUCURI.SucuriURL%%/inc/images/blank.png"
6
  class="sucuriscan-flag sucuriscan-flag-%%SUCURI.AccessLog.RequestCountryCode%%" />
7
  <span>%%SUCURI.AccessLog.RemoteAddr%%</span>
8
  <span>(%%SUCURI.AccessLog.RequestCountryName%%)</span>
2
  <tr>
3
  <td class="sucuriscan-firewall-accesslog sucuriscan-monospace">
4
  <div class="sucuriscan-accesslog-origin">
5
+ <img src="%%SUCURI.PluginURL%%/inc/images/blank.png"
6
  class="sucuriscan-flag sucuriscan-flag-%%SUCURI.AccessLog.RequestCountryCode%%" />
7
  <span>%%SUCURI.AccessLog.RemoteAddr%%</span>
8
  <span>(%%SUCURI.AccessLog.RequestCountryName%%)</span>
inc/tpl/lastlogins-blockedusers.html.tpl DELETED
@@ -1,47 +0,0 @@
1
-
2
- <div class="sucuriscan-panel">
3
- <h3 class="sucuriscan-title">Blocked Users</h3>
4
-
5
- <div class="inside">
6
- <p>Any attempt to authenticate an user account using the functions provided by WordPress will be intercepted and analyzed by the plugin, if the username coincides with any of the users in this list, the authentication process will be immediately stopped. These attemps will not be logged and no email alerts will be sent.</p>
7
-
8
- <div class="sucuriscan-inline-alert-info">
9
- <p>Take in consideration that this is not a 100% bulletproof mechanism to block unwanted user authentications from malicious users. Depending on the configuration of your website, installed plugins, installed themes, and even the version of WordPress there might still be weak points that automated tools can take advantage of to brute force the user accounts registered in your website. <a target="_blank" href="https://sucuri.net/website-firewall/?wp=bu" rel="noopener">Install a firewall</a> to have full protection and mitigate this and a myriad of other attacks.</p>
10
- </div>
11
-
12
- <div class="sucuriscan-inline-alert-error">
13
- <p>Blocking users per IP address is a feature provided by the <a href="https://sucuri.net/website-firewall/" target="_blank" rel="noopener">Sucuri Firewall</a>; to avoid the duplication of code and reduce the amount of false positives this feature will never be implemented in this plugin.</p>
14
- </div>
15
-
16
- <form action="%%SUCURI.URL.Lastlogins%%#blocked" method="post">
17
- <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
18
-
19
- <table class="wp-list-table widefat sucuriscan-table">
20
- <thead>
21
- <tr>
22
- <td id="cb" class="manage-column column-cb check-column">
23
- <label class="screen-reader-text" for="cb-select-all-1">Select All</label>
24
- <input id="cb-select-all-1" type="checkbox">
25
- </td>
26
- <th class="manage-column">Username</th>
27
- <th class="manage-column">Blocked At</th>
28
- <th class="manage-column">First Attempt</th>
29
- <th class="manage-column">Last Attempt</th>
30
- </tr>
31
- </thead>
32
-
33
- <tbody>
34
- %%%SUCURI.BlockedUsers.List%%%
35
-
36
- <tr class="sucuriscan-%%SUCURI.BlockedUsers.NoItemsVisibility%%">
37
- <td colspan="5">
38
- <em>no data available</em>
39
- </td>
40
- </tr>
41
- </tbody>
42
- </table>
43
-
44
- <button type="submit" class="button button-primary">Unblock</button>
45
- </form>
46
- </div>
47
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
inc/tpl/lastlogins-blockedusers.snippet.tpl DELETED
@@ -1,14 +0,0 @@
1
-
2
- <tr>
3
- <th class="check-column">
4
- <input type="checkbox" name="sucuriscan_unblock_user[]" value="%%SUCURI.BlockedUsers.Username%%">
5
- </th>
6
-
7
- <td><span class="sucuriscan-monospace">%%SUCURI.BlockedUsers.Username%%</span></td>
8
-
9
- <td><em>%%SUCURI.BlockedUsers.BlockedAt%%</em></td>
10
-
11
- <td><em>%%SUCURI.BlockedUsers.FirstAttempt%%</em></td>
12
-
13
- <td><em>%%SUCURI.BlockedUsers.LastAttempt%%</em></td>
14
- </tr>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
inc/tpl/lastlogins-failedlogins.html.tpl CHANGED
@@ -11,10 +11,6 @@
11
  <table class="wp-list-table widefat sucuriscan-table sucuriscan-lastlogins-failed">
12
  <thead>
13
  <tr>
14
- <td id="cb" class="manage-column column-cb check-column">
15
- <label class="screen-reader-text" for="cb-select-all-1">Select All</label>
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>
@@ -26,13 +22,13 @@
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>
11
  <table class="wp-list-table widefat sucuriscan-table sucuriscan-lastlogins-failed">
12
  <thead>
13
  <tr>
 
 
 
 
14
  <th class="manage-column">Username</th>
15
  <th class="manage-column">IP Address</th>
16
  <th class="manage-column">Date/Time</th>
22
  %%%SUCURI.FailedLogins.List%%%
23
 
24
  <tr class="sucuriscan-%%SUCURI.FailedLogins.NoItemsVisibility%%">
25
+ <td colspan="4">
26
  <em>no data available</em>
27
  </td>
28
  </tr>
29
 
30
  <tr class="sucuriscan-%%SUCURI.FailedLogins.PaginationVisibility%%">
31
+ <td colspan="4">
32
  <ul class="sucuriscan-pagination">
33
  %%%SUCURI.FailedLogins.PaginationLinks%%%
34
  </ul>
inc/tpl/lastlogins-failedlogins.snippet.tpl CHANGED
@@ -1,9 +1,5 @@
1
 
2
  <tr>
3
- <th class="check-column">
4
- <input type="checkbox" name="sucuriscan_block_user[]" value="%%SUCURI.FailedLogins.Username%%">
5
- </th>
6
-
7
  <td><span class="sucuriscan-monospace">%%SUCURI.FailedLogins.Username%%</span></td>
8
 
9
  <td><span class="sucuriscan-monospace">%%SUCURI.FailedLogins.RemoteAddr%%</span></td>
1
 
2
  <tr>
 
 
 
 
3
  <td><span class="sucuriscan-monospace">%%SUCURI.FailedLogins.Username%%</span></td>
4
 
5
  <td><span class="sucuriscan-monospace">%%SUCURI.FailedLogins.RemoteAddr%%</span></td>
inc/tpl/lastlogins.html.tpl CHANGED
@@ -5,7 +5,6 @@
5
  <li><a href="%%SUCURI.URL.Lastlogins%%#admins">Admins</a></li>
6
  <li><a href="%%SUCURI.URL.Lastlogins%%#loggedin">Logged-in Users</a></li>
7
  <li><a href="%%SUCURI.URL.Lastlogins%%#failed">Failed logins</a></li>
8
- <li><a href="%%SUCURI.URL.Lastlogins%%#blocked">Blocked Users</a></li>
9
  </ul>
10
 
11
  <div class="sucuriscan-tabs-containers">
@@ -24,9 +23,5 @@
24
  <div id="sucuriscan-tabs-failed">
25
  %%%SUCURI.FailedLogins%%%
26
  </div>
27
-
28
- <div id="sucuriscan-tabs-blocked">
29
- %%%SUCURI.BlockedUsers%%%
30
- </div>
31
  </div>
32
  </div>
5
  <li><a href="%%SUCURI.URL.Lastlogins%%#admins">Admins</a></li>
6
  <li><a href="%%SUCURI.URL.Lastlogins%%#loggedin">Logged-in Users</a></li>
7
  <li><a href="%%SUCURI.URL.Lastlogins%%#failed">Failed logins</a></li>
 
8
  </ul>
9
 
10
  <div class="sucuriscan-tabs-containers">
23
  <div id="sucuriscan-tabs-failed">
24
  %%%SUCURI.FailedLogins%%%
25
  </div>
 
 
 
 
26
  </div>
27
  </div>
inc/tpl/notification-pretty.html.tpl CHANGED
@@ -4,7 +4,7 @@
4
  <tr style="background-color:#4b4b4b;background-image:-moz-linear-gradient(top, #555555, #3b3b3b);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#555555), to(#3b3b3b));background-image:-webkit-linear-gradient(top, #555555, #3b3b3b);background-image:-o-linear-gradient(top, #555555, #3b3b3b);background-image:linear-gradient(to bottom, #555555, #3b3b3b);background-repeat:repeat-x">
5
  <td sytle="font-size:20px;font-weight:normal;color:#ffffff;padding:10px;border-right:1px solid #2f2f2f;border-left:1px solid #6f6f6f;-webkit-box-shadow:inset 0 1px 0 #888888;-moz-box-shadow:inset 0 1px 0 #888888;box-shadow:inset 0 1px 0 #888888;text-shadow:1px 1px 2px rgba(0, 0, 0, 0.5)">
6
  <a href="https://sucuri.net/" style="text-decoration:none;display:inline-block;margin:8px 0 5px 20px">
7
- <img src="%%SUCURI.SucuriURL%%/inc/images/mainlogo.png" alt="Sucuri, Inc." style="border:none" />
8
  </a>
9
  <span style="display:inline-block;line-height:46px;margin:0 20px 0 0;float:right;color:#ffffff">%%SUCURI.TemplateTitle%%</span>
10
  </td>
4
  <tr style="background-color:#4b4b4b;background-image:-moz-linear-gradient(top, #555555, #3b3b3b);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#555555), to(#3b3b3b));background-image:-webkit-linear-gradient(top, #555555, #3b3b3b);background-image:-o-linear-gradient(top, #555555, #3b3b3b);background-image:linear-gradient(to bottom, #555555, #3b3b3b);background-repeat:repeat-x">
5
  <td sytle="font-size:20px;font-weight:normal;color:#ffffff;padding:10px;border-right:1px solid #2f2f2f;border-left:1px solid #6f6f6f;-webkit-box-shadow:inset 0 1px 0 #888888;-moz-box-shadow:inset 0 1px 0 #888888;box-shadow:inset 0 1px 0 #888888;text-shadow:1px 1px 2px rgba(0, 0, 0, 0.5)">
6
  <a href="https://sucuri.net/" style="text-decoration:none;display:inline-block;margin:8px 0 5px 20px">
7
+ <img src="%%SUCURI.PluginURL%%/inc/images/mainlogo.png" alt="Sucuri, Inc." style="border:none" />
8
  </a>
9
  <span style="display:inline-block;line-height:46px;margin:0 20px 0 0;float:right;color:#ffffff">%%SUCURI.TemplateTitle%%</span>
10
  </td>
inc/tpl/settings-general-apikey.html.tpl CHANGED
@@ -7,11 +7,7 @@
7
  <h3 class="sucuriscan-title">API Key</h3>
8
 
9
  <div class="inside">
10
- <p>Most of the tools in this plugin can be used without a specific configuration, but the core features <b>require an API key</b> to communicate with the Sucuri services. The key is generated using your administrator e-mail and the domain of this site, this will allow you to have access to our free monitoring tool and other extra features.</p>
11
-
12
- <div class="sucuriscan-inline-alert-info">
13
- <p>Generating an API key implies that you agree to send the information collected by the plugin to the Sucuri API service which is a remote server where the information for the audit logs is stored, this is to prevent malicious users to delete the logs during an attack which may affect an investigation if you suspect that your website was hacked. We also use this information to display <a href="https://sucuri.net/security-reports/brute-force/" target="_blank" rel="noopener">statistics</a> and try to use the data in an anonymous way as we are concerned about your privacy too. Please do not generate an API key if you do not agree with this, you can keep using the plugin without it anyway.</p>
14
- </div>
15
 
16
  <div class="sucuriscan-inline-alert-error sucuriscan-%%SUCURI.InvalidDomainVisibility%%">
17
  <p>Your domain <code>%%SUCURI.CleanDomain%%</code> does not seems to have a DNS <code>A</code> record so it will be considered as <em>invalid</em> by the API interface when you request the generation of a new key. Adding <code>www</code> at the beginning of the domain name may fix this issue. If you do not understand what is this then send an email to our support team requesting the key.</p>
@@ -20,18 +16,18 @@
20
  <div class="sucuriscan-%%SUCURI.APIKey.RecoverVisibility%%">
21
  <div class="sucuriscan-hstatus sucuriscan-hstatus-0">
22
  <div class="sucuriscan-monospace">API Key: %%SUCURI.APIKey%%</div>
23
- <form action="%%SUCURI.URL.Settings%%" method="post">
24
  <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
25
  <button type="submit" name="sucuriscan_recover_key" class="button button-primary">Recover Via E-mail</button>
26
  </form>
27
  </div>
28
 
29
- <p>If you don't have access to the e-mail address used to generate the API key, but have a copy of the key at hand you can <a target="_self" href="%%SUCURI.URL.Settings%%&recover">click this link</a> to activate the plugin manually. Be aware that if the key is invalid the plugin will delete it afterwards.</p>
30
  </div>
31
 
32
  <div class="sucuriscan-hstatus sucuriscan-hstatus-1 sucuriscan-%%SUCURI.APIKey.RemoveVisibility%%">
33
  <div class="sucuriscan-monospace">API Key: %%SUCURI.APIKey%%</div>
34
- <form action="%%SUCURI.URL.Settings%%" method="post">
35
  <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
36
  <button type="submit" name="sucuriscan_remove_api_key" class="button button-primary">Delete</button>
37
  </form>
7
  <h3 class="sucuriscan-title">API Key</h3>
8
 
9
  <div class="inside">
10
+ <p>An API key is required to prevent attackers from deleting audit logs that can help you investigate and recover after a hack, and allows the plugin to display statistics. By generating an API key, you agree that Sucuri will collect and store anonymous data about your website. We take your privacy seriously.</p>
 
 
 
 
11
 
12
  <div class="sucuriscan-inline-alert-error sucuriscan-%%SUCURI.InvalidDomainVisibility%%">
13
  <p>Your domain <code>%%SUCURI.CleanDomain%%</code> does not seems to have a DNS <code>A</code> record so it will be considered as <em>invalid</em> by the API interface when you request the generation of a new key. Adding <code>www</code> at the beginning of the domain name may fix this issue. If you do not understand what is this then send an email to our support team requesting the key.</p>
16
  <div class="sucuriscan-%%SUCURI.APIKey.RecoverVisibility%%">
17
  <div class="sucuriscan-hstatus sucuriscan-hstatus-0">
18
  <div class="sucuriscan-monospace">API Key: %%SUCURI.APIKey%%</div>
19
+ <form action="%%SUCURI.URL.Settings%%#general" method="post">
20
  <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
21
  <button type="submit" name="sucuriscan_recover_key" class="button button-primary">Recover Via E-mail</button>
22
  </form>
23
  </div>
24
 
25
+ <p>If you do not have access to the administrator email, you can reinstall the plugin. The API key is generated using an administrator email and the domain of the website.</p>
26
  </div>
27
 
28
  <div class="sucuriscan-hstatus sucuriscan-hstatus-1 sucuriscan-%%SUCURI.APIKey.RemoveVisibility%%">
29
  <div class="sucuriscan-monospace">API Key: %%SUCURI.APIKey%%</div>
30
+ <form action="%%SUCURI.URL.Settings%%#general" method="post">
31
  <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
32
  <button type="submit" name="sucuriscan_remove_api_key" class="button button-primary">Delete</button>
33
  </form>
readme.txt CHANGED
@@ -4,7 +4,7 @@ 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,11 +181,21 @@ No, it is not required. The Website Firewall runs in the cloud without the need
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
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.13
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.13 =
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.13 =
190
+ * Add new version of the GPL v2 license file
191
+ * Remove unused option to reduce number of failed logins
192
+ * Fix multiple typos in the code found after a diff parse
193
+ * Modify name of the base library file for consistency
194
+ * Modify wording of the API key panel in the settings page
195
+ * Add option to include the hostname in the alert subject
196
+ * Fix open_basedir restriction was not considered on scans
197
+ * Remove firewall API key deletion on re-authentication
198
+
199
  = 1.8.12 =
200
  * Fix invalid array when deselecting all security alerts
201
  * Add language files to the list of ignored changes
src/api.lib.php CHANGED
@@ -297,7 +297,6 @@ class SucuriScanAPI extends SucuriScanOption
297
 
298
  SucuriScanOption::setRevProxy('disable', true);
299
  SucuriScanOption::setAddrHeader('REMOTE_ADDR', true);
300
- SucuriScanOption::deleteOption(':cloudproxy_apikey');
301
 
302
  return SucuriScanInterface::error($msg);
303
  }
297
 
298
  SucuriScanOption::setRevProxy('disable', true);
299
  SucuriScanOption::setAddrHeader('REMOTE_ADDR', true);
 
300
 
301
  return SucuriScanInterface::error($msg);
302
  }
src/{sucuriscan.lib.php → base.lib.php} RENAMED
@@ -1,7 +1,7 @@
1
  <?php
2
 
3
  /**
4
- * Code related to the sucuriscan.lib.php interface.
5
  *
6
  * PHP version 5
7
  *
1
  <?php
2
 
3
  /**
4
+ * Code related to the base.lib.php interface.
5
  *
6
  * PHP version 5
7
  *
src/cache.lib.php CHANGED
@@ -80,8 +80,9 @@ class SucuriScanCache extends SucuriScan
80
  /**
81
  * Initializes the cache library.
82
  *
83
- * @param string $datastore Name of the storage file.
84
- * @param bool $auto_create Forces the creation of the storage file.
 
85
  */
86
  public function __construct($datastore = '', $auto_create = true)
87
  {
80
  /**
81
  * Initializes the cache library.
82
  *
83
+ * @param string $datastore Name of the storage file.
84
+ * @param bool $auto_create Forces the creation of the storage file.
85
+ * @return void
86
  */
87
  public function __construct($datastore = '', $auto_create = true)
88
  {
src/fsscanner.lib.php CHANGED
@@ -97,12 +97,12 @@ class SucuriScanFSScanner extends SucuriScan
97
  /**
98
  * Returns a list of ignored directories.
99
  *
100
- * The method returns an array with the following keys:
101
- *
102
- * - raw: Contains the raw data from the local cache.
103
- * - checksums: Contains the md5 of all the directories.
104
- * - directories: Contains a list of directories.
105
- * - ignored_at_list: Contains a list of timestamps.
106
  *
107
  * @return array List of ignored directories.
108
  */
97
  /**
98
  * Returns a list of ignored directories.
99
  *
100
+ * <ul>
101
+ * <li><b>raw:</b> Contains the raw data from the local cache.</li>
102
+ * <li><b>checksums:</b> Contains the md5 of all the directories.</li>
103
+ * <li><b>directories:</b> Contains a list of directories.</li>
104
+ * <li><b>ignored_at_list:</b> Contains a list of timestamps.</li>
105
+ * </ul>
106
  *
107
  * @return array List of ignored directories.
108
  */
src/globals.php CHANGED
@@ -62,7 +62,6 @@ if (defined('SUCURISCAN')) {
62
  * execute the bootstrap method of the plugin.
63
  */
64
  add_action('init', 'SucuriScanInterface::initialize', 1);
65
- add_action('init', 'SucuriScanBlockedUsers::blockUserLogin', 1);
66
  add_action('admin_enqueue_scripts', 'SucuriScanInterface::enqueueScripts', 1);
67
 
68
  if (SucuriScan::runAdminInit()) {
62
  * execute the bootstrap method of the plugin.
63
  */
64
  add_action('init', 'SucuriScanInterface::initialize', 1);
 
65
  add_action('admin_enqueue_scripts', 'SucuriScanInterface::enqueueScripts', 1);
66
 
67
  if (SucuriScan::runAdminInit()) {
src/hook.lib.php CHANGED
@@ -28,8 +28,8 @@ if (!defined('SUCURISCAN_INIT') || SUCURISCAN_INIT !== true) {
28
  * The term hooking covers a range of techniques used to alter or augment the
29
  * behavior of an operating system, of applications, or of other software
30
  * components by intercepting method calls or messages or events passed
31
- * between software components. Code that handles such intercepted function
32
- * methods, events or messages is called a "hook".
33
  *
34
  * Hooking is used for many purposes, including debugging and extending
35
  * functionality. Examples might include intercepting keyboard or mouse event
28
  * The term hooking covers a range of techniques used to alter or augment the
29
  * behavior of an operating system, of applications, or of other software
30
  * components by intercepting method calls or messages or events passed
31
+ * between software components. Code that handles such intercepted methods,
32
+ * events or messages is called a "hook".
33
  *
34
  * Hooking is used for many purposes, including debugging and extending
35
  * functionality. Examples might include intercepting keyboard or mouse event
src/interface.lib.php CHANGED
@@ -64,68 +64,74 @@ class SucuriScanInterface
64
  public static function enqueueScripts()
65
  {
66
  wp_register_style(
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
 
74
  wp_register_script(
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
 
82
  if (SucuriScanRequest::get('page', 'sucuriscan_firewall') !== false) {
83
  wp_register_style(
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
  }
91
  }
92
 
93
  /**
94
- * Remove the old Sucuri plugins considering that with the new version (after
95
- * 1.6.0) all the functionality of the others will be merged here, this will
96
- * remove duplicated functionality, duplicated bugs and/or duplicated
97
- * maintenance reports allowing us to focus in one unique project.
 
 
98
  *
99
  * @return void
100
  */
101
  public static function handleOldPlugins()
102
  {
103
- if (class_exists('SucuriScanFileInfo')) {
104
- $finfo = new SucuriScanFileInfo();
105
- $finfo->ignore_files = false;
106
- $finfo->ignore_directories = false;
107
- $finfo->skip_directories = false;
108
- $finfo->run_recursively = true;
109
-
110
- $plugins = array(
111
- 'c3VjdXJpLXdwLXBsdWdpbi9zdWN1cmkucGhw',
112
- 'c3VjdXJpLWNsb3VkcHJveHktd2FmL2Nsb3VkcHJveHkucGhw',
113
- 'ZGVzc2t5LXNlY3VyaXR5L2Rlc3NreS1zZWN1cml0eS5waHA=',
114
- );
115
-
116
- foreach ($plugins as $plugin) {
117
- $plugin = base64_decode($plugin);
118
- $plugin_directory = dirname(WP_PLUGIN_DIR . '/' . $plugin);
 
119
 
120
- if (file_exists($plugin_directory)) {
121
- if (is_plugin_active($plugin)) {
122
- // @codeCoverageIgnoreStart
123
- deactivate_plugins($plugin);
124
- // @codeCoverageIgnoreEnd
125
- }
126
 
127
- $finfo->removeDirectoryTree($plugin_directory);
 
 
 
 
128
  }
 
 
129
  }
130
  }
131
  }
@@ -258,7 +264,7 @@ class SucuriScanInterface
258
  {
259
  if (!function_exists('current_user_can') || !current_user_can('manage_options')) {
260
  SucuriScan::throwException('Access denied; cannot manage options');
261
- wp_die('Access denied by Sucuri Inc.');
262
  }
263
  }
264
 
@@ -279,17 +285,7 @@ class SucuriScanInterface
279
 
280
  if (!$nonce_value || !wp_verify_nonce($nonce_value, $nonce_name)) {
281
  SucuriScan::throwException('Nonce is invalid');
282
- self::error(
283
- 'WordPress CSRF verification failed. The submitted form is'
284
- . ' missing an important unique code that prevents automat'
285
- . 'ed unwated access, go back and try again. If you did no'
286
- . 't submit a form, this error message could be an indicat'
287
- . 'ion of an incompatibility between this plugin and anoth'
288
- . 'er add-on; one of them is inserting data into the globa'
289
- . 'l POST variable when the HTTP request is coming via GET'
290
- . '. Disable them one by one (while reloading this page) t'
291
- . 'o find the culprit.'
292
- );
293
  return false;
294
  }
295
  }
64
  public static function enqueueScripts()
65
  {
66
  wp_register_style(
67
+ 'sucuriscan',
68
  SUCURISCAN_URL . '/inc/css/styles.css',
69
  array(/* empty */),
70
  SucuriScan::fileVersion('inc/css/styles.css')
71
  );
72
+ wp_enqueue_style('sucuriscan');
73
 
74
  wp_register_script(
75
+ 'sucuriscan',
76
  SUCURISCAN_URL . '/inc/js/scripts.js',
77
  array(/* empty */),
78
  SucuriScan::fileVersion('inc/js/scripts.js')
79
  );
80
+ wp_enqueue_script('sucuriscan');
81
 
82
  if (SucuriScanRequest::get('page', 'sucuriscan_firewall') !== false) {
83
  wp_register_style(
84
+ 'sucuriscan2',
85
  SUCURISCAN_URL . '/inc/css/flags.min.css',
86
  array(/* empty */),
87
  SucuriScan::fileVersion('inc/css/flags.min.css')
88
  );
89
+ wp_enqueue_style('sucuriscan2');
90
  }
91
  }
92
 
93
  /**
94
+ * Remove the old Sucuri plugins.
95
+ *
96
+ * Considering that in the new version (after 1.6.0) all the functionality
97
+ * of the others will be merged here, this will remove duplicated code,
98
+ * duplicated bugs and/or duplicated maintenance reports allowing us to
99
+ * focus in one unique project.
100
  *
101
  * @return void
102
  */
103
  public static function handleOldPlugins()
104
  {
105
+ // @codeCoverageIgnoreStart
106
+ if (!class_exists('SucuriScanFileInfo')) {
107
+ return;
108
+ }
109
+ // @codeCoverageIgnoreEnd
110
+
111
+ $finfo = new SucuriScanFileInfo();
112
+ $finfo->ignore_files = false;
113
+ $finfo->ignore_directories = false;
114
+ $finfo->skip_directories = false;
115
+ $finfo->run_recursively = true;
116
+
117
+ $plugins = array(
118
+ 'c3VjdXJpLXdwLXBsdWdpbi9zdWN1cmkucGhw',
119
+ 'c3VjdXJpLWNsb3VkcHJveHktd2FmL2Nsb3VkcHJveHkucGhw',
120
+ 'ZGVzc2t5LXNlY3VyaXR5L2Rlc3NreS1zZWN1cml0eS5waHA=',
121
+ );
122
 
123
+ foreach ($plugins as $plugin) {
124
+ $plugin = base64_decode($plugin);
125
+ $plugin_directory = dirname(WP_PLUGIN_DIR . '/' . $plugin);
 
 
 
126
 
127
+ if (file_exists($plugin_directory)) {
128
+ if (is_plugin_active($plugin)) {
129
+ // @codeCoverageIgnoreStart
130
+ deactivate_plugins($plugin);
131
+ // @codeCoverageIgnoreEnd
132
  }
133
+
134
+ $finfo->removeDirectoryTree($plugin_directory);
135
  }
136
  }
137
  }
264
  {
265
  if (!function_exists('current_user_can') || !current_user_can('manage_options')) {
266
  SucuriScan::throwException('Access denied; cannot manage options');
267
+ wp_die('Access denied by ' . SUCURISCAN_PLUGIN_NAME);
268
  }
269
  }
270
 
285
 
286
  if (!$nonce_value || !wp_verify_nonce($nonce_value, $nonce_name)) {
287
  SucuriScan::throwException('Nonce is invalid');
288
+ self::error('WordPress CSRF verification failed. The submitted form is missing an important unique code that prevents the execution of automated malicious scanners. Go back and try again. If you did not submit a form, this error message could be an indication of an incompatibility between this plugin and another add-on; one of them is inserting data into the global POST variable when the HTTP request is coming via GET. Disable them one by one (while reloading this page) to find the culprit.');
 
 
 
 
 
 
 
 
 
 
289
  return false;
290
  }
291
  }
src/lastlogins-blocked.php DELETED
@@ -1,232 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Code related to the lastlogins-blocked.php interface.
5
- *
6
- * PHP version 5
7
- *
8
- * @category Library
9
- * @package Sucuri
10
- * @subpackage SucuriScanner
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
- * Allows the website owner to block usernames.
27
- *
28
- * An admin can select one or more usernames from the list of failed login and
29
- * block them so the next time someone tries to log into the website with that
30
- * username the operation will be stopped before the request hits the database.
31
- *
32
- * Notice that this feature does not allows the website owner to block requests
33
- * coming from a specific IP address. This is because the feature already exists
34
- * in the Firewall service and it also provides a better filtering mechanism for
35
- * any other suspicious login attempt. We will encourage people to leverage the
36
- * power of the Firewall.
37
- *
38
- * @category Library
39
- * @package Sucuri
40
- * @subpackage SucuriScanner
41
- * @author Daniel Cid <dcid@sucuri.net>
42
- * @copyright 2010-2017 Sucuri Inc.
43
- * @license https://www.gnu.org/licenses/gpl-2.0.txt GPL2
44
- * @link https://wordpress.org/plugins/sucuri-scanner
45
- */
46
- class SucuriScanBlockedUsers extends SucuriScanLastLogins
47
- {
48
- /**
49
- * Renders the page with a list of blocked usernames.
50
- *
51
- * @return string HTML code with a list of blocked usernames.
52
- */
53
- public static function page()
54
- {
55
- $output = array();
56
- $output['BlockedUsers.List'] = '';
57
- $output['BlockedUsers.NoItemsVisibility'] = 'visible';
58
-
59
- if (SucuriScanInterface::checkNonce()) {
60
- $unblockUsers = SucuriScanRequest::post(':unblock_user', '_array');
61
-
62
- if (is_array($unblockUsers) && !empty($unblockUsers)) {
63
- self::unblock($unblockUsers);
64
- SucuriScanInterface::info('Selected user accounts were unblocked');
65
- }
66
- }
67
-
68
- $cache = new SucuriScanCache('blockedusers', false);
69
- $blocked = $cache->getAll();
70
-
71
- if (is_array($blocked) && !empty($blocked)) {
72
- foreach ($blocked as $data) {
73
- $output['BlockedUsers.List'] .= SucuriScanTemplate::getSnippet(
74
- 'lastlogins-blockedusers',
75
- array(
76
- 'BlockedUsers.Username' => $data->username,
77
- 'BlockedUsers.BlockedAt' => self::datetime($data->blocked_at),
78
- 'BlockedUsers.FirstAttempt' => self::datetime($data->first_attempt),
79
- 'BlockedUsers.LastAttempt' => self::datetime($data->last_attempt),
80
- )
81
- );
82
- }
83
-
84
- $output['BlockedUsers.NoItemsVisibility'] = 'hidden';
85
- }
86
-
87
- return SucuriScanTemplate::getSection('lastlogins-blockedusers', $output);
88
- }
89
-
90
- /**
91
- * Blocks one or more usernames.
92
- *
93
- * @param array $users List of usernames.
94
- * @return void
95
- */
96
- public static function block($users = array())
97
- {
98
- if (is_array($users) && !empty($users)) {
99
- $logs = sucuriscan_get_all_failed_logins();
100
- $cache = new SucuriScanCache('blockedusers');
101
- $blocked = $cache->getAll();
102
-
103
- foreach ($users as $user) {
104
- if (array_key_exists($user, $blocked)) {
105
- continue;
106
- }
107
-
108
- $firstAttempt = self::firstAttempt($logs, $user);
109
- $lastAttempt = self::lastAttempt($logs, $user);
110
- $data = array(
111
- 'username' => $user,
112
- 'blocked_at' => time(),
113
- 'first_attempt' => $firstAttempt,
114
- 'last_attempt' => $lastAttempt,
115
- );
116
- $cache->add(md5($user), $data);
117
- }
118
- }
119
- }
120
-
121
- /**
122
- * Unblocks one or more usernames.
123
- *
124
- * @param array $users List of usernames.
125
- * @return void
126
- */
127
- public static function unblock($users = array())
128
- {
129
- if (is_array($users) && !empty($users)) {
130
- $cache = new SucuriScanCache('blockedusers');
131
- $blocked = $cache->getAll();
132
-
133
- foreach ($users as $user) {
134
- $cache_key = md5($user);
135
-
136
- if (array_key_exists($cache_key, $blocked)) {
137
- $cache->delete($cache_key);
138
- }
139
- }
140
- }
141
- }
142
-
143
- /**
144
- * Stops an user login attempt.
145
- *
146
- * This method will run right after the user submits the login form. We will
147
- * check to see if the username has been blocked by an admin and proceed
148
- * according to the expected behavior. Either we will stop the request right
149
- * here or let it propagate to the authentication checker.
150
- *
151
- * @return void
152
- */
153
- public static function blockUserLogin()
154
- {
155
- if (!class_exists('SucuriScanRequest') || !class_exists('SucuriScanCache')) {
156
- return;
157
- }
158
-
159
- $username = SucuriScanRequest::post('log');
160
- $password = SucuriScanRequest::post('pwd');
161
-
162
- if ($username === false || $password === false) {
163
- return;
164
- }
165
-
166
- $cache = new SucuriScanCache('blockedusers');
167
- $blocked = $cache->getAll();
168
- $cache_key = md5($username);
169
-
170
- if (is_array($blocked)
171
- && is_string($cache_key)
172
- && array_key_exists($cache_key, $blocked)
173
- ) {
174
- $blocked[$cache_key]->last_attempt = time();
175
- $cache->set($cache_key, $blocked[$cache_key]);
176
-
177
- if (!headers_sent()) {
178
- header('HTTP/1.1 403 Forbidden');
179
- }
180
-
181
- exit(0);
182
- }
183
- }
184
-
185
- /**
186
- * Finds the first login attempt of a specific username.
187
- *
188
- * @param array $logs List of failed login attempts.
189
- * @param string $user Username to be inspected.
190
- * @return int Timestamp of the first login attempt.
191
- */
192
- private static function firstAttempt($logs, $user)
193
- {
194
- $attempts = array();
195
-
196
- foreach ($logs['entries'] as $login) {
197
- if ($login['user_login'] === $user) {
198
- $attempts[] = $login['attempt_time'];
199
- }
200
- }
201
-
202
- if (empty($attempts)) {
203
- return -1;
204
- }
205
-
206
- return min($attempts);
207
- }
208
-
209
- /**
210
- * Finds the last login attempt of a specific username.
211
- *
212
- * @param array $logs List of failed login attempts.
213
- * @param string $user Username to be inspected.
214
- * @return int Timestamp of the last login attempt.
215
- */
216
- private static function lastAttempt($logs, $user)
217
- {
218
- $attempts = array();
219
-
220
- foreach ($logs['entries'] as $login) {
221
- if ($login['user_login'] === $user) {
222
- $attempts[] = $login['attempt_time'];
223
- }
224
- }
225
-
226
- if (empty($attempts)) {
227
- return -1;
228
- }
229
-
230
- return max($attempts);
231
- }
232
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lastlogins-failed.php CHANGED
@@ -39,15 +39,6 @@ function sucuriscan_failed_logins_panel()
39
  'FailedLogins.PaginationVisibility' => 'hidden',
40
  );
41
 
42
- if (SucuriScanInterface::checkNonce()) {
43
- $blockUsers = SucuriScanRequest::post(':block_user', '_array');
44
-
45
- if (is_array($blockUsers) && !empty($blockUsers)) {
46
- SucuriScanBlockedUsers::block($blockUsers);
47
- SucuriScanInterface::info('Selected user accounts were blocked');
48
- }
49
- }
50
-
51
  // Define variables for the pagination.
52
  $page_number = SucuriScanTemplate::pageNumber();
53
  $max_per_page = SUCURISCAN_MAX_PAGINATION_BUTTONS;
39
  'FailedLogins.PaginationVisibility' => 'hidden',
40
  );
41
 
 
 
 
 
 
 
 
 
 
42
  // Define variables for the pagination.
43
  $page_number = SucuriScanTemplate::pageNumber();
44
  $max_per_page = SUCURISCAN_MAX_PAGINATION_BUTTONS;
src/lastlogins.php CHANGED
@@ -240,7 +240,7 @@ function sucuriscan_lastlogins_datastore_is_readable()
240
  return false;
241
  }
242
 
243
- if (!function_exists('sucuri_set_lastlogin')) {
244
  /**
245
  * Add a new user session to the list of last user logins.
246
  *
@@ -398,7 +398,7 @@ function sucuriscan_get_logins($limit = 10, $offset = 0, $user_id = 0)
398
  return $last_logins;
399
  }
400
 
401
- if (!function_exists('sucuri_login_redirect')) {
402
  /**
403
  * Hook for the wp-login action to redirect the user to a specific URL after
404
  * his successfully login to the administrator interface.
@@ -427,7 +427,7 @@ if (!function_exists('sucuri_login_redirect')) {
427
  }
428
  }
429
 
430
- if (!function_exists('sucuri_get_user_lastlogin')) {
431
  /**
432
  * Display the last user login at the top of the admin interface.
433
  *
240
  return false;
241
  }
242
 
243
+ if (!function_exists('sucuriscan_set_lastlogin')) {
244
  /**
245
  * Add a new user session to the list of last user logins.
246
  *
398
  return $last_logins;
399
  }
400
 
401
+ if (!function_exists('sucuriscan_login_redirect')) {
402
  /**
403
  * Hook for the wp-login action to redirect the user to a specific URL after
404
  * his successfully login to the administrator interface.
427
  }
428
  }
429
 
430
+ if (!function_exists('sucuriscan_get_user_lastlogin')) {
431
  /**
432
  * Display the last user login at the top of the admin interface.
433
  *
src/mail.lib.php CHANGED
@@ -122,9 +122,16 @@ class SucuriScanMail extends SucuriScanOption
122
  {
123
  $subject = self::getOption(':email_subject');
124
  $subject = strip_tags((string) $subject);
 
 
125
  $subject = str_replace(':event', $event, $subject);
126
  $subject = str_replace(':domain', self::getDomain(), $subject);
127
- $subject = str_replace(':remoteaddr', self::getRemoteAddr(), $subject);
 
 
 
 
 
128
 
129
  /* include data from the user in session, if necessary */
130
  if (strpos($subject, ':username') !== false
122
  {
123
  $subject = self::getOption(':email_subject');
124
  $subject = strip_tags((string) $subject);
125
+ $ip = self::getRemoteAddr();
126
+
127
  $subject = str_replace(':event', $event, $subject);
128
  $subject = str_replace(':domain', self::getDomain(), $subject);
129
+ $subject = str_replace(':remoteaddr', $ip, $subject);
130
+
131
+ if (strpos($subject, ':hostname') !== false) {
132
+ /* expensive operation; reverse user ip address if requested */
133
+ $subject = str_replace(':hostname', gethostbyaddr($ip), $subject);
134
+ }
135
 
136
  /* include data from the user in session, if necessary */
137
  if (strpos($subject, ':username') !== false
src/option.lib.php CHANGED
@@ -114,7 +114,7 @@ class SucuriScanOption extends SucuriScanRequest
114
  'sucuriscan_use_wpmail' => 'enabled',
115
  );
116
 
117
- return (array) apply_filters('sucuriscan_option_defaults', $defaults);
118
  }
119
 
120
  /**
@@ -178,7 +178,7 @@ class SucuriScanOption extends SucuriScanRequest
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;
114
  'sucuriscan_use_wpmail' => 'enabled',
115
  );
116
 
117
+ return $defaults;
118
  }
119
 
120
  /**
178
  */
179
  public static function getAllOptions()
180
  {
181
+ $options = wp_cache_get('alloptions', SUCURISCAN);
182
 
183
  if ($options && is_array($options)) {
184
  return $options;
src/pagehandler.php CHANGED
@@ -101,7 +101,6 @@ function sucuriscan_lastlogins_page()
101
  'LastLogins.Admins' => sucuriscan_lastlogins_admins(),
102
  'LoggedInUsers' => sucuriscan_loggedin_users_panel(),
103
  'FailedLogins' => sucuriscan_failed_logins_panel(),
104
- 'BlockedUsers' => SucuriScanBlockedUsers::page(),
105
  );
106
 
107
  echo SucuriScanTemplate::getTemplate('lastlogins', $params);
@@ -127,9 +126,9 @@ function sucuriscan_settings_page()
127
  $params['Settings.General.DataStorage'] = sucuriscan_settings_general_datastorage($nonce);
128
  $params['Settings.General.SelfHosting'] = sucuriscan_settings_general_selfhosting($nonce);
129
  $params['Settings.General.ReverseProxy'] = sucuriscan_settings_general_reverseproxy($nonce);
130
- $params['Settings.General.IPDiscoverer'] = sucuriscan_settings_general_ipdiscoverer($nonce);
131
  $params['Settings.General.ImportExport'] = sucuriscan_settings_general_importexport($nonce);
132
  $params['Settings.General.Timezone'] = sucuriscan_settings_general_timezone($nonce);
 
133
 
134
  /* settings - scanner */
135
  $params['Settings.Scanner.Cronjobs'] = SucuriScanSettingsScanner::cronjobs($nonce);
@@ -159,12 +158,12 @@ function sucuriscan_settings_page()
159
 
160
  /* settings - alerts */
161
  $params['Settings.Alerts.Recipients'] = sucuriscan_settings_alerts_recipients($nonce);
162
- $params['Settings.Alerts.TrustedIPs'] = sucuriscan_settings_alerts_trustedips();
163
  $params['Settings.Alerts.Subject'] = sucuriscan_settings_alerts_subject($nonce);
164
  $params['Settings.Alerts.PerHour'] = sucuriscan_settings_alerts_perhour($nonce);
165
  $params['Settings.Alerts.BruteForce'] = sucuriscan_settings_alerts_bruteforce($nonce);
166
  $params['Settings.Alerts.Events'] = sucuriscan_settings_alerts_events($nonce);
167
  $params['Settings.Alerts.IgnorePosts'] = sucuriscan_settings_alerts_ignore_posts();
 
168
 
169
  /* settings - api service */
170
  $params['Settings.APIService.Status'] = sucuriscan_settings_apiservice_status($nonce);
@@ -192,6 +191,8 @@ function sucuriscan_ajax()
192
  SucuriScanAuditLogs::ajaxAuditLogs();
193
  SucuriScanAuditLogs::ajaxAuditLogsSendLogs();
194
  SucuriScanSiteCheck::ajaxMalwareScan();
 
 
195
  SucuriScanFirewall::auditlogsAjax();
196
  SucuriScanFirewall::ipAccessAjax();
197
  SucuriScanFirewall::blacklistAjax();
@@ -199,8 +200,6 @@ function sucuriscan_ajax()
199
  SucuriScanFirewall::getSettingsAjax();
200
  SucuriScanFirewall::clearCacheAjax();
201
  SucuriScanFirewall::clearAutoCacheAjax();
202
- SucuriScanIntegrity::ajaxIntegrity();
203
- SucuriScanIntegrity::ajaxIntegrityDiffUtility();
204
  SucuriScanSettingsPosthack::availableUpdatesAjax();
205
  SucuriScanSettingsPosthack::getPluginsAjax();
206
  SucuriScanSettingsPosthack::resetPasswordAjax();
101
  'LastLogins.Admins' => sucuriscan_lastlogins_admins(),
102
  'LoggedInUsers' => sucuriscan_loggedin_users_panel(),
103
  'FailedLogins' => sucuriscan_failed_logins_panel(),
 
104
  );
105
 
106
  echo SucuriScanTemplate::getTemplate('lastlogins', $params);
126
  $params['Settings.General.DataStorage'] = sucuriscan_settings_general_datastorage($nonce);
127
  $params['Settings.General.SelfHosting'] = sucuriscan_settings_general_selfhosting($nonce);
128
  $params['Settings.General.ReverseProxy'] = sucuriscan_settings_general_reverseproxy($nonce);
 
129
  $params['Settings.General.ImportExport'] = sucuriscan_settings_general_importexport($nonce);
130
  $params['Settings.General.Timezone'] = sucuriscan_settings_general_timezone($nonce);
131
+ $params['Settings.General.IPDiscoverer'] = sucuriscan_settings_general_ipdiscoverer($nonce);
132
 
133
  /* settings - scanner */
134
  $params['Settings.Scanner.Cronjobs'] = SucuriScanSettingsScanner::cronjobs($nonce);
158
 
159
  /* settings - alerts */
160
  $params['Settings.Alerts.Recipients'] = sucuriscan_settings_alerts_recipients($nonce);
 
161
  $params['Settings.Alerts.Subject'] = sucuriscan_settings_alerts_subject($nonce);
162
  $params['Settings.Alerts.PerHour'] = sucuriscan_settings_alerts_perhour($nonce);
163
  $params['Settings.Alerts.BruteForce'] = sucuriscan_settings_alerts_bruteforce($nonce);
164
  $params['Settings.Alerts.Events'] = sucuriscan_settings_alerts_events($nonce);
165
  $params['Settings.Alerts.IgnorePosts'] = sucuriscan_settings_alerts_ignore_posts();
166
+ $params['Settings.Alerts.TrustedIPs'] = sucuriscan_settings_alerts_trustedips();
167
 
168
  /* settings - api service */
169
  $params['Settings.APIService.Status'] = sucuriscan_settings_apiservice_status($nonce);
191
  SucuriScanAuditLogs::ajaxAuditLogs();
192
  SucuriScanAuditLogs::ajaxAuditLogsSendLogs();
193
  SucuriScanSiteCheck::ajaxMalwareScan();
194
+ SucuriScanIntegrity::ajaxIntegrity();
195
+ SucuriScanIntegrity::ajaxIntegrityDiffUtility();
196
  SucuriScanFirewall::auditlogsAjax();
197
  SucuriScanFirewall::ipAccessAjax();
198
  SucuriScanFirewall::blacklistAjax();
200
  SucuriScanFirewall::getSettingsAjax();
201
  SucuriScanFirewall::clearCacheAjax();
202
  SucuriScanFirewall::clearAutoCacheAjax();
 
 
203
  SucuriScanSettingsPosthack::availableUpdatesAjax();
204
  SucuriScanSettingsPosthack::getPluginsAjax();
205
  SucuriScanSettingsPosthack::resetPasswordAjax();
src/settings-alerts.php CHANGED
@@ -210,6 +210,7 @@ function sucuriscan_settings_alerts_subject($nonce)
210
  'Sucuri Alert, :domain, :event, :username',
211
  'Sucuri Alert, :domain, :event, :email',
212
  'Sucuri Alert, :event, :remoteaddr',
 
213
  'Sucuri Alert, :event',
214
  );
215
 
@@ -396,7 +397,7 @@ function sucuriscan_settings_alerts_events($nonce)
396
  $params['Alerts.NoAlertsVisibility'] = 'hidden';
397
 
398
  $notify_options = array(
399
- 'sucuriscan_notify_plugin_change' => 'setting:' . 'Receive email alerts for changes in the settings of the Sucuri plugin',
400
  'sucuriscan_prettify_mails' => 'setting:' . 'Receive email alerts in HTML <em>(there may be issues with some mail services)</em>',
401
  'sucuriscan_use_wpmail' => 'setting:' . 'Use WordPress functions to send mails <em>(uncheck to use native PHP functions)</em>',
402
  'sucuriscan_lastlogin_redirection' => 'setting:' . 'Allow redirection after login to report the last-login information',
210
  'Sucuri Alert, :domain, :event, :username',
211
  'Sucuri Alert, :domain, :event, :email',
212
  'Sucuri Alert, :event, :remoteaddr',
213
+ 'Sucuri Alert, :event, :hostname',
214
  'Sucuri Alert, :event',
215
  );
216
 
397
  $params['Alerts.NoAlertsVisibility'] = 'hidden';
398
 
399
  $notify_options = array(
400
+ 'sucuriscan_notify_plugin_change' => 'setting:' . 'Receive email alerts for changes in the settings of the plugin',
401
  'sucuriscan_prettify_mails' => 'setting:' . 'Receive email alerts in HTML <em>(there may be issues with some mail services)</em>',
402
  'sucuriscan_use_wpmail' => 'setting:' . 'Use WordPress functions to send mails <em>(uncheck to use native PHP functions)</em>',
403
  'sucuriscan_lastlogin_redirection' => 'setting:' . 'Allow redirection after login to report the last-login information',
src/settings-general.php CHANGED
@@ -158,7 +158,7 @@ function sucuriscan_settings_general_datastorage($nonce)
158
  '', /* <root> */
159
  'auditlogs',
160
  'auditqueue',
161
- 'blockedusers',
162
  'failedlogins',
163
  'hookdata',
164
  'ignorescanning',
158
  '', /* <root> */
159
  'auditlogs',
160
  'auditqueue',
161
+ 'blockedusers', /* TODO: deprecated on 1.8.12 */
162
  'failedlogins',
163
  'hookdata',
164
  'ignorescanning',
src/settings-integrity.php CHANGED
@@ -28,7 +28,7 @@ if (!defined('SUCURISCAN_INIT') || SUCURISCAN_INIT !== true) {
28
  * Generates the HTML code to display a list of options in the settings page to
29
  * allow the website owner to configure the functionality of the WordPress core
30
  * integrity scanner and the optional Unix diff utility. This also includes some
31
- * options to configure the website installation language and the false/positive
32
  * cache file.
33
  *
34
  * @category Library
28
  * Generates the HTML code to display a list of options in the settings page to
29
  * allow the website owner to configure the functionality of the WordPress core
30
  * integrity scanner and the optional Unix diff utility. This also includes some
31
+ * options to configure the website installation language and the false positive
32
  * cache file.
33
  *
34
  * @category Library
src/template.lib.php CHANGED
@@ -267,7 +267,7 @@ class SucuriScanTemplate extends SucuriScanRequest
267
 
268
  $output = ''; /* initialize response */
269
  $_page = self::get('page', '_page');
270
- $params['SucuriURL'] = SUCURISCAN_URL;
271
  $trailing = $_page ? 'admin.php?page=' . $_page : '';
272
  $params['CurrentURL'] = SucuriScan::adminURL($trailing);
273
 
267
 
268
  $output = ''; /* initialize response */
269
  $_page = self::get('page', '_page');
270
+ $params['PluginURL'] = SUCURISCAN_URL;
271
  $trailing = $_page ? 'admin.php?page=' . $_page : '';
272
  $params['CurrentURL'] = SucuriScan::adminURL($trailing);
273
 
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.12
10
  *
11
  * PHP version 5
12
  *
@@ -83,7 +83,12 @@ define('SUCURISCAN', 'sucuriscan');
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.
@@ -189,7 +194,7 @@ if (!array_key_exists('SERVER_NAME', $_SERVER)) {
189
  }
190
 
191
  /* Load all classes before anything else. */
192
- require_once 'src/sucuriscan.lib.php';
193
  require_once 'src/request.lib.php';
194
  require_once 'src/fileinfo.lib.php';
195
  require_once 'src/cache.lib.php';
@@ -216,7 +221,6 @@ require_once 'src/pagehandler.php';
216
  require_once 'src/lastlogins.php';
217
  require_once 'src/lastlogins-loggedin.php';
218
  require_once 'src/lastlogins-failed.php';
219
- require_once 'src/lastlogins-blocked.php';
220
 
221
  /* Load handlers for main pages (settings). */
222
  require_once 'src/settings.php';
6
  * Plugin URI: https://wordpress.sucuri.net/
7
  * Author URI: https://sucuri.net/
8
  * Author: Sucuri Inc.
9
+ * Version: 1.8.13
10
  *
11
  * PHP version 5
12
  *
83
  /**
84
  * Current version of the plugin's code.
85
  */
86
+ define('SUCURISCAN_VERSION', '1.8.13');
87
+
88
+ /**
89
+ * Defines the human readable name of the plugin.
90
+ */
91
+ define('SUCURISCAN_PLUGIN_NAME', 'Sucuri Security - Auditing, Malware Scanner and Hardening');
92
 
93
  /**
94
  * The name of the folder where the plugin's files will be located.
194
  }
195
 
196
  /* Load all classes before anything else. */
197
+ require_once 'src/base.lib.php';
198
  require_once 'src/request.lib.php';
199
  require_once 'src/fileinfo.lib.php';
200
  require_once 'src/cache.lib.php';
221
  require_once 'src/lastlogins.php';
222
  require_once 'src/lastlogins-loggedin.php';
223
  require_once 'src/lastlogins-failed.php';
 
224
 
225
  /* Load handlers for main pages (settings). */
226
  require_once 'src/settings.php';