Version Description
Download this release
Release Info
Developer | dd@sucuri.net |
Plugin | Sucuri Security – Auditing, Malware Scanner and Security Hardening |
Version | 1.7.3 |
Comparing to | |
See all releases |
Code changes from version 1.7.2 to 1.7.3
- inc/css/sucuriscan-default-css.css +18 -6
- inc/tpl/infosys-errorlogs.html.tpl +69 -0
- inc/tpl/infosys-errorlogs.snippet.tpl +8 -0
- inc/tpl/infosys.html.tpl +7 -0
- inc/tpl/lastlogins-failedlogins.html.tpl +14 -2
- inc/tpl/lastlogins-failedlogins.snippet.tpl +1 -0
- inc/tpl/settings-general.html.tpl +24 -0
- inc/tpl/settings-ignorerules.html.tpl +0 -11
- inc/tpl/settings-ignorescanning.html.tpl +13 -0
- inc/tpl/settings-scanner.html.tpl +36 -0
- inc/tpl/settings-trustip.html.tpl +58 -0
- inc/tpl/settings-trustip.snippet.tpl +9 -0
- inc/tpl/settings.html.tpl +7 -0
- readme.txt +2 -2
- sucuri.php +770 -101
inc/css/sucuriscan-default-css.css
CHANGED
@@ -39,13 +39,13 @@
|
|
39 |
.sucuriscan-modal-inside p:first-child{margin-top:0}
|
40 |
.sucuriscan-modal-inside p:last-child{margin-bottom:0}
|
41 |
/* Label and Tags */
|
42 |
-
.sucuriscan-label, .sucuriscan-label-default, .sucuriscan-label-primary, .sucuriscan-label-success, .sucuriscan-label-info, .sucuriscan-label-warning, .sucuriscan-label-danger{display:inline;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;padding:0.2em 0.6em 0.3em;border-radius:0.25em}
|
43 |
-
.sucuriscan-label-default{background:#777}
|
44 |
-
.sucuriscan-label-
|
45 |
-
.sucuriscan-label-
|
46 |
-
.sucuriscan-label-info{background:#5bc0de}
|
47 |
.sucuriscan-label-warning{background:#f0ad4e}
|
48 |
-
.sucuriscan-label-
|
|
|
49 |
/* Interface Wrapper */
|
50 |
.sucuriscan-wrap{margin-top:20px}
|
51 |
.sucuriscan-wrap .sucuriscan-maincontent{margin:20px 0}
|
@@ -105,6 +105,7 @@ 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}
|
@@ -224,8 +225,19 @@ div.sucuriscan-alert > a.close{position:absolute;top:10px;right:10px;font-size:1
|
|
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 */
|
230 |
@media (max-width: 620px) {
|
231 |
.sucuriscan-tabs > ul li, .sucuriscan-tabs > ul li > a{display:block}
|
39 |
.sucuriscan-modal-inside p:first-child{margin-top:0}
|
40 |
.sucuriscan-modal-inside p:last-child{margin-bottom:0}
|
41 |
/* Label and Tags */
|
42 |
+
.sucuriscan-label, .sucuriscan-label-default, .sucuriscan-label-unknown, .sucuriscan-label-primary, .sucuriscan-label-success, .sucuriscan-label-info, .sucuriscan-label-notice, .sucuriscan-label-warning, .sucuriscan-label-danger, .sucuriscan-label-error{display:inline;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;padding:0.2em 0.6em 0.3em;border-radius:0.25em}
|
43 |
+
.sucuriscan-label-default, .sucuriscan-label-unknown{background:#777}
|
44 |
+
.sucuriscan-label-danger, .sucuriscan-label-error{background:#d9534f}
|
45 |
+
.sucuriscan-label-info, .sucuriscan-label-notice{background:#5bc0de}
|
|
|
46 |
.sucuriscan-label-warning{background:#f0ad4e}
|
47 |
+
.sucuriscan-label-success{background:#5cb85c}
|
48 |
+
.sucuriscan-label-primary{background:#428bca}
|
49 |
/* Interface Wrapper */
|
50 |
.sucuriscan-wrap{margin-top:20px}
|
51 |
.sucuriscan-wrap .sucuriscan-maincontent{margin: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 + div, .sucuriscan-inline-alert-warning + div, .sucuriscan-inline-alert-error + div, .sucuriscan-inline-alert-info + div{margin-top:10px}
|
109 |
.sucuriscan-inline-alert-updated{border-left-color:#7ad03a}
|
110 |
.sucuriscan-inline-alert-warning{border-left-color:#ffba00}
|
111 |
.sucuriscan-inline-alert-error{border-left-color:#dd3d36}
|
225 |
.sucuriscan-maincontent .sucuriscan-settings select, .sucuriscan-maincontent .sucuriscan-settings .input-text{width:220px}
|
226 |
.sucuriscan-maincontent .sucuriscan-settings-notifications{margin-top:0}
|
227 |
.sucuriscan-maincontent .sucuriscan-settings-ignorescanning{margin-top:0}
|
228 |
+
.sucuriscan-maincontent .sucuriscan-settings-trustip{margin-top:0}
|
229 |
.sucuriscan-maincontent .sucuriscan-settings-heartbeat{}
|
230 |
.sucuriscan-maincontent .sucuriscan-wpcron-list{margin-top:0}
|
231 |
+
.sucuriscan-maincontent .sucuriscan-infosys-htaccess .inside .sucuriscan-inline-alert-updated{margin-bottom:10px}
|
232 |
+
.sucuriscan-maincontent .sucuriscan-errorlogs .inside .sucuriscan-inline-alert-error{margin-top:10px}
|
233 |
+
.sucuriscan-maincontent .sucuriscan-errorlogs-list{}
|
234 |
+
/* Parent Resetter: Midnight */
|
235 |
+
.admin-color-blue .wrap div.sucuriscan-setup-notice, .admin-color-blue .sucuriscan-ad:nth-child(odd){background:#e5d1ae;border-color:#d39323}
|
236 |
+
.admin-color-coffee .wrap div.sucuriscan-setup-notice, .admin-color-coffee .sucuriscan-ad:nth-child(odd){background:#e4cfbe;border-color:#b78a66}
|
237 |
+
.admin-color-ectoplasm .wrap div.sucuriscan-setup-notice, .admin-color-ectoplasm .sucuriscan-ad:nth-child(odd){background:#ccd894;border-color:#a3b745}
|
238 |
+
.admin-color-midnight .wrap div.sucuriscan-setup-notice, .admin-color-midnight .sucuriscan-ad:nth-child(odd){background:#f1b8b4;border-color:#d02a21}
|
239 |
+
.admin-color-ocean .wrap div.sucuriscan-setup-notice, .admin-color-ocean .sucuriscan-ad:nth-child(odd){background:#c6e7c8;border-color:#719a74}
|
240 |
+
.admin-color-sunrise .wrap div.sucuriscan-setup-notice, .admin-color-sunrise .sucuriscan-ad:nth-child(odd){background:#ecc2a2;border-color:#c36822}
|
241 |
/* Responsive Styles */
|
242 |
@media (max-width: 620px) {
|
243 |
.sucuriscan-tabs > ul li, .sucuriscan-tabs > ul li > a{display:block}
|
inc/tpl/infosys-errorlogs.html.tpl
ADDED
@@ -0,0 +1,69 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
<div id="poststuff">
|
3 |
+
<div class="postbox sucuriscan-border sucuriscan-table-description sucuriscan-errorlogs">
|
4 |
+
<h3>Error Logs</h3>
|
5 |
+
|
6 |
+
<div class="inside">
|
7 |
+
<p>
|
8 |
+
Web servers like Apache, Nginx and others use files to record errors encountered
|
9 |
+
during the execution of a dynamic language or the server processes. Depending on
|
10 |
+
the configuration of the server, these files may be accessible from the web
|
11 |
+
opening a hole in your site to allow an attacker to gather sensitive information
|
12 |
+
of your project, so it is highly recommended to delete them.
|
13 |
+
</p>
|
14 |
+
|
15 |
+
<div class="sucuriscan-inline-alert-info">
|
16 |
+
<p>
|
17 |
+
If you are a developer, you may want to check the latest errors encountered by
|
18 |
+
the server before delete the log file, that way you can see where the
|
19 |
+
application is failing and fix the errors. Note that many error log files may
|
20 |
+
have thousand of lines, so you will only see the latest entries to prevent PHP
|
21 |
+
interpreter to stop the execution of the parser when the maximum execution time
|
22 |
+
is reached.
|
23 |
+
</p>
|
24 |
+
</div>
|
25 |
+
|
26 |
+
<div class="sucuriscan-inline-alert-error sucuriscan-%%SUCURI.ErrorLog.DisabledVisibility%%">
|
27 |
+
<p>
|
28 |
+
The analysis of error logs is disabled, go to the <em>Scanner Settings</em>
|
29 |
+
panel in the <em>Settings</em> page to enable it.
|
30 |
+
</p>
|
31 |
+
</div>
|
32 |
+
</div>
|
33 |
+
</div>
|
34 |
+
</div>
|
35 |
+
|
36 |
+
<table class="wp-list-table widefat sucuriscan-table sucuriscan-table-double-title sucuriscan-errorlogs-list">
|
37 |
+
<thead>
|
38 |
+
<tr>
|
39 |
+
<th colspan="5" class="thead-with-button">
|
40 |
+
<span>Error Logs (%%SUCURI.ErrorLog.FileSize%%)</span>
|
41 |
+
|
42 |
+
<form action="%%SUCURI.URL.Hardening%%#error-logs" method="post" class="thead-topright-action">
|
43 |
+
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
|
44 |
+
<input type="hidden" name="sucuriscan_run_hardening" value="1" />
|
45 |
+
<input type="hidden" name="sucuriscan_harden_errorlog" value="Harden" />
|
46 |
+
<button type="submit" class="button-primary">Delete logs</button>
|
47 |
+
</form>
|
48 |
+
</th>
|
49 |
+
</tr>
|
50 |
+
|
51 |
+
<tr>
|
52 |
+
<th width="100">Date Time</th>
|
53 |
+
<th width="50">Type</th>
|
54 |
+
<th>Error Message</th>
|
55 |
+
<th width="300">File</th>
|
56 |
+
<th width="50">Line</th>
|
57 |
+
</tr>
|
58 |
+
</thead>
|
59 |
+
|
60 |
+
<tbody>
|
61 |
+
%%SUCURI.ErrorLog.List%%
|
62 |
+
|
63 |
+
<tr class="sucuriscan-%%SUCURI.ErrorLog.NoItemsVisibility%%">
|
64 |
+
<td colspan="5">
|
65 |
+
<em>No logs so far.</em>
|
66 |
+
</td>
|
67 |
+
</tr>
|
68 |
+
</tbody>
|
69 |
+
</table>
|
inc/tpl/infosys-errorlogs.snippet.tpl
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
<tr class="%%SUCURI.ErrorLog.CssClass%%">
|
3 |
+
<td>%%SUCURI.ErrorLog.DateTime%%</td>
|
4 |
+
<td><a href="#" title="%%SUCURI.ErrorLog.ErrorType%%" class="sucuriscan-label-%%SUCURI.ErrorLog.ErrorCode%%">%%SUCURI.ErrorLog.ErrorAbbr%%</a></td>
|
5 |
+
<td>%%SUCURI.ErrorLog.ErrorMessage%%</td>
|
6 |
+
<td><span class="sucuriscan-monospace sucuriscan-wraptext">%%SUCURI.ErrorLog.FilePath%%</span></td>
|
7 |
+
<td><span class="sucuriscan-monospace">%%SUCURI.ErrorLog.LineNumber%%</span></td>
|
8 |
+
</tr>
|
inc/tpl/infosys.html.tpl
CHANGED
@@ -13,6 +13,9 @@
|
|
13 |
<li>
|
14 |
<a href="#" data-tabname="wpconfig-vars">Config. Variables</a>
|
15 |
</li>
|
|
|
|
|
|
|
16 |
</ul>
|
17 |
|
18 |
<div class="sucuriscan-tab-containers">
|
@@ -31,5 +34,9 @@
|
|
31 |
<div id="sucuriscan-wpconfig-vars">
|
32 |
%%SUCURI.WordpressConfig%%
|
33 |
</div>
|
|
|
|
|
|
|
|
|
34 |
</div>
|
35 |
</div>
|
13 |
<li>
|
14 |
<a href="#" data-tabname="wpconfig-vars">Config. Variables</a>
|
15 |
</li>
|
16 |
+
<li>
|
17 |
+
<a href="#" data-tabname="error-logs">Error Logs</a>
|
18 |
+
</li>
|
19 |
</ul>
|
20 |
|
21 |
<div class="sucuriscan-tab-containers">
|
34 |
<div id="sucuriscan-wpconfig-vars">
|
35 |
%%SUCURI.WordpressConfig%%
|
36 |
</div>
|
37 |
+
|
38 |
+
<div id="sucuriscan-error-logs">
|
39 |
+
%%SUCURI.ErrorLogs%%
|
40 |
+
</div>
|
41 |
</div>
|
42 |
</div>
|
inc/tpl/lastlogins-failedlogins.html.tpl
CHANGED
@@ -21,6 +21,17 @@
|
|
21 |
settings</a> to enable the brute-force attack alerts.
|
22 |
</p>
|
23 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
24 |
</div>
|
25 |
</div>
|
26 |
</div>
|
@@ -30,9 +41,10 @@
|
|
30 |
<tr>
|
31 |
<th width="20">No.</th>
|
32 |
<th>User</th>
|
|
|
33 |
<th>IP Address</th>
|
34 |
<th>Date/Time</th>
|
35 |
-
<th width="
|
36 |
</tr>
|
37 |
</thead>
|
38 |
|
@@ -40,7 +52,7 @@
|
|
40 |
%%SUCURI.FailedLogins.List%%
|
41 |
|
42 |
<tr class="sucuriscan-%%SUCURI.FailedLogins.NoItemsVisibility%%">
|
43 |
-
<td colspan="
|
44 |
<em>No logs so far.</em>
|
45 |
</td>
|
46 |
</tr>
|
21 |
settings</a> to enable the brute-force attack alerts.
|
22 |
</p>
|
23 |
</div>
|
24 |
+
|
25 |
+
<div class="sucuriscan-inline-alert-error sucuriscan-%%SUCURI.FailedLogins.CollectPasswordsVisibility%%">
|
26 |
+
<p>
|
27 |
+
If you type a wrong password by mistake your password, the plugin will log the
|
28 |
+
username and password in the security logs <em>(which are text/plain
|
29 |
+
files)</em>. If someone get access to your API key, or your server fails to
|
30 |
+
process the PHP files <em>(which is not usual but may happen)</em> then an
|
31 |
+
attacker may get your credentials and invade your site. Change this from the <a
|
32 |
+
href="%%SUCURI.URL.Settings%%#settings-general">general settings</a>
|
33 |
+
</p>
|
34 |
+
</div>
|
35 |
</div>
|
36 |
</div>
|
37 |
</div>
|
41 |
<tr>
|
42 |
<th width="20">No.</th>
|
43 |
<th>User</th>
|
44 |
+
<th>Password</th>
|
45 |
<th>IP Address</th>
|
46 |
<th>Date/Time</th>
|
47 |
+
<th width="300">User-Agent</th>
|
48 |
</tr>
|
49 |
</thead>
|
50 |
|
52 |
%%SUCURI.FailedLogins.List%%
|
53 |
|
54 |
<tr class="sucuriscan-%%SUCURI.FailedLogins.NoItemsVisibility%%">
|
55 |
+
<td colspan="6">
|
56 |
<em>No logs so far.</em>
|
57 |
</td>
|
58 |
</tr>
|
inc/tpl/lastlogins-failedlogins.snippet.tpl
CHANGED
@@ -2,6 +2,7 @@
|
|
2 |
<tr class="%%SUCURI.FailedLogins.CssClass%%">
|
3 |
<td>%%SUCURI.FailedLogins.Num%%</td>
|
4 |
<td>%%SUCURI.FailedLogins.Username%%</td>
|
|
|
5 |
<td><span class="sucuriscan-monospace">%%SUCURI.FailedLogins.RemoteAddr%%</span></td>
|
6 |
<td><em>%%SUCURI.FailedLogins.Datetime%%</em></td>
|
7 |
<td><div class="sucuriscan-wraptext">%%SUCURI.FailedLogins.UserAgent%%</div></td>
|
2 |
<tr class="%%SUCURI.FailedLogins.CssClass%%">
|
3 |
<td>%%SUCURI.FailedLogins.Num%%</td>
|
4 |
<td>%%SUCURI.FailedLogins.Username%%</td>
|
5 |
+
<td>%%SUCURI.FailedLogins.Password%%</td>
|
6 |
<td><span class="sucuriscan-monospace">%%SUCURI.FailedLogins.RemoteAddr%%</span></td>
|
7 |
<td><em>%%SUCURI.FailedLogins.Datetime%%</em></td>
|
8 |
<td><div class="sucuriscan-wraptext">%%SUCURI.FailedLogins.UserAgent%%</div></td>
|
inc/tpl/settings-general.html.tpl
CHANGED
@@ -127,5 +127,29 @@
|
|
127 |
</td>
|
128 |
</tr>
|
129 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
130 |
</tbody>
|
131 |
</table>
|
127 |
</td>
|
128 |
</tr>
|
129 |
|
130 |
+
<tr>
|
131 |
+
<td>Collect failed passwords</td>
|
132 |
+
<td>%%SUCURI.CollectWrongPasswords%%</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="text" name="sucuriscan_collect_wrong_passwords" class="input-text" placeholder="Type: YES or NO" />
|
137 |
+
<button type="submit" class="button-primary">Change</button>
|
138 |
+
</form>
|
139 |
+
</td>
|
140 |
+
</tr>
|
141 |
+
|
142 |
+
<tr>
|
143 |
+
<td>Log storage path</td>
|
144 |
+
<td><span class="sucuriscan-monospace" title="%%SUCURI.DatastorePath%%">%%SUCURI.DatastorePathShort%%</span></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="text" name="sucuriscan_datastore_path" class="input-text" placeholder="Directory to save logs..." />
|
149 |
+
<button type="submit" class="button-primary">Change</button>
|
150 |
+
</form>
|
151 |
+
</td>
|
152 |
+
</tr>
|
153 |
+
|
154 |
</tbody>
|
155 |
</table>
|
inc/tpl/settings-ignorerules.html.tpl
CHANGED
@@ -45,15 +45,4 @@
|
|
45 |
<tbody>
|
46 |
%%SUCURI.IgnoreRules.PostTypes%%
|
47 |
</tbody>
|
48 |
-
|
49 |
-
<tfoot>
|
50 |
-
<tr>
|
51 |
-
<td colspan="5">
|
52 |
-
<em>
|
53 |
-
<strong>Notifications example:</strong>
|
54 |
-
<code>Post_Type</code> changed from private to published <code>#ID</code> (<code>Title</code>)
|
55 |
-
</em>
|
56 |
-
</td>
|
57 |
-
</tr>
|
58 |
-
</tfoot>
|
59 |
</table>
|
45 |
<tbody>
|
46 |
%%SUCURI.IgnoreRules.PostTypes%%
|
47 |
</tbody>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
48 |
</table>
|
inc/tpl/settings-ignorescanning.html.tpl
CHANGED
@@ -13,6 +13,13 @@
|
|
13 |
directories, this will force the plugin to ignore the files inside these
|
14 |
folders.
|
15 |
</p>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
16 |
</div>
|
17 |
</div>
|
18 |
</div>
|
@@ -33,6 +40,12 @@
|
|
33 |
|
34 |
<tbody>
|
35 |
%%SUCURI.IgnoreScanning.ResourceList%%
|
|
|
|
|
|
|
|
|
|
|
|
|
36 |
</tbody>
|
37 |
|
38 |
<tfoot>
|
13 |
directories, this will force the plugin to ignore the files inside these
|
14 |
folders.
|
15 |
</p>
|
16 |
+
|
17 |
+
<div class="sucuriscan-inline-alert-warning sucuriscan-%%SUCURI.IgnoreScanning.DisabledVisibility%%">
|
18 |
+
<p>
|
19 |
+
The feature to ignore directories during the file system scans is disabled, go
|
20 |
+
to the <em>Scanner Settings</em> panel to enable it.
|
21 |
+
</p>
|
22 |
+
</div>
|
23 |
</div>
|
24 |
</div>
|
25 |
</div>
|
40 |
|
41 |
<tbody>
|
42 |
%%SUCURI.IgnoreScanning.ResourceList%%
|
43 |
+
|
44 |
+
<tr class="sucuriscan-%%SUCURI.IgnoreScanning.NoItemsVisibility%%">
|
45 |
+
<td colspan="4">
|
46 |
+
<em>List is empty.</em>
|
47 |
+
</td>
|
48 |
+
</tr>
|
49 |
</tbody>
|
50 |
|
51 |
<tfoot>
|
inc/tpl/settings-scanner.html.tpl
CHANGED
@@ -74,6 +74,18 @@
|
|
74 |
</tr>
|
75 |
|
76 |
<tr>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
77 |
<td>Scan error log files</td>
|
78 |
<td>%%SUCURI.ScanErrorlogsStatus%%</td>
|
79 |
<td class="td-with-button">
|
@@ -85,6 +97,18 @@
|
|
85 |
</td>
|
86 |
</tr>
|
87 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
88 |
<tr class="alternate">
|
89 |
<td>Last Scanning</td>
|
90 |
<td><span class="sucuriscan-monospace">%%SUCURI.ScanningRuntimeHuman%%</span></td>
|
@@ -124,5 +148,17 @@
|
|
124 |
</td>
|
125 |
</tr>
|
126 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
127 |
</tbody>
|
128 |
</table>
|
74 |
</tr>
|
75 |
|
76 |
<tr>
|
77 |
+
<td>Ignore some files</td>
|
78 |
+
<td>%%SUCURI.IgnoreScanningStatus%%</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_ignore_scanning" value="%%SUCURI.IgnoreScanningSwitchValue%%" />
|
83 |
+
<button type="submit" class="button-primary %%SUCURI.IgnoreScanningSwitchCssClass%%">%%SUCURI.IgnoreScanningSwitchText%%</button>
|
84 |
+
</form>
|
85 |
+
</td>
|
86 |
+
</tr>
|
87 |
+
|
88 |
+
<tr class="alternate">
|
89 |
<td>Scan error log files</td>
|
90 |
<td>%%SUCURI.ScanErrorlogsStatus%%</td>
|
91 |
<td class="td-with-button">
|
97 |
</td>
|
98 |
</tr>
|
99 |
|
100 |
+
<tr>
|
101 |
+
<td>Parse error logs</td>
|
102 |
+
<td>%%SUCURI.ParseErrorLogsStatus%%</td>
|
103 |
+
<td class="td-with-button">
|
104 |
+
<form action="%%SUCURI.URL.Settings%%#settings-scanner" method="post">
|
105 |
+
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
|
106 |
+
<input type="hidden" name="sucuriscan_parse_errorlogs" value="%%SUCURI.ParseErrorLogsSwitchValue%%" />
|
107 |
+
<button type="submit" class="button-primary %%SUCURI.ParseErrorLogsSwitchCssClass%%">%%SUCURI.ParseErrorLogsSwitchText%%</button>
|
108 |
+
</form>
|
109 |
+
</td>
|
110 |
+
</tr>
|
111 |
+
|
112 |
<tr class="alternate">
|
113 |
<td>Last Scanning</td>
|
114 |
<td><span class="sucuriscan-monospace">%%SUCURI.ScanningRuntimeHuman%%</span></td>
|
148 |
</td>
|
149 |
</tr>
|
150 |
|
151 |
+
<tr>
|
152 |
+
<td>Error logs limit</td>
|
153 |
+
<td>%%SUCURI.ErrorLogsLimit%% last lines</td>
|
154 |
+
<td class="td-with-button">
|
155 |
+
<form action="%%SUCURI.URL.Settings%%#settings-scanner" method="post">
|
156 |
+
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
|
157 |
+
<input type="text" name="sucuriscan_errorlogs_limit" placeholder="Number of lines to analyze" class="input-text" />
|
158 |
+
<button type="submit" class="button-primary">Change</button>
|
159 |
+
</form>
|
160 |
+
</td>
|
161 |
+
</tr>
|
162 |
+
|
163 |
</tbody>
|
164 |
</table>
|
inc/tpl/settings-trustip.html.tpl
ADDED
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
<div id="poststuff">
|
3 |
+
<div class="postbox sucuriscan-border sucuriscan-table-description sucuriscan-trustip-form">
|
4 |
+
<h3>Trust IP Address</h3>
|
5 |
+
|
6 |
+
<div class="inside">
|
7 |
+
<p>
|
8 |
+
If you are working in a LAN <em>(Local Area Network)</em> you may want to
|
9 |
+
include the IP addresses of all the nodes in the subnet, this will force the
|
10 |
+
plugin to stop sending email notifications about actions executed from trusted
|
11 |
+
IP addresses. Use the CIDR <em>(Classless Inter Domain Routing)</em> format to
|
12 |
+
specify ranges of IP addresses <em>(only 8, 16, and 24)</em>.
|
13 |
+
</p>
|
14 |
+
|
15 |
+
<form action="%%SUCURI.URL.Settings%%#settings-trustip" method="POST">
|
16 |
+
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
|
17 |
+
<input type="text" name="sucuriscan_trust_ip" placeholder="e.g. 182.120.56.0/24" />
|
18 |
+
<input type="submit" value="Add Entry" class="button button-primary" />
|
19 |
+
</form>
|
20 |
+
</div>
|
21 |
+
</div>
|
22 |
+
</div>
|
23 |
+
|
24 |
+
<form action="%%SUCURI.URL.Settings%%#settings-trustip" method="post">
|
25 |
+
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
|
26 |
+
|
27 |
+
<table class="wp-list-table widefat sucuriscan-table sucuriscan-settings-trustip">
|
28 |
+
<thead>
|
29 |
+
<tr>
|
30 |
+
<th class="manage-column column-cb check-column">
|
31 |
+
<label class="screen-reader-text" for="cb-select-all-1">Select All</label>
|
32 |
+
<input id="cb-select-all-1" type="checkbox">
|
33 |
+
</th>
|
34 |
+
<th class="manage-column">IP Address</th>
|
35 |
+
<th class="manage-column">CIDR Format</th>
|
36 |
+
<th class="manage-column">Added At</th>
|
37 |
+
</tr>
|
38 |
+
</thead>
|
39 |
+
|
40 |
+
<tbody>
|
41 |
+
%%SUCURI.TrustedIPs.List%%
|
42 |
+
|
43 |
+
<tr class="sucuriscan-%%SUCURI.TrustedIPs.NoItems.Visibility%%">
|
44 |
+
<td colspan="4">
|
45 |
+
<em>List is empty.</em>
|
46 |
+
</td>
|
47 |
+
</tr>
|
48 |
+
</tbody>
|
49 |
+
|
50 |
+
<tfoot>
|
51 |
+
<tr>
|
52 |
+
<td colspan="4">
|
53 |
+
<button type="submit" class="button button-primary">Removed selected</button>
|
54 |
+
</td>
|
55 |
+
</tr>
|
56 |
+
</tfoot>
|
57 |
+
</table>
|
58 |
+
</form>
|
inc/tpl/settings-trustip.snippet.tpl
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
<tr class="%%SUCURI.TrustIP.CssClass%%">
|
3 |
+
<td class="check-column">
|
4 |
+
<input type="checkbox" name="sucuriscan_del_trust_ip[]" value="%%SUCURI.TrustIP.CacheKey%%" />
|
5 |
+
</td>
|
6 |
+
<td><span class="sucuriscan-monospace">%%SUCURI.TrustIP.RemoteAddr%%</span></td>
|
7 |
+
<td><span class="sucuriscan-monospace">%%SUCURI.TrustIP.CIDRFormat%%</span></td>
|
8 |
+
<td><span class="sucuriscan-monospace">%%SUCURI.TrustIP.AddedAt%%</span></td>
|
9 |
+
</tr>
|
inc/tpl/settings.html.tpl
CHANGED
@@ -16,6 +16,9 @@
|
|
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>
|
21 |
</li>
|
@@ -42,6 +45,10 @@
|
|
42 |
%%SUCURI.Settings.IgnoreRules%%
|
43 |
</div>
|
44 |
|
|
|
|
|
|
|
|
|
45 |
<div id="sucuriscan-settings-heartbeat">
|
46 |
%%SUCURI.Settings.Heartbeat%%
|
47 |
</div>
|
16 |
<li>
|
17 |
<a href="#" data-tabname="settings-ignorerules">Ignore Alerts</a>
|
18 |
</li>
|
19 |
+
<li>
|
20 |
+
<a href="#" data-tabname="settings-trustip">Trust IP</a>
|
21 |
+
</li>
|
22 |
<li>
|
23 |
<a href="#" data-tabname="settings-heartbeat">Heartbeat</a>
|
24 |
</li>
|
45 |
%%SUCURI.Settings.IgnoreRules%%
|
46 |
</div>
|
47 |
|
48 |
+
<div id="sucuriscan-settings-trustip">
|
49 |
+
%%SUCURI.Settings.TrustIP%%
|
50 |
+
</div>
|
51 |
+
|
52 |
<div id="sucuriscan-settings-heartbeat">
|
53 |
%%SUCURI.Settings.Heartbeat%%
|
54 |
</div>
|
readme.txt
CHANGED
@@ -3,8 +3,8 @@ Contributors: dd@sucuri.net
|
|
3 |
Donate Link: http://sucuri.net/
|
4 |
Tags: malware, security, firewall, scan, spam, virus, sucuri, protection,WordPress Security, Login Security,Security Auditing,File Integrity,htaccess,phishing,backdoors,SQL Injection, RFI, LFI, XSS, CSRF, website firewall, Website Security, Performance Optimization, Zero Day, Software Vulnerability, Exploits, Hacks, Attackers, Bad Actors, Reverse Proxy, Two Factor Security, Two Factor Authentication, Security Logs, HeatBleed Vulnerability, Website Protection, Bash Vulnerability, RevSlider Vulnerability, MailPoet Vulnerability, Malware Prevention, Website Firewall, Website AntiVirus, Security Response, Security Detection, Security Prevention
|
5 |
Requires at least:3.2
|
6 |
-
Stable tag:1.7.
|
7 |
-
Tested up to: 4.0
|
8 |
|
9 |
The Sucuri WordPress Security plugin is a security toolset for security integrity monitoring, malware detection and security hardening.
|
10 |
|
3 |
Donate Link: http://sucuri.net/
|
4 |
Tags: malware, security, firewall, scan, spam, virus, sucuri, protection,WordPress Security, Login Security,Security Auditing,File Integrity,htaccess,phishing,backdoors,SQL Injection, RFI, LFI, XSS, CSRF, website firewall, Website Security, Performance Optimization, Zero Day, Software Vulnerability, Exploits, Hacks, Attackers, Bad Actors, Reverse Proxy, Two Factor Security, Two Factor Authentication, Security Logs, HeatBleed Vulnerability, Website Protection, Bash Vulnerability, RevSlider Vulnerability, MailPoet Vulnerability, Malware Prevention, Website Firewall, Website AntiVirus, Security Response, Security Detection, Security Prevention
|
5 |
Requires at least:3.2
|
6 |
+
Stable tag:1.7.3
|
7 |
+
Tested up to: 4.0.1
|
8 |
|
9 |
The Sucuri WordPress Security plugin is a security toolset for security integrity monitoring, malware detection and security hardening.
|
10 |
|
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.
|
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.
|
70 |
|
71 |
/**
|
72 |
* The name of the Sucuri plugin main file.
|
@@ -128,6 +128,11 @@ define('SUCURISCAN_LASTLOGINS_USERSLIMIT', 25);
|
|
128 |
*/
|
129 |
define('SUCURISCAN_AUDITLOGS_PER_PAGE', 50);
|
130 |
|
|
|
|
|
|
|
|
|
|
|
131 |
/**
|
132 |
* The minimum quantity of seconds to wait before each filesystem scan.
|
133 |
*/
|
@@ -240,6 +245,9 @@ if( defined('SUCURISCAN') ){
|
|
240 |
'false' => 'Stop peer\'s cert verification',
|
241 |
);
|
242 |
|
|
|
|
|
|
|
243 |
/**
|
244 |
* Remove the WordPress generator meta-tag from the source code.
|
245 |
*/
|
@@ -454,9 +462,24 @@ class SucuriScan {
|
|
454 |
* @return string The full filesystem path including the directory specified.
|
455 |
*/
|
456 |
public static function datastore_folder_path( $path='' ){
|
457 |
-
$
|
458 |
-
|
459 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
460 |
|
461 |
return $wp_filepath;
|
462 |
}
|
@@ -569,13 +592,13 @@ class SucuriScan {
|
|
569 |
|
570 |
if( self::is_behind_cloudproxy() ){
|
571 |
$alternatives = array(
|
|
|
572 |
'HTTP_X_REAL_IP',
|
573 |
'HTTP_CLIENT_IP',
|
574 |
'HTTP_X_FORWARDED_FOR',
|
575 |
'HTTP_X_FORWARDED',
|
576 |
'HTTP_FORWARDED_FOR',
|
577 |
'HTTP_FORWARDED',
|
578 |
-
'HTTP_X_SUCURI_CLIENTIP',
|
579 |
'SUCURI_RIP',
|
580 |
'REMOTE_ADDR',
|
581 |
);
|
@@ -664,6 +687,18 @@ class SucuriScan {
|
|
664 |
$host_by_name = @gethostbyaddr($host_by_addr);
|
665 |
$status = (bool) preg_match('/^cloudproxy[0-9]+\.sucuri\.net$/', $host_by_name);
|
666 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
667 |
if( $verbose ){
|
668 |
return array(
|
669 |
'http_host' => $http_host,
|
@@ -830,6 +865,44 @@ class SucuriScan {
|
|
830 |
return FALSE;
|
831 |
}
|
832 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
833 |
/**
|
834 |
* Validate email address.
|
835 |
*
|
@@ -961,6 +1034,30 @@ class SucuriScan {
|
|
961 |
}
|
962 |
}
|
963 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
964 |
}
|
965 |
|
966 |
/**
|
@@ -1069,6 +1166,15 @@ class SucuriScanRequest extends SucuriScan {
|
|
1069 |
*/
|
1070 |
class SucuriScanFileInfo extends SucuriScan {
|
1071 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1072 |
/**
|
1073 |
* Whether the list of files that can be ignored from the filesystem scan will
|
1074 |
* be used to return the directory tree, this should be disabled when scanning a
|
@@ -1117,14 +1223,13 @@ class SucuriScanFileInfo extends SucuriScan {
|
|
1117 |
* on some rules defined by the developer.
|
1118 |
*
|
1119 |
* @param string $directory Parent directory where the filesystem scan will start.
|
1120 |
-
* @param string $scan_with Set the tool used to scan the filesystem, SplFileInfo by default.
|
1121 |
* @param boolean $as_array Whether the result of the operation will be returned as an array or string.
|
1122 |
* @return array List of files in the main and subdirectories of the folder specified.
|
1123 |
*/
|
1124 |
-
public function get_directory_tree_md5( $directory='', $
|
1125 |
$project_signatures = '';
|
1126 |
$abs_path = rtrim( ABSPATH, '/' );
|
1127 |
-
$files = $this->get_directory_tree($directory
|
1128 |
|
1129 |
if( $as_array ){
|
1130 |
$project_signatures = array();
|
@@ -1168,20 +1273,24 @@ class SucuriScanFileInfo extends SucuriScan {
|
|
1168 |
* on some rules defined by the developer.
|
1169 |
*
|
1170 |
* @param string $directory Parent directory where the filesystem scan will start.
|
1171 |
-
* @param string $scan_with Set the tool used to scan the filesystem, SplFileInfo by default.
|
1172 |
* @return array List of files in the main and subdirectories of the folder specified.
|
1173 |
*/
|
1174 |
-
public function get_directory_tree($directory=''
|
1175 |
if( file_exists($directory) && is_dir($directory) ){
|
1176 |
$tree = array();
|
1177 |
-
$this->ignored_directories = SucuriScanFSScanner::get_ignored_directories();
|
1178 |
|
1179 |
-
|
|
|
|
|
|
|
|
|
|
|
1180 |
case 'spl':
|
1181 |
if( $this->is_spl_available() ){
|
1182 |
$tree = $this->get_directory_tree_with_spl($directory);
|
1183 |
} else {
|
1184 |
-
$
|
|
|
1185 |
}
|
1186 |
break;
|
1187 |
|
@@ -1194,7 +1303,8 @@ class SucuriScanFileInfo extends SucuriScan {
|
|
1194 |
break;
|
1195 |
|
1196 |
default:
|
1197 |
-
$
|
|
|
1198 |
break;
|
1199 |
}
|
1200 |
|
@@ -1321,14 +1431,18 @@ class SucuriScanFileInfo extends SucuriScan {
|
|
1321 |
foreach( $files_found as $filepath ){
|
1322 |
$filepath = realpath($filepath);
|
1323 |
$directory = dirname($filepath);
|
1324 |
-
$
|
|
|
1325 |
|
1326 |
if( is_dir($filepath) ){
|
1327 |
if( $this->ignore_folderpath($directory, $filename) ){ continue; }
|
1328 |
|
1329 |
if( $this->run_recursively ){
|
1330 |
-
$sub_files = $this->
|
1331 |
-
|
|
|
|
|
|
|
1332 |
}
|
1333 |
} else {
|
1334 |
if( $this->ignore_filepath($filename) ){ continue; }
|
@@ -1361,7 +1475,10 @@ class SucuriScanFileInfo extends SucuriScan {
|
|
1361 |
|
1362 |
if( $this->run_recursively ){
|
1363 |
$sub_files = $this->get_directory_tree_with_opendir($filepath);
|
1364 |
-
|
|
|
|
|
|
|
1365 |
}
|
1366 |
} else {
|
1367 |
if( $this->ignore_filepath($filename) ){ continue; }
|
@@ -1443,11 +1560,16 @@ class SucuriScanFileInfo extends SucuriScan {
|
|
1443 |
$dir_tree = $this->get_directory_tree($dir_tree);
|
1444 |
}
|
1445 |
|
1446 |
-
|
1447 |
-
$
|
|
|
1448 |
|
1449 |
-
|
1450 |
-
|
|
|
|
|
|
|
|
|
1451 |
}
|
1452 |
}
|
1453 |
|
@@ -1516,6 +1638,53 @@ class SucuriScanFileInfo extends SucuriScan {
|
|
1516 |
return @file( $filepath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES );
|
1517 |
}
|
1518 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1519 |
}
|
1520 |
|
1521 |
/**
|
@@ -1986,12 +2155,16 @@ class SucuriScanOption extends SucuriScanRequest {
|
|
1986 |
$defaults = array(
|
1987 |
'sucuriscan_api_key' => FALSE,
|
1988 |
'sucuriscan_account' => '',
|
|
|
1989 |
'sucuriscan_fs_scanner' => 'enabled',
|
1990 |
'sucuriscan_scan_frequency' => 'hourly',
|
1991 |
'sucuriscan_scan_interface' => 'spl',
|
1992 |
'sucuriscan_scan_modfiles' => 'enabled',
|
1993 |
'sucuriscan_scan_checksums' => 'enabled',
|
1994 |
'sucuriscan_scan_errorlogs' => 'enabled',
|
|
|
|
|
|
|
1995 |
'sucuriscan_runtime' => 0,
|
1996 |
'sucuriscan_lastlogin_redirection' => 'enabled',
|
1997 |
'sucuriscan_notify_to' => '',
|
@@ -2004,6 +2177,7 @@ class SucuriScanOption extends SucuriScanRequest {
|
|
2004 |
'sucuriscan_notify_post_publication' => 'enabled',
|
2005 |
'sucuriscan_notify_theme_editor' => 'enabled',
|
2006 |
'sucuriscan_maximum_failed_logins' => 30,
|
|
|
2007 |
'sucuriscan_ignored_events' => '',
|
2008 |
'sucuriscan_verify_ssl_cert' => 'true',
|
2009 |
'sucuriscan_request_timeout' => 90,
|
@@ -2310,10 +2484,8 @@ class SucuriScanOption extends SucuriScanRequest {
|
|
2310 |
|
2311 |
// Encode (old) serialized data into JSON.
|
2312 |
if( self::is_serialized($post_types) ){
|
2313 |
-
var_dump($post_types);
|
2314 |
$post_types_arr = @unserialize($post_types);
|
2315 |
$post_types_fix = json_encode($post_types_arr);
|
2316 |
-
echo 'fixed';
|
2317 |
self::update_option( ':ignored_events', $post_types_fix );
|
2318 |
|
2319 |
return $post_types_arr;
|
@@ -2542,8 +2714,8 @@ class SucuriScanEvent extends SucuriScan {
|
|
2542 |
self::report_site_version();
|
2543 |
|
2544 |
$sucuri_fileinfo = new SucuriScanFileInfo();
|
2545 |
-
$scan_interface = SucuriScanOption::get_option(':scan_interface');
|
2546 |
-
$signatures = $sucuri_fileinfo->get_directory_tree_md5(ABSPATH
|
2547 |
|
2548 |
if( $signatures ){
|
2549 |
$hashes_sent = SucuriScanAPI::send_hashes( $signatures );
|
@@ -2631,18 +2803,22 @@ class SucuriScanEvent extends SucuriScan {
|
|
2631 |
$email = SucuriScanOption::get_option(':notify_to');
|
2632 |
$email_params = array();
|
2633 |
|
|
|
|
|
|
|
|
|
2634 |
if( $notify == 'enabled' ){
|
2635 |
if( $event == 'post_publication' ){
|
2636 |
$event = 'post_update';
|
2637 |
}
|
2638 |
|
2639 |
elseif( $event == 'failed_login' ){
|
2640 |
-
$content .=
|
2641 |
-
|
2642 |
-
|
2643 |
-
|
2644 |
-
|
2645 |
-
|
2646 |
}
|
2647 |
|
2648 |
// Send a notification even if the limit of emails per hour was reached.
|
@@ -2659,6 +2835,58 @@ class SucuriScanEvent extends SucuriScan {
|
|
2659 |
return FALSE;
|
2660 |
}
|
2661 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2662 |
/**
|
2663 |
* Generate and set a new password for a specific user not in session.
|
2664 |
*
|
@@ -3011,12 +3239,18 @@ class SucuriScanHook extends SucuriScanEvent {
|
|
3011 |
public static function hook_wp_login_failed( $title='' ){
|
3012 |
if( empty($title) ){ $title = 'Unknown'; }
|
3013 |
|
3014 |
-
$
|
|
|
|
|
|
|
|
|
|
|
|
|
3015 |
self::report_event( 2, 'core', $message );
|
3016 |
self::notify_event( 'failed_login', $message );
|
3017 |
|
3018 |
// Log the failed login in the internal datastore for future reports.
|
3019 |
-
$logged = sucuriscan_log_failed_login($title);
|
3020 |
|
3021 |
// Check if the quantity of failed logins will be considered as a brute-force attack.
|
3022 |
if( $logged ){
|
@@ -3974,9 +4208,10 @@ class SucuriScanAPI extends SucuriScanOption {
|
|
3974 |
*/
|
3975 |
public static function get_official_checksums( $version=0 ){
|
3976 |
$url = 'http://api.wordpress.org/core/checksums/1.0/';
|
|
|
3977 |
$response = self::api_call( $url, 'GET', array(
|
3978 |
'version' => $version,
|
3979 |
-
'locale' =>
|
3980 |
));
|
3981 |
|
3982 |
if( $response ){
|
@@ -4027,8 +4262,8 @@ class SucuriScanAPI extends SucuriScanOption {
|
|
4027 |
|
4028 |
// Get the plugin's basic information from WordPress transient data.
|
4029 |
$plugins = get_plugins();
|
4030 |
-
$pattern = '/^http
|
4031 |
-
$wp_market = '
|
4032 |
|
4033 |
// Loop through each plugin data and complement its information with more attributes.
|
4034 |
foreach( $plugins as $plugin_path => $plugin_data ){
|
@@ -4043,7 +4278,7 @@ class SucuriScanAPI extends SucuriScanOption {
|
|
4043 |
&& preg_match($pattern, $plugin_data['PluginURI'], $match)
|
4044 |
){
|
4045 |
$repository = $match[0];
|
4046 |
-
$repository_name = $match[
|
4047 |
$is_free_plugin = TRUE;
|
4048 |
}
|
4049 |
|
@@ -4692,6 +4927,18 @@ class SucuriScanFSScanner extends SucuriScan {
|
|
4692 |
return FALSE;
|
4693 |
}
|
4694 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4695 |
/**
|
4696 |
* Add a new directory path to the list of ignored paths.
|
4697 |
*
|
@@ -4801,6 +5048,7 @@ class SucuriScanFSScanner extends SucuriScan {
|
|
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 ){
|
@@ -4810,6 +5058,77 @@ class SucuriScanFSScanner extends SucuriScan {
|
|
4810 |
return $response;
|
4811 |
}
|
4812 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4813 |
}
|
4814 |
|
4815 |
/**
|
@@ -4988,13 +5307,9 @@ class SucuriScanInterface {
|
|
4988 |
* @return void
|
4989 |
*/
|
4990 |
public static function initialize(){
|
4991 |
-
if(
|
4992 |
-
isset($_SERVER['HTTP_X_FORWARDED_FOR'])
|
4993 |
-
&& SucuriScan::is_valid_ip($_SERVER['HTTP_X_FORWARDED_FOR'])
|
4994 |
-
&& SucuriScan::is_behind_cloudproxy()
|
4995 |
-
){
|
4996 |
$_SERVER['SUCURIREAL_REMOTE_ADDR'] = $_SERVER['REMOTE_ADDR'];
|
4997 |
-
$_SERVER['REMOTE_ADDR'] =
|
4998 |
}
|
4999 |
}
|
5000 |
|
@@ -5213,6 +5528,7 @@ class SucuriScanInterface {
|
|
5213 |
public static function setup_notice(){
|
5214 |
if(
|
5215 |
current_user_can('manage_options')
|
|
|
5216 |
&& !SucuriScanAPI::get_plugin_key()
|
5217 |
&& SucuriScanRequest::post(':plugin_api_key') === FALSE
|
5218 |
&& SucuriScanRequest::post(':recover_key') === FALSE
|
@@ -6563,15 +6879,14 @@ function sucuriscan_harden_phpversion(){
|
|
6563 |
*/
|
6564 |
function sucuriscan_cloudproxy_enabled(){
|
6565 |
$btn_string = '';
|
6566 |
-
$
|
6567 |
-
$proxy_info = SucuriScan::is_behind_cloudproxy($verbosity);
|
6568 |
$status = 1;
|
6569 |
|
6570 |
$description = 'A WAF is a protection layer for your web site, blocking all sort of attacks (brute force attempts, '
|
6571 |
. 'DDoS, SQL injections, etc) and helping it remain malware and blacklist free. This test checks if your site is '
|
6572 |
. 'using <a href="http://cloudproxy.sucuri.net/" target="_blank">Sucuri\'s CloudProxy WAF</a> to protect your site.';
|
6573 |
|
6574 |
-
if( $proxy_info
|
6575 |
$status = 0;
|
6576 |
$btn_string = '<a href="http://cloudproxy.sucuri.net/" target="_blank" class="button button-primary">Harden</a>';
|
6577 |
}
|
@@ -6976,13 +7291,14 @@ function sucuriscan_get_integrity_tree( $dir='./', $recursive=FALSE ){
|
|
6976 |
$sucuri_fileinfo->ignore_files = FALSE;
|
6977 |
$sucuri_fileinfo->ignore_directories = FALSE;
|
6978 |
$sucuri_fileinfo->run_recursively = $recursive;
|
6979 |
-
$
|
|
|
6980 |
|
6981 |
-
if(
|
6982 |
-
|
6983 |
}
|
6984 |
|
6985 |
-
return
|
6986 |
}
|
6987 |
|
6988 |
/**
|
@@ -7055,10 +7371,16 @@ function sucuriscan_auditlogs(){
|
|
7055 |
$template_variables['AuditLogs.NoItemsVisibility'] = 'hidden';
|
7056 |
|
7057 |
if( $total_items > 0 ){
|
|
|
|
|
|
|
|
|
|
|
|
|
7058 |
$template_variables['AuditLogs.PaginationVisibility'] = 'visible';
|
7059 |
$template_variables['AuditLogs.PaginationLinks'] = SucuriScanTemplate::get_pagination(
|
7060 |
'%%SUCURI.URL.Home%%',
|
7061 |
-
$max_per_page *
|
7062 |
$max_per_page
|
7063 |
);
|
7064 |
}
|
@@ -7339,7 +7661,7 @@ function sucuriscan_modified_files(){
|
|
7339 |
// Search modified files among the project's files.
|
7340 |
$content_hashes = sucuriscan_get_integrity_tree( ABSPATH.'wp-content', true );
|
7341 |
|
7342 |
-
if( $content_hashes ){
|
7343 |
$template_variables['ModifiedFiles.Days'] = $back_days;
|
7344 |
$back_days = current_time('timestamp') - ( $back_days * 86400);
|
7345 |
$counter = 0;
|
@@ -8080,7 +8402,9 @@ if( !function_exists('sucuri_get_user_lastlogin') ){
|
|
8080 |
|
8081 |
$lastlogin_message = sprintf(
|
8082 |
'Last time you logged in was at <code>%s</code> from <code>%s</code> - <code>%s</code>',
|
8083 |
-
|
|
|
|
|
8084 |
);
|
8085 |
$lastlogin_message .= chr(32).'(<a href="'.SucuriScanTemplate::get_url('lastlogins').'">view all logs</a>)';
|
8086 |
SucuriScanInterface::info( $lastlogin_message );
|
@@ -8302,22 +8626,54 @@ function sucuriscan_failed_logins_panel(){
|
|
8302 |
'FailedLogins.MaxFailedLogins' => 0,
|
8303 |
'FailedLogins.NoItemsVisibility' => 'visible',
|
8304 |
'FailedLogins.WarningVisibility' => 'visible',
|
|
|
8305 |
);
|
8306 |
|
8307 |
$max_failed_logins = SucuriScanOption::get_option(':maximum_failed_logins');
|
8308 |
$notify_bruteforce_attack = SucuriScanOption::get_option(':notify_bruteforce_attack');
|
8309 |
$failed_logins = sucuriscan_get_failed_logins();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8310 |
|
8311 |
if( $failed_logins ){
|
8312 |
$counter = 0;
|
8313 |
|
8314 |
foreach( $failed_logins['entries'] as $login_data ){
|
8315 |
$css_class = ( $counter % 2 == 0 ) ? '' : 'alternate';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8316 |
|
8317 |
$template_variables['FailedLogins.List'] .= SucuriScanTemplate::get_snippet('lastlogins-failedlogins', array(
|
8318 |
'FailedLogins.CssClass' => $css_class,
|
8319 |
'FailedLogins.Num' => ($counter + 1),
|
8320 |
'FailedLogins.Username' => SucuriScan::escape($login_data['user_login']),
|
|
|
8321 |
'FailedLogins.RemoteAddr' => SucuriScan::escape($login_data['remote_addr']),
|
8322 |
'FailedLogins.Datetime' => SucuriScan::datetime($login_data['attempt_time']),
|
8323 |
'FailedLogins.UserAgent' => SucuriScan::escape($login_data['user_agent']),
|
@@ -8337,9 +8693,22 @@ function sucuriscan_failed_logins_panel(){
|
|
8337 |
$template_variables['FailedLogins.WarningVisibility'] = 'hidden';
|
8338 |
}
|
8339 |
|
|
|
|
|
|
|
|
|
8340 |
return SucuriScanTemplate::get_section('lastlogins-failedlogins', $template_variables);
|
8341 |
}
|
8342 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8343 |
/**
|
8344 |
* Find the full path of the file where the information of the failed logins
|
8345 |
* will be stored, it will be created automatically if does not exists (and if
|
@@ -8348,11 +8717,13 @@ function sucuriscan_failed_logins_panel(){
|
|
8348 |
*
|
8349 |
* @see sucuriscan_reset_failed_logins()
|
8350 |
*
|
8351 |
-
* @param boolean $
|
8352 |
-
* @
|
|
|
8353 |
*/
|
8354 |
-
function sucuriscan_failed_logins_datastore_path( $reset=
|
8355 |
-
$
|
|
|
8356 |
$default_content = sucuriscan_failed_logins_default_content();
|
8357 |
|
8358 |
// Create the file if it does not exists.
|
@@ -8390,10 +8761,11 @@ function sucuriscan_failed_logins_default_content(){
|
|
8390 |
* with the report) or reset the file after considering it a normal behavior of
|
8391 |
* the site.
|
8392 |
*
|
8393 |
-
* @
|
|
|
8394 |
*/
|
8395 |
-
function sucuriscan_get_failed_logins(){
|
8396 |
-
$datastore_path = sucuriscan_failed_logins_datastore_path();
|
8397 |
$default_content = sucuriscan_failed_logins_default_content();
|
8398 |
$default_content_n = substr_count($default_content, "\n");
|
8399 |
|
@@ -8419,6 +8791,10 @@ function sucuriscan_get_failed_logins(){
|
|
8419 |
$login_data['user_agent'] = 'Unknown';
|
8420 |
}
|
8421 |
|
|
|
|
|
|
|
|
|
8422 |
$failed_logins['entries'][] = $login_data;
|
8423 |
$failed_logins['count'] += 1;
|
8424 |
}
|
@@ -8445,15 +8821,22 @@ function sucuriscan_get_failed_logins(){
|
|
8445 |
* this entry will contain the username, timestamp of the login attempt, remote
|
8446 |
* address of the computer sending the request, and the user-agent.
|
8447 |
*
|
8448 |
-
* @param string $user_login
|
8449 |
-
* @
|
|
|
8450 |
*/
|
8451 |
-
function sucuriscan_log_failed_login( $user_login='' ){
|
8452 |
$datastore_path = sucuriscan_failed_logins_datastore_path();
|
8453 |
|
|
|
|
|
|
|
|
|
|
|
8454 |
if( $datastore_path ){
|
8455 |
$login_data = json_encode(array(
|
8456 |
'user_login' => $user_login,
|
|
|
8457 |
'attempt_time' => time(),
|
8458 |
'remote_addr' => SucuriScan::get_remote_addr(),
|
8459 |
'user_agent' => SucuriScan::get_user_agent(),
|
@@ -8479,6 +8862,7 @@ function sucuriscan_log_failed_login( $user_login='' ){
|
|
8479 |
function sucuriscan_report_failed_logins( $failed_logins=array() ){
|
8480 |
if( $failed_logins && $failed_logins['count'] > 0 ){
|
8481 |
$prettify_mails = SucuriScanMail::prettify_mails();
|
|
|
8482 |
$mail_content = '';
|
8483 |
|
8484 |
if( $prettify_mails ){
|
@@ -8488,6 +8872,11 @@ function sucuriscan_report_failed_logins( $failed_logins=array() ){
|
|
8488 |
$table_html .= '<thead>';
|
8489 |
$table_html .= '<tr>';
|
8490 |
$table_html .= '<th>Username</th>';
|
|
|
|
|
|
|
|
|
|
|
8491 |
$table_html .= '<th>IP Address</th>';
|
8492 |
$table_html .= '<th>Attempt Timestamp</th>';
|
8493 |
$table_html .= '<th>Attempt Date/Time</th>';
|
@@ -8501,6 +8890,11 @@ function sucuriscan_report_failed_logins( $failed_logins=array() ){
|
|
8501 |
if( $prettify_mails ){
|
8502 |
$table_html .= '<tr>';
|
8503 |
$table_html .= '<td>' . esc_attr($login_data['user_login']) . '</td>';
|
|
|
|
|
|
|
|
|
|
|
8504 |
$table_html .= '<td>' . esc_attr($login_data['remote_addr']) . '</td>';
|
8505 |
$table_html .= '<td>' . $login_data['attempt_time'] . '</td>';
|
8506 |
$table_html .= '<td>' . $login_data['attempt_date'] . '</td>';
|
@@ -8508,6 +8902,11 @@ function sucuriscan_report_failed_logins( $failed_logins=array() ){
|
|
8508 |
} else {
|
8509 |
$mail_content .= "\n";
|
8510 |
$mail_content .= 'Username: ' . $login_data['user_login'] . "\n";
|
|
|
|
|
|
|
|
|
|
|
8511 |
$mail_content .= 'IP Address: ' . $login_data['remote_addr'] . "\n";
|
8512 |
$mail_content .= 'Attempt Timestamp: ' . $login_data['attempt_time'] . "\n";
|
8513 |
$mail_content .= 'Attempt Date/Time: ' . $login_data['attempt_date'] . "\n";
|
@@ -8539,7 +8938,19 @@ function sucuriscan_report_failed_logins( $failed_logins=array() ){
|
|
8539 |
* @return boolean Whether the datastore file was resetted or not.
|
8540 |
*/
|
8541 |
function sucuriscan_reset_failed_logins(){
|
8542 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8543 |
}
|
8544 |
|
8545 |
/**
|
@@ -8557,6 +8968,7 @@ function sucuriscan_settings_page(){
|
|
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(),
|
8561 |
);
|
8562 |
|
@@ -8628,6 +9040,14 @@ function sucuriscan_settings_form_submissions( $page_nonce=NULL ){
|
|
8628 |
SucuriScanInterface::info( 'Filesystem scanner for file integrity was <code>' . $action_d . '</code>' );
|
8629 |
}
|
8630 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8631 |
// Enable or disable the filesystem scanner for error logs.
|
8632 |
if( $scan_errorlogs = SucuriScanRequest::post(':scan_errorlogs', '(en|dis)able') ){
|
8633 |
$action_d = $scan_errorlogs . 'd';
|
@@ -8636,6 +9056,28 @@ function sucuriscan_settings_form_submissions( $page_nonce=NULL ){
|
|
8636 |
SucuriScanInterface::info( 'Filesystem scanner for error logs was <code>' . $action_d . '</code>' );
|
8637 |
}
|
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) ){
|
@@ -8723,6 +9165,44 @@ function sucuriscan_settings_form_submissions( $page_nonce=NULL ){
|
|
8723 |
SucuriScanInterface::info( 'API request timeout set to <code>' . $request_timeout . '</code> seconds.' );
|
8724 |
}
|
8725 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8726 |
// Update the notification settings.
|
8727 |
if( SucuriScanRequest::post(':save_notification_settings') !== FALSE ){
|
8728 |
$options_updated_counter = 0;
|
@@ -8806,6 +9286,38 @@ function sucuriscan_settings_form_submissions( $page_nonce=NULL ){
|
|
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();
|
@@ -8919,6 +9431,9 @@ function sucuriscan_settings_general(){
|
|
8919 |
'VerifySSLCert' => 'Undefined',
|
8920 |
'VerifySSLCertOptions' => $verify_ssl_cert_options,
|
8921 |
'RequestTimeout' => SucuriScanOption::get_option(':request_timeout') . ' seconds',
|
|
|
|
|
|
|
8922 |
'ModalWhenAPIRegistered' => $api_registered_modal,
|
8923 |
);
|
8924 |
|
@@ -8934,6 +9449,14 @@ function sucuriscan_settings_general(){
|
|
8934 |
$template_variables['VerifySSLCert'] = $sucuriscan_verify_ssl_cert[$verify_ssl_cert];
|
8935 |
}
|
8936 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8937 |
return SucuriScanTemplate::get_section('settings-general', $template_variables);
|
8938 |
}
|
8939 |
|
@@ -8954,6 +9477,9 @@ function sucuriscan_settings_scanner(){
|
|
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.
|
@@ -8976,11 +9502,21 @@ function sucuriscan_settings_scanner(){
|
|
8976 |
'ScanChecksumsSwitchText' => 'Disable',
|
8977 |
'ScanChecksumsSwitchValue' => 'disable',
|
8978 |
'ScanChecksumsSwitchCssClass' => 'button-danger',
|
|
|
|
|
|
|
|
|
|
|
8979 |
/* Scan error logs. */
|
8980 |
'ScanErrorlogsStatus' => 'Enabled',
|
8981 |
'ScanErrorlogsSwitchText' => 'Disable',
|
8982 |
'ScanErrorlogsSwitchValue' => 'disable',
|
8983 |
'ScanErrorlogsSwitchCssClass' => 'button-danger',
|
|
|
|
|
|
|
|
|
|
|
8984 |
/* Filsystem scanning frequency. */
|
8985 |
'ScanningFrequency' => 'Undefined',
|
8986 |
'ScanningFrequencyOptions' => $scan_freq_options,
|
@@ -8988,6 +9524,7 @@ function sucuriscan_settings_scanner(){
|
|
8988 |
'ScanningInterfaceOptions' => $scan_interface_options,
|
8989 |
/* Filesystem scanning runtime. */
|
8990 |
'ScanningRuntimeHuman' => $runtime_scan_human,
|
|
|
8991 |
);
|
8992 |
|
8993 |
if( $fs_scanner == 'disabled' ){
|
@@ -9011,6 +9548,13 @@ function sucuriscan_settings_scanner(){
|
|
9011 |
$template_variables['ScanChecksumsSwitchCssClass'] = 'button-success';
|
9012 |
}
|
9013 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
9014 |
if( $scan_errorlogs == 'disabled' ){
|
9015 |
$template_variables['ScanErrorlogsStatus'] = 'Disabled';
|
9016 |
$template_variables['ScanErrorlogsSwitchText'] = 'Enable';
|
@@ -9018,6 +9562,13 @@ function sucuriscan_settings_scanner(){
|
|
9018 |
$template_variables['ScanErrorlogsSwitchCssClass'] = 'button-success';
|
9019 |
}
|
9020 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
9021 |
if( array_key_exists($scan_freq, $sucuriscan_schedule_allowed) ){
|
9022 |
$template_variables['ScanningFrequency'] = $sucuriscan_schedule_allowed[$scan_freq];
|
9023 |
}
|
@@ -9118,6 +9669,48 @@ function sucuriscan_settings_ignore_rules(){
|
|
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 |
*
|
@@ -9126,45 +9719,62 @@ function sucuriscan_settings_ignore_rules(){
|
|
9126 |
function sucuriscan_settings_ignorescanning(){
|
9127 |
$template_variables = array(
|
9128 |
'IgnoreScanning.ResourceList' => '',
|
|
|
|
|
9129 |
);
|
9130 |
|
9131 |
-
$
|
9132 |
-
$counter = 0;
|
9133 |
|
9134 |
-
|
9135 |
-
|
9136 |
-
|
9137 |
-
|
9138 |
-
'IgnoreScanning.CssClass' => '',
|
9139 |
-
'IgnoreScanning.Directory' => '',
|
9140 |
-
'IgnoreScanning.DirectoryPath' => '',
|
9141 |
-
'IgnoreScanning.IgnoredAt' => '',
|
9142 |
-
'IgnoreScanning.IgnoredAtText' => 'ok',
|
9143 |
-
'IgnoreScanning.IgnoredCssClass' => 'success',
|
9144 |
-
);
|
9145 |
|
9146 |
-
|
9147 |
-
|
9148 |
-
|
9149 |
-
|
9150 |
-
|
9151 |
-
$snippet_data['IgnoreScanning.IgnoredAtText'] = 'ignored';
|
9152 |
-
$snippet_data['IgnoreScanning.IgnoredCssClass'] = 'warning';
|
9153 |
-
}
|
9154 |
|
9155 |
-
|
9156 |
-
|
9157 |
-
$
|
9158 |
-
$snippet_data
|
9159 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
9160 |
|
9161 |
-
|
9162 |
-
|
9163 |
-
|
9164 |
-
|
9165 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
9166 |
}
|
9167 |
}
|
|
|
|
|
|
|
|
|
9168 |
}
|
9169 |
|
9170 |
return SucuriScanTemplate::get_section('settings-ignorescanning', $template_variables);
|
@@ -9251,6 +9861,7 @@ function sucuriscan_infosys_page(){
|
|
9251 |
'Cronjobs' => sucuriscan_show_cronjobs(),
|
9252 |
'HTAccessIntegrity' => sucuriscan_infosys_htaccess(),
|
9253 |
'WordpressConfig' => sucuriscan_infosys_wpconfig(),
|
|
|
9254 |
);
|
9255 |
|
9256 |
echo SucuriScanTemplate::get_template('infosys', $template_variables);
|
@@ -9368,19 +9979,23 @@ function sucuriscan_infosys_wpconfig(){
|
|
9368 |
|
9369 |
// Parse the main configuration file and look for constants and global variables.
|
9370 |
foreach( (array) $wp_config_content as $line ){
|
|
|
|
|
|
|
9371 |
// Detect PHP constants even if the line if indented.
|
9372 |
-
|
9373 |
-
$line = preg_replace('
|
9374 |
$line_parts = explode(',', $line, 2);
|
9375 |
}
|
9376 |
|
9377 |
// Detect global variables like the database table prefix.
|
9378 |
-
|
|
|
9379 |
$line_parts = explode('=', $line, 2);
|
9380 |
}
|
9381 |
|
9382 |
// Ignore other lines.
|
9383 |
-
else{ continue; }
|
9384 |
|
9385 |
// Clean and append the rule to the wp_config_rules variable.
|
9386 |
if( isset($line_parts) && count($line_parts)==2 ){
|
@@ -9541,6 +10156,59 @@ function sucuriscan_infosys_form_submissions(){
|
|
9541 |
}
|
9542 |
}
|
9543 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
9544 |
/**
|
9545 |
* Gather information from the server, database engine, and PHP interpreter.
|
9546 |
*
|
@@ -9601,6 +10269,7 @@ function sucuriscan_server_info(){
|
|
9601 |
|
9602 |
$field_names = array(
|
9603 |
'safe_mode',
|
|
|
9604 |
'allow_url_fopen',
|
9605 |
'memory_limit',
|
9606 |
'upload_max_filesize',
|
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.3
|
8 |
Author URI: http://sucuri.net
|
9 |
*/
|
10 |
|
66 |
/**
|
67 |
* Current version of the plugin's code.
|
68 |
*/
|
69 |
+
define('SUCURISCAN_VERSION', '1.7.3');
|
70 |
|
71 |
/**
|
72 |
* The name of the Sucuri plugin main file.
|
128 |
*/
|
129 |
define('SUCURISCAN_AUDITLOGS_PER_PAGE', 50);
|
130 |
|
131 |
+
/**
|
132 |
+
* The maximum quantity of buttons in the paginations.
|
133 |
+
*/
|
134 |
+
define('SUCURISCAN_MAX_PAGINATION_BUTTONS', 20);
|
135 |
+
|
136 |
/**
|
137 |
* The minimum quantity of seconds to wait before each filesystem scan.
|
138 |
*/
|
245 |
'false' => 'Stop peer\'s cert verification',
|
246 |
);
|
247 |
|
248 |
+
$sucuriscan_no_notices_in = array(
|
249 |
+
);
|
250 |
+
|
251 |
/**
|
252 |
* Remove the WordPress generator meta-tag from the source code.
|
253 |
*/
|
462 |
* @return string The full filesystem path including the directory specified.
|
463 |
*/
|
464 |
public static function datastore_folder_path( $path='' ){
|
465 |
+
$datastore_path = SucuriScanOption::get_option(':datastore_path');
|
466 |
+
|
467 |
+
// Use the uploads folder by default.
|
468 |
+
if ( empty($datastore_path) ) {
|
469 |
+
if ( function_exists('wp_upload_dir') ) {
|
470 |
+
$wp_dir_array = wp_upload_dir();
|
471 |
+
$wp_dir_array['basedir'] = untrailingslashit($wp_dir_array['basedir']);
|
472 |
+
$datastore_path = $wp_dir_array['basedir'] . '/sucuri';
|
473 |
+
}
|
474 |
+
|
475 |
+
else {
|
476 |
+
$datastore_path = rtrim(ABSPATH, '/') . '/wp-content/uploads/sucuri';
|
477 |
+
}
|
478 |
+
|
479 |
+
SucuriScanOption::update_option( ':datastore_path', $datastore_path );
|
480 |
+
}
|
481 |
+
|
482 |
+
$wp_filepath = rtrim($datastore_path, '/') . '/' . $path;
|
483 |
|
484 |
return $wp_filepath;
|
485 |
}
|
592 |
|
593 |
if( self::is_behind_cloudproxy() ){
|
594 |
$alternatives = array(
|
595 |
+
'HTTP_X_SUCURI_CLIENTIP',
|
596 |
'HTTP_X_REAL_IP',
|
597 |
'HTTP_CLIENT_IP',
|
598 |
'HTTP_X_FORWARDED_FOR',
|
599 |
'HTTP_X_FORWARDED',
|
600 |
'HTTP_FORWARDED_FOR',
|
601 |
'HTTP_FORWARDED',
|
|
|
602 |
'SUCURI_RIP',
|
603 |
'REMOTE_ADDR',
|
604 |
);
|
687 |
$host_by_name = @gethostbyaddr($host_by_addr);
|
688 |
$status = (bool) preg_match('/^cloudproxy[0-9]+\.sucuri\.net$/', $host_by_name);
|
689 |
|
690 |
+
/*
|
691 |
+
* If the DNS reversion failed but the CloudProxy API key is set, then consider
|
692 |
+
* the site as protected by a firewall. A fake key can be used to bypass the DNS
|
693 |
+
* checking, but that is not something that will affect us, only the client.
|
694 |
+
*/
|
695 |
+
if (
|
696 |
+
$status === FALSE
|
697 |
+
&& SucuriScanAPI::get_cloudproxy_key()
|
698 |
+
) {
|
699 |
+
$status = TRUE;
|
700 |
+
}
|
701 |
+
|
702 |
if( $verbose ){
|
703 |
return array(
|
704 |
'http_host' => $http_host,
|
865 |
return FALSE;
|
866 |
}
|
867 |
|
868 |
+
|
869 |
+
/**
|
870 |
+
* Check whether an IP address is formatted as CIDR or not.
|
871 |
+
*
|
872 |
+
* @param string $remote_addr The supposed ip address that will be checked.
|
873 |
+
* @return boolean Either TRUE or FALSE if the ip address specified is valid or not.
|
874 |
+
*/
|
875 |
+
public static function is_valid_cidr( $remote_addr='' ){
|
876 |
+
if ( preg_match('/^([0-9\.]{7,15})\/(8|16|24)$/', $remote_addr, $match) ) {
|
877 |
+
if ( self::is_valid_ip($match[1]) ) {
|
878 |
+
return TRUE;
|
879 |
+
}
|
880 |
+
}
|
881 |
+
|
882 |
+
return FALSE;
|
883 |
+
}
|
884 |
+
|
885 |
+
/**
|
886 |
+
* Separate the parts of an IP address.
|
887 |
+
*
|
888 |
+
* @param string $remote_addr The supposed ip address that will be formatted.
|
889 |
+
* @return array Clean address, CIDR range, and CIDR format; FALSE otherwise.
|
890 |
+
*/
|
891 |
+
public static function get_ip_info( $remote_addr='' ){
|
892 |
+
if ( $remote_addr ) {
|
893 |
+
$addr_info = array();
|
894 |
+
$ip_parts = explode( '/', $remote_addr );
|
895 |
+
$addr_info['remote_addr'] = $ip_parts[0];
|
896 |
+
$addr_info['cidr_range'] = isset($ip_parts[1]) ? $ip_parts[1] : '32';
|
897 |
+
$addr_info['cidr_format'] = $addr_info['remote_addr'] . '/' . $addr_info['cidr_range'];
|
898 |
+
|
899 |
+
|
900 |
+
return $addr_info;
|
901 |
+
}
|
902 |
+
|
903 |
+
return FALSE;
|
904 |
+
}
|
905 |
+
|
906 |
/**
|
907 |
* Validate email address.
|
908 |
*
|
1034 |
}
|
1035 |
}
|
1036 |
|
1037 |
+
/**
|
1038 |
+
* Determine if the plugin notices can be displayed in the current page.
|
1039 |
+
*
|
1040 |
+
* @param string $current_page Identifier of the current page.
|
1041 |
+
* @return boolean TRUE if the current page must not have noticies.
|
1042 |
+
*/
|
1043 |
+
public static function no_notices_here( $current_page=false ){
|
1044 |
+
global $sucuriscan_no_notices_in;
|
1045 |
+
|
1046 |
+
if ( $current_page === false ) {
|
1047 |
+
$current_page = SucuriScanRequest::get('page');
|
1048 |
+
}
|
1049 |
+
|
1050 |
+
if (
|
1051 |
+
isset($sucuriscan_no_notices_in)
|
1052 |
+
&& is_array($sucuriscan_no_notices_in)
|
1053 |
+
&& !empty($sucuriscan_no_notices_in)
|
1054 |
+
) {
|
1055 |
+
return (bool) in_array($current_page, $sucuriscan_no_notices_in);
|
1056 |
+
}
|
1057 |
+
|
1058 |
+
return false;
|
1059 |
+
}
|
1060 |
+
|
1061 |
}
|
1062 |
|
1063 |
/**
|
1166 |
*/
|
1167 |
class SucuriScanFileInfo extends SucuriScan {
|
1168 |
|
1169 |
+
/**
|
1170 |
+
* Define the interface that will be used to execute the file system scans, the
|
1171 |
+
* available options are SPL, OpenDir, and Glob (all in lowercase). This can be
|
1172 |
+
* configured from the settings page.
|
1173 |
+
*
|
1174 |
+
* @var string
|
1175 |
+
*/
|
1176 |
+
public $scan_interface = 'spl';
|
1177 |
+
|
1178 |
/**
|
1179 |
* Whether the list of files that can be ignored from the filesystem scan will
|
1180 |
* be used to return the directory tree, this should be disabled when scanning a
|
1223 |
* on some rules defined by the developer.
|
1224 |
*
|
1225 |
* @param string $directory Parent directory where the filesystem scan will start.
|
|
|
1226 |
* @param boolean $as_array Whether the result of the operation will be returned as an array or string.
|
1227 |
* @return array List of files in the main and subdirectories of the folder specified.
|
1228 |
*/
|
1229 |
+
public function get_directory_tree_md5( $directory='', $as_array=FALSE ){
|
1230 |
$project_signatures = '';
|
1231 |
$abs_path = rtrim( ABSPATH, '/' );
|
1232 |
+
$files = $this->get_directory_tree($directory);
|
1233 |
|
1234 |
if( $as_array ){
|
1235 |
$project_signatures = array();
|
1273 |
* on some rules defined by the developer.
|
1274 |
*
|
1275 |
* @param string $directory Parent directory where the filesystem scan will start.
|
|
|
1276 |
* @return array List of files in the main and subdirectories of the folder specified.
|
1277 |
*/
|
1278 |
+
public function get_directory_tree($directory=''){
|
1279 |
if( file_exists($directory) && is_dir($directory) ){
|
1280 |
$tree = array();
|
|
|
1281 |
|
1282 |
+
// Check whether the ignore scanning feature is enabled or not.
|
1283 |
+
if( SucuriScanFSScanner::will_ignore_scanning() ){
|
1284 |
+
$this->ignored_directories = SucuriScanFSScanner::get_ignored_directories();
|
1285 |
+
}
|
1286 |
+
|
1287 |
+
switch( $this->scan_interface ){
|
1288 |
case 'spl':
|
1289 |
if( $this->is_spl_available() ){
|
1290 |
$tree = $this->get_directory_tree_with_spl($directory);
|
1291 |
} else {
|
1292 |
+
$this->scan_interface = 'opendir';
|
1293 |
+
$tree = $this->get_directory_tree($directory);
|
1294 |
}
|
1295 |
break;
|
1296 |
|
1303 |
break;
|
1304 |
|
1305 |
default:
|
1306 |
+
$this->scan_interface = 'spl';
|
1307 |
+
$tree = $this->get_directory_tree($directory);
|
1308 |
break;
|
1309 |
}
|
1310 |
|
1431 |
foreach( $files_found as $filepath ){
|
1432 |
$filepath = realpath($filepath);
|
1433 |
$directory = dirname($filepath);
|
1434 |
+
$filepath_parts = explode('/', $filepath);
|
1435 |
+
$filename = array_pop($filepath_parts);
|
1436 |
|
1437 |
if( is_dir($filepath) ){
|
1438 |
if( $this->ignore_folderpath($directory, $filename) ){ continue; }
|
1439 |
|
1440 |
if( $this->run_recursively ){
|
1441 |
+
$sub_files = $this->get_directory_tree_with_glob($filepath);
|
1442 |
+
|
1443 |
+
if( $sub_files ){
|
1444 |
+
$files = array_merge($files, $sub_files);
|
1445 |
+
}
|
1446 |
}
|
1447 |
} else {
|
1448 |
if( $this->ignore_filepath($filename) ){ continue; }
|
1475 |
|
1476 |
if( $this->run_recursively ){
|
1477 |
$sub_files = $this->get_directory_tree_with_opendir($filepath);
|
1478 |
+
|
1479 |
+
if( $sub_files ){
|
1480 |
+
$files = array_merge($files, $sub_files);
|
1481 |
+
}
|
1482 |
}
|
1483 |
} else {
|
1484 |
if( $this->ignore_filepath($filename) ){ continue; }
|
1560 |
$dir_tree = $this->get_directory_tree($dir_tree);
|
1561 |
}
|
1562 |
|
1563 |
+
if( is_array($dir_tree) && !empty($dir_tree) ){
|
1564 |
+
foreach( $dir_tree as $filepath ){
|
1565 |
+
$dir_path = dirname($filepath);
|
1566 |
|
1567 |
+
if(
|
1568 |
+
!in_array($dir_path, $dirs)
|
1569 |
+
&& !in_array($dir_path, $this->ignored_directories['directories'])
|
1570 |
+
){
|
1571 |
+
$dirs[] = $dir_path;
|
1572 |
+
}
|
1573 |
}
|
1574 |
}
|
1575 |
|
1638 |
return @file( $filepath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES );
|
1639 |
}
|
1640 |
|
1641 |
+
/**
|
1642 |
+
* Function to emulate the UNIX tail function by displaying the last X number of
|
1643 |
+
* lines in a file. Useful for large files, such as logs, when you want to
|
1644 |
+
* process lines in PHP or write lines to a database.
|
1645 |
+
*
|
1646 |
+
* @param string $file_path Path to the file.
|
1647 |
+
* @param integer $lines Number of lines to retrieve from the end of the file.
|
1648 |
+
* @param boolean $adaptive Whether the buffer will adapt to a specific number of bytes or not.
|
1649 |
+
* @return string Text contained at the end of the file.
|
1650 |
+
*/
|
1651 |
+
public static function tail_file( $file_path='', $lines=1, $adaptive=true ) {
|
1652 |
+
$file = @fopen( $file_path, 'rb' );
|
1653 |
+
$limit = $lines;
|
1654 |
+
|
1655 |
+
if ( $file ) {
|
1656 |
+
fseek( $file, -1, SEEK_END );
|
1657 |
+
|
1658 |
+
if ( $adaptive && $lines < 2 ) { $buffer = 64; }
|
1659 |
+
elseif ( $adaptive && $lines < 10 ) { $buffer = 512; }
|
1660 |
+
else { $buffer = 4096; }
|
1661 |
+
|
1662 |
+
if ( fread($file, 1) != "\n" ) { $lines -= 1; }
|
1663 |
+
|
1664 |
+
$output = '';
|
1665 |
+
$chunk = '';
|
1666 |
+
|
1667 |
+
while ( ftell($file) > 0 && $lines >= 0 ) {
|
1668 |
+
$seek = min( ftell($file), $buffer );
|
1669 |
+
fseek( $file, -$seek, SEEK_CUR );
|
1670 |
+
$chunk = fread( $file, $seek );
|
1671 |
+
$output = $chunk . $output;
|
1672 |
+
fseek( $file, -mb_strlen($chunk, '8bit'), SEEK_CUR );
|
1673 |
+
$lines -= substr_count( $chunk, "\n" );
|
1674 |
+
}
|
1675 |
+
|
1676 |
+
fclose($file);
|
1677 |
+
|
1678 |
+
$lines_arr = explode( "\n", $output );
|
1679 |
+
$lines_count = count($lines_arr);
|
1680 |
+
$result = array_slice( $lines_arr, ($lines_count - $limit) );
|
1681 |
+
|
1682 |
+
return $result;
|
1683 |
+
}
|
1684 |
+
|
1685 |
+
return FALSE;
|
1686 |
+
}
|
1687 |
+
|
1688 |
}
|
1689 |
|
1690 |
/**
|
2155 |
$defaults = array(
|
2156 |
'sucuriscan_api_key' => FALSE,
|
2157 |
'sucuriscan_account' => '',
|
2158 |
+
'sucuriscan_datastore_path' => '',
|
2159 |
'sucuriscan_fs_scanner' => 'enabled',
|
2160 |
'sucuriscan_scan_frequency' => 'hourly',
|
2161 |
'sucuriscan_scan_interface' => 'spl',
|
2162 |
'sucuriscan_scan_modfiles' => 'enabled',
|
2163 |
'sucuriscan_scan_checksums' => 'enabled',
|
2164 |
'sucuriscan_scan_errorlogs' => 'enabled',
|
2165 |
+
'sucuriscan_parse_errorlogs' => 'enabled',
|
2166 |
+
'sucuriscan_errorlogs_limit' => 30,
|
2167 |
+
'sucuriscan_ignore_scanning' => 'disabled',
|
2168 |
'sucuriscan_runtime' => 0,
|
2169 |
'sucuriscan_lastlogin_redirection' => 'enabled',
|
2170 |
'sucuriscan_notify_to' => '',
|
2177 |
'sucuriscan_notify_post_publication' => 'enabled',
|
2178 |
'sucuriscan_notify_theme_editor' => 'enabled',
|
2179 |
'sucuriscan_maximum_failed_logins' => 30,
|
2180 |
+
'sucuriscan_collect_wrong_passwords' => 'disabled',
|
2181 |
'sucuriscan_ignored_events' => '',
|
2182 |
'sucuriscan_verify_ssl_cert' => 'true',
|
2183 |
'sucuriscan_request_timeout' => 90,
|
2484 |
|
2485 |
// Encode (old) serialized data into JSON.
|
2486 |
if( self::is_serialized($post_types) ){
|
|
|
2487 |
$post_types_arr = @unserialize($post_types);
|
2488 |
$post_types_fix = json_encode($post_types_arr);
|
|
|
2489 |
self::update_option( ':ignored_events', $post_types_fix );
|
2490 |
|
2491 |
return $post_types_arr;
|
2714 |
self::report_site_version();
|
2715 |
|
2716 |
$sucuri_fileinfo = new SucuriScanFileInfo();
|
2717 |
+
$sucuri_fileinfo->scan_interface = SucuriScanOption::get_option(':scan_interface');
|
2718 |
+
$signatures = $sucuri_fileinfo->get_directory_tree_md5(ABSPATH);
|
2719 |
|
2720 |
if( $signatures ){
|
2721 |
$hashes_sent = SucuriScanAPI::send_hashes( $signatures );
|
2803 |
$email = SucuriScanOption::get_option(':notify_to');
|
2804 |
$email_params = array();
|
2805 |
|
2806 |
+
if ( self::is_trusted_ip() ) {
|
2807 |
+
$notify = 'disabled';
|
2808 |
+
}
|
2809 |
+
|
2810 |
if( $notify == 'enabled' ){
|
2811 |
if( $event == 'post_publication' ){
|
2812 |
$event = 'post_update';
|
2813 |
}
|
2814 |
|
2815 |
elseif( $event == 'failed_login' ){
|
2816 |
+
$content .= "<br>\n<br>\n<em>Explanation: Someone failed to login to your site. If you";
|
2817 |
+
$content .= " are getting too many of these messages, it is likely your site is under a brute";
|
2818 |
+
$content .= " force attack. You can disable the notifications for failed logins from here [1].";
|
2819 |
+
$content .= " More details at Password Guessing Brute Force Attacks [2].</em><br>\n<br>\n";
|
2820 |
+
$content .= "[1] " . SucuriScanTemplate::get_url('settings') . " <br>\n";
|
2821 |
+
$content .= "[2] http://kb.sucuri.net/definitions/attacks/brute-force/password-guessing <br>\n";
|
2822 |
}
|
2823 |
|
2824 |
// Send a notification even if the limit of emails per hour was reached.
|
2835 |
return FALSE;
|
2836 |
}
|
2837 |
|
2838 |
+
/**
|
2839 |
+
* Check whether an IP address is being trusted or not.
|
2840 |
+
*
|
2841 |
+
* @param string $remote_addr The supposed ip address that will be checked.
|
2842 |
+
* @return boolean TRUE if the IP address of the user is trusted, FALSE otherwise.
|
2843 |
+
*/
|
2844 |
+
private static function is_trusted_ip( $remote_addr='' ){
|
2845 |
+
$cache = new SucuriScanCache('trustip');
|
2846 |
+
$trusted_ips = $cache->get_all();
|
2847 |
+
|
2848 |
+
if ( !$remote_addr ) {
|
2849 |
+
$remote_addr = SucuriScan::get_remote_addr();
|
2850 |
+
}
|
2851 |
+
|
2852 |
+
$addr_md5 = md5($remote_addr);
|
2853 |
+
|
2854 |
+
// Check if the CIDR in range 32 of this IP is trusted.
|
2855 |
+
if (
|
2856 |
+
is_array($trusted_ips)
|
2857 |
+
&& !empty($trusted_ips)
|
2858 |
+
&& array_key_exists($addr_md5, $trusted_ips)
|
2859 |
+
) {
|
2860 |
+
return TRUE;
|
2861 |
+
}
|
2862 |
+
|
2863 |
+
foreach ( $trusted_ips as $cache_key => $ip_info ) {
|
2864 |
+
$ip_parts = explode( '.', $ip_info->remote_addr );
|
2865 |
+
$ip_pattern = FALSE;
|
2866 |
+
|
2867 |
+
// Generate the regular expression for CIDR range 24.
|
2868 |
+
if ( $ip_info->cidr_range == 24 ) {
|
2869 |
+
$ip_pattern = sprintf( '/^%d\.%d\.%d\.[0-9]{1,3}$/', $ip_parts[0], $ip_parts[1], $ip_parts[2] );
|
2870 |
+
}
|
2871 |
+
|
2872 |
+
// Generate the regular expression for CIDR range 16.
|
2873 |
+
elseif ( $ip_info->cidr_range == 16 ) {
|
2874 |
+
$ip_pattern = sprintf( '/^%d\.%d(\.[0-9]{1,3}){2}$/', $ip_parts[0], $ip_parts[1] );
|
2875 |
+
}
|
2876 |
+
|
2877 |
+
// Generate the regular expression for CIDR range 8.
|
2878 |
+
elseif ( $ip_info->cidr_range == 8 ) {
|
2879 |
+
$ip_pattern = sprintf( '/^%d(\.[0-9]{1,3}){3}$/', $ip_parts[0] );
|
2880 |
+
}
|
2881 |
+
|
2882 |
+
if ( $ip_pattern && preg_match($ip_pattern, $remote_addr) ) {
|
2883 |
+
return TRUE;
|
2884 |
+
}
|
2885 |
+
}
|
2886 |
+
|
2887 |
+
return FALSE;
|
2888 |
+
}
|
2889 |
+
|
2890 |
/**
|
2891 |
* Generate and set a new password for a specific user not in session.
|
2892 |
*
|
3239 |
public static function hook_wp_login_failed( $title='' ){
|
3240 |
if( empty($title) ){ $title = 'Unknown'; }
|
3241 |
|
3242 |
+
$password = SucuriScanRequest::post('pwd');
|
3243 |
+
$message = 'User authentication failed: ' . $title;
|
3244 |
+
|
3245 |
+
if ( sucuriscan_collect_wrong_passwords() === true ) {
|
3246 |
+
$message .= "<br>\nUser wrong password: " . $password;
|
3247 |
+
}
|
3248 |
+
|
3249 |
self::report_event( 2, 'core', $message );
|
3250 |
self::notify_event( 'failed_login', $message );
|
3251 |
|
3252 |
// Log the failed login in the internal datastore for future reports.
|
3253 |
+
$logged = sucuriscan_log_failed_login( $title, $password );
|
3254 |
|
3255 |
// Check if the quantity of failed logins will be considered as a brute-force attack.
|
3256 |
if( $logged ){
|
4208 |
*/
|
4209 |
public static function get_official_checksums( $version=0 ){
|
4210 |
$url = 'http://api.wordpress.org/core/checksums/1.0/';
|
4211 |
+
$language = defined('WPLANG') ? WPLANG : 'en_US';
|
4212 |
$response = self::api_call( $url, 'GET', array(
|
4213 |
'version' => $version,
|
4214 |
+
'locale' => $language,
|
4215 |
));
|
4216 |
|
4217 |
if( $response ){
|
4262 |
|
4263 |
// Get the plugin's basic information from WordPress transient data.
|
4264 |
$plugins = get_plugins();
|
4265 |
+
$pattern = '/^http(s)?:\/\/wordpress\.org\/plugins\/(.*)\/$/';
|
4266 |
+
$wp_market = 'https://wordpress.org/plugins/%s/';
|
4267 |
|
4268 |
// Loop through each plugin data and complement its information with more attributes.
|
4269 |
foreach( $plugins as $plugin_path => $plugin_data ){
|
4278 |
&& preg_match($pattern, $plugin_data['PluginURI'], $match)
|
4279 |
){
|
4280 |
$repository = $match[0];
|
4281 |
+
$repository_name = $match[2];
|
4282 |
$is_free_plugin = TRUE;
|
4283 |
}
|
4284 |
|
4927 |
return FALSE;
|
4928 |
}
|
4929 |
|
4930 |
+
/**
|
4931 |
+
* Check whether the administrator enabled the feature to ignore some
|
4932 |
+
* directories during the file system scans. This function is overwritten by a
|
4933 |
+
* GET parameter in the settings page named no_scan which must be equal to the
|
4934 |
+
* number one.
|
4935 |
+
*
|
4936 |
+
* @return boolean Whether the feature to ignore files is enabled or not.
|
4937 |
+
*/
|
4938 |
+
public static function will_ignore_scanning(){
|
4939 |
+
return ( SucuriScanOption::get_option(':ignore_scanning') === 'enabled' );
|
4940 |
+
}
|
4941 |
+
|
4942 |
/**
|
4943 |
* Add a new directory path to the list of ignored paths.
|
4944 |
*
|
5048 |
$sucuri_fileinfo = new SucuriScanFileInfo();
|
5049 |
$sucuri_fileinfo->ignore_files = TRUE;
|
5050 |
$sucuri_fileinfo->ignore_directories = TRUE;
|
5051 |
+
$sucuri_fileinfo->scan_interface = SucuriScanOption::get_option(':scan_interface');
|
5052 |
$directory_list = $sucuri_fileinfo->get_diretories_only(ABSPATH);
|
5053 |
|
5054 |
if( $directory_list ){
|
5058 |
return $response;
|
5059 |
}
|
5060 |
|
5061 |
+
/**
|
5062 |
+
* Read and parse the lines inside a PHP error log file.
|
5063 |
+
*
|
5064 |
+
* @param array $error_logs The content of an error log file, or an array with the lines.
|
5065 |
+
* @return array List of valid error logs with their attributes separated.
|
5066 |
+
*/
|
5067 |
+
public static function parse_error_logs( $error_logs=array() ){
|
5068 |
+
$logs_arr = array();
|
5069 |
+
$pattern = '/^'
|
5070 |
+
. '(\[(\S+) ([0-9:]{5,8})( \S+)?\] )?' // Detect date, time, and timezone.
|
5071 |
+
. '(PHP )?([a-zA-Z ]+):\s' // Detect PHP error severity.
|
5072 |
+
. '(.+) in (.+)' // Detect error message, and file path.
|
5073 |
+
. '(:| on line )([0-9]+)' // Detect line number.
|
5074 |
+
. '$/';
|
5075 |
+
|
5076 |
+
if ( is_string($error_logs) ) {
|
5077 |
+
$error_logs = explode( "\n", $error_logs );
|
5078 |
+
}
|
5079 |
+
|
5080 |
+
foreach ( (array) $error_logs as $line ) {
|
5081 |
+
if ( !is_string($line) || empty($line) ) { continue; }
|
5082 |
+
|
5083 |
+
if ( preg_match($pattern, $line, $match) ) {
|
5084 |
+
$data_set = array(
|
5085 |
+
'date' => '',
|
5086 |
+
'time' => '',
|
5087 |
+
'timestamp' => 0,
|
5088 |
+
'date_time' => '',
|
5089 |
+
'time_zone' => '',
|
5090 |
+
'error_type' => '',
|
5091 |
+
'error_code' => 'unknown',
|
5092 |
+
'error_message' => '',
|
5093 |
+
'file_path' => '',
|
5094 |
+
'line_number' => 0,
|
5095 |
+
);
|
5096 |
+
|
5097 |
+
// Basic attributes from the scrapping.
|
5098 |
+
$data_set['date'] = $match[2];
|
5099 |
+
$data_set['time'] = $match[3];
|
5100 |
+
$data_set['time_zone'] = trim($match[4]);
|
5101 |
+
$data_set['error_type'] = trim($match[6]);
|
5102 |
+
$data_set['error_message'] = trim($match[7]);
|
5103 |
+
$data_set['file_path'] = trim($match[8]);
|
5104 |
+
$data_set['line_number'] = (int) $match[10];
|
5105 |
+
|
5106 |
+
// Additional data from the attributes.
|
5107 |
+
if ( $data_set['date'] ) {
|
5108 |
+
$data_set['date_time'] = $data_set['date']
|
5109 |
+
. "\x20" . $data_set['time']
|
5110 |
+
. "\x20" . $data_set['time_zone'];
|
5111 |
+
$data_set['timestamp'] = strtotime( $data_set['date_time'] );
|
5112 |
+
}
|
5113 |
+
|
5114 |
+
if ( $data_set['error_type'] ) {
|
5115 |
+
$valid_types = array( 'warning', 'notice', 'error' );
|
5116 |
+
|
5117 |
+
foreach ( $valid_types as $valid_type ) {
|
5118 |
+
if ( stripos($data_set['error_type'], $valid_type) !== FALSE ) {
|
5119 |
+
$data_set['error_code'] = $valid_type;
|
5120 |
+
break;
|
5121 |
+
}
|
5122 |
+
}
|
5123 |
+
}
|
5124 |
+
|
5125 |
+
$logs_arr[] = (object) $data_set;
|
5126 |
+
}
|
5127 |
+
}
|
5128 |
+
|
5129 |
+
return $logs_arr;
|
5130 |
+
}
|
5131 |
+
|
5132 |
}
|
5133 |
|
5134 |
/**
|
5307 |
* @return void
|
5308 |
*/
|
5309 |
public static function initialize(){
|
5310 |
+
if ( SucuriScan::is_behind_cloudproxy() ) {
|
|
|
|
|
|
|
|
|
5311 |
$_SERVER['SUCURIREAL_REMOTE_ADDR'] = $_SERVER['REMOTE_ADDR'];
|
5312 |
+
$_SERVER['REMOTE_ADDR'] = SucuriScan::get_remote_addr();
|
5313 |
}
|
5314 |
}
|
5315 |
|
5528 |
public static function setup_notice(){
|
5529 |
if(
|
5530 |
current_user_can('manage_options')
|
5531 |
+
&& SucuriScan::no_notices_here() === false
|
5532 |
&& !SucuriScanAPI::get_plugin_key()
|
5533 |
&& SucuriScanRequest::post(':plugin_api_key') === FALSE
|
5534 |
&& SucuriScanRequest::post(':recover_key') === FALSE
|
6879 |
*/
|
6880 |
function sucuriscan_cloudproxy_enabled(){
|
6881 |
$btn_string = '';
|
6882 |
+
$proxy_info = SucuriScan::is_behind_cloudproxy();
|
|
|
6883 |
$status = 1;
|
6884 |
|
6885 |
$description = 'A WAF is a protection layer for your web site, blocking all sort of attacks (brute force attempts, '
|
6886 |
. 'DDoS, SQL injections, etc) and helping it remain malware and blacklist free. This test checks if your site is '
|
6887 |
. 'using <a href="http://cloudproxy.sucuri.net/" target="_blank">Sucuri\'s CloudProxy WAF</a> to protect your site.';
|
6888 |
|
6889 |
+
if( $proxy_info === FALSE ){
|
6890 |
$status = 0;
|
6891 |
$btn_string = '<a href="http://cloudproxy.sucuri.net/" target="_blank" class="button button-primary">Harden</a>';
|
6892 |
}
|
7291 |
$sucuri_fileinfo->ignore_files = FALSE;
|
7292 |
$sucuri_fileinfo->ignore_directories = FALSE;
|
7293 |
$sucuri_fileinfo->run_recursively = $recursive;
|
7294 |
+
$sucuri_fileinfo->scan_interface = 'opendir';
|
7295 |
+
$integrity_tree = $sucuri_fileinfo->get_directory_tree_md5( $dir, TRUE );
|
7296 |
|
7297 |
+
if( !$integrity_tree ){
|
7298 |
+
$integrity_tree = array();
|
7299 |
}
|
7300 |
|
7301 |
+
return $integrity_tree;
|
7302 |
}
|
7303 |
|
7304 |
/**
|
7371 |
$template_variables['AuditLogs.NoItemsVisibility'] = 'hidden';
|
7372 |
|
7373 |
if( $total_items > 0 ){
|
7374 |
+
$max_pages = ceil( $audit_logs->total_entries / $max_per_page );
|
7375 |
+
|
7376 |
+
if( $max_pages > SUCURISCAN_MAX_PAGINATION_BUTTONS ){
|
7377 |
+
$max_pages = SUCURISCAN_MAX_PAGINATION_BUTTONS;
|
7378 |
+
}
|
7379 |
+
|
7380 |
$template_variables['AuditLogs.PaginationVisibility'] = 'visible';
|
7381 |
$template_variables['AuditLogs.PaginationLinks'] = SucuriScanTemplate::get_pagination(
|
7382 |
'%%SUCURI.URL.Home%%',
|
7383 |
+
$max_per_page * $max_pages,
|
7384 |
$max_per_page
|
7385 |
);
|
7386 |
}
|
7661 |
// Search modified files among the project's files.
|
7662 |
$content_hashes = sucuriscan_get_integrity_tree( ABSPATH.'wp-content', true );
|
7663 |
|
7664 |
+
if( !empty($content_hashes) ){
|
7665 |
$template_variables['ModifiedFiles.Days'] = $back_days;
|
7666 |
$back_days = current_time('timestamp') - ( $back_days * 86400);
|
7667 |
$counter = 0;
|
8402 |
|
8403 |
$lastlogin_message = sprintf(
|
8404 |
'Last time you logged in was at <code>%s</code> from <code>%s</code> - <code>%s</code>',
|
8405 |
+
SucuriScan::datetime($row->user_lastlogin_timestamp),
|
8406 |
+
$row->user_remoteaddr,
|
8407 |
+
$row->user_hostname
|
8408 |
);
|
8409 |
$lastlogin_message .= chr(32).'(<a href="'.SucuriScanTemplate::get_url('lastlogins').'">view all logs</a>)';
|
8410 |
SucuriScanInterface::info( $lastlogin_message );
|
8626 |
'FailedLogins.MaxFailedLogins' => 0,
|
8627 |
'FailedLogins.NoItemsVisibility' => 'visible',
|
8628 |
'FailedLogins.WarningVisibility' => 'visible',
|
8629 |
+
'FailedLogins.CollectPasswordsVisibility' => 'visible',
|
8630 |
);
|
8631 |
|
8632 |
$max_failed_logins = SucuriScanOption::get_option(':maximum_failed_logins');
|
8633 |
$notify_bruteforce_attack = SucuriScanOption::get_option(':notify_bruteforce_attack');
|
8634 |
$failed_logins = sucuriscan_get_failed_logins();
|
8635 |
+
$old_failed_logins = sucuriscan_get_failed_logins(true);
|
8636 |
+
|
8637 |
+
// Merge the new and old failed logins.
|
8638 |
+
if (
|
8639 |
+
is_array($old_failed_logins)
|
8640 |
+
&& !empty($old_failed_logins)
|
8641 |
+
) {
|
8642 |
+
if (
|
8643 |
+
is_array($failed_logins)
|
8644 |
+
&& !empty($failed_logins)
|
8645 |
+
) {
|
8646 |
+
$failed_logins = array_merge( $failed_logins, $old_failed_logins );
|
8647 |
+
} else {
|
8648 |
+
$failed_logins = $old_failed_logins;
|
8649 |
+
}
|
8650 |
+
}
|
8651 |
|
8652 |
if( $failed_logins ){
|
8653 |
$counter = 0;
|
8654 |
|
8655 |
foreach( $failed_logins['entries'] as $login_data ){
|
8656 |
$css_class = ( $counter % 2 == 0 ) ? '' : 'alternate';
|
8657 |
+
$wrong_user_password = '<span class="sucuriscan-label-default">hidden</span>';
|
8658 |
+
|
8659 |
+
if ( sucuriscan_collect_wrong_passwords() === true ) {
|
8660 |
+
if (
|
8661 |
+
isset($login_data['user_password'])
|
8662 |
+
&& !empty($login_data['user_password'])
|
8663 |
+
) {
|
8664 |
+
$wrong_user_password = SucuriScan::escape($login_data['user_password']);
|
8665 |
+
}
|
8666 |
+
|
8667 |
+
else {
|
8668 |
+
$wrong_user_password = '<span class="sucuriscan-label-info">empty</span>';
|
8669 |
+
}
|
8670 |
+
}
|
8671 |
|
8672 |
$template_variables['FailedLogins.List'] .= SucuriScanTemplate::get_snippet('lastlogins-failedlogins', array(
|
8673 |
'FailedLogins.CssClass' => $css_class,
|
8674 |
'FailedLogins.Num' => ($counter + 1),
|
8675 |
'FailedLogins.Username' => SucuriScan::escape($login_data['user_login']),
|
8676 |
+
'FailedLogins.Password' => $wrong_user_password,
|
8677 |
'FailedLogins.RemoteAddr' => SucuriScan::escape($login_data['remote_addr']),
|
8678 |
'FailedLogins.Datetime' => SucuriScan::datetime($login_data['attempt_time']),
|
8679 |
'FailedLogins.UserAgent' => SucuriScan::escape($login_data['user_agent']),
|
8693 |
$template_variables['FailedLogins.WarningVisibility'] = 'hidden';
|
8694 |
}
|
8695 |
|
8696 |
+
if( sucuriscan_collect_wrong_passwords() !== true ){
|
8697 |
+
$template_variables['FailedLogins.CollectPasswordsVisibility'] = 'hidden';
|
8698 |
+
}
|
8699 |
+
|
8700 |
return SucuriScanTemplate::get_section('lastlogins-failedlogins', $template_variables);
|
8701 |
}
|
8702 |
|
8703 |
+
/**
|
8704 |
+
* Whether or not to collect the password of failed logins.
|
8705 |
+
*
|
8706 |
+
* @return boolean TRUE if the password must be collected, FALSE otherwise.
|
8707 |
+
*/
|
8708 |
+
function sucuriscan_collect_wrong_passwords(){
|
8709 |
+
return (bool) ( SucuriScanOption::get_option(':collect_wrong_passwords') === 'enabled' );
|
8710 |
+
}
|
8711 |
+
|
8712 |
/**
|
8713 |
* Find the full path of the file where the information of the failed logins
|
8714 |
* will be stored, it will be created automatically if does not exists (and if
|
8717 |
*
|
8718 |
* @see sucuriscan_reset_failed_logins()
|
8719 |
*
|
8720 |
+
* @param boolean $get_old_logs Whether the old logs will be retrieved or not.
|
8721 |
+
* @param boolean $reset Whether the file will be resetted or not.
|
8722 |
+
* @return string The full (relative) path where the file is located.
|
8723 |
*/
|
8724 |
+
function sucuriscan_failed_logins_datastore_path( $get_old_logs=false, $reset=false ){
|
8725 |
+
$file_name = $get_old_logs ? 'sucuri-oldfailedlogins.php' : 'sucuri-failedlogins.php';
|
8726 |
+
$datastore_path = SucuriScan::datastore_folder_path($file_name);
|
8727 |
$default_content = sucuriscan_failed_logins_default_content();
|
8728 |
|
8729 |
// Create the file if it does not exists.
|
8761 |
* with the report) or reset the file after considering it a normal behavior of
|
8762 |
* the site.
|
8763 |
*
|
8764 |
+
* @param boolean $get_old_logs Whether the old logs will be retrieved or not.
|
8765 |
+
* @return array Information and entries gathered from the failed logins datastore file.
|
8766 |
*/
|
8767 |
+
function sucuriscan_get_failed_logins( $get_old_logs=false ){
|
8768 |
+
$datastore_path = sucuriscan_failed_logins_datastore_path($get_old_logs);
|
8769 |
$default_content = sucuriscan_failed_logins_default_content();
|
8770 |
$default_content_n = substr_count($default_content, "\n");
|
8771 |
|
8791 |
$login_data['user_agent'] = 'Unknown';
|
8792 |
}
|
8793 |
|
8794 |
+
if ( !isset($login_data['user_password'])) {
|
8795 |
+
$login_data['user_password'] = '';
|
8796 |
+
}
|
8797 |
+
|
8798 |
$failed_logins['entries'][] = $login_data;
|
8799 |
$failed_logins['count'] += 1;
|
8800 |
}
|
8821 |
* this entry will contain the username, timestamp of the login attempt, remote
|
8822 |
* address of the computer sending the request, and the user-agent.
|
8823 |
*
|
8824 |
+
* @param string $user_login Information from the current failed login event.
|
8825 |
+
* @param string $wrong_password Wrong password used during the supposed attack.
|
8826 |
+
* @return boolean Whether the information of the current failed login event was stored or not.
|
8827 |
*/
|
8828 |
+
function sucuriscan_log_failed_login( $user_login='', $wrong_password='' ){
|
8829 |
$datastore_path = sucuriscan_failed_logins_datastore_path();
|
8830 |
|
8831 |
+
// Do not collect wrong passwords if it is not necessary.
|
8832 |
+
if ( sucuriscan_collect_wrong_passwords() !== true ) {
|
8833 |
+
$wrong_password = '';
|
8834 |
+
}
|
8835 |
+
|
8836 |
if( $datastore_path ){
|
8837 |
$login_data = json_encode(array(
|
8838 |
'user_login' => $user_login,
|
8839 |
+
'user_password' => $wrong_password,
|
8840 |
'attempt_time' => time(),
|
8841 |
'remote_addr' => SucuriScan::get_remote_addr(),
|
8842 |
'user_agent' => SucuriScan::get_user_agent(),
|
8862 |
function sucuriscan_report_failed_logins( $failed_logins=array() ){
|
8863 |
if( $failed_logins && $failed_logins['count'] > 0 ){
|
8864 |
$prettify_mails = SucuriScanMail::prettify_mails();
|
8865 |
+
$collect_wrong_passwords = sucuriscan_collect_wrong_passwords();
|
8866 |
$mail_content = '';
|
8867 |
|
8868 |
if( $prettify_mails ){
|
8872 |
$table_html .= '<thead>';
|
8873 |
$table_html .= '<tr>';
|
8874 |
$table_html .= '<th>Username</th>';
|
8875 |
+
|
8876 |
+
if ( $collect_wrong_passwords === true ) {
|
8877 |
+
$table_html .= '<th>Password</th>';
|
8878 |
+
}
|
8879 |
+
|
8880 |
$table_html .= '<th>IP Address</th>';
|
8881 |
$table_html .= '<th>Attempt Timestamp</th>';
|
8882 |
$table_html .= '<th>Attempt Date/Time</th>';
|
8890 |
if( $prettify_mails ){
|
8891 |
$table_html .= '<tr>';
|
8892 |
$table_html .= '<td>' . esc_attr($login_data['user_login']) . '</td>';
|
8893 |
+
|
8894 |
+
if ( $collect_wrong_passwords === true ) {
|
8895 |
+
$table_html .= '<td>' . esc_attr($login_data['user_password']) . '</td>';
|
8896 |
+
}
|
8897 |
+
|
8898 |
$table_html .= '<td>' . esc_attr($login_data['remote_addr']) . '</td>';
|
8899 |
$table_html .= '<td>' . $login_data['attempt_time'] . '</td>';
|
8900 |
$table_html .= '<td>' . $login_data['attempt_date'] . '</td>';
|
8902 |
} else {
|
8903 |
$mail_content .= "\n";
|
8904 |
$mail_content .= 'Username: ' . $login_data['user_login'] . "\n";
|
8905 |
+
|
8906 |
+
if ( $collect_wrong_passwords === true ) {
|
8907 |
+
$mail_content .= 'Password: ' . $login_data['user_password'] . "\n";
|
8908 |
+
}
|
8909 |
+
|
8910 |
$mail_content .= 'IP Address: ' . $login_data['remote_addr'] . "\n";
|
8911 |
$mail_content .= 'Attempt Timestamp: ' . $login_data['attempt_time'] . "\n";
|
8912 |
$mail_content .= 'Attempt Date/Time: ' . $login_data['attempt_date'] . "\n";
|
8938 |
* @return boolean Whether the datastore file was resetted or not.
|
8939 |
*/
|
8940 |
function sucuriscan_reset_failed_logins(){
|
8941 |
+
$datastore_path = SucuriScan::datastore_folder_path('sucuri-failedlogins.php');
|
8942 |
+
$datastore_backup_path = sucuriscan_failed_logins_datastore_path(true, false);
|
8943 |
+
$default_content = sucuriscan_failed_logins_default_content();
|
8944 |
+
$current_content = @file_get_contents($datastore_path);
|
8945 |
+
$current_content = str_replace( $default_content, '', $current_content );
|
8946 |
+
|
8947 |
+
@file_put_contents(
|
8948 |
+
$datastore_backup_path,
|
8949 |
+
$current_content,
|
8950 |
+
FILE_APPEND
|
8951 |
+
);
|
8952 |
+
|
8953 |
+
return (bool) sucuriscan_failed_logins_datastore_path(false, true);
|
8954 |
}
|
8955 |
|
8956 |
/**
|
8968 |
'Settings.IgnoreScanning' => sucuriscan_settings_ignorescanning(),
|
8969 |
'Settings.Notifications' => sucuriscan_settings_notifications(),
|
8970 |
'Settings.IgnoreRules' => sucuriscan_settings_ignore_rules(),
|
8971 |
+
'Settings.TrustIP' => sucuriscan_settings_trust_ip(),
|
8972 |
'Settings.Heartbeat' => sucuriscan_settings_heartbeat(),
|
8973 |
);
|
8974 |
|
9040 |
SucuriScanInterface::info( 'Filesystem scanner for file integrity was <code>' . $action_d . '</code>' );
|
9041 |
}
|
9042 |
|
9043 |
+
// Enable or disable the filesystem scanner for error logs.
|
9044 |
+
if( $ignore_scanning = SucuriScanRequest::post(':ignore_scanning', '(en|dis)able') ){
|
9045 |
+
$action_d = $ignore_scanning . 'd';
|
9046 |
+
SucuriScanOption::update_option(':ignore_scanning', $action_d);
|
9047 |
+
SucuriScanEvent::notify_event( 'plugin_change', 'Filesystem scanner rules to ignore directories was: ' . $action_d );
|
9048 |
+
SucuriScanInterface::info( 'Filesystem scanner rules to ignore directories was <code>' . $action_d . '</code>' );
|
9049 |
+
}
|
9050 |
+
|
9051 |
// Enable or disable the filesystem scanner for error logs.
|
9052 |
if( $scan_errorlogs = SucuriScanRequest::post(':scan_errorlogs', '(en|dis)able') ){
|
9053 |
$action_d = $scan_errorlogs . 'd';
|
9056 |
SucuriScanInterface::info( 'Filesystem scanner for error logs was <code>' . $action_d . '</code>' );
|
9057 |
}
|
9058 |
|
9059 |
+
// Enable or disable the error logs parsing.
|
9060 |
+
if( $parse_errorlogs = SucuriScanRequest::post(':parse_errorlogs', '(en|dis)able') ){
|
9061 |
+
$action_d = $parse_errorlogs . 'd';
|
9062 |
+
SucuriScanOption::update_option(':parse_errorlogs', $action_d);
|
9063 |
+
SucuriScanEvent::notify_event( 'plugin_change', 'Analysis of error logs was: ' . $action_d );
|
9064 |
+
SucuriScanInterface::info( 'Analysis of error logs was <code>' . $action_d . '</code>' );
|
9065 |
+
}
|
9066 |
+
|
9067 |
+
// Update the limit of error log lines to parse.
|
9068 |
+
if( $errorlogs_limit = SucuriScanRequest::post(':errorlogs_limit', '[0-9]+') ){
|
9069 |
+
if ( $errorlogs_limit > 1000 ) {
|
9070 |
+
SucuriScanInterface::error( 'Analyze more than 1,000 lines will take too much time.' );
|
9071 |
+
} else {
|
9072 |
+
SucuriScanOption::update_option(':errorlogs_limit', $errorlogs_limit);
|
9073 |
+
SucuriScanInterface::info( 'Analyze last <code>' . $errorlogs_limit . '</code> entries encountered in the error logs.' );
|
9074 |
+
|
9075 |
+
if ( $errorlogs_limit == 0 ) {
|
9076 |
+
SucuriScanOption::update_option(':parse_errorlogs', 'disabled');
|
9077 |
+
}
|
9078 |
+
}
|
9079 |
+
}
|
9080 |
+
|
9081 |
// Modify the schedule of the filesystem scanner.
|
9082 |
if( $frequency = SucuriScanRequest::post(':scan_frequency') ){
|
9083 |
if( array_key_exists($frequency, $sucuriscan_schedule_allowed) ){
|
9165 |
SucuriScanInterface::info( 'API request timeout set to <code>' . $request_timeout . '</code> seconds.' );
|
9166 |
}
|
9167 |
|
9168 |
+
// Update the collection of failed passwords settings.
|
9169 |
+
if( $collect_wrong_passwords = SucuriScanRequest::post(':collect_wrong_passwords') ){
|
9170 |
+
$collect_wrong_passwords = strtolower($collect_wrong_passwords);
|
9171 |
+
$collect_action = 'disabled';
|
9172 |
+
|
9173 |
+
if ( $collect_wrong_passwords == 'yes' ) {
|
9174 |
+
$collect_action = 'enabled';
|
9175 |
+
}
|
9176 |
+
|
9177 |
+
SucuriScanOption::update_option(':collect_wrong_passwords', $collect_action);
|
9178 |
+
SucuriScanInterface::info( 'Option to collection wrong passwords updated to <code>' . $collect_action . '</code>' );
|
9179 |
+
}
|
9180 |
+
|
9181 |
+
// Update the datastore path (if the new directory exists).
|
9182 |
+
if( $datastore_path = SucuriScanRequest::post(':datastore_path') ){
|
9183 |
+
$current_datastore_path = SucuriScanOption::datastore_folder_path();
|
9184 |
+
|
9185 |
+
if ( file_exists($datastore_path) ) {
|
9186 |
+
if ( is_writable($datastore_path) ) {
|
9187 |
+
SucuriScanOption::update_option(':datastore_path', $datastore_path);
|
9188 |
+
SucuriScanInterface::info( 'Datastore path changed to <code>' . $datastore_path . '</code>' );
|
9189 |
+
|
9190 |
+
if ( file_exists($current_datastore_path) ) {
|
9191 |
+
$new_datastore_path = SucuriScanOption::datastore_folder_path();
|
9192 |
+
@rename( $current_datastore_path, $new_datastore_path );
|
9193 |
+
}
|
9194 |
+
}
|
9195 |
+
|
9196 |
+
else {
|
9197 |
+
SucuriScanInterface::error( 'The new directory path is not writable.' );
|
9198 |
+
}
|
9199 |
+
}
|
9200 |
+
|
9201 |
+
else {
|
9202 |
+
SucuriScanInterface::error( 'The directory path specified does not exists.' );
|
9203 |
+
}
|
9204 |
+
}
|
9205 |
+
|
9206 |
// Update the notification settings.
|
9207 |
if( SucuriScanRequest::post(':save_notification_settings') !== FALSE ){
|
9208 |
$options_updated_counter = 0;
|
9286 |
}
|
9287 |
}
|
9288 |
|
9289 |
+
// Trust and IP address to ignore notifications for a subnet.
|
9290 |
+
if( $trust_ip = SucuriScanRequest::post(':trust_ip') ){
|
9291 |
+
if(
|
9292 |
+
SucuriScan::is_valid_ip($trust_ip)
|
9293 |
+
|| SucuriScan::is_valid_cidr($trust_ip)
|
9294 |
+
){
|
9295 |
+
$cache = new SucuriScanCache('trustip');
|
9296 |
+
$ip_info = SucuriScan::get_ip_info($trust_ip);
|
9297 |
+
$ip_info['added_at'] = SucuriScan::local_time();
|
9298 |
+
$cache_key = md5($ip_info['remote_addr']);
|
9299 |
+
|
9300 |
+
if ( $cache->exists($cache_key) ) {
|
9301 |
+
SucuriScanInterface::error( 'The IP address specified was already trusted.' );
|
9302 |
+
} elseif ( $cache->add( $cache_key, $ip_info ) ) {
|
9303 |
+
SucuriScanInterface::info( 'The IP address specified was trusted successfully.' );
|
9304 |
+
} else {
|
9305 |
+
SucuriScanInterface::error( 'The new entry was not saved in the datastore file.' );
|
9306 |
+
}
|
9307 |
+
}
|
9308 |
+
}
|
9309 |
+
|
9310 |
+
// Trust and IP address to ignore notifications for a subnet.
|
9311 |
+
if( $del_trust_ip = SucuriScanRequest::post(':del_trust_ip', '_array') ){
|
9312 |
+
$cache = new SucuriScanCache('trustip');
|
9313 |
+
|
9314 |
+
foreach ( $del_trust_ip as $cache_key ) {
|
9315 |
+
$cache->delete($cache_key);
|
9316 |
+
}
|
9317 |
+
|
9318 |
+
SucuriScanInterface::info( 'The IP addresses selected were deleted successfully.' );
|
9319 |
+
}
|
9320 |
+
|
9321 |
// Update the settings for the heartbeat API.
|
9322 |
if( $heartbeat_status = SucuriScanRequest::post(':heartbeat_status') ){
|
9323 |
$statuses_allowed = SucuriScanHeartbeat::statuses_allowed();
|
9431 |
'VerifySSLCert' => 'Undefined',
|
9432 |
'VerifySSLCertOptions' => $verify_ssl_cert_options,
|
9433 |
'RequestTimeout' => SucuriScanOption::get_option(':request_timeout') . ' seconds',
|
9434 |
+
'DatastorePath' => SucuriScanOption::get_option(':datastore_path'),
|
9435 |
+
'DatastorePathShort' => '',
|
9436 |
+
'CollectWrongPasswords' => 'No collect passwords',
|
9437 |
'ModalWhenAPIRegistered' => $api_registered_modal,
|
9438 |
);
|
9439 |
|
9449 |
$template_variables['VerifySSLCert'] = $sucuriscan_verify_ssl_cert[$verify_ssl_cert];
|
9450 |
}
|
9451 |
|
9452 |
+
if ( !empty($template_variables['DatastorePath']) ) {
|
9453 |
+
$template_variables['DatastorePathShort'] = SucuriScan::excerpt_rev( $template_variables['DatastorePath'], 30 );
|
9454 |
+
}
|
9455 |
+
|
9456 |
+
if ( sucuriscan_collect_wrong_passwords() === true ) {
|
9457 |
+
$template_variables['CollectWrongPasswords'] = '<span class="sucuriscan-label-error">Yes, collect passwords</span>';
|
9458 |
+
}
|
9459 |
+
|
9460 |
return SucuriScanTemplate::get_section('settings-general', $template_variables);
|
9461 |
}
|
9462 |
|
9477 |
$scan_modfiles = SucuriScanOption::get_option(':scan_modfiles');
|
9478 |
$scan_checksums = SucuriScanOption::get_option(':scan_checksums');
|
9479 |
$scan_errorlogs = SucuriScanOption::get_option(':scan_errorlogs');
|
9480 |
+
$parse_errorlogs = SucuriScanOption::get_option(':parse_errorlogs');
|
9481 |
+
$errorlogs_limit = SucuriScanOption::get_option(':errorlogs_limit');
|
9482 |
+
$ignore_scanning = SucuriScanOption::get_option(':ignore_scanning');
|
9483 |
$runtime_scan_human = SucuriScanFSScanner::get_filesystem_runtime(TRUE);
|
9484 |
|
9485 |
// Generate the HTML code for the option list in the form select fields.
|
9502 |
'ScanChecksumsSwitchText' => 'Disable',
|
9503 |
'ScanChecksumsSwitchValue' => 'disable',
|
9504 |
'ScanChecksumsSwitchCssClass' => 'button-danger',
|
9505 |
+
/* Ignore scanning. */
|
9506 |
+
'IgnoreScanningStatus' => 'Enabled',
|
9507 |
+
'IgnoreScanningSwitchText' => 'Disable',
|
9508 |
+
'IgnoreScanningSwitchValue' => 'disable',
|
9509 |
+
'IgnoreScanningSwitchCssClass' => 'button-danger',
|
9510 |
/* Scan error logs. */
|
9511 |
'ScanErrorlogsStatus' => 'Enabled',
|
9512 |
'ScanErrorlogsSwitchText' => 'Disable',
|
9513 |
'ScanErrorlogsSwitchValue' => 'disable',
|
9514 |
'ScanErrorlogsSwitchCssClass' => 'button-danger',
|
9515 |
+
/* Parse error logs. */
|
9516 |
+
'ParseErrorLogsStatus' => 'Enabled',
|
9517 |
+
'ParseErrorLogsSwitchText' => 'Disable',
|
9518 |
+
'ParseErrorLogsSwitchValue' => 'disable',
|
9519 |
+
'ParseErrorLogsSwitchCssClass' => 'button-danger',
|
9520 |
/* Filsystem scanning frequency. */
|
9521 |
'ScanningFrequency' => 'Undefined',
|
9522 |
'ScanningFrequencyOptions' => $scan_freq_options,
|
9524 |
'ScanningInterfaceOptions' => $scan_interface_options,
|
9525 |
/* Filesystem scanning runtime. */
|
9526 |
'ScanningRuntimeHuman' => $runtime_scan_human,
|
9527 |
+
'ErrorLogsLimit' => $errorlogs_limit,
|
9528 |
);
|
9529 |
|
9530 |
if( $fs_scanner == 'disabled' ){
|
9548 |
$template_variables['ScanChecksumsSwitchCssClass'] = 'button-success';
|
9549 |
}
|
9550 |
|
9551 |
+
if( $ignore_scanning == 'disabled' ){
|
9552 |
+
$template_variables['IgnoreScanningStatus'] = 'Disabled';
|
9553 |
+
$template_variables['IgnoreScanningSwitchText'] = 'Enable';
|
9554 |
+
$template_variables['IgnoreScanningSwitchValue'] = 'enable';
|
9555 |
+
$template_variables['IgnoreScanningSwitchCssClass'] = 'button-success';
|
9556 |
+
}
|
9557 |
+
|
9558 |
if( $scan_errorlogs == 'disabled' ){
|
9559 |
$template_variables['ScanErrorlogsStatus'] = 'Disabled';
|
9560 |
$template_variables['ScanErrorlogsSwitchText'] = 'Enable';
|
9562 |
$template_variables['ScanErrorlogsSwitchCssClass'] = 'button-success';
|
9563 |
}
|
9564 |
|
9565 |
+
if( $parse_errorlogs == 'disabled' ){
|
9566 |
+
$template_variables['ParseErrorLogsStatus'] = 'Disabled';
|
9567 |
+
$template_variables['ParseErrorLogsSwitchText'] = 'Enable';
|
9568 |
+
$template_variables['ParseErrorLogsSwitchValue'] = 'enable';
|
9569 |
+
$template_variables['ParseErrorLogsSwitchCssClass'] = 'button-success';
|
9570 |
+
}
|
9571 |
+
|
9572 |
if( array_key_exists($scan_freq, $sucuriscan_schedule_allowed) ){
|
9573 |
$template_variables['ScanningFrequency'] = $sucuriscan_schedule_allowed[$scan_freq];
|
9574 |
}
|
9669 |
return SucuriScanTemplate::get_section('settings-ignorerules', $template_variables);
|
9670 |
}
|
9671 |
|
9672 |
+
/**
|
9673 |
+
* Read and parse the content of the trust-ip settings template.
|
9674 |
+
*
|
9675 |
+
* @return string Parsed HTML code for the trust-ip settings panel.
|
9676 |
+
*/
|
9677 |
+
function sucuriscan_settings_trust_ip(){
|
9678 |
+
$template_variables = array(
|
9679 |
+
'TrustedIPs.List' => '',
|
9680 |
+
'TrustedIPs.NoItems.Visibility' => 'visible',
|
9681 |
+
);
|
9682 |
+
|
9683 |
+
$cache = new SucuriScanCache('trustip');
|
9684 |
+
$trusted_ips = $cache->get_all();
|
9685 |
+
|
9686 |
+
if ( $trusted_ips ) {
|
9687 |
+
$counter = 0;
|
9688 |
+
|
9689 |
+
foreach ( $trusted_ips as $cache_key => $ip_info ) {
|
9690 |
+
$css_class = ( $counter % 2 == 0 ) ? '' : 'alternate';
|
9691 |
+
|
9692 |
+
if ( $ip_info->cidr_range == 32 ) {
|
9693 |
+
$ip_info->cidr_format = 'n/a';
|
9694 |
+
}
|
9695 |
+
|
9696 |
+
$template_variables['TrustedIPs.List'] .= SucuriScanTemplate::get_snippet('settings-trustip', array(
|
9697 |
+
'TrustIP.CssClass' => $css_class,
|
9698 |
+
'TrustIP.CacheKey' => $cache_key,
|
9699 |
+
'TrustIP.RemoteAddr' => SucuriScan::escape($ip_info->remote_addr),
|
9700 |
+
'TrustIP.CIDRFormat' => SucuriScan::escape($ip_info->cidr_format),
|
9701 |
+
'TrustIP.AddedAt' => SucuriScan::datetime($ip_info->added_at),
|
9702 |
+
));
|
9703 |
+
$counter += 1;
|
9704 |
+
}
|
9705 |
+
|
9706 |
+
if ( $counter > 0 ) {
|
9707 |
+
$template_variables['TrustedIPs.NoItems.Visibility'] = 'hidden';
|
9708 |
+
}
|
9709 |
+
}
|
9710 |
+
|
9711 |
+
return SucuriScanTemplate::get_section('settings-trustip', $template_variables);
|
9712 |
+
}
|
9713 |
+
|
9714 |
/**
|
9715 |
* Read and parse the content of the ignore-scanning settings template.
|
9716 |
*
|
9719 |
function sucuriscan_settings_ignorescanning(){
|
9720 |
$template_variables = array(
|
9721 |
'IgnoreScanning.ResourceList' => '',
|
9722 |
+
'IgnoreScanning.DisabledVisibility' => 'visible',
|
9723 |
+
'IgnoreScanning.NoItemsVisibility' => 'visible',
|
9724 |
);
|
9725 |
|
9726 |
+
$ignore_scanning = SucuriScanFSScanner::will_ignore_scanning();
|
|
|
9727 |
|
9728 |
+
// Allow disable of this option temporarily.
|
9729 |
+
if( SucuriScanRequest::get('no_scan') == 1 ){
|
9730 |
+
$ignore_scanning = FALSE;
|
9731 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
9732 |
|
9733 |
+
// Scan the project and get the ignored paths.
|
9734 |
+
if( $ignore_scanning === TRUE ){
|
9735 |
+
$counter = 0;
|
9736 |
+
$template_variables['IgnoreScanning.DisabledVisibility'] = 'hidden';
|
9737 |
+
$dir_list_list = SucuriScanFSScanner::get_ignored_directories_live();
|
|
|
|
|
|
|
9738 |
|
9739 |
+
foreach( $dir_list_list as $group => $dir_list ){
|
9740 |
+
foreach( $dir_list as $dir_data ){
|
9741 |
+
$valid_entry = FALSE;
|
9742 |
+
$snippet_data = array(
|
9743 |
+
'IgnoreScanning.CssClass' => '',
|
9744 |
+
'IgnoreScanning.Directory' => '',
|
9745 |
+
'IgnoreScanning.DirectoryPath' => '',
|
9746 |
+
'IgnoreScanning.IgnoredAt' => '',
|
9747 |
+
'IgnoreScanning.IgnoredAtText' => 'ok',
|
9748 |
+
'IgnoreScanning.IgnoredCssClass' => 'success',
|
9749 |
+
);
|
9750 |
|
9751 |
+
if( $group == 'is_ignored' ){
|
9752 |
+
$valid_entry = TRUE;
|
9753 |
+
$snippet_data['IgnoreScanning.Directory'] = urlencode($dir_data['directory_path']);
|
9754 |
+
$snippet_data['IgnoreScanning.DirectoryPath'] = SucuriScan::escape($dir_data['directory_path']);
|
9755 |
+
$snippet_data['IgnoreScanning.IgnoredAt'] = SucuriScan::datetime($dir_data['ignored_at']);
|
9756 |
+
$snippet_data['IgnoreScanning.IgnoredAtText'] = 'ignored';
|
9757 |
+
$snippet_data['IgnoreScanning.IgnoredCssClass'] = 'warning';
|
9758 |
+
}
|
9759 |
+
|
9760 |
+
elseif( $group == 'is_not_ignored' ){
|
9761 |
+
$valid_entry = TRUE;
|
9762 |
+
$snippet_data['IgnoreScanning.Directory'] = urlencode($dir_data);
|
9763 |
+
$snippet_data['IgnoreScanning.DirectoryPath'] = SucuriScan::escape($dir_data);
|
9764 |
+
}
|
9765 |
+
|
9766 |
+
if( $valid_entry ){
|
9767 |
+
$css_class = ( $counter %2 == 0 ) ? '' : 'alternate';
|
9768 |
+
$snippet_data['IgnoreScanning.CssClass'] = $css_class;
|
9769 |
+
$template_variables['IgnoreScanning.ResourceList'] .= SucuriScanTemplate::get_snippet('settings-ignorescanning', $snippet_data);
|
9770 |
+
$counter += 1;
|
9771 |
+
}
|
9772 |
}
|
9773 |
}
|
9774 |
+
|
9775 |
+
if( $counter > 0 ){
|
9776 |
+
$template_variables['IgnoreScanning.NoItemsVisibility'] = 'hidden';
|
9777 |
+
}
|
9778 |
}
|
9779 |
|
9780 |
return SucuriScanTemplate::get_section('settings-ignorescanning', $template_variables);
|
9861 |
'Cronjobs' => sucuriscan_show_cronjobs(),
|
9862 |
'HTAccessIntegrity' => sucuriscan_infosys_htaccess(),
|
9863 |
'WordpressConfig' => sucuriscan_infosys_wpconfig(),
|
9864 |
+
'ErrorLogs' => sucuriscan_infosys_errorlogs(),
|
9865 |
);
|
9866 |
|
9867 |
echo SucuriScanTemplate::get_template('infosys', $template_variables);
|
9979 |
|
9980 |
// Parse the main configuration file and look for constants and global variables.
|
9981 |
foreach( (array) $wp_config_content as $line ){
|
9982 |
+
// Ignore commented lines.
|
9983 |
+
if ( preg_match('/^\s?(#|\/\/)/', $line) ) { continue; }
|
9984 |
+
|
9985 |
// Detect PHP constants even if the line if indented.
|
9986 |
+
elseif ( preg_match('/define\(/', $line) ) {
|
9987 |
+
$line = preg_replace('/.*define\((.+)\);.*/', '$1', $line);
|
9988 |
$line_parts = explode(',', $line, 2);
|
9989 |
}
|
9990 |
|
9991 |
// Detect global variables like the database table prefix.
|
9992 |
+
elseif( preg_match('/^\$[a-zA-Z_]+/', $line) ){
|
9993 |
+
$line = preg_replace( '/;\s\/\/.*/', ';', $line );
|
9994 |
$line_parts = explode('=', $line, 2);
|
9995 |
}
|
9996 |
|
9997 |
// Ignore other lines.
|
9998 |
+
else { continue; }
|
9999 |
|
10000 |
// Clean and append the rule to the wp_config_rules variable.
|
10001 |
if( isset($line_parts) && count($line_parts)==2 ){
|
10156 |
}
|
10157 |
}
|
10158 |
|
10159 |
+
/**
|
10160 |
+
* Locate, parse and display the latest error logged in the main error_log file.
|
10161 |
+
*
|
10162 |
+
* @return array A list of pseudo-variables and values that will replace them in the HTML template.
|
10163 |
+
*/
|
10164 |
+
function sucuriscan_infosys_errorlogs(){
|
10165 |
+
$template_variables = array(
|
10166 |
+
'ErrorLog.Path' => '',
|
10167 |
+
'ErrorLog.Exists' => 'No',
|
10168 |
+
'ErrorLog.NoItemsVisibility' => 'visible',
|
10169 |
+
'ErrorLog.DisabledVisibility' => 'visible',
|
10170 |
+
'ErrorLog.FileSize' => '0B',
|
10171 |
+
'ErrorLog.List' => '',
|
10172 |
+
);
|
10173 |
+
|
10174 |
+
$error_log_path = realpath( ABSPATH . '/error_log' );
|
10175 |
+
$parse_errorlogs = ( SucuriScanOption::get_option(':parse_errorlogs') !== 'disabled' );
|
10176 |
+
$errorlogs_limit = SucuriScanOption::get_option(':errorlogs_limit');
|
10177 |
+
|
10178 |
+
if ( $error_log_path && $parse_errorlogs ) {
|
10179 |
+
$template_variables['ErrorLog.Path'] = $error_log_path;
|
10180 |
+
$template_variables['ErrorLog.Exists'] = 'Yes';
|
10181 |
+
$template_variables['ErrorLog.FileSize'] = SucuriScan::human_filesize( filesize($error_log_path) );
|
10182 |
+
$template_variables['ErrorLog.DisabledVisibility'] = 'hidden';
|
10183 |
+
|
10184 |
+
$last_lines = SucuriScanFileInfo::tail_file( $error_log_path, $errorlogs_limit );
|
10185 |
+
$error_logs = SucuriScanFSScanner::parse_error_logs($last_lines);
|
10186 |
+
$error_logs = array_reverse($error_logs);
|
10187 |
+
$counter = 0;
|
10188 |
+
|
10189 |
+
foreach ( $error_logs as $error_log ) {
|
10190 |
+
$css_class = ( $counter % 2 == 0 ) ? '' : 'alternate';
|
10191 |
+
$template_variables['ErrorLog.List'] .= SucuriScanTemplate::get_snippet('infosys-errorlogs', array(
|
10192 |
+
'ErrorLog.CssClass' => $css_class,
|
10193 |
+
'ErrorLog.DateTime' => SucuriScan::datetime( $error_log->timestamp ),
|
10194 |
+
'ErrorLog.ErrorType' => SucuriScan::escape( $error_log->error_type ),
|
10195 |
+
'ErrorLog.ErrorCode' => SucuriScan::escape($error_log->error_code),
|
10196 |
+
'ErrorLog.ErrorAbbr' => strtoupper( substr($error_log->error_code, 0, 1) ),
|
10197 |
+
'ErrorLog.ErrorMessage' => SucuriScan::escape( $error_log->error_message ),
|
10198 |
+
'ErrorLog.FilePath' => SucuriScan::escape( $error_log->file_path ),
|
10199 |
+
'ErrorLog.LineNumber' => SucuriScan::escape( $error_log->line_number ),
|
10200 |
+
));
|
10201 |
+
$counter += 1;
|
10202 |
+
}
|
10203 |
+
|
10204 |
+
if ( $counter > 0 ) {
|
10205 |
+
$template_variables['ErrorLog.NoItemsVisibility'] = 'hidden';
|
10206 |
+
}
|
10207 |
+
}
|
10208 |
+
|
10209 |
+
return SucuriScanTemplate::get_section('infosys-errorlogs', $template_variables);
|
10210 |
+
}
|
10211 |
+
|
10212 |
/**
|
10213 |
* Gather information from the server, database engine, and PHP interpreter.
|
10214 |
*
|
10269 |
|
10270 |
$field_names = array(
|
10271 |
'safe_mode',
|
10272 |
+
'expose_php',
|
10273 |
'allow_url_fopen',
|
10274 |
'memory_limit',
|
10275 |
'upload_max_filesize',
|