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

Version Description

  • Added Hardening option to remove error log files
  • Bug fixes on some new registrations.
  • Changed format of the internal logs to json.
Download this release

Release Info

Developer dd@sucuri.net
Plugin Icon 128x128 Sucuri Security – Auditing, Malware Scanner and Security Hardening
Version 1.7.0
Comparing to
See all releases

Code changes from version 1.6.9 to 1.7.0

inc/tpl/notification-pretty.html.tpl CHANGED
@@ -1,15 +1,10 @@
1
- <!DOCTYPE html>
2
- <html>
3
- <head>
4
- <title>%%SUCURI.TemplateTitle%%</title>
5
- </head>
6
- <body>
7
<table class="sucuriscan-template" style="width:90%;background:#fff;font-family:Arial,Helvetica,sans-serif;border-spacing:0">
8
<thead sytle="border-bottom:1px solid #ccc">
9
<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">
10
<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)">
11
<a href="http://sucuri.net/" style="text-decoration:none;display:inline-block;margin:8px 0 5px 20px">
12
- <img src="http://sucuri.net/wp-content/themes/sucuri-two/images/main-logo.png" style="border:none" />
13
</a>
14
<span style="display:inline-block;line-height:46px;margin:0 20px 0 0;float:right;color:#ffffff">%%SUCURI.TemplateTitle%%</span>
15
</td>
@@ -34,5 +29,3 @@
34
</tr>
35
</tbody>
36
</table>
37
- </body>
38
- </html>
1
+
2
<table class="sucuriscan-template" style="width:90%;background:#fff;font-family:Arial,Helvetica,sans-serif;border-spacing:0">
3
<thead sytle="border-bottom:1px solid #ccc">
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="http://sucuri.net/" style="text-decoration:none;display:inline-block;margin:8px 0 5px 20px">
7
+ <img src="http://sucuri.net/wp-content/themes/sucuri-two/images/main-logo.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>
29
</tr>
30
</tbody>
31
</table>
inc/tpl/settings-general.html.tpl CHANGED
@@ -38,11 +38,11 @@
38
</tr>
39
40
<tr class="alternate">
41
- <td>API Key</td>
42
<td>
43
<span class="sucuriscan-monospace">%%SUCURI.APIKey%%</span>
44
</td>
45
- <td class="td-with-button">
46
<form action="%%SUCURI.URL.Settings%%" method="post" class="sucuriscan-%%SUCURI.APIKey.RecoverVisibility%%">
47
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
48
<button type="submit" name="sucuriscan_recover_key" class="button-primary">Recover</button>
@@ -63,7 +63,7 @@
63
64
<tr>
65
<td>Notify events to</td>
66
- <td><a href="mailto:%%SUCURI.NotifyTo%%">%%SUCURI.NotifyTo%%</a></td>
67
<td class="td-with-button">
68
<form action="%%SUCURI.URL.Settings%%" method="post">
69
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
@@ -164,6 +164,18 @@
164
</tr>
165
166
<tr>
167
<td>Last Scanning</td>
168
<td><span class="sucuriscan-monospace">%%SUCURI.ScanningRuntimeHuman%%</span></td>
169
<td class="td-with-button">
@@ -174,7 +186,7 @@
174
</td>
175
</tr>
176
177
- <tr class="alternate">
178
<td>Scanning frequency</td>
179
<td>%%SUCURI.ScanningFrequency%%</td>
180
<td class="td-with-button">
@@ -188,7 +200,7 @@
188
</td>
189
</tr>
190
191
- <tr class="sucuriscan-%%SUCURI.ScanningInterfaceVisibility%%">
192
<td>Scanning interface</td>
193
<td>%%SUCURI.ScanningInterface%%</td>
194
<td class="td-with-button">
38
</tr>
39
40
<tr class="alternate">
41
+ <td width="200">API Key</td>
42
<td>
43
<span class="sucuriscan-monospace">%%SUCURI.APIKey%%</span>
44
</td>
45
+ <td width="350" class="td-with-button">
46
<form action="%%SUCURI.URL.Settings%%" method="post" class="sucuriscan-%%SUCURI.APIKey.RecoverVisibility%%">
47
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
48
<button type="submit" name="sucuriscan_recover_key" class="button-primary">Recover</button>
63
64
<tr>
65
<td>Notify events to</td>
66
+ <td>%%SUCURI.NotifyTo%%</td>
67
<td class="td-with-button">
68
<form action="%%SUCURI.URL.Settings%%" method="post">
69
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
164
</tr>
165
166
<tr>
167
+ <td>Scan error log files</td>
168
+ <td>%%SUCURI.ScanErrorlogsStatus%%</td>
169
+ <td class="td-with-button">
170
+ <form action="%%SUCURI.URL.Settings%%" method="post">
171
+ <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
172
+ <input type="hidden" name="sucuriscan_scan_errorlogs" value="%%SUCURI.ScanErrorlogsSwitchValue%%" />
173
+ <button type="submit" class="button-primary %%SUCURI.ScanErrorlogsSwitchCssClass%%">%%SUCURI.ScanErrorlogsSwitchText%%</button>
174
+ </form>
175
+ </td>
176
+ </tr>
177
+
178
+ <tr class="alternate">
179
<td>Last Scanning</td>
180
<td><span class="sucuriscan-monospace">%%SUCURI.ScanningRuntimeHuman%%</span></td>
181
<td class="td-with-button">
186
</td>
187
</tr>
188
189
+ <tr>
190
<td>Scanning frequency</td>
191
<td>%%SUCURI.ScanningFrequency%%</td>
192
<td class="td-with-button">
200
</td>
201
</tr>
202
203
+ <tr class="alternate sucuriscan-%%SUCURI.ScanningInterfaceVisibility%%">
204
<td>Scanning interface</td>
205
<td>%%SUCURI.ScanningInterface%%</td>
206
<td class="td-with-button">
inc/tpl/settings-notifications.html.tpl CHANGED
@@ -1,10 +1,37 @@
1
2
<form action="%%SUCURI.URL.Settings%%#settings-notifications" method="post">
3
<table class="wp-list-table widefat sucuriscan-table sucuriscan-settings-notifications">
4
<thead>
5
<tr>
6
<th colspan="3" class="thead-with-button">
7
- <span>Email Alerts Settings</span>
8
<div class="thead-topright-action">
9
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
10
<button type="submit" name="sucuriscan_save_notification_settings" class="button-primary">Save</button>
1
2
+ <div id="poststuff">
3
+ <div class="postbox sucuriscan-border sucuriscan-table-description">
4
+ <h3>Notification Settings</h3>
5
+
6
+ <div class="inside">
7
+ <p>
8
+ Check the boxes bellow to receive alerts via email of the events explained in
9
+ the table, by the default the notifications will be sent to the address
10
+ configured during the installation of your site, you can change this in the
11
+ <em>General Settings</em> panel. You can specify multiple recipients separating
12
+ each address with a comma.
13
+ </p>
14
+
15
+ <div class="sucuriscan-inline-alert-warning sucuriscan-%%SUCURI.PrettifyMailsWarningVisibility%%">
16
+ <p>
17
+ Some emails sent by this plugin will be rejected outright by some popular email
18
+ services. To fix this you will need to use a third-party email service, or use a
19
+ plugin to force the site to use SMTP <em>(Simple Mail Transfer Protocol)</em>
20
+ for sending emails, and then configure your SMTP server to properly handle
21
+ messages. You can also <strong>disable HTML alerts</strong> to get notifications
22
+ in <em>text/plain</em> format.
23
+ </p>
24
+ </div>
25
+ </div>
26
+ </div>
27
+ </div>
28
+
29
<form action="%%SUCURI.URL.Settings%%#settings-notifications" method="post">
30
<table class="wp-list-table widefat sucuriscan-table sucuriscan-settings-notifications">
31
<thead>
32
<tr>
33
<th colspan="3" class="thead-with-button">
34
+ <span>Notification Settings</span>
35
<div class="thead-topright-action">
36
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
37
<button type="submit" name="sucuriscan_save_notification_settings" class="button-primary">Save</button>
readme.txt CHANGED
@@ -1,71 +1,233 @@
1
=== Sucuri Security - Auditing, Malware Scanner and Hardening ===
2
Contributors: dd@sucuri.net
3
Donate Link: http://sitecheck.sucuri.net
4
- Tags: malware, security, firewall, scan, spam, virus, sucuri, protection
5
Requires at least:3.2
6
- Stable tag:1.6.9
7
Tested up to: 4.0
8
9
- The Sucuri WordPress Security plugin provides the website owner the best Activity Auditing, SiteCheck Remote Malware Scanning, Effective Security Hardening and Post-Hack features.
10
11
== Description ==
12
13
- The Sucuri Security - Auditing, SiteCheck Malware Scanner and Hardening is a security plugin enables you to scan your WordPress site using Sucuri SiteCheck for security and malware issues, and also verifies the security integrity of your core files right in your dashboard. It includes audit trails and post-hack security ions to help you reset passwords and secret keys in case it has been already hacked, or infected with malware.
14
15
- You can also run the checks for malware, blacklisting, and overall security status by scanning for free at <a href="http://sitecheck.sucuri.net">SiteCheck.Sucuri.net</a>.
16
17
- Sucuri SiteCheck detects various types of malware, SPAM injections, website errors, disabled sites, database connection issues and code anomalies that require special attention to include:
18
19
- * Obfuscated JavaScript injections
20
- * Cross Site Scripting (XSS)
21
- * Website Defacements
22
- * Hidden & Malicious iFrames
23
- * PHP Mailers
24
- * Phishing Attempts
25
- * Malicious Redirects
26
- * Anomalies
27
- * Drive-by-Downloads
28
- * IP Cloaking
29
- * Social Engineering Attacks
30
31
32
- There are a number of blacklisting authorities that monitor for malware, SPAM, and phishing attempts. Sucuri SiteCheck leverages the APIs for these authorities to check your website blacklisting status:
33
34
- * Sucuri
35
- * Google Safe Browsing
36
- * Norton
37
- * AVG
38
- * Phish Tank (Phishing Specifically)
39
- * ESET
40
- * McAfee SiteAdvisor
41
- * Yandex
42
43
- We augment the SiteCheck Malware Scanner with various. 1-click hardening options. Some of these options do not provide a high level of security, but collectively these options do lower your risk floor:
44
45
- * Verify WordPress Version
46
- * Protect Uploads Directory
47
- * Restrict wp-content Access
48
- * Restrict wp-includes Access
49
- * Verify PHP Version
50
- * Disable the theme and plugin editors
51
52
- On the newest versions of the plugin we also added an option to verify all WordPress core files for changes,
53
- which can be useful to detect hidden backdoors.
54
55
- Note that if your site is compromised and you need urgent help, you can leverage the
56
- Sucuri plans here: http://sucuri.net (even if our free options are not finding
57
- the compromise on your site).
58
59
60
== Installation ==
61
62
- 1. Download the plugin.
63
- 1. Go to the WordPress Plugin menu and activate it.
64
- 1. That's it!
65
66
67
== Changelog ==
68
69
= 1.6.9 =
70
* Multiple bug fixes (as reported on the support forums).
71
* Added heartbeat for the file scans.
@@ -129,7 +291,8 @@ the compromise on your site).
129
= 1.5.4 = Bug fixes.
130
131
= 1.5.2 =
132
- * Adding additional information about .htaccess hacks and the server environment.
133
134
= 1.5.0 =
135
* Fixing last login and giving better warns on permission errors.
@@ -151,7 +314,8 @@ the compromise on your site).
151
* Fixing some issues on the last login and allowing the option to disable it.
152
153
= 1.4.4 =
154
- * Small bug fixes + forcing a re-scan on every scan attempt (not using the cache anymore).
155
156
= 1.4.3 =
157
* Fixing a few PHP warnings.
@@ -210,6 +374,7 @@ the compromise on your site).
210
= 1.1.1 =
211
* First public release.
212
213
== Credits ==
214
215
* <a href="http://sucuri.net">Sucuri Security</a>
1
=== Sucuri Security - Auditing, Malware Scanner and Hardening ===
2
Contributors: dd@sucuri.net
3
Donate Link: http://sitecheck.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,
5
Requires at least:3.2
6
+ Stable tag:1.7.0
7
Tested up to: 4.0
8
9
+ The Sucuri WordPress Security plugin is the best security toolset for security integrity monitoring, activity monitoring and malware detection. It’s a complementary toolset to your existing security posture.
10
+
11
12
== Description ==
13
14
15
+ Sucuri Inc is a globally recognized authority in all matters related to
16
+ website security, with specialization in WordPress Security.
17
+
18
+ The Sucuri Security WordPress Security plugin is free to all WordPress users.
19
+ It is a security suite meant to complement your existing security posture. It
20
+ offers it’s users four key security features for their website, each designed
21
+ to have a positive affect on their security posture:
22
+
23
+ <ol>
24
+ <li>Security Activity Auditing</li>
25
+ <li>File Integrity Monitoring</li>
26
+ <li>Remote Malware Scanning</li>
27
+ <li>Blacklist Monitoring</li>
28
+ <li>Effective Security Hardening</li>
29
+ <li>Post-Hack Security Actions</li>
30
+ <li>Security Notifications</li>
31
+ <li>Website Firewall (add on)</li>
32
+ </ol>
33
+
34
+
35
+ = Security Activity Monitoring =
36
+
37
+ This is perhaps the most underutilized security function. It’s the act of
38
+ monitoring all security related events within your WordPress install. The
39
+ challenge is, what makes up a security event. In the eyes of Sucuri, any
40
+ change that occurs within the application could be categorized as a security
41
+ event, as such we try to record it.
42
+
43
+ This is important because it allows you, the website owner, the ability keep a
44
+ good eye on the various changes occurring within your environment. Who is
45
+ logging in? What changes are being made?
46
+
47
+ This feature is logging all activity to the Sucuri cloud, for safe keeping.
48
+ This ensures that an attacker is not able to wipe your forensic data and
49
+ prevent further security analysis after a compromise. If an attacker is able
50
+ to bypass your security controls, your security logs will be kept safe within
51
+ the Sucuri Security Operations Center (SOC).
52
+
53
+ This feature is particularly important to website / system administrators and
54
+ security experts looking to understand what is going on with their website and
55
+ when it’s happening.
56
+
57
+
58
+ = Security File Integrity Monitoring =
59
+
60
+ Security File Integrity Monitoring has been fundamental to the world of
61
+ security. It’s the act of comparing a known good with the current state. If
62
+ the current state differs from the known good, you know you have a problem.
63
+ This is the basis of a lot of host Intrusion detection systems. It’s what we
64
+ have built into the plugin.
65
+
66
+ It will create a <strong>known good</strong> the minute the plugin is
67
+ installed. This will be of all the directories at the root of the install,
68
+ this includes plugins, themes and core files.
69
+
70
+
71
+ = Remote Security Malware Scanning =
72
+
73
+ This feature is powered by our very powerful scanning engine, found on our
74
+ free security scanner - <a href="http://sitecheck.sucuri.net">SiteCheck. It’s
75
+ important to take some time to <a
76
+ href="http://blog.sucuri.net/2012/10/ask-sucuri-how-does-sitecheck-work.html">understand
77
+ how this scanner works</a>.
78
+
79
+ There are limitations with the way this scanner works, you can find more info
80
+ on that in the FAQ section.
81
+
82
+
83
+ = Security Blacklist Monitoring =
84
+
85
+ Another very interesting feature of the Security Malware Scanner is that it
86
+ incorporates various blacklist engines. Security blacklist engines include the
87
+ following:
88
+
89
+ <ol>
90
+ <li>Sucuri Labs</li>
91
+ <li>Google Safe Browsing</li>
92
+ <li>Norton</li>
93
+ <li>AVG</li>
94
+ <li>Phish Tank</li>
95
+ <li>ESET</li>
96
+ <li>McAfee Site Advisor</li>
97
+ <li>Yandex</li>
98
+ <li>SpamHaus</li>
99
+ <li>Bitdefender</li>
100
+ </ol>
101
+
102
+ These are some of the largest blacklisting entities, each having the ability
103
+ to directly impact your brands online reputation. By synchronize with their
104
+ environments we’re able to tell you, upon scan, whether any of them are
105
+ negatively flagging your website with a security related issue.
106
+
107
+ If they do, then via our Website AntiVirus product, we’re able to help you get
108
+ off the their security blacklist.
109
+
110
+
111
+ = Effective Security Hardening =
112
+
113
+ It’s easy to get lost in the world of security hardening. At Sucuri we clean
114
+ 100’s of websites a day, many with the various security hardening
115
+ configurations you find in various WordPress Security presentations. In this
116
+ section, we add those that we feel to be most effective, and that complement
117
+ the entire Sucuri suite of products.
118
119
120
+ = Post-Hack Security Actions =
121
122
+ Regardless of how good your security posture is, sometimes it’s impossible to
123
+ prevent the inevitable. When this happens, we’ve included a section to help
124
+ you walk through the three key things you should do after a compromise.
125
126
127
+ = Security Notifications =
128
129
+ Having all these security features would be useless unless you were notified
130
+ of the issues. This is why we have made available security notifications. We
131
+ have also expanded the various security related events, to provide website
132
+ owners more flexibility in regards to what they want to know about. As a
133
+ website owner, you have the option to make these security alerts as quiet or
134
+ noisy as you would like.
135
136
137
+ = Website Firewall (add on) =
138
139
+ This is by far the coolest security feature Sucuri has to offer everyday
140
+ website owners. It’s an enterprise grade Website Firewall known as CloudProxy.
141
+ It is designed to give you the best security protection any website can hope
142
+ for. It protects your website from a variety of website attacks and security
143
+ events to include:
144
+
145
+ <ol>
146
+ <li>Denial of Service (DOS / DDOS) Attacks</li>
147
+ <li>Exploitation of Software Vulnerabilities</li>
148
+ <li>Zero Day Disclosure Patches</li>
149
+ <li>Brute Force Attacks against your Access Control Mechanisms</li>
150
+ </ol>
151
+
152
+ This is coupled with a number of features like:
153
+
154
+ <ol>
155
+ <li>Performance Optimization</li>
156
+ <li>Advanced Access Control Features</li>
157
+ <li>Failover and Redundancy</li>
158
+ </ol>
159
+
160
+ This is not included as a <strong>Free</strong> option to the plugin, but is
161
+ integrated so that if purchased you are able to activate.
162
+
163
+ The Sucuri Security WordPress Security plugin is built by the team that is
164
+ known for their proactive approach to security. It is built using intelligence
165
+ gathered from thousands upon thousands of remediation cases, millions of
166
+ unique domain scans and 10’s of millions of website security attack blocks.
167
168
169
== Installation ==
170
171
+ The installation of the Sucuri Security WordPress Security plugin is very
172
+ simple and straight forward. <a
173
+ href="https://sucuri.net/wordpress-security-plugin-installation">A detailed
174
+ breakdown of the process is available, including images,</a> below however we
175
+ outline the bare minimum steps.
176
+
177
+ To install Sucuri Security and complement your Security posture:
178
+
179
+
180
+ 1. You will want to log into your WordPress administration panel - (e.g.,
181
+ http://yourdomain/wp-admin)
182
+
183
+ 2. Navigate to <strong>Plugins Menu</strong> option in your WordPress
184
+ administration panel
185
+
186
+ 3. Select <strong>Add New</strong>
187
+
188
+ 4. Type <strong>Sucuri</strong> in the <strong>Search</strong> box, and click
189
+ <strong>Search</strong> plugins.
190
+
191
+ 5. The first option you get should be for <strong>Sucuri Security - Auditing,
192
+ Malware Scanner and Hardening</strong>
193
+
194
+ 6. Select <strong>Install Now</strong>
195
+
196
+ 7. Now choose to <strong>Activate</strong> the plugin.
197
+
198
+ 8. Once activated, you will need to create an API key, this is done
199
+ automatically for you. Simply click on <strong>Generate API Key for
200
+ XXXXXX</strong>
201
+
202
+ 9. Once the API key is generated the page will redirect you to your dashboard
203
+ and the plugin is automatically configured for you.
204
+
205
+
206
+ To configure the Sucuri WordPress Security plugin for your specific Security
207
+ needs:
208
+
209
+ 1. Navigate to the <strong>Sucuri Security</strong> menu option (left hand
210
+ side).
211
+
212
+ 2. Hover or click on the name.
213
+
214
+ 3. Click on <strong>Settings</strong>
215
+
216
+ The <strong>Settings</strong> page allows you to configure the website to your
217
+ preferred security needs. Some of it’s features include changing the email
218
+ notifications, via the <strong>notification settings</strong> tab or disabling
219
+ integrity checking. We encourage you to visit this section and tune your
220
+ security needs as you see fit.
221
+
222
223
224
== Changelog ==
225
226
+ = 1.7.0 =
227
+ * Added Hardening option to remove error log files
228
+ * Bug fixes on some new registrations.
229
+ * Changed format of the internal logs to json.
230
+
231
= 1.6.9 =
232
* Multiple bug fixes (as reported on the support forums).
233
* Added heartbeat for the file scans.
291
= 1.5.4 = Bug fixes.
292
293
= 1.5.2 =
294
+ * Adding additional information about .htaccess hacks and the server
295
+ * environment.
296
297
= 1.5.0 =
298
* Fixing last login and giving better warns on permission errors.
314
* Fixing some issues on the last login and allowing the option to disable it.
315
316
= 1.4.4 =
317
+ * Small bug fixes + forcing a re-scan on every scan attempt (not using the
318
+ * cache anymore).
319
320
= 1.4.3 =
321
* Fixing a few PHP warnings.
374
= 1.1.1 =
375
* First public release.
376
377
+
378
== Credits ==
379
380
* <a href="http://sucuri.net">Sucuri Security</a>
sucuri.php CHANGED
@@ -4,7 +4,7 @@ Plugin Name: Sucuri Security - Auditing, Malware Scanner and Hardening
4
Plugin URI: http://wordpress.sucuri.net/
5
Description: The <a href="http://sucuri.net/" target="_blank">Sucuri</a> plugin provides the website owner the best Activity Auditing, SiteCheck Remote Malware Scanning, Effective Security Hardening and Post-Hack features. SiteCheck will check for malware, spam, blacklisting and other security issues like .htaccess redirects, hidden eval code, etc. The best thing about it is it's completely free.
6
Author: Sucuri, INC
7
- Version: 1.6.9
8
Author URI: http://sucuri.net
9
*/
10
@@ -66,7 +66,7 @@ define('SUCURISCAN', 'sucuriscan');
66
/**
67
* Current version of the plugin's code.
68
*/
69
- define('SUCURISCAN_VERSION', '1.6.9');
70
71
/**
72
* The name of the Sucuri plugin main file.
@@ -182,6 +182,8 @@ if( defined('SUCURISCAN') ){
182
*/
183
184
$sucuriscan_notify_options = array(
185
'sucuriscan_notify_user_registration' => 'Enable email alerts for new user registration',
186
'sucuriscan_notify_success_login' => 'Enable email alerts for successful logins',
187
'sucuriscan_notify_failed_login' => 'Enable email alerts for failed logins',
@@ -200,8 +202,6 @@ if( defined('SUCURISCAN') ){
200
'sucuriscan_notify_plugin_updated' => 'Enable email alerts when a plugin is updated',
201
'sucuriscan_notify_plugin_installed' => 'Enable email alerts when a plugin is installed',
202
'sucuriscan_notify_plugin_deleted' => 'Enable email alerts when a plugin is deleted',
203
- 'sucuriscan_prettify_mails' => 'Enable email alerts in HTML (uncheck to get email in text/plain)',
204
- 'sucuriscan_lastlogin_redirection' => 'Allow redirection after login to report the last-login information',
205
);
206
207
$sucuriscan_schedule_allowed = array(
@@ -371,6 +371,31 @@ class SucuriScan {
371
return $var_name;
372
}
373
374
/**
375
* Encodes the less-than, greater-than, ampersand, double quote and single quote
376
* characters, will never double encode entities.
@@ -537,8 +562,9 @@ class SucuriScan {
537
*
538
* @return string The real ip address of the user in the current request.
539
*/
540
- public static function get_remote_addr(){
541
$remote_addr = '';
542
543
if( self::is_behind_cloudproxy() ){
544
$alternatives = array(
@@ -548,8 +574,9 @@ class SucuriScan {
548
'HTTP_X_FORWARDED',
549
'HTTP_FORWARDED_FOR',
550
'HTTP_FORWARDED',
551
- 'REMOTE_ADDR',
552
'SUCURI_RIP',
553
);
554
555
foreach( $alternatives as $alternative ){
@@ -558,6 +585,7 @@ class SucuriScan {
558
&& self::is_valid_ip($_SERVER[$alternative])
559
){
560
$remote_addr = $_SERVER[$alternative];
561
break;
562
}
563
}
@@ -565,15 +593,29 @@ class SucuriScan {
565
566
elseif( isset($_SERVER['REMOTE_ADDR']) ) {
567
$remote_addr = $_SERVER['REMOTE_ADDR'];
568
}
569
570
if( $remote_addr == '::1' ){
571
$remote_addr = '127.0.0.1';
572
}
573
574
return $remote_addr;
575
}
576
577
/**
578
* Retrieve the user-agent from the current request.
579
*
@@ -617,9 +659,9 @@ class SucuriScan {
617
*/
618
public static function is_behind_cloudproxy( $verbose=FALSE ){
619
$http_host = self::get_domain();
620
- $host_by_name = @gethostbyname($http_host);
621
- $host_by_addr = @gethostbyaddr($host_by_name);
622
- $status = (bool) preg_match('/^cloudproxy[0-9]+\.sucuri\.net#x2F;', $host_by_addr);
623
624
if( $verbose ){
625
return array(
@@ -672,6 +714,17 @@ class SucuriScan {
672
return NULL;
673
}
674
675
/**
676
* Return the time passed since the specified timestamp until now.
677
*
@@ -683,7 +736,8 @@ class SucuriScan {
683
$timestamp = strtotime($timestamp);
684
}
685
686
- $diff = abs( time() - intval($timestamp) );
687
688
if( $diff == 0 ){ return 'just now'; }
689
@@ -724,6 +778,16 @@ class SucuriScan {
724
return $var_name;
725
}
726
727
/**
728
* Check whether an IP address has a valid format or not.
729
*
@@ -773,6 +837,43 @@ class SucuriScan {
773
}
774
}
775
776
/**
777
* Cut a long text to the length specified, and append suspensive points at the end.
778
*
@@ -856,7 +957,11 @@ class SucuriScanRequest extends SucuriScan {
856
public static function request( $list=array(), $key='', $pattern='' ){
857
$key = self::variable_prefix($key);
858
859
- if( is_array($list) && isset($list[$key]) ){
860
// Select the key from the list and escape its content.
861
$key_value = $list[$key];
862
@@ -868,7 +973,7 @@ class SucuriScanRequest extends SucuriScan {
868
case '_nonce': $pattern = '/^[a-z0-9]{10}#x2F;'; break;
869
case '_page': $pattern = '/^[a-z_]+#x2F;'; break;
870
case '_array': $pattern = '_array'; break;
871
- case '_yyyymmdd': $pattern = '/^[0-9]{4}\-[0-9]{2}\-[0-9]{2}#x2F;'; break;
872
default: $pattern = '/^'.$pattern.'#x2F;'; break;
873
}
874
}
@@ -1056,6 +1161,36 @@ class SucuriScanFileInfo extends SucuriScan {
1056
return FALSE;
1057
}
1058
1059
/**
1060
* Check whether the built-in class SplFileObject is available in the system
1061
* or not, it is required to have PHP >= 5.1.0. The SplFileObject class offers
@@ -1196,7 +1331,7 @@ class SucuriScanFileInfo extends SucuriScan {
1196
}
1197
1198
/**
1199
- * Skip some specific directories and filepaths from the filesystem scan.
1200
*
1201
* @param string $directory Directory where the scanner is located at the moment.
1202
* @param string $filename Name of the folder or file being scanned at the moment.
@@ -1803,13 +1938,14 @@ class SucuriScanOption extends SucuriScanRequest {
1803
'sucuriscan_scan_interface' => 'spl',
1804
'sucuriscan_scan_modfiles' => 'enabled',
1805
'sucuriscan_scan_checksums' => 'enabled',
1806
'sucuriscan_runtime' => 0,
1807
'sucuriscan_lastlogin_redirection' => 'enabled',
1808
'sucuriscan_notify_to' => '',
1809
'sucuriscan_emails_sent' => 0,
1810
'sucuriscan_emails_per_hour' => 5,
1811
'sucuriscan_last_email_at' => time(),
1812
- 'sucuriscan_prettify_mails' => 'enabled',
1813
'sucuriscan_notify_success_login' => 'enabled',
1814
'sucuriscan_notify_failed_login' => 'enabled',
1815
'sucuriscan_notify_post_publication' => 'enabled',
@@ -2117,7 +2253,23 @@ class SucuriScanOption extends SucuriScanRequest {
2117
*/
2118
public static function get_ignored_events(){
2119
$post_types = self::get_option(':ignored_events');
2120
- $post_types_arr = @unserialize($post_types);
2121
2122
if( !is_array($post_types_arr) ){
2123
$post_types_arr = array();
@@ -2143,7 +2295,7 @@ class SucuriScanOption extends SucuriScanRequest {
2143
// Check if the event is not ignored already.
2144
if( !array_key_exists($event_name, $ignored_events) ){
2145
$ignored_events[$event_name] = time();
2146
- $saved = self::update_option( ':ignored_events', serialize($ignored_events) );
2147
2148
return $saved;
2149
}
@@ -2164,7 +2316,7 @@ class SucuriScanOption extends SucuriScanRequest {
2164
2165
if( array_key_exists($event_name, $ignored_events) ){
2166
unset( $ignored_events[$event_name] );
2167
- $saved = self::update_option( ':ignored_events', serialize($ignored_events) );
2168
2169
return $saved;
2170
}
@@ -3060,9 +3212,11 @@ class SucuriScanHook extends SucuriScanEvent {
3060
elseif(
3061
current_user_can('update_themes')
3062
&& SucuriScanRequest::get('action', '(upgrade-theme|do-theme-upgrade)')
3063
- && SucuriScanRequest::post('checked')
3064
){
3065
- foreach( (array) $_POST['checked'] as $theme ){
3066
$theme_info = wp_get_theme($theme);
3067
$theme_name = ucwords($theme);
3068
$theme_version = '0.0';
@@ -3304,9 +3458,10 @@ class SucuriScanAPI extends SucuriScanOption {
3304
$response['body'] = @json_decode($response['body_raw']);
3305
}
3306
3307
- // Check if the response data is serialized, then unserialize it.
3308
- elseif( preg_match('/^(a|O):[0-9]+:.+/', $response['body']) ){
3309
- $response['body'] = @unserialize($response['body']);
3310
}
3311
3312
return $response;
@@ -3738,12 +3893,12 @@ class SucuriScanAPI extends SucuriScanOption {
3738
*/
3739
public static function get_sitecheck_results( $domain='' ){
3740
if( !empty($domain) ){
3741
- $url = 'http://sitecheck.sucuri.net/scanner/';
3742
$response = self::api_call( $url, 'GET', array(
3743
- 'serialized' => 1,
3744
- 'clear' => 1,
3745
- 'fromwp' => 2,
3746
'scan' => $domain,
3747
));
3748
3749
if( $response ){
@@ -3989,7 +4144,8 @@ class SucuriScanMail extends SucuriScanOption {
3989
* @return boolean Whether the emails will be in HTML or Plain/Text.
3990
*/
3991
public static function prettify_mails(){
3992
- return ( self::get_option(':prettify_mails') === 'enabled' );
3993
}
3994
3995
/**
@@ -4028,7 +4184,7 @@ class SucuriScanMail extends SucuriScanOption {
4028
4029
// Check whether the email notifications will be sent in HTML or Plain/Text.
4030
if( self::prettify_mails() ){
4031
- $headers = array( 'Content-type: text/html' );
4032
$data_set['PrettifyType'] = 'pretty';
4033
} else {
4034
$message = strip_tags($message);
@@ -4040,15 +4196,9 @@ class SucuriScanMail extends SucuriScanOption {
4040
if( $debug ){ die($message); }
4041
4042
$subject = sprintf( 'Sucuri Alert, %s, %s', $wp_domain, $subject );
4043
4044
- $email_sent = wp_mail(
4045
- $email,
4046
- $subject,
4047
- $message,
4048
- $headers
4049
- );
4050
-
4051
- if( $email_sent ){
4052
$emails_sent_num = (int) self::get_option(':emails_sent');
4053
self::update_option( ':emails_sent', $emails_sent_num + 1 );
4054
self::update_option( ':last_email_at', time() );
@@ -4071,7 +4221,6 @@ class SucuriScanMail extends SucuriScanOption {
4071
private static function prettify_mail( $subject='', $message='', $data_set=array() ){
4072
$prettify_type = isset($data_set['PrettifyType']) ? $data_set['PrettifyType'] : 'simple';
4073
$template_name = 'notification-' . $prettify_type;
4074
- $remote_addr = self::get_remote_addr();
4075
$user = wp_get_current_user();
4076
$display_name = '';
4077
@@ -4087,10 +4236,10 @@ class SucuriScanMail extends SucuriScanOption {
4087
'TemplateTitle' => 'Sucuri Alert',
4088
'Subject' => $subject,
4089
'Website' => self::get_option('siteurl'),
4090
- 'RemoteAddress' => $remote_addr,
4091
'Message' => $message,
4092
'User' => $display_name,
4093
- 'Time' => date('d/M/Y H:i:s'),
4094
);
4095
4096
foreach( $data_set as $var_key => $var_value ){
@@ -4936,8 +5085,12 @@ function sucuriscan_sitecheck_info( $res=array() ){
4936
$res = SucuriScanAPI::get_sitecheck_results($clean_domain);
4937
4938
// Check for error messages in the request's response.
4939
- if( is_string($res) && preg_match('/^ERROR:(.*)/', $res, $error_m) ){
4940
- SucuriScanInterface::error( 'The site <code>' . $clean_domain . '</code> was not scanned: ' . $error_m[1] );
4941
}
4942
4943
else {
@@ -5181,14 +5334,16 @@ function sucuriscan_sitecheck_info( $res=array() ){
5181
<?php endforeach; ?>
5182
<?php endif; ?>
5183
5184
- <?php foreach( $res['SYSTEM']['NOTICE'] as $j=>$notice ): ?>
5185
- <?php if( is_array($notice) ){ $notice = implode(', ', $notice); } ?>
5186
- <tr>
5187
- <td colspan="2">
5188
- <span class="sucuriscan-monospace"><?php _e($notice) ?></span>
5189
- </td>
5190
- </tr>
5191
- <?php endforeach; ?>
5192
5193
<!-- Possible recommendations or outdated software on the site. -->
5194
<?php if( $outdated_warns_exist || $recommendations_exist ): ?>
@@ -5844,6 +5999,7 @@ function sucuriscan_hardening_page(){
5844
sucuriscan_harden_adminuser();
5845
sucuriscan_harden_fileeditor();
5846
sucuriscan_harden_dbtables();
5847
?>
5848
</form>
5849
</div>
@@ -6226,11 +6382,7 @@ function sucuriscan_cloudproxy_enabled(){
6226
6227
$description = 'A WAF is a protection layer for your web site, blocking all sort of attacks (brute force attempts, '
6228
. 'DDoS, SQL injections, etc) and helping it remain malware and blacklist free. This test checks if your site is '
6229
- . 'using <a href="http://cloudproxy.sucuri.net/" target="_blank">Sucuri\'s CloudProxy WAF</a> to protect your site. '
6230
- . '</p><p>'
6231
- . '<b>HTTP Host:</b> <span class="sucuriscan-monospace">' . $proxy_info['http_host'] . '</span><br>'
6232
- . '<b>Host Name:</b> <span class="sucuriscan-monospace">' . $proxy_info['host_name'] . '</span><br>'
6233
- . '<b>Host Address:</b> <span class="sucuriscan-monospace">' . $proxy_info['host_addr'] . '</span>';
6234
6235
if( $proxy_info['status'] === FALSE ){
6236
$status = 0;
@@ -6461,6 +6613,76 @@ function sucuriscan_harden_dbtables(){
6461
);
6462
}
6463
6464
/**
6465
* WordPress core integrity page.
6466
*
@@ -7508,7 +7730,7 @@ if( !function_exists('sucuri_set_lastlogin') ){
7508
'user_lastlogin' => current_time('mysql')
7509
);
7510
7511
- @file_put_contents($datastore_filepath, serialize($login_info)."\n", FILE_APPEND);
7512
}
7513
}
7514
add_action('wp_login', 'sucuriscan_set_lastlogin', 50);
@@ -7563,8 +7785,14 @@ function sucuriscan_get_logins( $limit=10, $offset=0, $user_id=0 ){
7563
for( $i=$offset; $i<$total_lines; $i++ ){
7564
$line = $reversed_lines[$i] ? trim($reversed_lines[$i]) : '';
7565
7566
- if( preg_match('/^a:[0-9]+:.+/', $line) ){
7567
- $last_login = @unserialize($line);
7568
$last_login['user_lastlogin_timestamp'] = strtotime($last_login['user_lastlogin']);
7569
$last_login['user_registered_timestamp'] = 0;
7570
@@ -8205,6 +8433,14 @@ function sucuriscan_settings_form_submissions( $page_nonce=NULL ){
8205
SucuriScanInterface::info( 'Filesystem scanner for file integrity was <code>' . $action_d . '</code>' );
8206
}
8207
8208
// Modify the schedule of the filesystem scanner.
8209
if( $frequency = SucuriScanRequest::post(':scan_frequency') ){
8210
$allowed_frequency = array_keys($sucuriscan_schedule_allowed);
@@ -8247,8 +8483,10 @@ function sucuriscan_settings_form_submissions( $page_nonce=NULL ){
8247
8248
// Update the email where the event notifications will be sent.
8249
if( $new_email = SucuriScanRequest::post(':notify_to') ){
8250
- if( SucuriScan::is_valid_email($new_email) ){
8251
- SucuriScanOption::update_option( ':notify_to', $new_email );
8252
SucuriScanEvent::notify_event( 'plugin_change', 'Email address to get the event notifications was changed' );
8253
SucuriScanInterface::info( 'All the event notifications will be sent to the email specified.' );
8254
} else {
@@ -8439,6 +8677,7 @@ function sucuriscan_settings_general(){
8439
$scan_interface = SucuriScanOption::get_option(':scan_interface');
8440
$scan_modfiles = SucuriScanOption::get_option(':scan_modfiles');
8441
$scan_checksums = SucuriScanOption::get_option(':scan_checksums');
8442
$emails_per_hour = SucuriScanOption::get_option(':emails_per_hour');
8443
$maximum_failed_logins = SucuriScanOption::get_option(':maximum_failed_logins');
8444
$verify_ssl_cert = SucuriScanOption::get_option(':verify_ssl_cert');
@@ -8479,6 +8718,11 @@ function sucuriscan_settings_general(){
8479
'ScanChecksumsSwitchText' => 'Disable',
8480
'ScanChecksumsSwitchValue' => 'disable',
8481
'ScanChecksumsSwitchCssClass' => 'button-danger',
8482
/* Filsystem scanning frequency. */
8483
'ScanningFrequency' => 'Undefined',
8484
'ScanningFrequencyOptions' => $scan_freq_options,
@@ -8520,6 +8764,13 @@ function sucuriscan_settings_general(){
8520
$template_variables['ScanChecksumsSwitchCssClass'] = 'button-success';
8521
}
8522
8523
if( array_key_exists($scan_freq, $sucuriscan_schedule_allowed) ){
8524
$template_variables['ScanningFrequency'] = $sucuriscan_schedule_allowed[$scan_freq];
8525
}
@@ -8549,6 +8800,7 @@ function sucuriscan_settings_notifications(){
8549
8550
$template_variables = array(
8551
'NotificationOptions' => '',
8552
);
8553
8554
$counter = 0;
@@ -9018,7 +9270,12 @@ function sucuriscan_server_info(){
9018
'Plugin_version' => SUCURISCAN_VERSION,
9019
'Plugin_checksum' => SUCURISCAN_PLUGIN_CHECKSUM,
9020
'Last_filesystem_scan' => SucuriScanOption::get_filesystem_runtime(TRUE),
9021
- 'Using_CloudProxy' => 'No',
9022
'Operating_system' => sprintf('%s (%d Bit)', PHP_OS, PHP_INT_SIZE*8),
9023
'Server' => 'Unknown',
9024
'Developer_mode' => 'OFF',
@@ -9028,9 +9285,11 @@ function sucuriscan_server_info(){
9028
'PHP_version' => PHP_VERSION,
9029
);
9030
9031
- if( SucuriScan::is_behind_cloudproxy() ){
9032
- $info_vars['Using_CloudProxy'] = 'Yes';
9033
- }
9034
9035
if( defined('WP_DEBUG') && WP_DEBUG ){
9036
$info_vars['Developer_mode'] = 'ON';
@@ -9064,7 +9323,7 @@ function sucuriscan_server_info(){
9064
);
9065
9066
foreach( $field_names as $php_flag ){
9067
- $php_flag_value = ini_get($php_flag);
9068
$php_flag_name = 'PHP_' . $php_flag;
9069
$info_vars[$php_flag_name] = $php_flag_value ? $php_flag_value : 'N/A';
9070
}
4
Plugin URI: http://wordpress.sucuri.net/
5
Description: The <a href="http://sucuri.net/" target="_blank">Sucuri</a> plugin provides the website owner the best Activity Auditing, SiteCheck Remote Malware Scanning, Effective Security Hardening and Post-Hack features. SiteCheck will check for malware, spam, blacklisting and other security issues like .htaccess redirects, hidden eval code, etc. The best thing about it is it's completely free.
6
Author: Sucuri, INC
7
+ Version: 1.7.0
8
Author URI: http://sucuri.net
9
*/
10
66
/**
67
* Current version of the plugin's code.
68
*/
69
+ define('SUCURISCAN_VERSION', '1.7.0');
70
71
/**
72
* The name of the Sucuri plugin main file.
182
*/
183
184
$sucuriscan_notify_options = array(
185
+ // 'sucuriscan_prettify_mails' => 'Enable email alerts in HTML (uncheck to get email in text/plain)', // TODO: Investigate HTML mails issues.
186
+ 'sucuriscan_lastlogin_redirection' => 'Allow redirection after login to report the last-login information',
187
'sucuriscan_notify_user_registration' => 'Enable email alerts for new user registration',
188
'sucuriscan_notify_success_login' => 'Enable email alerts for successful logins',
189
'sucuriscan_notify_failed_login' => 'Enable email alerts for failed logins',
202
'sucuriscan_notify_plugin_updated' => 'Enable email alerts when a plugin is updated',
203
'sucuriscan_notify_plugin_installed' => 'Enable email alerts when a plugin is installed',
204
'sucuriscan_notify_plugin_deleted' => 'Enable email alerts when a plugin is deleted',
205
);
206
207
$sucuriscan_schedule_allowed = array(
371
return $var_name;
372
}
373
374
+ /**
375
+ * Gets the value of a configuration option.
376
+ *
377
+ * @param string $property The configuration option name.
378
+ * @return string Value of the configuration option as a string on success.
379
+ */
380
+ public static function ini_get( $property='' ){
381
+ $ini_value = ini_get($property);
382
+
383
+ if( empty($ini_value) || is_null($ini_value) ){
384
+ switch( $property ){
385
+ case 'error_log': $ini_value = 'error_log'; break;
386
+ case 'safe_mode': $ini_value = 'Off'; break;
387
+ case 'allow_url_fopen': $ini_value = '1'; break;
388
+ case 'memory_limit': $ini_value = '128M'; break;
389
+ case 'upload_max_filesize': $ini_value = '2M'; break;
390
+ case 'post_max_size': $ini_value = '8M'; break;
391
+ case 'max_execution_time': $ini_value = '30'; break;
392
+ case 'max_input_time': $ini_value = '-1'; break;
393
+ }
394
+ }
395
+
396
+ return $ini_value;
397
+ }
398
+
399
/**
400
* Encodes the less-than, greater-than, ampersand, double quote and single quote
401
* characters, will never double encode entities.
562
*
563
* @return string The real ip address of the user in the current request.
564
*/
565
+ public static function get_remote_addr( $return_header=FALSE ){
566
$remote_addr = '';
567
+ $header_used = 'unknown';
568
569
if( self::is_behind_cloudproxy() ){
570
$alternatives = array(
574
'HTTP_X_FORWARDED',
575
'HTTP_FORWARDED_FOR',
576
'HTTP_FORWARDED',
577
+ 'HTTP_X_SUCURI_CLIENTIP',
578
'SUCURI_RIP',
579
+ 'REMOTE_ADDR',
580
);
581
582
foreach( $alternatives as $alternative ){
585
&& self::is_valid_ip($_SERVER[$alternative])
586
){
587
$remote_addr = $_SERVER[$alternative];
588
+ $header_used = $alternative;
589
break;
590
}
591
}
593
594
elseif( isset($_SERVER['REMOTE_ADDR']) ) {
595
$remote_addr = $_SERVER['REMOTE_ADDR'];
596
+ $header_used = 'REMOTE_ADDR';
597
}
598
599
if( $remote_addr == '::1' ){
600
$remote_addr = '127.0.0.1';
601
}
602
603
+ if( $return_header ){
604
+ return $header_used;
605
+ }
606
+
607
return $remote_addr;
608
}
609
610
+ /**
611
+ * Return the HTTP header used to retrieve the remote address.
612
+ *
613
+ * @return string The HTTP header used to retrieve the remote address.
614
+ */
615
+ public static function get_remote_addr_header(){
616
+ return self::get_remote_addr(TRUE);
617
+ }
618
+
619
/**
620
* Retrieve the user-agent from the current request.
621
*
659
*/
660
public static function is_behind_cloudproxy( $verbose=FALSE ){
661
$http_host = self::get_domain();
662
+ $host_by_addr = @gethostbyname($http_host);
663
+ $host_by_name = @gethostbyaddr($host_by_addr);
664
+ $status = (bool) preg_match('/^cloudproxy[0-9]+\.sucuri\.net#x2F;', $host_by_name);
665
666
if( $verbose ){
667
return array(
714
return NULL;
715
}
716
717
+ /**
718
+ * Retrieve the date in localized format based on the current time.
719
+ *
720
+ * @return string The date, translated if locale specifies it.
721
+ */
722
+ public static function current_datetime(){
723
+ $local_time = current_time('timestamp');
724
+
725
+ return self::datetime($local_time);
726
+ }
727
+
728
/**
729
* Return the time passed since the specified timestamp until now.
730
*
736
$timestamp = strtotime($timestamp);
737
}
738
739
+ $local_time = current_time('timestamp');
740
+ $diff = abs( $local_time - intval($timestamp) );
741
742
if( $diff == 0 ){ return 'just now'; }
743
778
return $var_name;
779
}
780
781
+ /**
782
+ * Check whether a variable contains a serialized data or not.
783
+ *
784
+ * @param string $data The data that will be checked.
785
+ * @return boolean TRUE if the data was serialized, FALSE otherwise.
786
+ */
787
+ public static function is_serialized( $data='' ){
788
+ return ( is_string($data) && preg_match('/^(a|O):[0-9]+:.+/', $data) );
789
+ }
790
+
791
/**
792
* Check whether an IP address has a valid format or not.
793
*
837
}
838
}
839
840
+ /**
841
+ * Return a string with all the valid email addresses.
842
+ *
843
+ * @param string $email The string that will be validated as an email address.
844
+ * @param boolean $as_array TRUE to return the list of valid email addresses as an array.
845
+ * @return string All the valid email addresses separated by a comma.
846
+ */
847
+ public static function get_valid_email( $email='', $as_array=FALSE ){
848
+ $valid_emails = array();
849
+
850
+ if( strpos($email, ',') !== FALSE ){
851
+ $addresses = explode(',', $email);
852
+
853
+ foreach( $addresses as $address ){
854
+ $address = trim($address);
855
+
856
+ if( self::is_valid_email($address) ){
857
+ $valid_emails[] = $address;
858
+ }
859
+ }
860
+ }
861
+
862
+ elseif( self::is_valid_email($email) ){
863
+ $valid_emails[] = $email;
864
+ }
865
+
866
+ if( !empty($valid_emails) ){
867
+ if( $as_array === TRUE ){
868
+ return $valid_emails;
869
+ }
870
+
871
+ return self::implode(', ', $valid_emails);
872
+ }
873
+
874
+ return FALSE;
875
+ }
876
+
877
/**
878
* Cut a long text to the length specified, and append suspensive points at the end.
879
*
957
public static function request( $list=array(), $key='', $pattern='' ){
958
$key = self::variable_prefix($key);
959
960
+ if(
961
+ is_array($list)
962
+ && is_string($key)
963
+ && isset($list[$key])
964
+ ){
965
// Select the key from the list and escape its content.
966
$key_value = $list[$key];
967
973
case '_nonce': $pattern = '/^[a-z0-9]{10}#x2F;'; break;
974
case '_page': $pattern = '/^[a-z_]+#x2F;'; break;
975
case '_array': $pattern = '_array'; break;
976
+ case '_yyyymmdd': $pattern = '/^[0-9]{4}(\-[0-9]{2}){2}#x2F;'; break;
977
default: $pattern = '/^'.$pattern.'#x2F;'; break;
978
}
979
}
1161
return FALSE;
1162
}
1163
1164
+ /**
1165
+ * Find a file under the directory tree specified.
1166
+ *
1167
+ * @param string $filename Name of the folder or file being scanned at the moment.
1168
+ * @param string $directory Directory where the scanner is located at the moment.
1169
+ * @return array List of file paths where the file was found.
1170
+ */
1171
+ public function find_file( $filename='', $directory=NULL ){
1172
+ $file_paths = array();
1173
+
1174
+ if(
1175
+ is_null($directory)
1176
+ && defined('ABSPATH')
1177
+ ){
1178
+ $directory = ABSPATH;
1179
+ }
1180
+
1181
+ if( is_dir($directory) ){
1182
+ $dir_tree = $this->get_directory_tree( $directory );
1183
+
1184
+ foreach( $dir_tree as $filepath ){
1185
+ if( stripos($filepath, $filename) !== FALSE ){
1186
+ $file_paths[] = $filepath;
1187
+ }
1188
+ }
1189
+ }
1190
+
1191
+ return $file_paths;
1192
+ }
1193
+
1194
/**
1195
* Check whether the built-in class SplFileObject is available in the system
1196
* or not, it is required to have PHP >= 5.1.0. The SplFileObject class offers
1331
}
1332
1333
/**
1334
+ * Skip some specific directories and file paths from the filesystem scan.
1335
*
1336
* @param string $directory Directory where the scanner is located at the moment.
1337
* @param string $filename Name of the folder or file being scanned at the moment.
1938
'sucuriscan_scan_interface' => 'spl',
1939
'sucuriscan_scan_modfiles' => 'enabled',
1940
'sucuriscan_scan_checksums' => 'enabled',
1941
+ 'sucuriscan_scan_errorlogs' => 'enabled',
1942
'sucuriscan_runtime' => 0,
1943
'sucuriscan_lastlogin_redirection' => 'enabled',
1944
'sucuriscan_notify_to' => '',
1945
'sucuriscan_emails_sent' => 0,
1946
'sucuriscan_emails_per_hour' => 5,
1947
'sucuriscan_last_email_at' => time(),
1948
+ 'sucuriscan_prettify_mails' => 'disabled',
1949
'sucuriscan_notify_success_login' => 'enabled',
1950
'sucuriscan_notify_failed_login' => 'enabled',
1951
'sucuriscan_notify_post_publication' => 'enabled',
2253
*/
2254
public static function get_ignored_events(){
2255
$post_types = self::get_option(':ignored_events');
2256
+ $post_types_arr = FALSE;
2257
+
2258
+ // Encode (old) serialized data into JSON.
2259
+ if( self::is_serialized($post_types) ){
2260
+ var_dump($post_types);
2261
+ $post_types_arr = @unserialize($post_types);
2262
+ $post_types_fix = json_encode($post_types_arr);
2263
+ echo 'fixed';
2264
+ self::update_option( ':ignored_events', $post_types_fix );
2265
+
2266
+ return $post_types_arr;
2267
+ }
2268
+
2269
+ // Decode JSON-encoded data as an array.
2270
+ elseif( preg_match('/^\{.+\}#x2F;', $post_types) ){
2271
+ $post_types_arr = @json_decode( $post_types, TRUE );
2272
+ }
2273
2274
if( !is_array($post_types_arr) ){
2275
$post_types_arr = array();
2295
// Check if the event is not ignored already.
2296
if( !array_key_exists($event_name, $ignored_events) ){
2297
$ignored_events[$event_name] = time();
2298
+ $saved = self::update_option( ':ignored_events', json_encode($ignored_events) );
2299
2300
return $saved;
2301
}
2316
2317
if( array_key_exists($event_name, $ignored_events) ){
2318
unset( $ignored_events[$event_name] );
2319
+ $saved = self::update_option( ':ignored_events', json_encode($ignored_events) );
2320
2321
return $saved;
2322
}
3212
elseif(
3213
current_user_can('update_themes')
3214
&& SucuriScanRequest::get('action', '(upgrade-theme|do-theme-upgrade)')
3215
+ && SucuriScanRequest::post('checked', '_array')
3216
){
3217
+ $themes = SucuriScanRequest::post('checked', '_array');
3218
+
3219
+ foreach( $themes as $theme ){
3220
$theme_info = wp_get_theme($theme);
3221
$theme_name = ucwords($theme);
3222
$theme_version = '0.0';
3458
$response['body'] = @json_decode($response['body_raw']);
3459
}
3460
3461
+ // Check if the response data is serialized (which we will consider as insecure).
3462
+ elseif( self::is_serialized($response['body']) ){
3463
+ $response['body_raw'] = NULL;
3464
+ $response['body'] = 'ERROR:Serialized data is not supported.';
3465
}
3466
3467
return $response;
3893
*/
3894
public static function get_sitecheck_results( $domain='' ){
3895
if( !empty($domain) ){
3896
+ $url = 'http://sitecheck.sucuri.net/';
3897
$response = self::api_call( $url, 'GET', array(
3898
'scan' => $domain,
3899
+ 'fromwp' => 2,
3900
+ 'clear' => 1,
3901
+ 'json' => 1,
3902
));
3903
3904
if( $response ){
4144
* @return boolean Whether the emails will be in HTML or Plain/Text.
4145
*/
4146
public static function prettify_mails(){
4147
+ // return ( self::get_option(':prettify_mails') === 'enabled' ); // TODO: Investigate HTML mails issues.
4148
+ return FALSE;
4149
}
4150
4151
/**
4184
4185
// Check whether the email notifications will be sent in HTML or Plain/Text.
4186
if( self::prettify_mails() ){
4187
+ $headers = array( 'content-type: text/html' );
4188
$data_set['PrettifyType'] = 'pretty';
4189
} else {
4190
$message = strip_tags($message);
4196
if( $debug ){ die($message); }
4197
4198
$subject = sprintf( 'Sucuri Alert, %s, %s', $wp_domain, $subject );
4199
+ $mail_sent = wp_mail( $email, $subject, $message, $headers );
4200
4201
+ if( $mail_sent ){
4202
$emails_sent_num = (int) self::get_option(':emails_sent');
4203
self::update_option( ':emails_sent', $emails_sent_num + 1 );
4204
self::update_option( ':last_email_at', time() );
4221
private static function prettify_mail( $subject='', $message='', $data_set=array() ){
4222
$prettify_type = isset($data_set['PrettifyType']) ? $data_set['PrettifyType'] : 'simple';
4223
$template_name = 'notification-' . $prettify_type;
4224
$user = wp_get_current_user();
4225
$display_name = '';
4226
4236
'TemplateTitle' => 'Sucuri Alert',
4237
'Subject' => $subject,
4238
'Website' => self::get_option('siteurl'),
4239
+ 'RemoteAddress' => self::get_remote_addr(),
4240
'Message' => $message,
4241
'User' => $display_name,
4242
+ 'Time' => SucuriScan::current_datetime(),
4243
);
4244
4245
foreach( $data_set as $var_key => $var_value ){
5085
$res = SucuriScanAPI::get_sitecheck_results($clean_domain);
5086
5087
// Check for error messages in the request's response.
5088
+ if( is_string($res) ){
5089
+ if( preg_match('/^ERROR:(.*)/', $res, $error_m) ){
5090
+ SucuriScanInterface::error( 'The site <code>' . $clean_domain . '</code> was not scanned: ' . $error_m[1] );
5091
+ } else {
5092
+ SucuriScanInterface::error( 'The API returned data that can not be processed.' );
5093
+ }
5094
}
5095
5096
else {
5334
<?php endforeach; ?>
5335
<?php endif; ?>
5336
5337
+ <?php if( isset($res['SYSTEM']['NOTICE']) ): ?>
5338
+ <?php foreach( $res['SYSTEM']['NOTICE'] as $j=>$notice ): ?>
5339
+ <?php if( is_array($notice) ){ $notice = implode(', ', $notice); } ?>
5340
+ <tr>
5341
+ <td colspan="2">
5342
+ <span class="sucuriscan-monospace"><?php _e($notice) ?></span>
5343
+ </td>
5344
+ </tr>
5345
+ <?php endforeach; ?>
5346
+ <?php endif; ?>
5347
5348
<!-- Possible recommendations or outdated software on the site. -->
5349
<?php if( $outdated_warns_exist || $recommendations_exist ): ?>
5999
sucuriscan_harden_adminuser();
6000
sucuriscan_harden_fileeditor();
6001
sucuriscan_harden_dbtables();
6002
+ sucuriscan_harden_errorlog();
6003
?>
6004
</form>
6005
</div>
6382
6383
$description = 'A WAF is a protection layer for your web site, blocking all sort of attacks (brute force attempts, '
6384
. 'DDoS, SQL injections, etc) and helping it remain malware and blacklist free. This test checks if your site is '
6385
+ . 'using <a href="http://cloudproxy.sucuri.net/" target="_blank">Sucuri\'s CloudProxy WAF</a> to protect your site.';
6386
6387
if( $proxy_info['status'] === FALSE ){
6388
$status = 0;
6613
);
6614
}
6615
6616
+ /**
6617
+ * Check whether an error_log file exists in the project.
6618
+ *
6619
+ * @return void
6620
+ */
6621
+ function sucuriscan_harden_errorlog(){
6622
+ $hardened = 1;
6623
+ $log_filename = SucuriScan::ini_get('error_log');
6624
+ $scan_errorlogs = SucuriScanOption::get_option(':scan_errorlogs');
6625
+
6626
+ $description = 'PHP uses files named as <code>' . $log_filename . '</code> to log errors found in '
6627
+ . 'the code, these files may leak sensitive information of your project allowing an attacker '
6628
+ . 'to find vulnerabilities in the code. You must use these files to fix any bug while using '
6629
+ . 'a development environment, and remove them in production mode.';
6630
+
6631
+ // Search error log files in the project.
6632
+ if( $scan_errorlogs != 'disabled' ){
6633
+ $sucuri_fileinfo = new SucuriScanFileInfo();
6634
+ $sucuri_fileinfo->ignore_files = FALSE;
6635
+ $sucuri_fileinfo->ignore_directories = FALSE;
6636
+ $error_logs = $sucuri_fileinfo->find_file('error_log');
6637
+ $total_log_files = count($error_logs);
6638
+ } else {
6639
+ $error_logs = array();
6640
+ $total_log_files = 0;
6641
+ $description .= '<div class="sucuriscan-inline-alert-error"><p>The filesystem scan for error '
6642
+ . 'log files is disabled, so even if there are logs in your project they will be not '
6643
+ . 'shown here. You can enable the scanner again from the plugin <em>Settings</em> '
6644
+ . 'page.</p></div>';
6645
+ }
6646
+
6647
+ // Remove every error log file found in the filesystem scan.
6648
+ if( SucuriScanRequest::post(':run_hardening') ){
6649
+ if( SucuriScanRequest::post(':harden_errorlog') ){
6650
+ $removed_logs = 0;
6651
+
6652
+ foreach( $error_logs as $i => $error_log_path ){
6653
+ if( unlink($error_log_path) ){
6654
+ unset($error_logs[$i]);
6655
+ $removed_logs += 1;
6656
+ }
6657
+ }
6658
+
6659
+ SucuriScanInterface::info( 'Error log files removed <code>' . $removed_logs . ' out of ' . $total_log_files . '</code>' );
6660
+ }
6661
+ }
6662
+
6663
+ // List the error log files in a HTML table.
6664
+ if( !empty($error_logs) ){
6665
+ $hardened = 0;
6666
+ $description .= '</p><ul class="sucuriscan-list-as-table">';
6667
+
6668
+ foreach( $error_logs as $error_log_path ){
6669
+ $description .= '<li>' . $error_log_path . '</li>';
6670
+ }
6671
+
6672
+ $description .= '</ul><p>';
6673
+ }
6674
+
6675
+ sucuriscan_harden_status(
6676
+ 'Error logs',
6677
+ $hardened,
6678
+ ( $hardened == 0 ? 'sucuriscan_harden_errorlog' : NULL ),
6679
+ 'There are no error log files in your project.',
6680
+ 'There are ' . $total_log_files . ' error log files in your project.',
6681
+ $description,
6682
+ NULL
6683
+ );
6684
+ }
6685
+
6686
/**
6687
* WordPress core integrity page.
6688
*
7730
'user_lastlogin' => current_time('mysql')
7731
);
7732
7733
+ @file_put_contents($datastore_filepath, json_encode($login_info)."\n", FILE_APPEND);
7734
}
7735
}
7736
add_action('wp_login', 'sucuriscan_set_lastlogin', 50);
7785
for( $i=$offset; $i<$total_lines; $i++ ){
7786
$line = $reversed_lines[$i] ? trim($reversed_lines[$i]) : '';
7787
7788
+ // Check if the data is serialized (which we will consider as insecure).
7789
+ if( SucuriScan::is_serialized($line) ){
7790
+ $last_login = @unserialize($line); // TODO: Remove after version 1.7.5
7791
+ } else {
7792
+ $last_login = @json_decode($line, TRUE);
7793
+ }
7794
+
7795
+ if( $last_login ){
7796
$last_login['user_lastlogin_timestamp'] = strtotime($last_login['user_lastlogin']);
7797
$last_login['user_registered_timestamp'] = 0;
7798
8433
SucuriScanInterface::info( 'Filesystem scanner for file integrity was <code>' . $action_d . '</code>' );
8434
}
8435
8436
+ // Enable or disable the filesystem scanner for error logs.
8437
+ if( $scan_errorlogs = SucuriScanRequest::post(':scan_errorlogs', '(en|dis)able') ){
8438
+ $action_d = $scan_errorlogs . 'd';
8439
+ SucuriScanOption::update_option(':scan_errorlogs', $action_d);
8440
+ SucuriScanEvent::notify_event( 'plugin_change', 'Filesystem scanner for error logs was: ' . $action_d );
8441
+ SucuriScanInterface::info( 'Filesystem scanner for error logs was <code>' . $action_d . '</code>' );
8442
+ }
8443
+
8444
// Modify the schedule of the filesystem scanner.
8445
if( $frequency = SucuriScanRequest::post(':scan_frequency') ){
8446
$allowed_frequency = array_keys($sucuriscan_schedule_allowed);
8483
8484
// Update the email where the event notifications will be sent.
8485
if( $new_email = SucuriScanRequest::post(':notify_to') ){
8486
+ $valid_email = SucuriScan::get_valid_email($new_email);
8487
+
8488
+ if( $valid_email ){
8489
+ SucuriScanOption::update_option( ':notify_to', $valid_email );
8490
SucuriScanEvent::notify_event( 'plugin_change', 'Email address to get the event notifications was changed' );
8491
SucuriScanInterface::info( 'All the event notifications will be sent to the email specified.' );
8492
} else {
8677
$scan_interface = SucuriScanOption::get_option(':scan_interface');
8678
$scan_modfiles = SucuriScanOption::get_option(':scan_modfiles');
8679
$scan_checksums = SucuriScanOption::get_option(':scan_checksums');
8680
+ $scan_errorlogs = SucuriScanOption::get_option(':scan_errorlogs');
8681
$emails_per_hour = SucuriScanOption::get_option(':emails_per_hour');
8682
$maximum_failed_logins = SucuriScanOption::get_option(':maximum_failed_logins');
8683
$verify_ssl_cert = SucuriScanOption::get_option(':verify_ssl_cert');
8718
'ScanChecksumsSwitchText' => 'Disable',
8719
'ScanChecksumsSwitchValue' => 'disable',
8720
'ScanChecksumsSwitchCssClass' => 'button-danger',
8721
+ /* Scan error logs. */
8722
+ 'ScanErrorlogsStatus' => 'Enabled',
8723
+ 'ScanErrorlogsSwitchText' => 'Disable',
8724
+ 'ScanErrorlogsSwitchValue' => 'disable',
8725
+ 'ScanErrorlogsSwitchCssClass' => 'button-danger',
8726
/* Filsystem scanning frequency. */
8727
'ScanningFrequency' => 'Undefined',
8728
'ScanningFrequencyOptions' => $scan_freq_options,
8764
$template_variables['ScanChecksumsSwitchCssClass'] = 'button-success';
8765
}
8766
8767
+ if( $scan_errorlogs == 'disabled' ){
8768
+ $template_variables['ScanErrorlogsStatus'] = 'Disabled';
8769
+ $template_variables['ScanErrorlogsSwitchText'] = 'Enable';
8770
+ $template_variables['ScanErrorlogsSwitchValue'] = 'enable';
8771
+ $template_variables['ScanErrorlogsSwitchCssClass'] = 'button-success';
8772
+ }
8773
+
8774
if( array_key_exists($scan_freq, $sucuriscan_schedule_allowed) ){
8775
$template_variables['ScanningFrequency'] = $sucuriscan_schedule_allowed[$scan_freq];
8776
}
8800
8801
$template_variables = array(
8802
'NotificationOptions' => '',
8803
+ 'PrettifyMailsWarningVisibility' => SucuriScanTemplate::visibility( SucuriScanMail::prettify_mails() ),
8804
);
8805
8806
$counter = 0;
9270
'Plugin_version' => SUCURISCAN_VERSION,
9271
'Plugin_checksum' => SUCURISCAN_PLUGIN_CHECKSUM,
9272
'Last_filesystem_scan' => SucuriScanOption::get_filesystem_runtime(TRUE),
9273
+ 'Using_CloudProxy' => 'Unknown',
9274
+ 'HTTP_Host' => 'Unknown',
9275
+ 'Host_Name' => 'Unknown',
9276
+ 'Host_Address' => 'Unknown',
9277
+ 'Remote_Address' => SucuriScan::get_remote_addr(),
9278
+ 'Remote_Address_Header' => SucuriScan::get_remote_addr_header(),
9279
'Operating_system' => sprintf('%s (%d Bit)', PHP_OS, PHP_INT_SIZE*8),
9280
'Server' => 'Unknown',
9281
'Developer_mode' => 'OFF',
9285
'PHP_version' => PHP_VERSION,
9286
);
9287
9288
+ $proxy_info = SucuriScan::is_behind_cloudproxy(TRUE);
9289
+ $info_vars['HTTP_Host'] = $proxy_info['http_host'];
9290
+ $info_vars['Host_Name'] = $proxy_info['host_name'];
9291
+ $info_vars['Host_Address'] = $proxy_info['host_addr'];
9292
+ $info_vars['Using_CloudProxy'] = $proxy_info['status'] ? 'Yes' : 'No';
9293
9294
if( defined('WP_DEBUG') && WP_DEBUG ){
9295
$info_vars['Developer_mode'] = 'ON';
9323
);
9324
9325
foreach( $field_names as $php_flag ){
9326
+ $php_flag_value = SucuriScan::ini_get($php_flag);
9327
$php_flag_name = 'PHP_' . $php_flag;
9328
$info_vars[$php_flag_name] = $php_flag_value ? $php_flag_value : 'N/A';
9329
}