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

Version Description

  • Fixed remote scanning that was not loading automatically on some installs.
Download this release

Release Info

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

Code changes from version 1.7.0 to 1.7.1

inc/css/sucuriscan-default-css.css CHANGED
@@ -103,11 +103,12 @@
103
/* WordPress Alerts */
104
div.sucuriscan-alert{position:relative;margin:0 0 20px 0}
105
div.sucuriscan-alert > a.close{position:absolute;top:10px;right:10px;font-size:18px;font-weight:bold;text-decoration:none}
106
- .sucuriscan-inline-alert, .sucuriscan-inline-alert-updated, .sucuriscan-inline-alert-error, .sucuriscan-inline-alert-warning{background:#fff;box-shadow:0 1px 1px 0 rgba(0,0,0,.1);padding:0;border-left:4px solid #ddd}
107
- .sucuriscan-inline-alert > p, .sucuriscan-inline-alert-updated > p, .sucuriscan-inline-alert-error > p, .sucuriscan-inline-alert-warning > p{margin:0;padding:8px 12px;border:1px solid #ddd;border-left:0}
108
.sucuriscan-inline-alert-updated{border-left-color:#7ad03a}
109
.sucuriscan-inline-alert-warning{border-left-color:#ffba00}
110
.sucuriscan-inline-alert-error{border-left-color:#dd3d36}
111
/* Tabulation Panels */
112
.sucuriscan-tabs{}
113
.sucuriscan-tabs > ul{margin:0}
@@ -222,6 +223,7 @@ div.sucuriscan-alert > a.close{position:absolute;top:10px;right:10px;font-size:1
222
.sucuriscan-maincontent .sucuriscan-settings form{display:inline-block}
223
.sucuriscan-maincontent .sucuriscan-settings select, .sucuriscan-maincontent .sucuriscan-settings .input-text{width:220px}
224
.sucuriscan-maincontent .sucuriscan-settings-notifications{margin-top:0}
225
.sucuriscan-maincontent .sucuriscan-settings-heartbeat{}
226
.sucuriscan-maincontent .sucuriscan-wpcron-list{margin-top:0}
227
/* Responsive Styles */
@@ -247,7 +249,6 @@ div.sucuriscan-alert > a.close{position:absolute;top:10px;right:10px;font-size:1
247
.sucuriscan-maincontent #poststuff{min-width:initial;padding-top:0}
248
.sucuriscan-maincontent .widefat tbody th.check-column{padding:6px 0 3px 0}
249
.sucuriscan-maincontent .hardening-box .primary-secondary{margin:0 0 0 10px}
250
- .sucuri-inline-error{font-weight:bold;color:red}
251
.sucuriscan-maincontent .alternate{background:#f5f5f5}
252
.sucuriscan-maincontent hr{border:none;border-top:1px solid #999}
253
.sucuriscan-maincontent table td > table{background:#fff}
103
/* WordPress Alerts */
104
div.sucuriscan-alert{position:relative;margin:0 0 20px 0}
105
div.sucuriscan-alert > a.close{position:absolute;top:10px;right:10px;font-size:18px;font-weight:bold;text-decoration:none}
106
+ .sucuriscan-inline-alert, .sucuriscan-inline-alert-updated, .sucuriscan-inline-alert-error, .sucuriscan-inline-alert-warning, .sucuriscan-inline-alert-info{background:#fff;box-shadow:0 1px 1px 0 rgba(0,0,0,.1);padding:0;border-left:4px solid #ddd}
107
+ .sucuriscan-inline-alert > p, .sucuriscan-inline-alert-updated > p, .sucuriscan-inline-alert-error > p, .sucuriscan-inline-alert-warning > p, .sucuriscan-inline-alert-info > p{margin:0;padding:8px 12px;border:1px solid #ddd;border-left:0}
108
.sucuriscan-inline-alert-updated{border-left-color:#7ad03a}
109
.sucuriscan-inline-alert-warning{border-left-color:#ffba00}
110
.sucuriscan-inline-alert-error{border-left-color:#dd3d36}
111
+ .sucuriscan-inline-alert-info{border-left-color:#2ea2cc}
112
/* Tabulation Panels */
113
.sucuriscan-tabs{}
114
.sucuriscan-tabs > ul{margin:0}
223
.sucuriscan-maincontent .sucuriscan-settings form{display:inline-block}
224
.sucuriscan-maincontent .sucuriscan-settings select, .sucuriscan-maincontent .sucuriscan-settings .input-text{width:220px}
225
.sucuriscan-maincontent .sucuriscan-settings-notifications{margin-top:0}
226
+ .sucuriscan-maincontent .sucuriscan-settings-ignorescanning{margin-top:0}
227
.sucuriscan-maincontent .sucuriscan-settings-heartbeat{}
228
.sucuriscan-maincontent .sucuriscan-wpcron-list{margin-top:0}
229
/* Responsive Styles */
249
.sucuriscan-maincontent #poststuff{min-width:initial;padding-top:0}
250
.sucuriscan-maincontent .widefat tbody th.check-column{padding:6px 0 3px 0}
251
.sucuriscan-maincontent .hardening-box .primary-secondary{margin:0 0 0 10px}
252
.sucuriscan-maincontent .alternate{background:#f5f5f5}
253
.sucuriscan-maincontent hr{border:none;border-top:1px solid #999}
254
.sucuriscan-maincontent table td > table{background:#fff}
inc/tpl/posthack-resetpassword.html.tpl CHANGED
@@ -15,7 +15,7 @@
15
<div class="sucuriscan-inline-alert-warning">
16
<p>
17
If you choose to change the password of your own user, then your current session
18
- will expire inmediately. You will need to log into the admin panel with the new
19
password that will be sent to your email. If you are unsure of this, do not
20
select your account from the list.
21
</p>
15
<div class="sucuriscan-inline-alert-warning">
16
<p>
17
If you choose to change the password of your own user, then your current session
18
+ will expire immediately. You will need to log into the admin panel with the new
19
password that will be sent to your email. If you are unsure of this, do not
20
select your account from the list.
21
</p>
inc/tpl/settings-general.html.tpl CHANGED
@@ -127,92 +127,5 @@
127
</td>
128
</tr>
129
130
- <tr class="alternate">
131
- <td>Filesystem scanner</td>
132
- <td>%%SUCURI.FsScannerStatus%%</td>
133
- <td class="td-with-button">
134
- <form action="%%SUCURI.URL.Settings%%" method="post">
135
- <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
136
- <input type="hidden" name="sucuriscan_fs_scanner" value="%%SUCURI.FsScannerSwitchValue%%" />
137
- <button type="submit" class="button-primary %%SUCURI.FsScannerSwitchCssClass%%">%%SUCURI.FsScannerSwitchText%%</button>
138
- </form>
139
- </td>
140
- </tr>
141
-
142
- <tr>
143
- <td>Scan modified files</td>
144
- <td>%%SUCURI.ScanModfilesStatus%%</td>
145
- <td class="td-with-button">
146
- <form action="%%SUCURI.URL.Settings%%" method="post">
147
- <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
148
- <input type="hidden" name="sucuriscan_scan_modfiles" value="%%SUCURI.ScanModfilesSwitchValue%%" />
149
- <button type="submit" class="button-primary %%SUCURI.ScanModfilesSwitchCssClass%%">%%SUCURI.ScanModfilesSwitchText%%</button>
150
- </form>
151
- </td>
152
- </tr>
153
-
154
- <tr class="alternate">
155
- <td>Integrity checking</td>
156
- <td>%%SUCURI.ScanChecksumsStatus%%</td>
157
- <td class="td-with-button">
158
- <form action="%%SUCURI.URL.Settings%%" method="post">
159
- <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
160
- <input type="hidden" name="sucuriscan_scan_checksums" value="%%SUCURI.ScanChecksumsSwitchValue%%" />
161
- <button type="submit" class="button-primary %%SUCURI.ScanChecksumsSwitchCssClass%%">%%SUCURI.ScanChecksumsSwitchText%%</button>
162
- </form>
163
- </td>
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">
182
- <form action="%%SUCURI.URL.Home%%" method="post">
183
- <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
184
- <button type="submit" name="sucuriscan_force_scan" class="button-primary">Force Scan</button>
185
- </form>
186
- </td>
187
- </tr>
188
-
189
- <tr>
190
- <td>Scanning frequency</td>
191
- <td>%%SUCURI.ScanningFrequency%%</td>
192
- <td class="td-with-button">
193
- <form action="%%SUCURI.URL.Settings%%" method="post">
194
- <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
195
- <select name="sucuriscan_scan_frequency">
196
- %%SUCURI.ScanningFrequencyOptions%%
197
- </select>
198
- <button type="submit" class="button-primary">Change</button>
199
- </form>
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">
207
- <form action="%%SUCURI.URL.Settings%%" method="post">
208
- <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
209
- <select name="sucuriscan_scan_interface">
210
- %%SUCURI.ScanningInterfaceOptions%%
211
- </select>
212
- <button type="submit" class="button-primary">Change</button>
213
- </form>
214
- </td>
215
- </tr>
216
-
217
</tbody>
218
</table>
127
</td>
128
</tr>
129
130
</tbody>
131
</table>
inc/tpl/settings-ignorescanning.html.tpl ADDED
@@ -0,0 +1,62 @@
1
+
2
+ <div id="poststuff">
3
+ <div class="postbox sucuriscan-border sucuriscan-table-description">
4
+ <h3>Ignore Scanning</h3>
5
+
6
+ <div class="inside">
7
+ <p>
8
+ If your project has too many directories and/or files it may cause the file
9
+ system scanners to fail, you may want to increase the maximum execution time of
10
+ the PHP scripts and the memory limit to allow the functions executed during the
11
+ file system scans to finish successfully. If you do not want or do not have
12
+ sufficient privileges to increase these values then you may want to skip some
13
+ directories, this will force the plugin to ignore the files inside these
14
+ folders.
15
+ </p>
16
+ </div>
17
+ </div>
18
+ </div>
19
+
20
+ <form action="%%SUCURI.URL.Settings%%#settings-ignorescanning" method="post">
21
+ <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
22
+
23
+ <table class="wp-list-table widefat sucuriscan-table sucuriscan-settings-ignorescanning">
24
+ <thead>
25
+ <th class="manage-column column-cb check-column">
26
+ <label class="screen-reader-text" for="cb-select-all-1">Select All</label>
27
+ <input id="cb-select-all-1" type="checkbox">
28
+ </th>
29
+ <th class="manage-column" width="80">Ignored</th>
30
+ <th class="manage-column">Directory</th>
31
+ <th class="manage-column" width="180">Ignored At</th>
32
+ </thead>
33
+
34
+ <tbody>
35
+ %%SUCURI.IgnoreScanning.ResourceList%%
36
+ </tbody>
37
+
38
+ <tfoot>
39
+ <tr>
40
+ <td colspan="4">
41
+ <p>
42
+ Selecting one or more directories from the list will force the plugin to ignore
43
+ the monitoring of the sub-folders and files inside these directories during the
44
+ execution of any of the file system scanners. This will applies to all the
45
+ scanners <em>(general scanner, modified files, integrity checks, error
46
+ logs)</em>.
47
+ </p>
48
+
49
+ <label>
50
+ <select name="sucuriscan_ignorescanning_action">
51
+ <option value="">Choose action</option>
52
+ <option value="ignore">Ignore items</option>
53
+ <option value="unignore">Un-ignore items</option>
54
+ </select>
55
+ </label>
56
+
57
+ <button type="submit" class="button button-primary">Send action</button>
58
+ </td>
59
+ </tr>
60
+ </tfoot>
61
+ </table>
62
+ </form>
inc/tpl/settings-ignorescanning.snippet.tpl ADDED
@@ -0,0 +1,9 @@
1
+
2
+ <tr class="%%SUCURI.IgnoreScanning.CssClass%%">
3
+ <td class="check-column">
4
+ <input type="checkbox" name="sucuriscan_ignorescanning_dirs[]" value="%%SUCURI.IgnoreScanning.DirectoryPath%%" />
5
+ </td>
6
+ <td><span class="sucuriscan-label-%%SUCURI.IgnoreScanning.IgnoredCssClass%%">%%SUCURI.IgnoreScanning.IgnoredAtText%%</span></td>
7
+ <td><span class="sucuriscan-monospace sucuriscan-wraptext">%%SUCURI.IgnoreScanning.DirectoryPath%%</span></td>
8
+ <td>%%SUCURI.IgnoreScanning.IgnoredAt%%</td>
9
+ </tr>
inc/tpl/settings-scanner.html.tpl ADDED
@@ -0,0 +1,128 @@
1
+
2
+ <div id="poststuff">
3
+ <div class="postbox sucuriscan-border sucuriscan-table-description">
4
+ <h3>Scanner Settings</h3>
5
+
6
+ <div class="inside">
7
+ <p>
8
+ There are multiple scanners implemented in the code of the plugin, all of them
9
+ are enabled by default and you can deactivate them separately without affect the
10
+ others. You may want to disable a scanner because your site has too many
11
+ directories and/or files to scan, or because the maximum quantity of memory
12
+ allowed for your project is not enough to execute one these functions. You can
13
+ enable and disable any of the scanners anything you want.
14
+ </p>
15
+
16
+ <div class="sucuriscan-inline-alert-info">
17
+ <p>
18
+ The <em>Scanning Interface</em> is the method that will be used internally to
19
+ retrieve the diretories and files inside the project when the file system
20
+ scanners are executed. In the best case <strong>SPL</strong> will be enough
21
+ <em>(and it is the default option)</em>, but with older versions of PHP you may
22
+ need to choose a different method like <strong>OpenDir</strong> or
23
+ <strong>Glob</strong> which provide the same results.
24
+ </p>
25
+ </div>
26
+ </div>
27
+ </div>
28
+ </div>
29
+
30
+ <table class="wp-list-table widefat sucuriscan-table sucuriscan-settings sucuriscan-settings-scanner">
31
+ <thead>
32
+ <tr>
33
+ <th>Option</th>
34
+ <th>Value</th>
35
+ <th>&nbsp;</th>
36
+ </tr>
37
+ </thead>
38
+
39
+ <tbody>
40
+ <tr class="alternate">
41
+ <td>Filesystem scanner</td>
42
+ <td>%%SUCURI.FsScannerStatus%%</td>
43
+ <td class="td-with-button">
44
+ <form action="%%SUCURI.URL.Settings%%#settings-scanner" method="post">
45
+ <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
46
+ <input type="hidden" name="sucuriscan_fs_scanner" value="%%SUCURI.FsScannerSwitchValue%%" />
47
+ <button type="submit" class="button-primary %%SUCURI.FsScannerSwitchCssClass%%">%%SUCURI.FsScannerSwitchText%%</button>
48
+ </form>
49
+ </td>
50
+ </tr>
51
+
52
+ <tr>
53
+ <td>Scan modified files</td>
54
+ <td>%%SUCURI.ScanModfilesStatus%%</td>
55
+ <td class="td-with-button">
56
+ <form action="%%SUCURI.URL.Settings%%#settings-scanner" method="post">
57
+ <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
58
+ <input type="hidden" name="sucuriscan_scan_modfiles" value="%%SUCURI.ScanModfilesSwitchValue%%" />
59
+ <button type="submit" class="button-primary %%SUCURI.ScanModfilesSwitchCssClass%%">%%SUCURI.ScanModfilesSwitchText%%</button>
60
+ </form>
61
+ </td>
62
+ </tr>
63
+
64
+ <tr class="alternate">
65
+ <td>Integrity checking</td>
66
+ <td>%%SUCURI.ScanChecksumsStatus%%</td>
67
+ <td class="td-with-button">
68
+ <form action="%%SUCURI.URL.Settings%%#settings-scanner" method="post">
69
+ <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
70
+ <input type="hidden" name="sucuriscan_scan_checksums" value="%%SUCURI.ScanChecksumsSwitchValue%%" />
71
+ <button type="submit" class="button-primary %%SUCURI.ScanChecksumsSwitchCssClass%%">%%SUCURI.ScanChecksumsSwitchText%%</button>
72
+ </form>
73
+ </td>
74
+ </tr>
75
+
76
+ <tr>
77
+ <td>Scan error log files</td>
78
+ <td>%%SUCURI.ScanErrorlogsStatus%%</td>
79
+ <td class="td-with-button">
80
+ <form action="%%SUCURI.URL.Settings%%#settings-scanner" method="post">
81
+ <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
82
+ <input type="hidden" name="sucuriscan_scan_errorlogs" value="%%SUCURI.ScanErrorlogsSwitchValue%%" />
83
+ <button type="submit" class="button-primary %%SUCURI.ScanErrorlogsSwitchCssClass%%">%%SUCURI.ScanErrorlogsSwitchText%%</button>
84
+ </form>
85
+ </td>
86
+ </tr>
87
+
88
+ <tr class="alternate">
89
+ <td>Last Scanning</td>
90
+ <td><span class="sucuriscan-monospace">%%SUCURI.ScanningRuntimeHuman%%</span></td>
91
+ <td class="td-with-button">
92
+ <form action="%%SUCURI.URL.Home%%" method="post">
93
+ <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
94
+ <button type="submit" name="sucuriscan_force_scan" class="button-primary">Force Scan</button>
95
+ </form>
96
+ </td>
97
+ </tr>
98
+
99
+ <tr>
100
+ <td>Scanning frequency</td>
101
+ <td>%%SUCURI.ScanningFrequency%%</td>
102
+ <td class="td-with-button">
103
+ <form action="%%SUCURI.URL.Settings%%#settings-scanner" method="post">
104
+ <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
105
+ <select name="sucuriscan_scan_frequency">
106
+ %%SUCURI.ScanningFrequencyOptions%%
107
+ </select>
108
+ <button type="submit" class="button-primary">Change</button>
109
+ </form>
110
+ </td>
111
+ </tr>
112
+
113
+ <tr class="alternate">
114
+ <td>Scanning interface</td>
115
+ <td>%%SUCURI.ScanningInterface%%</td>
116
+ <td class="td-with-button">
117
+ <form action="%%SUCURI.URL.Settings%%#settings-scanner" method="post">
118
+ <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
119
+ <select name="sucuriscan_scan_interface">
120
+ %%SUCURI.ScanningInterfaceOptions%%
121
+ </select>
122
+ <button type="submit" class="button-primary">Change</button>
123
+ </form>
124
+ </td>
125
+ </tr>
126
+
127
+ </tbody>
128
+ </table>
inc/tpl/settings.html.tpl CHANGED
@@ -5,10 +5,16 @@
5
<a href="#" data-tabname="settings-general">General Settings</a>
6
</li>
7
<li>
8
- <a href="#" data-tabname="settings-notifications">Notification Settings</a>
9
</li>
10
<li>
11
- <a href="#" data-tabname="settings-ignorerules">Ignore Notifications</a>
12
</li>
13
<li>
14
<a href="#" data-tabname="settings-heartbeat">Heartbeat</a>
@@ -20,6 +26,14 @@
20
%%SUCURI.Settings.General%%
21
</div>
22
23
<div id="sucuriscan-settings-notifications">
24
%%SUCURI.Settings.Notifications%%
25
</div>
5
<a href="#" data-tabname="settings-general">General Settings</a>
6
</li>
7
<li>
8
+ <a href="#" data-tabname="settings-scanner">Scanner Settings</a>
9
</li>
10
<li>
11
+ <a href="#" data-tabname="settings-ignorescanning">Ignore Scanning</a>
12
+ </li>
13
+ <li>
14
+ <a href="#" data-tabname="settings-notifications">Alert Settings</a>
15
+ </li>
16
+ <li>
17
+ <a href="#" data-tabname="settings-ignorerules">Ignore Alerts</a>
18
</li>
19
<li>
20
<a href="#" data-tabname="settings-heartbeat">Heartbeat</a>
26
%%SUCURI.Settings.General%%
27
</div>
28
29
+ <div id="sucuriscan-settings-scanner">
30
+ %%SUCURI.Settings.Scanner%%
31
+ </div>
32
+
33
+ <div id="sucuriscan-settings-ignorescanning">
34
+ %%SUCURI.Settings.IgnoreScanning%%
35
+ </div>
36
+
37
<div id="sucuriscan-settings-notifications">
38
%%SUCURI.Settings.Notifications%%
39
</div>
readme.txt CHANGED
@@ -3,7 +3,7 @@ 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.
@@ -220,9 +220,90 @@ 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.
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.1
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.
220
security needs as you see fit.
221
222
223
+ == FAQ ==
224
+
225
+ = If I install the Sucuri Security plugin do I get a Sucuri account? =
226
+
227
+ No, this is a free plugin that we offer at no charge. It does not mean you get a free account.
228
+
229
+
230
+ = If I have the premium plugin, do I need the Free plugin? =
231
+
232
+ The free plugin will be replacing the Premium plugin in the coming weeks.
233
+ Eventually, there will only be one plugin. If you have the premium plugin, and
234
+ install the free version, the free version will overwrite the premium version.
235
+
236
+ = Do I still need Sucuri’s products if I have this plugin? =
237
+
238
+ Yes. This plugin compliments your existing security toolsets. It is not
239
+ designed to replace the Sucuri AntiVirus or Firewall products.
240
+
241
+ = Where do I get support for this plugin? =
242
+
243
+ The best place is to engage us via the <a
244
+ href=“https://wordpress.org/support/plugin/sucuri-scanner”>Support Forum. If
245
+ you are a client, <a href=“https://support.sucuri.net/support/?new”you can
246
+ submit a ticket here</a>.
247
+
248
+ = Does your plugin conflict with WordFence? =
249
+
250
+ The plugin does not, but there might be issues with our scanners. If you get
251
+ an “Unable to Properly Scan Your Site” It’s likely because the WordFence
252
+ plugin is blocking our scanner as an invalid crawler.
253
+
254
+ You would have to white list our IP address on the WordFence dashboard.
255
+
256
+
257
+ = What are the Remote Security Malware Scanning Limitations? =
258
+
259
+ Because the security malware scanner is remote, it is unable to see things
260
+ that are on the server but that are not displaying on the browser. If you are
261
+ interested in this, we encourage you to subscribe to our Website AntiVirus
262
+ product.
263
+
264
+ This issues includes things like Phishing pages, Backdoors, Mailer Scripts,
265
+ etc…
266
+
267
+ = Your plugin didn’t detect this malware? =
268
+
269
+ This happens, reference the Remote scanner limitations above. This should not
270
+ be confused with our Website AntiVirus product. If you have malware, and you
271
+ are a client, submit a ticket so that <a
272
+ href=“https://support.sucuri.net/support/?new&mremoval”>we can help you get
273
+ clean.</a>
274
+
275
+ If you are not a client, and you want to share what you have found please send
276
+ it to <a href=“mailto:labs@sucuri.net”>labs@sucuri.net</a>.
277
+
278
+ The plugin is not performing application level malware / security scanning so
279
+ this is not uncommon.
280
+
281
+ = Is it free to enable the Website Firewall option? =
282
+
283
+ No, it is not. To enable you must subscribe to the <a
284
+ href=“https://sucuri.net/website-firewall-signup”>Website Firewall
285
+ service</a>.
286
+
287
+ = Will this plugin impact the performance of my website? =
288
+
289
+ No, it will not.
290
+
291
+ = Do the logs get stored to my database? =
292
+
293
+ No, it does not.
294
+
295
+ = Are there any issues installing your plugin with any hosts? =
296
+
297
+ Not that we are aware of.
298
+
299
+
300
+
301
302
== Changelog ==
303
304
+ = 1.7.1 =
305
+ * Fixed remote scanning that was not loading automatically on some installs.
306
+
307
= 1.7.0 =
308
* Added Hardening option to remove error log files
309
* Bug fixes on some new registrations.
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.7.0
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.7.0');
70
71
/**
72
* The name of the Sucuri plugin main file.
@@ -560,7 +560,8 @@ class SucuriScan {
560
/**
561
* Retrieve the real ip address of the user in the current request.
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 = '';
@@ -692,6 +693,19 @@ class SucuriScan {
692
return FALSE;
693
}
694
695
/**
696
* Retrieve the date in localized format, based on timestamp.
697
*
@@ -720,7 +734,7 @@ class SucuriScan {
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
}
@@ -736,7 +750,7 @@ class SucuriScan {
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'; }
@@ -891,6 +905,21 @@ class SucuriScan {
891
return $text;
892
}
893
894
/**
895
* Check whether an list is a multidimensional array or not.
896
*
@@ -984,7 +1013,7 @@ class SucuriScanRequest extends SucuriScan {
984
}
985
986
// Check the format of the request data with a regex defined above.
987
- if( preg_match($pattern, $key_value) ){
988
return self::escape($key_value);
989
}
990
}
@@ -1058,6 +1087,16 @@ class SucuriScanFileInfo extends SucuriScan {
1058
*/
1059
public $ignore_directories = TRUE;
1060
1061
/**
1062
* Whether the filesystem scanner should run recursively or not.
1063
*
@@ -1086,34 +1125,37 @@ class SucuriScanFileInfo extends SucuriScan {
1086
$project_signatures = '';
1087
$abs_path = rtrim( ABSPATH, '/' );
1088
$files = $this->get_directory_tree($directory, $scan_with);
1089
- sort($files);
1090
1091
if( $as_array ){
1092
$project_signatures = array();
1093
}
1094
1095
- foreach( $files as $filepath){
1096
- $file_checksum = @md5_file($filepath);
1097
- $filesize = @filesize($filepath);
1098
1099
- if( $as_array ){
1100
- $basename = str_replace( $abs_path . '/', '', $filepath );
1101
- $project_signatures[$basename] = array(
1102
- 'filepath' => $filepath,
1103
- 'checksum' => $file_checksum,
1104
- 'filesize' => $filesize,
1105
- 'created_at' => filectime($filepath),
1106
- 'modified_at' => filemtime($filepath),
1107
- );
1108
- } else {
1109
- $filepath = str_replace( $abs_path, $abs_path . '/', $filepath );
1110
- $project_signatures .= sprintf(
1111
- "%s%s%s%s\n",
1112
- $file_checksum,
1113
- $filesize,
1114
- chr(32),
1115
- $filepath
1116
- );
1117
}
1118
}
1119
@@ -1132,6 +1174,7 @@ class SucuriScanFileInfo extends SucuriScan {
1132
public function get_directory_tree($directory='', $scan_with='spl'){
1133
if( file_exists($directory) && is_dir($directory) ){
1134
$tree = array();
1135
1136
switch( $scan_with ){
1137
case 'spl':
@@ -1333,21 +1376,31 @@ class SucuriScanFileInfo extends SucuriScan {
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.
1338
- * @return boolean Either TRUE or FALSE representing that the scan should ignore this folder or not.
1339
*/
1340
private function ignore_folderpath( $directory='', $filename='' ){
1341
// Ignoring current and parent folders.
1342
if( $filename == '.' || $filename == '..' ){ return TRUE; }
1343
1344
if( $this->ignore_directories ){
1345
$filepath = realpath( $directory . '/' . $filename );
1346
$pattern = '/\/wp-content\/(uploads|cache|backup|w3tc)/';
1347
1348
if( preg_match($pattern, $filepath) ){
1349
return TRUE;
1350
}
1351
}
1352
1353
return FALSE;
@@ -2381,30 +2434,6 @@ class SucuriScanOption extends SucuriScanRequest {
2381
return $response;
2382
}
2383
2384
- /**
2385
- * Retrieve the last time when the filesystem scan was ran.
2386
- *
2387
- * @param boolean $format Whether the timestamp must be formatted as date/time or not.
2388
- * @return string The timestamp of the runtime, or an string with the date/time.
2389
- */
2390
- public static function get_filesystem_runtime( $format=FALSE ){
2391
- $runtime = self::get_option(':runtime');
2392
-
2393
- if( $runtime > 0 ){
2394
- if( $format ){
2395
- return SucuriScan::datetime($runtime);
2396
- }
2397
-
2398
- return $runtime;
2399
- }
2400
-
2401
- if( $format ){
2402
- return '<em>Unknown</em>';
2403
- }
2404
-
2405
- return FALSE;
2406
- }
2407
-
2408
}
2409
2410
/**
@@ -3455,7 +3484,8 @@ class SucuriScanAPI extends SucuriScanOption {
3455
isset($response['headers']['content-type'])
3456
&& $response['headers']['content-type'] == 'application/json'
3457
){
3458
- $response['body'] = @json_decode($response['body_raw']);
3459
}
3460
3461
// Check if the response data is serialized (which we will consider as insecure).
@@ -3899,6 +3929,8 @@ class SucuriScanAPI extends SucuriScanOption {
3899
'fromwp' => 2,
3900
'clear' => 1,
3901
'json' => 1,
3902
));
3903
3904
if( $response ){
@@ -4625,6 +4657,161 @@ class SucuriScanTemplate extends SucuriScanRequest {
4625
4626
}
4627
4628
/**
4629
* Heartbeat library.
4630
*
@@ -6960,7 +7147,13 @@ function sucuriscan_core_files(){
6960
6961
foreach( $file_list as $file_path ){
6962
// Skip files that were marked as fixed.
6963
- if( array_key_exists(md5($file_path), $ignored_files) ){ continue; }
6964
6965
// Generate the HTML code from the snippet template for this file.
6966
$css_class = ( $counter % 2 == 0 ) ? '' : 'alternate';
@@ -8360,6 +8553,8 @@ function sucuriscan_settings_page(){
8360
$template_variables = array(
8361
'PageTitle' => 'Settings',
8362
'Settings.General' => sucuriscan_settings_general(),
8363
'Settings.Notifications' => sucuriscan_settings_notifications(),
8364
'Settings.IgnoreRules' => sucuriscan_settings_ignore_rules(),
8365
'Settings.Heartbeat' => sucuriscan_settings_heartbeat(),
@@ -8443,9 +8638,7 @@ function sucuriscan_settings_form_submissions( $page_nonce=NULL ){
8443
8444
// Modify the schedule of the filesystem scanner.
8445
if( $frequency = SucuriScanRequest::post(':scan_frequency') ){
8446
- $allowed_frequency = array_keys($sucuriscan_schedule_allowed);
8447
-
8448
- if( in_array($frequency, $allowed_frequency) ){
8449
SucuriScanOption::update_option(':scan_frequency', $frequency);
8450
wp_clear_scheduled_hook('sucuriscan_scheduled_scan');
8451
@@ -8453,8 +8646,9 @@ function sucuriscan_settings_form_submissions( $page_nonce=NULL ){
8453
wp_schedule_event( time()+10, $frequency, 'sucuriscan_scheduled_scan' );
8454
}
8455
8456
- SucuriScanEvent::notify_event( 'plugin_change', 'Filesystem scanning frequency changed to: ' . $frequency );
8457
- SucuriScanInterface::info( 'Filesystem scan scheduled to run <code>'.$frequency.'</code>' );
8458
}
8459
}
8460
@@ -8587,6 +8781,31 @@ function sucuriscan_settings_form_submissions( $page_nonce=NULL ){
8587
}
8588
}
8589
8590
// Update the settings for the heartbeat API.
8591
if( $heartbeat_status = SucuriScanRequest::post(':heartbeat_status') ){
8592
$statuses_allowed = SucuriScanHeartbeat::statuses_allowed();
@@ -8639,9 +8858,7 @@ function sucuriscan_settings_form_submissions( $page_nonce=NULL ){
8639
*/
8640
function sucuriscan_settings_general(){
8641
8642
- global $sucuriscan_schedule_allowed,
8643
- $sucuriscan_interface_allowed,
8644
- $sucuriscan_emails_per_hour,
8645
$sucuriscan_maximum_failed_logins,
8646
$sucuriscan_verify_ssl_cert;
8647
@@ -8672,16 +8889,9 @@ function sucuriscan_settings_general(){
8672
8673
// Get initial variables to decide some things bellow.
8674
$api_key = SucuriScanAPI::get_plugin_key();
8675
- $fs_scanner = SucuriScanOption::get_option(':fs_scanner');
8676
- $scan_freq = SucuriScanOption::get_option(':scan_frequency');
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');
8684
- $runtime_scan_human = SucuriScanOption::get_filesystem_runtime(TRUE);
8685
8686
// Check whether the domain name is valid or not.
8687
if( !$api_key ){
@@ -8691,18 +8901,66 @@ function sucuriscan_settings_general(){
8691
}
8692
8693
// Generate the HTML code for the option list in the form select fields.
8694
- $scan_freq_options = SucuriScanTemplate::get_select_options( $sucuriscan_schedule_allowed, $scan_freq );
8695
- $scan_interface_options = SucuriScanTemplate::get_select_options( $sucuriscan_interface_allowed, $scan_interface );
8696
$emails_per_hour_options = SucuriScanTemplate::get_select_options( $sucuriscan_emails_per_hour, $emails_per_hour );
8697
$maximum_failed_logins_options = SucuriScanTemplate::get_select_options( $sucuriscan_maximum_failed_logins, $maximum_failed_logins );
8698
$verify_ssl_cert_options = SucuriScanTemplate::get_select_options( $sucuriscan_verify_ssl_cert, $verify_ssl_cert );
8699
8700
$template_variables = array(
8701
- 'APIKey' => $api_key,
8702
'APIKey.RecoverVisibility' => SucuriScanTemplate::visibility( !$api_key && !$display_manual_key_form ),
8703
'APIKey.ManualKeyFormVisibility' => SucuriScanTemplate::visibility($display_manual_key_form),
8704
'APIKey.RemoveVisibility' => SucuriScanTemplate::visibility($api_key),
8705
'InvalidDomainVisibility' => SucuriScanTemplate::visibility($invalid_domain),
8706
/* Filesystem scanner */
8707
'FsScannerStatus' => 'Enabled',
8708
'FsScannerSwitchText' => 'Disable',
@@ -8728,19 +8986,8 @@ function sucuriscan_settings_general(){
8728
'ScanningFrequencyOptions' => $scan_freq_options,
8729
'ScanningInterface' => ( $scan_interface ? $sucuriscan_interface_allowed[$scan_interface] : 'Undefined' ),
8730
'ScanningInterfaceOptions' => $scan_interface_options,
8731
- 'ScanningInterfaceVisibility' => SucuriScanTemplate::visibility( !SucuriScanFileInfo::is_spl_available() ),
8732
/* Filesystem scanning runtime. */
8733
'ScanningRuntimeHuman' => $runtime_scan_human,
8734
- 'ModalWhenAPIRegistered' => $api_registered_modal,
8735
- 'NotifyTo' => SucuriScanOption::get_option(':notify_to'),
8736
- 'EmailsPerHour' => 'Undefined',
8737
- 'EmailsPerHourOptions' => $emails_per_hour_options,
8738
- 'MaximumFailedLogins' => 'Undefined',
8739
- 'MaximumFailedLoginsOptions' => $maximum_failed_logins_options,
8740
- 'VerifySSLCert' => 'Undefined',
8741
- 'VerifySSLCertOptions' => $verify_ssl_cert_options,
8742
- 'RequestTimeout' => SucuriScanOption::get_option(':request_timeout') . ' seconds',
8743
- 'ModalWhenAPIRegistered' => $api_registered_modal,
8744
);
8745
8746
if( $fs_scanner == 'disabled' ){
@@ -8775,19 +9022,7 @@ function sucuriscan_settings_general(){
8775
$template_variables['ScanningFrequency'] = $sucuriscan_schedule_allowed[$scan_freq];
8776
}
8777
8778
- if( array_key_exists($emails_per_hour, $sucuriscan_emails_per_hour) ){
8779
- $template_variables['EmailsPerHour'] = $sucuriscan_emails_per_hour[$emails_per_hour];
8780
- }
8781
-
8782
- if( array_key_exists($maximum_failed_logins, $sucuriscan_maximum_failed_logins) ){
8783
- $template_variables['MaximumFailedLogins'] = $sucuriscan_maximum_failed_logins[$maximum_failed_logins];
8784
- }
8785
-
8786
- if( array_key_exists($verify_ssl_cert, $sucuriscan_verify_ssl_cert) ){
8787
- $template_variables['VerifySSLCert'] = $sucuriscan_verify_ssl_cert[$verify_ssl_cert];
8788
- }
8789
-
8790
- return SucuriScanTemplate::get_section('settings-general', $template_variables);
8791
}
8792
8793
/**
@@ -8883,10 +9118,62 @@ function sucuriscan_settings_ignore_rules(){
8883
return SucuriScanTemplate::get_section('settings-ignorerules', $template_variables);
8884
}
8885
8886
/**
8887
* Read and parse the content of the heartbeat settings template.
8888
*
8889
- * @return string Parsed HTML code for the ignored-rules settings panel.
8890
*/
8891
function sucuriscan_settings_heartbeat(){
8892
// Current values set in the options table.
@@ -9269,7 +9556,7 @@ function sucuriscan_server_info(){
9269
$info_vars = array(
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',
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.1
8
Author URI: http://sucuri.net
9
*/
10
66
/**
67
* Current version of the plugin's code.
68
*/
69
+ define('SUCURISCAN_VERSION', '1.7.1');
70
71
/**
72
* The name of the Sucuri plugin main file.
560
/**
561
* Retrieve the real ip address of the user in the current request.
562
*
563
+ * @param boolean $return_header Whether the header name where the address was found must be returned.
564
+ * @return string The real ip address of the user in the current request.
565
*/
566
public static function get_remote_addr( $return_header=FALSE ){
567
$remote_addr = '';
693
return FALSE;
694
}
695
696
+ /**
697
+ * Returns the current time measured in the number of seconds since the Unix Epoch.
698
+ *
699
+ * @return integer Return current Unix timestamp.
700
+ */
701
+ public static function local_time(){
702
+ if( function_exists('current_time') ){
703
+ return current_time('timestamp');
704
+ } else {
705
+ return time();
706
+ }
707
+ }
708
+
709
/**
710
* Retrieve the date in localized format, based on timestamp.
711
*
734
* @return string The date, translated if locale specifies it.
735
*/
736
public static function current_datetime(){
737
+ $local_time = self::local_time();
738
739
return self::datetime($local_time);
740
}
750
$timestamp = strtotime($timestamp);
751
}
752
753
+ $local_time = self::local_time();
754
$diff = abs( $local_time - intval($timestamp) );
755
756
if( $diff == 0 ){ return 'just now'; }
905
return $text;
906
}
907
908
+ /**
909
+ * Same as the excerpt method but with the string reversed.
910
+ *
911
+ * @param string $text String of characters that will be cut.
912
+ * @param integer $length Maximum length of the returned string, default is 10.
913
+ * @return string Short version of the text specified.
914
+ */
915
+ public static function excerpt_rev( $text='', $length=10 ){
916
+ $str_reversed = strrev($text);
917
+ $str_excerpt = self::excerpt( $str_reversed, $length );
918
+ $text_transformed = strrev($str_excerpt);
919
+
920
+ return $text_transformed;
921
+ }
922
+
923
/**
924
* Check whether an list is a multidimensional array or not.
925
*
1013
}
1014
1015
// Check the format of the request data with a regex defined above.
1016
+ if( @preg_match($pattern, $key_value) ){
1017
return self::escape($key_value);
1018
}
1019
}
1087
*/
1088
public $ignore_directories = TRUE;
1089
1090
+ /**
1091
+ * A list of ignored directory paths, these folders will be skipped during the
1092
+ * execution of the file system scans, and any sub-directory or files inside
1093
+ * these paths will be ignored too.
1094
+ *
1095
+ * @see SucuriScanFSScanner.get_ignored_directories()
1096
+ * @var array
1097
+ */
1098
+ private $ignored_directories = array();
1099
+
1100
/**
1101
* Whether the filesystem scanner should run recursively or not.
1102
*
1125
$project_signatures = '';
1126
$abs_path = rtrim( ABSPATH, '/' );
1127
$files = $this->get_directory_tree($directory, $scan_with);
1128
1129
if( $as_array ){
1130
$project_signatures = array();
1131
}
1132
1133
+ if( $files ){
1134
+ sort($files);
1135
1136
+ foreach( $files as $filepath){
1137
+ $file_checksum = @md5_file($filepath);
1138
+ $filesize = @filesize($filepath);
1139
+
1140
+ if( $as_array ){
1141
+ $basename = str_replace( $abs_path . '/', '', $filepath );
1142
+ $project_signatures[$basename] = array(
1143
+ 'filepath' => $filepath,
1144
+ 'checksum' => $file_checksum,
1145
+ 'filesize' => $filesize,
1146
+ 'created_at' => filectime($filepath),
1147
+ 'modified_at' => filemtime($filepath),
1148
+ );
1149
+ } else {
1150
+ $filepath = str_replace( $abs_path, $abs_path . '/', $filepath );
1151
+ $project_signatures .= sprintf(
1152
+ "%s%s%s%s\n",
1153
+ $file_checksum,
1154
+ $filesize,
1155
+ chr(32),
1156
+ $filepath
1157
+ );
1158
+ }
1159
}
1160
}
1161
1174
public function get_directory_tree($directory='', $scan_with='spl'){
1175
if( file_exists($directory) && is_dir($directory) ){
1176
$tree = array();
1177
+ $this->ignored_directories = SucuriScanFSScanner::get_ignored_directories();
1178
1179
switch( $scan_with ){
1180
case 'spl':
1376
/**
1377
* Skip some specific directories and file paths from the filesystem scan.
1378
*
1379
+ * @param string $directory Directory where the scanner is located at the moment.
1380
+ * @param string $filename Name of the folder or file being scanned at the moment.
1381
+ * @return boolean Either TRUE or FALSE representing that the scan should ignore this folder or not.
1382
*/
1383
private function ignore_folderpath( $directory='', $filename='' ){
1384
// Ignoring current and parent folders.
1385
if( $filename == '.' || $filename == '..' ){ return TRUE; }
1386
1387
if( $this->ignore_directories ){
1388
+ // Ignore directories based on a common regular expression.
1389
$filepath = realpath( $directory . '/' . $filename );
1390
$pattern = '/\/wp-content\/(uploads|cache|backup|w3tc)/';
1391
1392
if( preg_match($pattern, $filepath) ){
1393
return TRUE;
1394
}
1395
+
1396
+ // Ignore directories specified by the administrator.
1397
+ if( !empty($this->ignored_directories) ){
1398
+ foreach( $this->ignored_directories['directories'] as $ignored_dir ){
1399
+ if( strpos($directory, $ignored_dir) !== FALSE ){
1400
+ return TRUE;
1401
+ }
1402
+ }
1403
+ }
1404
}
1405
1406
return FALSE;
2434
return $response;
2435
}
2436
2437
}
2438
2439
/**
3484
isset($response['headers']['content-type'])
3485
&& $response['headers']['content-type'] == 'application/json'
3486
){
3487
+ $assoc = ( isset($args['assoc']) && $args['assoc'] === TRUE ) ? TRUE : FALSE;
3488
+ $response['body'] = @json_decode($response['body_raw'], $assoc);
3489
}
3490
3491
// Check if the response data is serialized (which we will consider as insecure).
3929
'fromwp' => 2,
3930
'clear' => 1,
3931
'json' => 1,
3932
+ ), array(
3933
+ 'assoc' => TRUE
3934
));
3935
3936
if( $response ){
4657
4658
}
4659
4660
+ /**
4661
+ * File System Scanner
4662
+ *
4663
+ * The File System Scanner component performs full and incremental scans over a
4664
+ * file system folder, maintaining a snapshot of the filesystem and comparing it
4665
+ * with the current content to establish what content has been updated. Updated
4666
+ * content is then submitted to the remote server and it is stored for future
4667
+ * analysis.
4668
+ */
4669
+ class SucuriScanFSScanner extends SucuriScan {
4670
+
4671
+ /**
4672
+ * Retrieve the last time when the filesystem scan was ran.
4673
+ *
4674
+ * @param boolean $format Whether the timestamp must be formatted as date/time or not.
4675
+ * @return string The timestamp of the runtime, or an string with the date/time.
4676
+ */
4677
+ public static function get_filesystem_runtime( $format=FALSE ){
4678
+ $runtime = SucuriScanOption::get_option(':runtime');
4679
+
4680
+ if( $runtime > 0 ){
4681
+ if( $format ){
4682
+ return SucuriScan::datetime($runtime);
4683
+ }
4684
+
4685
+ return $runtime;
4686
+ }
4687
+
4688
+ if( $format ){
4689
+ return '<em>Unknown</em>';
4690
+ }
4691
+
4692
+ return FALSE;
4693
+ }
4694
+
4695
+ /**
4696
+ * Add a new directory path to the list of ignored paths.
4697
+ *
4698
+ * @param string $directory_path The (full) absolute path of a directory.
4699
+ * @return boolean TRUE if the directory path was added to the list, FALSE otherwise.
4700
+ */
4701
+ public static function ignore_directory( $directory_path='' ){
4702
+ $cache = new SucuriScanCache('ignorescanning');
4703
+
4704
+ // Use the checksum of the directory path as the cache key.
4705
+ $cache_key = md5($directory_path);
4706
+ $cache_value = array(
4707
+ 'directory_path' => $directory_path,
4708
+ 'ignored_at' => self::local_time(),
4709
+ );
4710
+ $cached = $cache->add( $cache_key, $cache_value );
4711
+
4712
+ return $cached;
4713
+ }
4714
+
4715
+ /**
4716
+ * Remove a directory path from the list of ignored paths.
4717
+ *
4718
+ * @param string $directory_path The (full) absolute path of a directory.
4719
+ * @return boolean TRUE if the directory path was removed to the list, FALSE otherwise.
4720
+ */
4721
+ public static function unignore_directory( $directory_path='' ){
4722
+ $cache = new SucuriScanCache('ignorescanning');
4723
+
4724
+ // Use the checksum of the directory path as the cache key.
4725
+ $cache_key = md5($directory_path);
4726
+ $removed = $cache->delete($cache_key);
4727
+
4728
+ return $removed;
4729
+ }
4730
+
4731
+ /**
4732
+ * Retrieve a list of directories ignored.
4733
+ *
4734
+ * Retrieve a list of directory paths that will be ignored during the file
4735
+ * system scans, any sub-directory and files inside these folders will be
4736
+ * skipped automatically and will not be used to detect malware or modifications
4737
+ * in the site.
4738
+ *
4739
+ * The structure of the array returned by the function will always be composed
4740
+ * by four (4) indexes which will facilitate the execution of common conditions
4741
+ * in the implementation code.
4742
+ *
4743
+ * <ul>
4744
+ * <li>raw: Will contains the raw data retrieved from the built-in cache system.</li>
4745
+ * <li>checksums: Will contains the md5 of all the directory paths.</li>
4746
+ * <li>directories: Will contains a list of directory paths.</li>
4747
+ * <li>ignored_at_list: Will contains a list of timestamps for when the directories were ignored.</li>
4748
+ * </ul>
4749
+ *
4750
+ * @return array List of ignored directory paths.
4751
+ */
4752
+ public static function get_ignored_directories(){
4753
+ $response = array(
4754
+ 'raw' => array(),
4755
+ 'checksums' => array(),
4756
+ 'directories' => array(),
4757
+ 'ignored_at_list' => array(),
4758
+ );
4759
+
4760
+ $cache = new SucuriScanCache('ignorescanning');
4761
+ $cache_lifetime = 0; // It is not necessary to expire this cache.
4762
+ $ignored_directories = $cache->get_all( $cache_lifetime, 'array' );
4763
+
4764
+ if( $ignored_directories ){
4765
+ $response['raw'] = $ignored_directories;
4766
+
4767
+ foreach( $ignored_directories as $checksum => $data ){
4768
+ $response['checksums'][] = $checksum;
4769
+ $response['directories'][] = $data['directory_path'];
4770
+ $response['ignored_at_list'][] = $data['ignored_at'];
4771
+ }
4772
+ }
4773
+
4774
+ return $response;
4775
+ }
4776
+
4777
+ /**
4778
+ * Run file system scan and retrieve ignored folders.
4779
+ *
4780
+ * Run a file system scan and retrieve an array with two indexes, the first
4781
+ * containing a list of ignored directory paths and their respective timestamps
4782
+ * of when they were added by an administrator user, and the second containing a
4783
+ * list of directories that are not being ignored.
4784
+ *
4785
+ * @return array List of ignored and not ignored directories.
4786
+ */
4787
+ public static function get_ignored_directories_live(){
4788
+ $response = array(
4789
+ 'is_ignored' => array(),
4790
+ 'is_not_ignored' => array(),
4791
+ );
4792
+
4793
+ // Get the ignored directories from the cache.
4794
+ $ignored_directories = self::get_ignored_directories();
4795
+
4796
+ if( $ignored_directories ){
4797
+ $response['is_ignored'] = $ignored_directories['raw'];
4798
+ }
4799
+
4800
+ // Scan the project and file all directories.
4801
+ $sucuri_fileinfo = new SucuriScanFileInfo();
4802
+ $sucuri_fileinfo->ignore_files = TRUE;
4803
+ $sucuri_fileinfo->ignore_directories = TRUE;
4804
+ $directory_list = $sucuri_fileinfo->get_diretories_only(ABSPATH);
4805
+
4806
+ if( $directory_list ){
4807
+ $response['is_not_ignored'] = $directory_list;
4808
+ }
4809
+
4810
+ return $response;
4811
+ }
4812
+
4813
+ }
4814
+
4815
/**
4816
* Heartbeat library.
4817
*
7147
7148
foreach( $file_list as $file_path ){
7149
// Skip files that were marked as fixed.
7150
+ if( $ignored_files ){
7151
+ $file_path_checksum = md5($file_path);
7152
+
7153
+ if( array_key_exists($file_path_checksum, $ignored_files) ){
7154
+ continue;
7155
+ }
7156
+ }
7157
7158
// Generate the HTML code from the snippet template for this file.
7159
$css_class = ( $counter % 2 == 0 ) ? '' : 'alternate';
8553
$template_variables = array(
8554
'PageTitle' => 'Settings',
8555
'Settings.General' => sucuriscan_settings_general(),
8556
+ 'Settings.Scanner' => sucuriscan_settings_scanner(),
8557
+ 'Settings.IgnoreScanning' => sucuriscan_settings_ignorescanning(),
8558
'Settings.Notifications' => sucuriscan_settings_notifications(),
8559
'Settings.IgnoreRules' => sucuriscan_settings_ignore_rules(),
8560
'Settings.Heartbeat' => sucuriscan_settings_heartbeat(),
8638
8639
// Modify the schedule of the filesystem scanner.
8640
if( $frequency = SucuriScanRequest::post(':scan_frequency') ){
8641
+ if( array_key_exists($frequency, $sucuriscan_schedule_allowed) ){
8642
SucuriScanOption::update_option(':scan_frequency', $frequency);
8643
wp_clear_scheduled_hook('sucuriscan_scheduled_scan');
8644
8646
wp_schedule_event( time()+10, $frequency, 'sucuriscan_scheduled_scan' );
8647
}
8648
8649
+ $frequency_title = $sucuriscan_schedule_allowed[$frequency];
8650
+ SucuriScanEvent::notify_event( 'plugin_change', 'Filesystem scanning frequency changed to: ' . $frequency_title );
8651
+ SucuriScanInterface::info( 'Filesystem scan scheduled to run <code>'.$frequency_title.'</code>' );
8652
}
8653
}
8654
8781
}
8782
}
8783
8784
+ // Ignore a new directory path for the file system scans.
8785
+ if( $action = SucuriScanRequest::post(':ignorescanning_action', '(ignore|unignore)') ){
8786
+ $ignore_directories = SucuriScanRequest::post(':ignorescanning_dirs', '_array');
8787
+
8788
+ if( empty($ignore_directories) ){
8789
+ SucuriScanInterface::error( 'You did not choose a directory path from the list.' );
8790
+ }
8791
+
8792
+ elseif( $action == 'ignore' ){
8793
+ foreach( $ignore_directories as $directory_path ){
8794
+ SucuriScanFSScanner::ignore_directory($directory_path);
8795
+ }
8796
+
8797
+ SucuriScanInterface::info( 'Directories selected from the list will be ignored in future scans.' );
8798
+ }
8799
+
8800
+ elseif( $action == 'unignore' ) {
8801
+ foreach( $ignore_directories as $directory_path ){
8802
+ SucuriScanFSScanner::unignore_directory($directory_path);
8803
+ }
8804
+
8805
+ SucuriScanInterface::info( 'Directories selected from the list will not be ignored anymore.' );
8806
+ }
8807
+ }
8808
+
8809
// Update the settings for the heartbeat API.
8810
if( $heartbeat_status = SucuriScanRequest::post(':heartbeat_status') ){
8811
$statuses_allowed = SucuriScanHeartbeat::statuses_allowed();
8858
*/
8859
function sucuriscan_settings_general(){
8860
8861
+ global $sucuriscan_emails_per_hour,
8862
$sucuriscan_maximum_failed_logins,
8863
$sucuriscan_verify_ssl_cert;
8864
8889
8890
// Get initial variables to decide some things bellow.
8891
$api_key = SucuriScanAPI::get_plugin_key();
8892
$emails_per_hour = SucuriScanOption::get_option(':emails_per_hour');
8893
$maximum_failed_logins = SucuriScanOption::get_option(':maximum_failed_logins');
8894
$verify_ssl_cert = SucuriScanOption::get_option(':verify_ssl_cert');
8895
8896
// Check whether the domain name is valid or not.
8897
if( !$api_key ){
8901
}
8902
8903
// Generate the HTML code for the option list in the form select fields.
8904
$emails_per_hour_options = SucuriScanTemplate::get_select_options( $sucuriscan_emails_per_hour, $emails_per_hour );
8905
$maximum_failed_logins_options = SucuriScanTemplate::get_select_options( $sucuriscan_maximum_failed_logins, $maximum_failed_logins );
8906
$verify_ssl_cert_options = SucuriScanTemplate::get_select_options( $sucuriscan_verify_ssl_cert, $verify_ssl_cert );
8907
8908
$template_variables = array(
8909
+ 'APIKey' => ( !$api_key ? '<em>(not set)</em>' : $api_key ),
8910
'APIKey.RecoverVisibility' => SucuriScanTemplate::visibility( !$api_key && !$display_manual_key_form ),
8911
'APIKey.ManualKeyFormVisibility' => SucuriScanTemplate::visibility($display_manual_key_form),
8912
'APIKey.RemoveVisibility' => SucuriScanTemplate::visibility($api_key),
8913
'InvalidDomainVisibility' => SucuriScanTemplate::visibility($invalid_domain),
8914
+ 'NotifyTo' => SucuriScanOption::get_option(':notify_to'),
8915
+ 'EmailsPerHour' => 'Undefined',
8916
+ 'EmailsPerHourOptions' => $emails_per_hour_options,
8917
+ 'MaximumFailedLogins' => 'Undefined',
8918
+ 'MaximumFailedLoginsOptions' => $maximum_failed_logins_options,
8919
+ 'VerifySSLCert' => 'Undefined',
8920
+ 'VerifySSLCertOptions' => $verify_ssl_cert_options,
8921
+ 'RequestTimeout' => SucuriScanOption::get_option(':request_timeout') . ' seconds',
8922
+ 'ModalWhenAPIRegistered' => $api_registered_modal,
8923
+ );
8924
+
8925
+ if( array_key_exists($emails_per_hour, $sucuriscan_emails_per_hour) ){
8926
+ $template_variables['EmailsPerHour'] = $sucuriscan_emails_per_hour[$emails_per_hour];
8927
+ }
8928
+
8929
+ if( array_key_exists($maximum_failed_logins, $sucuriscan_maximum_failed_logins) ){
8930
+ $template_variables['MaximumFailedLogins'] = $sucuriscan_maximum_failed_logins[$maximum_failed_logins];
8931
+ }
8932
+
8933
+ if( array_key_exists($verify_ssl_cert, $sucuriscan_verify_ssl_cert) ){
8934
+ $template_variables['VerifySSLCert'] = $sucuriscan_verify_ssl_cert[$verify_ssl_cert];
8935
+ }
8936
+
8937
+ return SucuriScanTemplate::get_section('settings-general', $template_variables);
8938
+ }
8939
+
8940
+ /**
8941
+ * Read and parse the content of the scanner settings template.
8942
+ *
8943
+ * @return string Parsed HTML code for the scanner settings panel.
8944
+ */
8945
+ function sucuriscan_settings_scanner(){
8946
+
8947
+ global $sucuriscan_schedule_allowed,
8948
+ $sucuriscan_interface_allowed;
8949
+
8950
+ // Get initial variables to decide some things bellow.
8951
+ $fs_scanner = SucuriScanOption::get_option(':fs_scanner');
8952
+ $scan_freq = SucuriScanOption::get_option(':scan_frequency');
8953
+ $scan_interface = SucuriScanOption::get_option(':scan_interface');
8954
+ $scan_modfiles = SucuriScanOption::get_option(':scan_modfiles');
8955
+ $scan_checksums = SucuriScanOption::get_option(':scan_checksums');
8956
+ $scan_errorlogs = SucuriScanOption::get_option(':scan_errorlogs');
8957
+ $runtime_scan_human = SucuriScanFSScanner::get_filesystem_runtime(TRUE);
8958
+
8959
+ // Generate the HTML code for the option list in the form select fields.
8960
+ $scan_freq_options = SucuriScanTemplate::get_select_options( $sucuriscan_schedule_allowed, $scan_freq );
8961
+ $scan_interface_options = SucuriScanTemplate::get_select_options( $sucuriscan_interface_allowed, $scan_interface );
8962
+
8963
+ $template_variables = array(
8964
/* Filesystem scanner */
8965
'FsScannerStatus' => 'Enabled',
8966
'FsScannerSwitchText' => 'Disable',
8986
'ScanningFrequencyOptions' => $scan_freq_options,
8987
'ScanningInterface' => ( $scan_interface ? $sucuriscan_interface_allowed[$scan_interface] : 'Undefined' ),
8988
'ScanningInterfaceOptions' => $scan_interface_options,
8989
/* Filesystem scanning runtime. */
8990
'ScanningRuntimeHuman' => $runtime_scan_human,
8991
);
8992
8993
if( $fs_scanner == 'disabled' ){
9022
$template_variables['ScanningFrequency'] = $sucuriscan_schedule_allowed[$scan_freq];
9023
}
9024
9025
+ return SucuriScanTemplate::get_section('settings-scanner', $template_variables);
9026
}
9027
9028
/**
9118
return SucuriScanTemplate::get_section('settings-ignorerules', $template_variables);
9119
}
9120
9121
+ /**
9122
+ * Read and parse the content of the ignore-scanning settings template.
9123
+ *
9124
+ * @return string Parsed HTML code for the ignore-scanning settings panel.
9125
+ */
9126
+ function sucuriscan_settings_ignorescanning(){
9127
+ $template_variables = array(
9128
+ 'IgnoreScanning.ResourceList' => '',
9129
+ );
9130
+
9131
+ $dir_list_list = SucuriScanFSScanner::get_ignored_directories_live();
9132
+ $counter = 0;
9133
+
9134
+ foreach( $dir_list_list as $group => $dir_list ){
9135
+ foreach( $dir_list as $dir_data ){
9136
+ $valid_entry = FALSE;
9137
+ $snippet_data = array(
9138
+ 'IgnoreScanning.CssClass' => '',
9139
+ 'IgnoreScanning.Directory' => '',
9140
+ 'IgnoreScanning.DirectoryPath' => '',
9141
+ 'IgnoreScanning.IgnoredAt' => '',
9142
+ 'IgnoreScanning.IgnoredAtText' => 'ok',
9143
+ 'IgnoreScanning.IgnoredCssClass' => 'success',
9144
+ );
9145
+
9146
+ if( $group == 'is_ignored' ){
9147
+ $valid_entry = TRUE;
9148
+ $snippet_data['IgnoreScanning.Directory'] = urlencode($dir_data['directory_path']);
9149
+ $snippet_data['IgnoreScanning.DirectoryPath'] = SucuriScan::escape($dir_data['directory_path']);
9150
+ $snippet_data['IgnoreScanning.IgnoredAt'] = SucuriScan::datetime($dir_data['ignored_at']);
9151
+ $snippet_data['IgnoreScanning.IgnoredAtText'] = 'ignored';
9152
+ $snippet_data['IgnoreScanning.IgnoredCssClass'] = 'warning';
9153
+ }
9154
+
9155
+ elseif( $group == 'is_not_ignored' ){
9156
+ $valid_entry = TRUE;
9157
+ $snippet_data['IgnoreScanning.Directory'] = urlencode($dir_data);
9158
+ $snippet_data['IgnoreScanning.DirectoryPath'] = SucuriScan::escape($dir_data);
9159
+ }
9160
+
9161
+ if( $valid_entry ){
9162
+ $css_class = ( $counter %2 == 0 ) ? '' : 'alternate';
9163
+ $snippet_data['IgnoreScanning.CssClass'] = $css_class;
9164
+ $template_variables['IgnoreScanning.ResourceList'] .= SucuriScanTemplate::get_snippet('settings-ignorescanning', $snippet_data);
9165
+ $counter += 1;
9166
+ }
9167
+ }
9168
+ }
9169
+
9170
+ return SucuriScanTemplate::get_section('settings-ignorescanning', $template_variables);
9171
+ }
9172
+
9173
/**
9174
* Read and parse the content of the heartbeat settings template.
9175
*
9176
+ * @return string Parsed HTML code for the heartbeat settings panel.
9177
*/
9178
function sucuriscan_settings_heartbeat(){
9179
// Current values set in the options table.
9556
$info_vars = array(
9557
'Plugin_version' => SUCURISCAN_VERSION,
9558
'Plugin_checksum' => SUCURISCAN_PLUGIN_CHECKSUM,
9559
+ 'Last_filesystem_scan' => SucuriScanFSScanner::get_filesystem_runtime(TRUE),
9560
'Using_CloudProxy' => 'Unknown',
9561
'HTTP_Host' => 'Unknown',
9562
'Host_Name' => 'Unknown',