Version Description
- Internal code cleanup and re-organization.
- More white lists for the integrity checks.
- Additional settings to customize some of the warnings.
Download this release
Release Info
Developer | dd@sucuri.net |
Plugin | Sucuri Security – Auditing, Malware Scanner and Security Hardening |
Version | 1.6.6 |
Comparing to | |
See all releases |
Code changes from version 1.6.5 to 1.6.6
- inc/css/index.html +1 -0
- inc/css/index.php +0 -15
- inc/css/sucuriscan-default-css.css +13 -4
- inc/images/index.html +1 -0
- inc/images/index.php +0 -15
- inc/index.html +1 -0
- inc/index.php +0 -15
- inc/js/index.html +1 -0
- inc/js/index.php +0 -15
- inc/tpl/index.html +1 -0
- inc/tpl/index.php +0 -15
- inc/tpl/infosys-cronjobs.html.tpl +66 -18
- inc/tpl/infosys-cronjobs.snippet.tpl +6 -4
- inc/tpl/infosys-htaccess.html.tpl +6 -5
- inc/tpl/infosys-serverinfo.html.tpl +1 -64
- inc/tpl/infosys-serverinfo.snippet.tpl +5 -0
- inc/tpl/infosys-wpconfig.html.tpl +2 -12
- inc/tpl/infosys-wpconfig.snippet.tpl +3 -2
- inc/tpl/infosys.html.tpl +3 -3
- inc/tpl/malwarescan.html.tpl +3 -6
- inc/tpl/monitoring.html.tpl +21 -21
- inc/tpl/posthack-resetpassword.html.tpl +12 -4
- inc/tpl/posthack-updatesecretkeys.html.tpl +30 -8
- inc/tpl/posthack-updatesecretkeys.snippet.tpl +6 -0
- inc/tpl/posthack.html.tpl +2 -2
- inc/tpl/settings-general.html.tpl +64 -28
- inc/tpl/{setup_notice.html.tpl → setup-notice.html.tpl} +1 -1
- index.html +1 -0
- index.php +0 -15
- readme.txt +7 -2
- sucuri.php +4632 -4099
inc/css/index.html
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
<!-- Avoid the directory listing. -->
|
inc/css/index.php
DELETED
@@ -1,15 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/**
|
4 |
-
* Avoid directory listing.
|
5 |
-
*
|
6 |
-
* @package Sucuri Plugin - SiteCheck Malware Scanner
|
7 |
-
* @author Yorman Arias <yorman.arias@sucuri.net>
|
8 |
-
* @author Daniel Cid <dcid@sucuri.net>
|
9 |
-
* @copyright Since 2010-2014 Sucuri Inc.
|
10 |
-
* @license Released under the GPL - see LICENSE file for details.
|
11 |
-
* @link https://wordpress.sucuri.net/
|
12 |
-
* @since File available since Release 0.1
|
13 |
-
*/
|
14 |
-
|
15 |
-
if( !defined('SUCURISCAN') ){ exit(0); }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
inc/css/sucuriscan-default-css.css
CHANGED
@@ -16,7 +16,13 @@
|
|
16 |
.sucuriscan-pull-right{float:right}
|
17 |
.sucuriscan-list li{list-style:disc;margin:0 0 5px 15px}
|
18 |
.sucuriscan-gradient, .sucuriscan-modal-header, .sucuriscan-maincontent .sucuriscan-table tr > th{background:#f1f1f1;background-image:-webkit-gradient(linear,left bottom,left top,from(#ececec),to(#f9f9f9));background-image:-webkit-linear-gradient(bottom,#ececec,#f9f9f9);background-image:-moz-linear-gradient(bottom,#ececec,#f9f9f9);background-image:-o-linear-gradient(bottom,#ececec,#f9f9f9);background-image:linear-gradient(to top,#ececec,#f9f9f9)}
|
19 |
-
/* WordPress Extra Buttons */
|
|
|
|
|
|
|
|
|
|
|
|
|
20 |
.wp-core-ui .button-danger.button-danger{background:#cc2e2e;border-color:#a20000;box-shadow:inset 0 1px 0 rgba(230, 120, 120, 0.6)}
|
21 |
.wp-core-ui .button-danger.focus, .wp-core-ui .button-danger.hover, .wp-core-ui .button-danger:focus, .wp-core-ui .button-danger:hover{background:#be1e1e}
|
22 |
.wp-core-ui .button-danger.focus, .wp-core-ui .button-danger:focus{border-color:#500e0e}
|
@@ -97,9 +103,10 @@
|
|
97 |
/* WordPress Alerts */
|
98 |
div.sucuriscan-alert{position:relative;margin:0 0 20px 0}
|
99 |
div.sucuriscan-alert > a.close{position:absolute;top:10px;right:10px;font-size:18px;font-weight:bold;text-decoration:none}
|
100 |
-
.sucuriscan-inline-alert, .sucuriscan-inline-alert-updated, .sucuriscan-inline-alert-error{background:#fff;box-shadow:0 1px 1px 0 rgba(0,0,0,.1);padding:0;border-left:4px solid #ddd}
|
101 |
-
.sucuriscan-inline-alert > p, .sucuriscan-inline-alert-updated > p, .sucuriscan-inline-alert-error > p{margin:0;padding:8px 12px;border:1px solid #ddd;border-left:0}
|
102 |
.sucuriscan-inline-alert-updated{border-left-color:#7ad03a}
|
|
|
103 |
.sucuriscan-inline-alert-error{border-left-color:#dd3d36}
|
104 |
/* Tabulation Panels */
|
105 |
.sucuriscan-tabs{}
|
@@ -124,6 +131,8 @@ div.sucuriscan-alert > a.close{position:absolute;top:10px;right:10px;font-size:1
|
|
124 |
.sucuriscan-loading .title{font-size:26px;margin-bottom:10px}
|
125 |
.sucuriscan-loading .description{font-size:18px}
|
126 |
.sucuriscan-sitelogo{width:190px;height:100px;background:url('http://sitecheck.sucuri.net/images/sucuri-sprite.png') no-repeat;margin:0 auto}
|
|
|
|
|
127 |
/* Scanner Results */
|
128 |
.sucuriscan-maincontent .sucuriscan-border{border:0;border-left:4px solid #ddd}
|
129 |
.sucuriscan-maincontent .sucuriscan-border > h3, .sucuriscan-maincontent .sucuriscan-border > .inside{border-top:1px solid #e5e5e5;border-right:1px solid #e5e5e5}
|
@@ -212,7 +221,7 @@ div.sucuriscan-alert > a.close{position:absolute;top:10px;right:10px;font-size:1
|
|
212 |
.sucuriscan-maincontent .sucuriscan-settings form{display:inline-block}
|
213 |
.sucuriscan-maincontent .sucuriscan-settings select, .sucuriscan-maincontent .sucuriscan-settings .input-text{min-width:220px}
|
214 |
.sucuriscan-maincontent .sucuriscan-settings-notifications{margin-top:0}
|
215 |
-
.sucuriscan-
|
216 |
/* Responsive Styles */
|
217 |
@media (max-width: 620px) {
|
218 |
.sucuriscan-tabs > ul li, .sucuriscan-tabs > ul li > a{display:block}
|
16 |
.sucuriscan-pull-right{float:right}
|
17 |
.sucuriscan-list li{list-style:disc;margin:0 0 5px 15px}
|
18 |
.sucuriscan-gradient, .sucuriscan-modal-header, .sucuriscan-maincontent .sucuriscan-table tr > th{background:#f1f1f1;background-image:-webkit-gradient(linear,left bottom,left top,from(#ececec),to(#f9f9f9));background-image:-webkit-linear-gradient(bottom,#ececec,#f9f9f9);background-image:-moz-linear-gradient(bottom,#ececec,#f9f9f9);background-image:-o-linear-gradient(bottom,#ececec,#f9f9f9);background-image:linear-gradient(to top,#ececec,#f9f9f9)}
|
19 |
+
/* WordPress Extra Buttons (success) */
|
20 |
+
.wp-core-ui .button-success.button-success{background:#74cc2e;border-color:#2da200;box-shadow:inset 0 1px 0 rgba(155, 230, 120, 0.6)}
|
21 |
+
.wp-core-ui .button-success.focus, .wp-core-ui .button-success.hover, .wp-core-ui .button-success:focus, .wp-core-ui .button-success:hover{background:#4bbe1e}
|
22 |
+
.wp-core-ui .button-success.focus, .wp-core-ui .button-success:focus{border-color:#23500e}
|
23 |
+
.wp-core-ui .button-success.active, .wp-core-ui .button-success.active:focus, .wp-core-ui .button-success.active:hover, .wp-core-ui .button-success:active{background:#47a61b;border-color:#358400}
|
24 |
+
.wp-core-ui .button-success-disabled, .wp-core-ui .button-success.disabled, .wp-core-ui .button-success:disabled, .wp-core-ui .button-success[disabled]{color:#b2e794 !important;background:#74ba29 !important;border-color:#3f7f1b !important}
|
25 |
+
/* WordPress Extra Buttons (danger) */
|
26 |
.wp-core-ui .button-danger.button-danger{background:#cc2e2e;border-color:#a20000;box-shadow:inset 0 1px 0 rgba(230, 120, 120, 0.6)}
|
27 |
.wp-core-ui .button-danger.focus, .wp-core-ui .button-danger.hover, .wp-core-ui .button-danger:focus, .wp-core-ui .button-danger:hover{background:#be1e1e}
|
28 |
.wp-core-ui .button-danger.focus, .wp-core-ui .button-danger:focus{border-color:#500e0e}
|
103 |
/* WordPress Alerts */
|
104 |
div.sucuriscan-alert{position:relative;margin:0 0 20px 0}
|
105 |
div.sucuriscan-alert > a.close{position:absolute;top:10px;right:10px;font-size:18px;font-weight:bold;text-decoration:none}
|
106 |
+
.sucuriscan-inline-alert, .sucuriscan-inline-alert-updated, .sucuriscan-inline-alert-error, .sucuriscan-inline-alert-warning{background:#fff;box-shadow:0 1px 1px 0 rgba(0,0,0,.1);padding:0;border-left:4px solid #ddd}
|
107 |
+
.sucuriscan-inline-alert > p, .sucuriscan-inline-alert-updated > p, .sucuriscan-inline-alert-error > p, .sucuriscan-inline-alert-warning > p{margin:0;padding:8px 12px;border:1px solid #ddd;border-left:0}
|
108 |
.sucuriscan-inline-alert-updated{border-left-color:#7ad03a}
|
109 |
+
.sucuriscan-inline-alert-warning{border-left-color:#ffba00}
|
110 |
.sucuriscan-inline-alert-error{border-left-color:#dd3d36}
|
111 |
/* Tabulation Panels */
|
112 |
.sucuriscan-tabs{}
|
131 |
.sucuriscan-loading .title{font-size:26px;margin-bottom:10px}
|
132 |
.sucuriscan-loading .description{font-size:18px}
|
133 |
.sucuriscan-sitelogo{width:190px;height:100px;background:url('http://sitecheck.sucuri.net/images/sucuri-sprite.png') no-repeat;margin:0 auto}
|
134 |
+
.sucuriscan-sitecheck-form{margin:20px 0 0 0}
|
135 |
+
.sucuriscan-sitecheck-form .button.button-hero{padding:0 46px}
|
136 |
/* Scanner Results */
|
137 |
.sucuriscan-maincontent .sucuriscan-border{border:0;border-left:4px solid #ddd}
|
138 |
.sucuriscan-maincontent .sucuriscan-border > h3, .sucuriscan-maincontent .sucuriscan-border > .inside{border-top:1px solid #e5e5e5;border-right:1px solid #e5e5e5}
|
221 |
.sucuriscan-maincontent .sucuriscan-settings form{display:inline-block}
|
222 |
.sucuriscan-maincontent .sucuriscan-settings select, .sucuriscan-maincontent .sucuriscan-settings .input-text{min-width:220px}
|
223 |
.sucuriscan-maincontent .sucuriscan-settings-notifications{margin-top:0}
|
224 |
+
.sucuriscan-maincontent .sucuriscan-wpcron-list{margin-top:0}
|
225 |
/* Responsive Styles */
|
226 |
@media (max-width: 620px) {
|
227 |
.sucuriscan-tabs > ul li, .sucuriscan-tabs > ul li > a{display:block}
|
inc/images/index.html
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
<!-- Avoid the directory listing. -->
|
inc/images/index.php
DELETED
@@ -1,15 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/**
|
4 |
-
* Avoid directory listing.
|
5 |
-
*
|
6 |
-
* @package Sucuri Plugin - SiteCheck Malware Scanner
|
7 |
-
* @author Yorman Arias <yorman.arias@sucuri.net>
|
8 |
-
* @author Daniel Cid <dcid@sucuri.net>
|
9 |
-
* @copyright Since 2010-2014 Sucuri Inc.
|
10 |
-
* @license Released under the GPL - see LICENSE file for details.
|
11 |
-
* @link https://wordpress.sucuri.net/
|
12 |
-
* @since File available since Release 0.1
|
13 |
-
*/
|
14 |
-
|
15 |
-
if( !defined('SUCURISCAN') ){ exit(0); }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
inc/index.html
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
<!-- Avoid the directory listing. -->
|
inc/index.php
DELETED
@@ -1,15 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/**
|
4 |
-
* Avoid directory listing.
|
5 |
-
*
|
6 |
-
* @package Sucuri Plugin - SiteCheck Malware Scanner
|
7 |
-
* @author Yorman Arias <yorman.arias@sucuri.net>
|
8 |
-
* @author Daniel Cid <dcid@sucuri.net>
|
9 |
-
* @copyright Since 2010-2014 Sucuri Inc.
|
10 |
-
* @license Released under the GPL - see LICENSE file for details.
|
11 |
-
* @link https://wordpress.sucuri.net/
|
12 |
-
* @since File available since Release 0.1
|
13 |
-
*/
|
14 |
-
|
15 |
-
if( !defined('SUCURISCAN') ){ exit(0); }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
inc/js/index.html
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
<!-- Avoid the directory listing. -->
|
inc/js/index.php
DELETED
@@ -1,15 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/**
|
4 |
-
* Avoid directory listing.
|
5 |
-
*
|
6 |
-
* @package Sucuri Plugin - SiteCheck Malware Scanner
|
7 |
-
* @author Yorman Arias <yorman.arias@sucuri.net>
|
8 |
-
* @author Daniel Cid <dcid@sucuri.net>
|
9 |
-
* @copyright Since 2010-2014 Sucuri Inc.
|
10 |
-
* @license Released under the GPL - see LICENSE file for details.
|
11 |
-
* @link https://wordpress.sucuri.net/
|
12 |
-
* @since File available since Release 0.1
|
13 |
-
*/
|
14 |
-
|
15 |
-
if( !defined('SUCURISCAN') ){ exit(0); }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
inc/tpl/index.html
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
<!-- Avoid the directory listing. -->
|
inc/tpl/index.php
DELETED
@@ -1,15 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/**
|
4 |
-
* Avoid directory listing.
|
5 |
-
*
|
6 |
-
* @package Sucuri Plugin - SiteCheck Malware Scanner
|
7 |
-
* @author Yorman Arias <yorman.arias@sucuri.net>
|
8 |
-
* @author Daniel Cid <dcid@sucuri.net>
|
9 |
-
* @copyright Since 2010-2014 Sucuri Inc.
|
10 |
-
* @license Released under the GPL - see LICENSE file for details.
|
11 |
-
* @link https://wordpress.sucuri.net/
|
12 |
-
* @since File available since Release 0.1
|
13 |
-
*/
|
14 |
-
|
15 |
-
if( !defined('SUCURISCAN') ){ exit(0); }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
inc/tpl/infosys-cronjobs.html.tpl
CHANGED
@@ -1,19 +1,67 @@
|
|
1 |
|
2 |
-
<
|
3 |
-
<
|
4 |
-
<
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
</
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
|
2 |
+
<div id="poststuff">
|
3 |
+
<div class="postbox sucuriscan-border sucuriscan-table-description sucuriscan-%%SUCURI.IgnoreRules.TableVisibility%%">
|
4 |
+
<h3>Scheduled Tasks (%%SUCURI.Cronjobs.Total%% tasks)</h3>
|
5 |
+
|
6 |
+
<div class="inside">
|
7 |
+
<p>
|
8 |
+
<strong>Scheduled Tasks</strong> are rules registered in your database by a
|
9 |
+
plugin, theme, or the base system itself; they are used to automatically execute
|
10 |
+
actions defined in the code every certain amount of time. A good use of these
|
11 |
+
rules is to generate backup files of your site, execute a security scanner, or
|
12 |
+
remove unused elements like drafts.
|
13 |
+
</p>
|
14 |
+
|
15 |
+
<div class="sucuriscan-inline-alert-warning">
|
16 |
+
<p>
|
17 |
+
Note that there are some scheduled tasks <em>(registered by the base
|
18 |
+
system)</em> that can not be removed permanently using this tool, tasks such as
|
19 |
+
the <strong>addon update</strong> and <strong>version checker</strong> are
|
20 |
+
required by the site to work correctly.
|
21 |
+
</p>
|
22 |
+
</div>
|
23 |
+
</div>
|
24 |
+
</div>
|
25 |
+
</div>
|
26 |
+
|
27 |
+
<form action="%%SUCURI.URL.Infosys%%#wordpress-cronjobs" method="post">
|
28 |
+
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
|
29 |
+
|
30 |
+
<table class="wp-list-table widefat sucuriscan-table sucuriscan-wpcron-list">
|
31 |
+
<thead>
|
32 |
+
<tr>
|
33 |
+
<th class="manage-column column-cb check-column">
|
34 |
+
<label class="screen-reader-text" for="cb-select-all-1">Select All</label>
|
35 |
+
<input id="cb-select-all-1" type="checkbox">
|
36 |
+
</th>
|
37 |
+
<th>Task</th>
|
38 |
+
<th>Schedule</th>
|
39 |
+
<th>Next due</th>
|
40 |
+
<th>Arguments</th>
|
41 |
+
</tr>
|
42 |
+
</thead>
|
43 |
+
|
44 |
+
<tbody>
|
45 |
+
%%SUCURI.Cronjobs.List%%
|
46 |
+
</tbody>
|
47 |
+
|
48 |
+
<tfoot>
|
49 |
+
<tr>
|
50 |
+
<td colspan="5">
|
51 |
+
<label>
|
52 |
+
<select name="sucuriscan_cronjob_action">
|
53 |
+
<option value="">Choose action</option>
|
54 |
+
<option value="runnow">Execute now</option>
|
55 |
+
<option value="hourly">Re-schedule to hourly</option>
|
56 |
+
<option value="twicedaily">Re-schedule to twicedaily</option>
|
57 |
+
<option value="daily">Re-schedule to daily</option>
|
58 |
+
<option value="remove">Remove</option>
|
59 |
+
</select>
|
60 |
+
</label>
|
61 |
+
<button type="submit" class="button button-primary">Send action</button>
|
62 |
+
</td>
|
63 |
+
</tr>
|
64 |
+
</tfoot>
|
65 |
+
</table>
|
66 |
+
|
67 |
+
</form>
|
inc/tpl/infosys-cronjobs.snippet.tpl
CHANGED
@@ -1,8 +1,10 @@
|
|
1 |
|
2 |
<tr class="%%SUCURI.Cronjob.CssClass%%">
|
3 |
-
<td
|
4 |
-
|
5 |
-
|
6 |
<td><span class="sucuriscan-monospace">%%SUCURI.Cronjob.Hook%%</span></td>
|
7 |
-
|
|
|
|
|
8 |
</tr>
|
1 |
|
2 |
<tr class="%%SUCURI.Cronjob.CssClass%%">
|
3 |
+
<td class="check-column">
|
4 |
+
<input type="checkbox" name="sucuriscan_cronjobs[]" value="%%SUCURI.Cronjob.Hook%%" />
|
5 |
+
</td>
|
6 |
<td><span class="sucuriscan-monospace">%%SUCURI.Cronjob.Hook%%</span></td>
|
7 |
+
<td>%%SUCURI.Cronjob.Schedule%%</td>
|
8 |
+
<td>%%SUCURI.Cronjob.NextTime%%</td>
|
9 |
+
<td>%%SUCURI.Cronjob.Arguments%%</td>
|
10 |
</tr>
|
inc/tpl/infosys-htaccess.html.tpl
CHANGED
@@ -1,14 +1,15 @@
|
|
1 |
|
2 |
<div id="poststuff" class="sucuriscan-infosys-htaccess">
|
3 |
<div class="postbox">
|
4 |
-
<h3>
|
5 |
|
6 |
<div class="inside">
|
7 |
<p>
|
8 |
-
The <code>.htaccess</code> is a distributed configuration file, and is how
|
9 |
-
configuration changes on a per-directory basis.
|
10 |
-
|
11 |
-
modifies this file to be
|
|
|
12 |
</p>
|
13 |
|
14 |
<div class="sucuriscan-inline-alert-%%SUCURI.HTAccess.MessageType%% sucuriscan-%%SUCURI.HTAccess.MessageVisible%%">
|
1 |
|
2 |
<div id="poststuff" class="sucuriscan-infosys-htaccess">
|
3 |
<div class="postbox">
|
4 |
+
<h3>Access File Integrity</h3>
|
5 |
|
6 |
<div class="inside">
|
7 |
<p>
|
8 |
+
The <code>.htaccess</code> is a distributed configuration file, and is how the
|
9 |
+
Apache web server handles configuration changes on a per-directory basis.
|
10 |
+
WordPress uses this file to manipulate how Apache serves files from its root
|
11 |
+
directory and subdirectories thereof; most notably, it modifies this file to be
|
12 |
+
able to handle pretty permalinks.
|
13 |
</p>
|
14 |
|
15 |
<div class="sucuriscan-inline-alert-%%SUCURI.HTAccess.MessageType%% sucuriscan-%%SUCURI.HTAccess.MessageVisible%%">
|
inc/tpl/infosys-serverinfo.html.tpl
CHANGED
@@ -1,69 +1,6 @@
|
|
1 |
|
2 |
<table class="wp-list-table widefat sucuriscan-server-info">
|
3 |
<tbody>
|
4 |
-
|
5 |
-
<td>Sucuri Plugin version</td>
|
6 |
-
<td><span class="sucuriscan-monospace">%%SUCURI.PluginVersion%%</span></td>
|
7 |
-
</tr>
|
8 |
-
<tr>
|
9 |
-
<td>Sucuri Plugin MD5Sum (sucuri.php)</td>
|
10 |
-
<td><span class="sucuriscan-monospace">%%SUCURI.PluginMD5%%</span></td>
|
11 |
-
</tr>
|
12 |
-
<tr class="alternate">
|
13 |
-
<td>Sucuri Plugin Last-time scan</td>
|
14 |
-
<td><span class="sucuriscan-monospace">%%SUCURI.PluginRuntimeDatetime%%</span></td>
|
15 |
-
</tr>
|
16 |
-
<tr>
|
17 |
-
<td>Operating System</td>
|
18 |
-
<td><span class="sucuriscan-monospace">%%SUCURI.OperatingSystem%%</span></td>
|
19 |
-
</tr>
|
20 |
-
<tr class="alternate">
|
21 |
-
<td>Server</td>
|
22 |
-
<td><span class="sucuriscan-monospace">%%SUCURI.Server%%</span></td>
|
23 |
-
</tr>
|
24 |
-
<tr>
|
25 |
-
<td>Memory usage</td>
|
26 |
-
<td><span class="sucuriscan-monospace">%%SUCURI.MemoryUsage%%</span></td>
|
27 |
-
</tr>
|
28 |
-
<tr class="alternate">
|
29 |
-
<td>MYSQL Version</td>
|
30 |
-
<td><span class="sucuriscan-monospace">%%SUCURI.MySQLVersion%%</span></td>
|
31 |
-
</tr>
|
32 |
-
<tr>
|
33 |
-
<td>SQL Mode</td>
|
34 |
-
<td><span class="sucuriscan-monospace">%%SUCURI.SQLMode%%</span></td>
|
35 |
-
</tr>
|
36 |
-
<tr class="alternate">
|
37 |
-
<td>PHP Version</td>
|
38 |
-
<td><span class="sucuriscan-monospace">%%SUCURI.PHPVersion%%</span></td>
|
39 |
-
</tr>
|
40 |
-
<tr>
|
41 |
-
<td>PHP Safe Mode</td>
|
42 |
-
<td><span class="sucuriscan-monospace">%%SUCURI.SafeMode%%</span></td>
|
43 |
-
</tr>
|
44 |
-
<tr class="alternate">
|
45 |
-
<td>PHP Allow URL fopen</td>
|
46 |
-
<td><span class="sucuriscan-monospace">%%SUCURI.AllowUrlFopen%%</span></td>
|
47 |
-
</tr>
|
48 |
-
<tr>
|
49 |
-
<td>PHP Memory Limit</td>
|
50 |
-
<td><span class="sucuriscan-monospace">%%SUCURI.MemoryLimit%%</span></td>
|
51 |
-
</tr>
|
52 |
-
<tr class="alternate">
|
53 |
-
<td>PHP Max Upload Size</td>
|
54 |
-
<td><span class="sucuriscan-monospace">%%SUCURI.UploadMaxFilesize%%</span></td>
|
55 |
-
</tr>
|
56 |
-
<tr>
|
57 |
-
<td>PHP Max Post Size</td>
|
58 |
-
<td><span class="sucuriscan-monospace">%%SUCURI.PostMaxSize%%</span></td>
|
59 |
-
</tr>
|
60 |
-
<tr class="alternate">
|
61 |
-
<td>PHP Max Script Execute Time</td>
|
62 |
-
<td><span class="sucuriscan-monospace">%%SUCURI.MaxExecutionTime%%</span></td>
|
63 |
-
</tr>
|
64 |
-
<tr>
|
65 |
-
<td>PHP Max Input Time</td>
|
66 |
-
<td><span class="sucuriscan-monospace">%%SUCURI.MaxInputTime%%</span></td>
|
67 |
-
</tr>
|
68 |
</tbody>
|
69 |
</table>
|
1 |
|
2 |
<table class="wp-list-table widefat sucuriscan-server-info">
|
3 |
<tbody>
|
4 |
+
%%SUCURI.ServerInfo.Variables%%
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5 |
</tbody>
|
6 |
</table>
|
inc/tpl/infosys-serverinfo.snippet.tpl
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
<tr class="%%SUCURI.ServerInfo.CssClass%%">
|
3 |
+
<td>%%SUCURI.ServerInfo.Title%%</td>
|
4 |
+
<td><span class="sucuriscan-monospace">%%SUCURI.ServerInfo.Value%%</span></td>
|
5 |
+
</tr>
|
inc/tpl/infosys-wpconfig.html.tpl
CHANGED
@@ -1,14 +1,8 @@
|
|
1 |
|
2 |
-
<table class="wp-list-table widefat sucuriscan-wpconfig-rules">
|
3 |
<thead>
|
4 |
-
<th colspan="7" class="thead-with-button">
|
5 |
-
<span>WP-Config Variables</span>
|
6 |
-
<div class="thead-topright-action">
|
7 |
-
<a href="%%SUCURI.WordpressConfig.ThickboxURL%%" title="WordPress Config Variables" class="button button-primary thickbox">View File</a>
|
8 |
-
</div>
|
9 |
-
</th>
|
10 |
<tr>
|
11 |
-
<th>Variable
|
12 |
<th>Value</th>
|
13 |
</tr>
|
14 |
</thead>
|
@@ -17,7 +11,3 @@
|
|
17 |
%%SUCURI.WordpressConfig.Rules%%
|
18 |
</tbody>
|
19 |
</table>
|
20 |
-
|
21 |
-
<div id="sucuriscan-wpconfig-content" style="display:none">
|
22 |
-
<textarea class="sucuriscan-full-textarea sucuriscan-wpconfig-textarea sucuriscan-monospace">%%SUCURI.WordpressConfig.Content%%</textarea>
|
23 |
-
</div>
|
1 |
|
2 |
+
<table class="wp-list-table widefat sucuriscan-table sucuriscan-wpconfig-rules">
|
3 |
<thead>
|
|
|
|
|
|
|
|
|
|
|
|
|
4 |
<tr>
|
5 |
+
<th>Variable</th>
|
6 |
<th>Value</th>
|
7 |
</tr>
|
8 |
</thead>
|
11 |
%%SUCURI.WordpressConfig.Rules%%
|
12 |
</tbody>
|
13 |
</table>
|
|
|
|
|
|
|
|
inc/tpl/infosys-wpconfig.snippet.tpl
CHANGED
@@ -1,4 +1,5 @@
|
|
|
|
1 |
<tr class="%%SUCURI.WordpressConfig.CssClass%%">
|
2 |
-
<td class="sucuriscan-monospace"
|
3 |
-
<td class="
|
4 |
</tr>
|
1 |
+
|
2 |
<tr class="%%SUCURI.WordpressConfig.CssClass%%">
|
3 |
+
<td><span class="sucuriscan-monospace">%%SUCURI.WordpressConfig.VariableName%%</span></td>
|
4 |
+
<td><span class="%%SUCURI.WordpressConfig.VariableCssClass%%">%%SUCURI.WordpressConfig.VariableValue%%</span></td>
|
5 |
</tr>
|
inc/tpl/infosys.html.tpl
CHANGED
@@ -5,13 +5,13 @@
|
|
5 |
<a href="#" data-tabname="server-info">Plugin & Server Info</a>
|
6 |
</li>
|
7 |
<li>
|
8 |
-
<a href="#" data-tabname="wordpress-cronjobs">
|
9 |
</li>
|
10 |
<li>
|
11 |
-
<a href="#" data-tabname="htaccess-integrity">
|
12 |
</li>
|
13 |
<li>
|
14 |
-
<a href="#" data-tabname="wpconfig-vars">
|
15 |
</li>
|
16 |
</ul>
|
17 |
|
5 |
<a href="#" data-tabname="server-info">Plugin & Server Info</a>
|
6 |
</li>
|
7 |
<li>
|
8 |
+
<a href="#" data-tabname="wordpress-cronjobs">Scheduled Tasks</a>
|
9 |
</li>
|
10 |
<li>
|
11 |
+
<a href="#" data-tabname="htaccess-integrity">Access File Integrity</a>
|
12 |
</li>
|
13 |
<li>
|
14 |
+
<a href="#" data-tabname="wpconfig-vars">Config. Variables</a>
|
15 |
</li>
|
16 |
</ul>
|
17 |
|
inc/tpl/malwarescan.html.tpl
CHANGED
@@ -4,14 +4,11 @@
|
|
4 |
|
5 |
<p class="description">Visit our <a href="http://sucuri.net/signup?fromloader" target="_blank">coverage & pricing</a> page for details on how sucuri can help you.</p>
|
6 |
|
7 |
-
<
|
8 |
-
|
9 |
-
<div class="sucuriscan-sitelogo"> </div>
|
10 |
-
|
11 |
-
<form method="post" name="sucuriscan_sitecheck_form">
|
12 |
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
|
13 |
<input type="hidden" name="sucuriscan_malware_scan" value="1" />
|
|
|
14 |
</form>
|
15 |
|
16 |
-
<
|
17 |
</div>
|
4 |
|
5 |
<p class="description">Visit our <a href="http://sucuri.net/signup?fromloader" target="_blank">coverage & pricing</a> page for details on how sucuri can help you.</p>
|
6 |
|
7 |
+
<form action="%%SUCURI.URL.Scanner%%" method="post" name="sucuriscan_sitecheck_form">
|
|
|
|
|
|
|
|
|
8 |
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
|
9 |
<input type="hidden" name="sucuriscan_malware_scan" value="1" />
|
10 |
+
<button type="submit" class="button button-hero button-primary">Scan Website</button>
|
11 |
</form>
|
12 |
|
13 |
+
<div class="sucuriscan-sitelogo"> </div>
|
14 |
</div>
|
inc/tpl/monitoring.html.tpl
CHANGED
@@ -1,34 +1,34 @@
|
|
1 |
|
2 |
<div id="poststuff">
|
3 |
|
4 |
-
<div class="postbox sucuriscan-
|
5 |
-
<h3>
|
6 |
|
7 |
<div class="inside">
|
8 |
<p>
|
9 |
-
A powerful <b>WAF</b> <em>(Web Application Firewall)</em> and <b>Intrusion
|
10 |
-
system for any WordPress user
|
11 |
-
|
|
|
|
|
|
|
|
|
12 |
</p>
|
13 |
|
14 |
-
<
|
15 |
-
<
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
<a href="https://dashboard.sucuri.net/cloudproxy/" target="_blank"> CloudProxy Dashboard</a>
|
22 |
-
or use our documentation here <a href="http://kb.sucuri.net/cloudproxy" target="_blank">
|
23 |
-
KB CloudProxy</a>.
|
24 |
-
</li>
|
25 |
-
<li>You are all set. There is nothing else to do.</li>
|
26 |
-
</ol>
|
27 |
|
28 |
<p>
|
29 |
-
|
30 |
-
|
31 |
-
|
|
|
|
|
32 |
</p>
|
33 |
</div>
|
34 |
</div>
|
1 |
|
2 |
<div id="poststuff">
|
3 |
|
4 |
+
<div class="postbox sucuriscan-border sucuriscan-border-info sucuriscan-%%SUCURI.Monitoring.InstructionsVisibility%%">
|
5 |
+
<h3>Activation instructions</h3>
|
6 |
|
7 |
<div class="inside">
|
8 |
<p>
|
9 |
+
A powerful <b>WAF</b> <em>(Web Application Firewall)</em> and <b>Intrusion
|
10 |
+
Prevention</b> system for any WordPress user and many other platforms. This page
|
11 |
+
will help you to configure and monitor your site through <strong>Sucuri
|
12 |
+
CloudProxy</strong>. Once enabled, our firewall will act as a shield, protecting
|
13 |
+
your site from attacks and preventing malware infections and reinfections. It
|
14 |
+
will block SQL injection attempts, brute force attacks, XSS, RFI, backdoors and
|
15 |
+
many other threats against your site.
|
16 |
</p>
|
17 |
|
18 |
+
<p>
|
19 |
+
Add your <strong>API key</strong> in the form bellow, click in the
|
20 |
+
<em>activate</em> button and after that your site will start communicating with
|
21 |
+
the official CloudProxy API service. Your account settings, whitelisted IP
|
22 |
+
addresses, audit logs, and the cache status will be displayed when the API key
|
23 |
+
is validated.
|
24 |
+
</p>
|
|
|
|
|
|
|
|
|
|
|
|
|
25 |
|
26 |
<p>
|
27 |
+
<em>[1]</em> More information about <a href="http://cloudproxy.sucuri.net/" target="_blank">CloudProxy</a>.<br>
|
28 |
+
<em>[2]</em> Configuration instructions and videos in the official <a href="http://kb.sucuri.net/cloudproxy"
|
29 |
+
target="_blank">Knowledge Base</a> site.<br>
|
30 |
+
<em>[3]</em> <a href="https://login.sucuri.net/signup2/create?CloudProxy" target="_blank">Sign up</a> for a new
|
31 |
+
account and start protecting your site with CloudProxy.
|
32 |
</p>
|
33 |
</div>
|
34 |
</div>
|
inc/tpl/posthack-resetpassword.html.tpl
CHANGED
@@ -7,12 +7,20 @@
|
|
7 |
<input type="hidden" name="sucuriscan_reset_password" value="1" />
|
8 |
|
9 |
<p>
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
password reset your current session will be closed and you'll need to login again.
|
14 |
</p>
|
15 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
16 |
<table class="wp-list-table widefat sucuriscan-table">
|
17 |
<thead>
|
18 |
<tr>
|
7 |
<input type="hidden" name="sucuriscan_reset_password" value="1" />
|
8 |
|
9 |
<p>
|
10 |
+
You can generate a new random password for the user accounts that you select
|
11 |
+
from the list. An email with the new password will be sent to the email address
|
12 |
+
of each chosen users.
|
|
|
13 |
</p>
|
14 |
|
15 |
+
<div class="sucuriscan-inline-alert-warning">
|
16 |
+
<p>
|
17 |
+
If you choose to change the password of your own user, then your current session
|
18 |
+
will expire inmediately. You will need to log into the admin panel with the new
|
19 |
+
password that will be sent to your email. If you are unsure of this, do not
|
20 |
+
select your account from the list.
|
21 |
+
</p>
|
22 |
+
</div>
|
23 |
+
|
24 |
<table class="wp-list-table widefat sucuriscan-table">
|
25 |
<thead>
|
26 |
<tr>
|
inc/tpl/posthack-updatesecretkeys.html.tpl
CHANGED
@@ -1,17 +1,39 @@
|
|
1 |
|
2 |
-
<div id="poststuff" class="sucuriscan-update-
|
3 |
<div class="postbox">
|
4 |
<div class="inside">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5 |
<form method="post">
|
6 |
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
|
7 |
<input type="hidden" name="sucuriscan_update_wpconfig" value="1" />
|
8 |
|
9 |
-
<p>
|
10 |
-
Use this button to update the security keys stored in the <code>wp-config.php</code>
|
11 |
-
file, we will use the official WordPress Secret-Key API Generator. After the
|
12 |
-
update your current session will be closed and you'll need to login again.
|
13 |
-
</p>
|
14 |
-
|
15 |
<p>
|
16 |
<label>
|
17 |
<input type="hidden" name="sucuriscan_process_form" value="0" />
|
@@ -20,7 +42,7 @@
|
|
20 |
</label>
|
21 |
</p>
|
22 |
|
23 |
-
<input type="submit" value="
|
24 |
</form>
|
25 |
|
26 |
<div class="sucuriscan_wpconfig_keys_updated sucuriscan-%%SUCURI.WPConfigUpdate.Visibility%%">
|
1 |
|
2 |
+
<div id="poststuff" class="sucuriscan-update-security-keys">
|
3 |
<div class="postbox">
|
4 |
<div class="inside">
|
5 |
+
<p>
|
6 |
+
The secret or security keys are a list of constants added to your site to ensure
|
7 |
+
better encryption of information stored in the user's cookies. A secret key
|
8 |
+
makes your site harder to hack and access by adding random elements to the
|
9 |
+
password. You do not have to remember the keys, just write a random,
|
10 |
+
complicated, and long string in the <code>wp-config.php</code> file. You can
|
11 |
+
change these keys at any point in time to invalidate all existing cookies,
|
12 |
+
forcing all users to login again.
|
13 |
+
</p>
|
14 |
+
|
15 |
+
<div class="sucuriscan-inline-alert-warning">
|
16 |
+
<p>Your session will expire immediately after the security keys are changed.</p>
|
17 |
+
</div>
|
18 |
+
|
19 |
+
<table class="wp-list-table widefat sucuriscan-table sucuriscan-security-keys-table">
|
20 |
+
<thead>
|
21 |
+
<tr>
|
22 |
+
<th>Key</th>
|
23 |
+
<th>Value</th>
|
24 |
+
<th>Status</th>
|
25 |
+
</tr>
|
26 |
+
</thead>
|
27 |
+
|
28 |
+
<tbody>
|
29 |
+
%%SUCURI.SecurityKeys.List%%
|
30 |
+
</tbody>
|
31 |
+
</table>
|
32 |
+
|
33 |
<form method="post">
|
34 |
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
|
35 |
<input type="hidden" name="sucuriscan_update_wpconfig" value="1" />
|
36 |
|
|
|
|
|
|
|
|
|
|
|
|
|
37 |
<p>
|
38 |
<label>
|
39 |
<input type="hidden" name="sucuriscan_process_form" value="0" />
|
42 |
</label>
|
43 |
</p>
|
44 |
|
45 |
+
<input type="submit" value="Generate New Security Keys" class="button button-primary" />
|
46 |
</form>
|
47 |
|
48 |
<div class="sucuriscan_wpconfig_keys_updated sucuriscan-%%SUCURI.WPConfigUpdate.Visibility%%">
|
inc/tpl/posthack-updatesecretkeys.snippet.tpl
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
<tr class="%%SUCURI.SecurityKey.CssClass%%">
|
3 |
+
<td><span class="sucuriscan-monospace">%%SUCURI.SecurityKey.KeyName%%</span></td>
|
4 |
+
<td><span class="sucuriscan-monospace">%%SUCURI.SecurityKey.KeyValue%%</span></td>
|
5 |
+
<td><span class="sucuriscan-label-%%SUCURI.SecurityKey.KeyStatusCssClass%%">%%SUCURI.SecurityKey.KeyStatusText%%</span></td>
|
6 |
+
</tr>
|
inc/tpl/posthack.html.tpl
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
<div class="sucuriscan-tabs">
|
3 |
<ul>
|
4 |
<li>
|
5 |
-
<a href="#" data-tabname="update-
|
6 |
</li>
|
7 |
<li>
|
8 |
<a href="#" data-tabname="reset-users-password">Reset User's Password</a>
|
@@ -13,7 +13,7 @@
|
|
13 |
</ul>
|
14 |
|
15 |
<div class="sucuriscan-tab-containers">
|
16 |
-
<div id="sucuriscan-update-
|
17 |
%%SUCURI.UpdateSecretKeys%%
|
18 |
</div>
|
19 |
|
2 |
<div class="sucuriscan-tabs">
|
3 |
<ul>
|
4 |
<li>
|
5 |
+
<a href="#" data-tabname="update-security-keys">Security Keys</a>
|
6 |
</li>
|
7 |
<li>
|
8 |
<a href="#" data-tabname="reset-users-password">Reset User's Password</a>
|
13 |
</ul>
|
14 |
|
15 |
<div class="sucuriscan-tab-containers">
|
16 |
+
<div id="sucuriscan-update-security-keys">
|
17 |
%%SUCURI.UpdateSecretKeys%%
|
18 |
</div>
|
19 |
|
inc/tpl/settings-general.html.tpl
CHANGED
@@ -6,7 +6,7 @@
|
|
6 |
<tr>
|
7 |
<th colspan="3" class="thead-with-button">
|
8 |
<span>Plugin Settings</span>
|
9 |
-
<form method="post" class="thead-topright-action">
|
10 |
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
|
11 |
<button type="submit" name="sucuriscan_reset_options" class="button-primary">Reset plugin options</button>
|
12 |
</form>
|
@@ -34,18 +34,18 @@
|
|
34 |
<span class="sucuriscan-monospace">%%SUCURI.APIKey%%</span>
|
35 |
</td>
|
36 |
<td class="td-with-button">
|
37 |
-
<form method="post" class="sucuriscan-%%SUCURI.APIKey.RecoverVisibility%%">
|
38 |
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
|
39 |
-
<button type="submit" name="
|
40 |
</form>
|
41 |
|
42 |
-
<form method="post" class="sucuriscan-%%SUCURI.APIKey.ManualKeyFormVisibility%%">
|
43 |
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
|
44 |
<input type="text" name="sucuriscan_manual_api_key" class="input-text" placeholder="API key sent to your email" />
|
45 |
<button type="submit" class="button-primary">Save</button>
|
46 |
</form>
|
47 |
|
48 |
-
<form method="post" class="sucuriscan-%%SUCURI.APIKey.RemoveVisibility%%">
|
49 |
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
|
50 |
<button type="submit" name="sucuriscan_remove_api_key" class="button-primary button-danger">Remove</button>
|
51 |
</form>
|
@@ -53,21 +53,10 @@
|
|
53 |
</tr>
|
54 |
|
55 |
<tr>
|
56 |
-
<td>Last Scanning</td>
|
57 |
-
<td><span class="sucuriscan-monospace">%%SUCURI.ScanningRuntimeHuman%%</span></td>
|
58 |
-
<td class="td-with-button">
|
59 |
-
<form action="%%SUCURI.URL.Home%%" method="post">
|
60 |
-
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
|
61 |
-
<button type="submit" name="sucuriscan_force_scan" class="button-primary">Force Scan</button>
|
62 |
-
</form>
|
63 |
-
</td>
|
64 |
-
</tr>
|
65 |
-
|
66 |
-
<tr class="alternate">
|
67 |
<td>Notify events to</td>
|
68 |
<td><a href="mailto:%%SUCURI.NotifyTo%%">%%SUCURI.NotifyTo%%</a></td>
|
69 |
<td class="td-with-button">
|
70 |
-
<form method="post">
|
71 |
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
|
72 |
<input type="text" name="sucuriscan_notify_to" class="input-text" placeholder="Send notifications to..." />
|
73 |
<button type="submit" class="button-primary">Change</button>
|
@@ -75,11 +64,11 @@
|
|
75 |
</td>
|
76 |
</tr>
|
77 |
|
78 |
-
<tr>
|
79 |
<td>Alerts per hour</td>
|
80 |
<td>%%SUCURI.EmailsPerHour%%</td>
|
81 |
<td class="td-with-button">
|
82 |
-
<form method="post">
|
83 |
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
|
84 |
<select name="sucuriscan_emails_per_hour">
|
85 |
%%SUCURI.EmailsPerHourOptions%%
|
@@ -89,11 +78,11 @@
|
|
89 |
</td>
|
90 |
</tr>
|
91 |
|
92 |
-
<tr
|
93 |
<td>Consider brute-force after</td>
|
94 |
<td>%%SUCURI.MaximumFailedLogins%%</td>
|
95 |
<td class="td-with-button">
|
96 |
-
<form method="post">
|
97 |
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
|
98 |
<select name="sucuriscan_maximum_failed_logins">
|
99 |
%%SUCURI.MaximumFailedLoginsOptions%%
|
@@ -103,11 +92,11 @@
|
|
103 |
</td>
|
104 |
</tr>
|
105 |
|
106 |
-
<tr>
|
107 |
<td>Verify SSL Cert</td>
|
108 |
<td>%%SUCURI.VerifySSLCert%%</td>
|
109 |
<td class="td-with-button">
|
110 |
-
<form method="post">
|
111 |
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
|
112 |
<select name="sucuriscan_verify_ssl_cert">
|
113 |
%%SUCURI.VerifySSLCertOptions%%
|
@@ -117,11 +106,58 @@
|
|
117 |
</td>
|
118 |
</tr>
|
119 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
120 |
<tr class="alternate">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
121 |
<td>Scanning frequency</td>
|
122 |
-
<td
|
123 |
<td class="td-with-button">
|
124 |
-
<form method="post">
|
125 |
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
|
126 |
<select name="sucuriscan_scan_frequency">
|
127 |
%%SUCURI.ScanningFrequencyOptions%%
|
@@ -131,11 +167,11 @@
|
|
131 |
</td>
|
132 |
</tr>
|
133 |
|
134 |
-
<tr class="sucuriscan-%%SUCURI.ScanningInterfaceVisibility%%">
|
135 |
<td>Scanning interface</td>
|
136 |
-
<td
|
137 |
<td class="td-with-button">
|
138 |
-
<form method="post">
|
139 |
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
|
140 |
<select name="sucuriscan_scan_interface">
|
141 |
%%SUCURI.ScanningInterfaceOptions%%
|
6 |
<tr>
|
7 |
<th colspan="3" class="thead-with-button">
|
8 |
<span>Plugin Settings</span>
|
9 |
+
<form action="%%SUCURI.URL.Settings%%" method="post" class="thead-topright-action">
|
10 |
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
|
11 |
<button type="submit" name="sucuriscan_reset_options" class="button-primary">Reset plugin options</button>
|
12 |
</form>
|
34 |
<span class="sucuriscan-monospace">%%SUCURI.APIKey%%</span>
|
35 |
</td>
|
36 |
<td class="td-with-button">
|
37 |
+
<form action="%%SUCURI.URL.Settings%%" method="post" class="sucuriscan-%%SUCURI.APIKey.RecoverVisibility%%">
|
38 |
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
|
39 |
+
<button type="submit" name="sucuriscan_recover_key" class="button-primary">Recover</button>
|
40 |
</form>
|
41 |
|
42 |
+
<form action="%%SUCURI.URL.Settings%%" method="post" class="sucuriscan-%%SUCURI.APIKey.ManualKeyFormVisibility%%">
|
43 |
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
|
44 |
<input type="text" name="sucuriscan_manual_api_key" class="input-text" placeholder="API key sent to your email" />
|
45 |
<button type="submit" class="button-primary">Save</button>
|
46 |
</form>
|
47 |
|
48 |
+
<form action="%%SUCURI.URL.Settings%%" method="post" class="sucuriscan-%%SUCURI.APIKey.RemoveVisibility%%">
|
49 |
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
|
50 |
<button type="submit" name="sucuriscan_remove_api_key" class="button-primary button-danger">Remove</button>
|
51 |
</form>
|
53 |
</tr>
|
54 |
|
55 |
<tr>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
56 |
<td>Notify events to</td>
|
57 |
<td><a href="mailto:%%SUCURI.NotifyTo%%">%%SUCURI.NotifyTo%%</a></td>
|
58 |
<td class="td-with-button">
|
59 |
+
<form action="%%SUCURI.URL.Settings%%" method="post">
|
60 |
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
|
61 |
<input type="text" name="sucuriscan_notify_to" class="input-text" placeholder="Send notifications to..." />
|
62 |
<button type="submit" class="button-primary">Change</button>
|
64 |
</td>
|
65 |
</tr>
|
66 |
|
67 |
+
<tr class="alternate">
|
68 |
<td>Alerts per hour</td>
|
69 |
<td>%%SUCURI.EmailsPerHour%%</td>
|
70 |
<td class="td-with-button">
|
71 |
+
<form action="%%SUCURI.URL.Settings%%" method="post">
|
72 |
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
|
73 |
<select name="sucuriscan_emails_per_hour">
|
74 |
%%SUCURI.EmailsPerHourOptions%%
|
78 |
</td>
|
79 |
</tr>
|
80 |
|
81 |
+
<tr>
|
82 |
<td>Consider brute-force after</td>
|
83 |
<td>%%SUCURI.MaximumFailedLogins%%</td>
|
84 |
<td class="td-with-button">
|
85 |
+
<form action="%%SUCURI.URL.Settings%%" method="post">
|
86 |
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
|
87 |
<select name="sucuriscan_maximum_failed_logins">
|
88 |
%%SUCURI.MaximumFailedLoginsOptions%%
|
92 |
</td>
|
93 |
</tr>
|
94 |
|
95 |
+
<tr class="alternate">
|
96 |
<td>Verify SSL Cert</td>
|
97 |
<td>%%SUCURI.VerifySSLCert%%</td>
|
98 |
<td class="td-with-button">
|
99 |
+
<form action="%%SUCURI.URL.Settings%%" method="post">
|
100 |
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
|
101 |
<select name="sucuriscan_verify_ssl_cert">
|
102 |
%%SUCURI.VerifySSLCertOptions%%
|
106 |
</td>
|
107 |
</tr>
|
108 |
|
109 |
+
<tr>
|
110 |
+
<td>Filesystem scanner</td>
|
111 |
+
<td>%%SUCURI.FsScannerStatus%%</td>
|
112 |
+
<td class="td-with-button">
|
113 |
+
<form action="%%SUCURI.URL.Settings%%" method="post">
|
114 |
+
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
|
115 |
+
<input type="hidden" name="sucuriscan_fs_scanner" value="%%SUCURI.FsScannerSwitchValue%%" />
|
116 |
+
<button type="submit" class="button-primary %%SUCURI.FsScannerSwitchCssClass%%">%%SUCURI.FsScannerSwitchText%%</button>
|
117 |
+
</form>
|
118 |
+
</td>
|
119 |
+
</tr>
|
120 |
+
|
121 |
<tr class="alternate">
|
122 |
+
<td>Scan modified files</td>
|
123 |
+
<td>%%SUCURI.ScanModfilesStatus%%</td>
|
124 |
+
<td class="td-with-button">
|
125 |
+
<form action="%%SUCURI.URL.Settings%%" method="post">
|
126 |
+
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
|
127 |
+
<input type="hidden" name="sucuriscan_scan_modfiles" value="%%SUCURI.ScanModfilesSwitchValue%%" />
|
128 |
+
<button type="submit" class="button-primary %%SUCURI.ScanModfilesSwitchCssClass%%">%%SUCURI.ScanModfilesSwitchText%%</button>
|
129 |
+
</form>
|
130 |
+
</td>
|
131 |
+
</tr>
|
132 |
+
|
133 |
+
<tr>
|
134 |
+
<td>Integrity checking</td>
|
135 |
+
<td>%%SUCURI.ScanChecksumsStatus%%</td>
|
136 |
+
<td class="td-with-button">
|
137 |
+
<form action="%%SUCURI.URL.Settings%%" method="post">
|
138 |
+
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
|
139 |
+
<input type="hidden" name="sucuriscan_scan_checksums" value="%%SUCURI.ScanChecksumsSwitchValue%%" />
|
140 |
+
<button type="submit" class="button-primary %%SUCURI.ScanChecksumsSwitchCssClass%%">%%SUCURI.ScanChecksumsSwitchText%%</button>
|
141 |
+
</form>
|
142 |
+
</td>
|
143 |
+
</tr>
|
144 |
+
|
145 |
+
<tr class="alternate">
|
146 |
+
<td>Last Scanning</td>
|
147 |
+
<td><span class="sucuriscan-monospace">%%SUCURI.ScanningRuntimeHuman%%</span></td>
|
148 |
+
<td class="td-with-button">
|
149 |
+
<form action="%%SUCURI.URL.Home%%" method="post">
|
150 |
+
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
|
151 |
+
<button type="submit" name="sucuriscan_force_scan" class="button-primary">Force Scan</button>
|
152 |
+
</form>
|
153 |
+
</td>
|
154 |
+
</tr>
|
155 |
+
|
156 |
+
<tr>
|
157 |
<td>Scanning frequency</td>
|
158 |
+
<td>%%SUCURI.ScanningFrequency%%</td>
|
159 |
<td class="td-with-button">
|
160 |
+
<form action="%%SUCURI.URL.Settings%%" method="post">
|
161 |
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
|
162 |
<select name="sucuriscan_scan_frequency">
|
163 |
%%SUCURI.ScanningFrequencyOptions%%
|
167 |
</td>
|
168 |
</tr>
|
169 |
|
170 |
+
<tr class="alternate sucuriscan-%%SUCURI.ScanningInterfaceVisibility%%">
|
171 |
<td>Scanning interface</td>
|
172 |
+
<td>%%SUCURI.ScanningInterface%%</td>
|
173 |
<td class="td-with-button">
|
174 |
+
<form action="%%SUCURI.URL.Settings%%" method="post">
|
175 |
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
|
176 |
<select name="sucuriscan_scan_interface">
|
177 |
%%SUCURI.ScanningInterfaceOptions%%
|
inc/tpl/{setup_notice.html.tpl → setup-notice.html.tpl}
RENAMED
@@ -14,7 +14,7 @@
|
|
14 |
<div class="sucuriscan-pull-right sucuriscan-setup-form">
|
15 |
<form action="%%SUCURI.URL.Settings%%" method="post">
|
16 |
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
|
17 |
-
<button type="submit" name="
|
18 |
<span class="sucuriscan-button-title">Generate API key</span>
|
19 |
<span class="sucuriscan-button-subtitle">for <b>%%SUCURI.CleanDomain%%</b> / <b>%%SUCURI.AdminEmail%%</b></span>
|
20 |
</button>
|
14 |
<div class="sucuriscan-pull-right sucuriscan-setup-form">
|
15 |
<form action="%%SUCURI.URL.Settings%%" method="post">
|
16 |
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
|
17 |
+
<button type="submit" name="sucuriscan_plugin_api_key" class="button button-primary button-hero">
|
18 |
<span class="sucuriscan-button-title">Generate API key</span>
|
19 |
<span class="sucuriscan-button-subtitle">for <b>%%SUCURI.CleanDomain%%</b> / <b>%%SUCURI.AdminEmail%%</b></span>
|
20 |
</button>
|
index.html
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
<!-- Avoid the directory listing. -->
|
index.php
DELETED
@@ -1,15 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/**
|
4 |
-
* Avoid directory listing.
|
5 |
-
*
|
6 |
-
* @package Sucuri Plugin - SiteCheck Malware Scanner
|
7 |
-
* @author Yorman Arias <yorman.arias@sucuri.net>
|
8 |
-
* @author Daniel Cid <dcid@sucuri.net>
|
9 |
-
* @copyright Since 2010-2014 Sucuri Inc.
|
10 |
-
* @license Released under the GPL - see LICENSE file for details.
|
11 |
-
* @link https://wordpress.sucuri.net/
|
12 |
-
* @since File available since Release 0.1
|
13 |
-
*/
|
14 |
-
|
15 |
-
if( !defined('SUCURISCAN') ){ exit(0); }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
readme.txt
CHANGED
@@ -3,8 +3,8 @@ Contributors: dd@sucuri.net
|
|
3 |
Donate Link: http://sitecheck.sucuri.net
|
4 |
Tags: malware, security, firewall, scan, spam, virus, sucuri, protection
|
5 |
Requires at least:3.2
|
6 |
-
Stable tag:1.6.
|
7 |
-
Tested up to: 3.9.
|
8 |
|
9 |
The Sucuri Security - Auditing, SiteCheck Malware Scanner and Hardening is a security plugin enables you to scan your WordPress site using Sucuri SiteCheck for security and malware issues, and also verifies the security integrity of your core files right in your dashboard. It includes audit trails and post-hack security ions to help you reset passwords and secret keys in case it has been already hacked, or infected with malware.
|
10 |
|
@@ -66,6 +66,11 @@ the compromise on your site).
|
|
66 |
|
67 |
== Changelog ==
|
68 |
|
|
|
|
|
|
|
|
|
|
|
69 |
= 1.6.5 =
|
70 |
* Fixed integrity checking display.
|
71 |
|
3 |
Donate Link: http://sitecheck.sucuri.net
|
4 |
Tags: malware, security, firewall, scan, spam, virus, sucuri, protection
|
5 |
Requires at least:3.2
|
6 |
+
Stable tag:1.6.6
|
7 |
+
Tested up to: 3.9.2
|
8 |
|
9 |
The Sucuri Security - Auditing, SiteCheck Malware Scanner and Hardening is a security plugin enables you to scan your WordPress site using Sucuri SiteCheck for security and malware issues, and also verifies the security integrity of your core files right in your dashboard. It includes audit trails and post-hack security ions to help you reset passwords and secret keys in case it has been already hacked, or infected with malware.
|
10 |
|
66 |
|
67 |
== Changelog ==
|
68 |
|
69 |
+
= 1.6.6 =
|
70 |
+
* Internal code cleanup and re-organization.
|
71 |
+
* More white lists for the integrity checks.
|
72 |
+
* Additional settings to customize some of the warnings.
|
73 |
+
|
74 |
= 1.6.5 =
|
75 |
* Fixed integrity checking display.
|
76 |
|
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 Security</a> <em>(Auditing, Malware Scanner and Hardening)</em> plugin enables you to scan your WordPress site using <a href="http://sitecheck.sucuri.net/" target="_blank">Sucuri SiteCheck</a> right in your dashboard. SiteCheck will check for malware, spam, blacklisting and other security issues like .htaccess redirects, hidden eval code, etc. The best thing about it is it's completely free.
|
6 |
Author: Sucuri, INC
|
7 |
-
Version: 1.6.
|
8 |
Author URI: http://sucuri.net
|
9 |
*/
|
10 |
|
@@ -12,7 +12,7 @@ Author URI: http://sucuri.net
|
|
12 |
/**
|
13 |
* Main file to control the plugin.
|
14 |
*
|
15 |
-
* @package Sucuri
|
16 |
* @author Yorman Arias <yorman.arias@sucuri.net>
|
17 |
* @author Daniel Cid <dcid@sucuri.net>
|
18 |
* @copyright Since 2010-2014 Sucuri Inc.
|
@@ -22,26 +22,51 @@ Author URI: http://sucuri.net
|
|
22 |
*/
|
23 |
|
24 |
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
29 |
}
|
30 |
|
31 |
/**
|
32 |
-
*
|
|
|
|
|
|
|
|
|
|
|
|
|
33 |
*/
|
34 |
-
define('SUCURISCAN','sucuriscan');
|
35 |
|
36 |
/**
|
37 |
-
*
|
38 |
*/
|
39 |
-
define('
|
40 |
|
41 |
/**
|
42 |
-
*
|
43 |
*/
|
44 |
-
define('
|
45 |
|
46 |
/**
|
47 |
* The name of the Sucuri plugin main file.
|
@@ -63,6 +88,11 @@ define('SUCURISCAN_PLUGIN_PATH', WP_PLUGIN_DIR.'/'.SUCURISCAN_PLUGIN_FOLDER);
|
|
63 |
*/
|
64 |
define('SUCURISCAN_PLUGIN_FILEPATH', SUCURISCAN_PLUGIN_PATH.'/'.SUCURISCAN_PLUGIN_FILE);
|
65 |
|
|
|
|
|
|
|
|
|
|
|
66 |
/**
|
67 |
* Checksum of this file to check the integrity of the plugin.
|
68 |
*/
|
@@ -113,6 +143,184 @@ define('SUCURISCAN_SITECHECK_LIFETIME', 1200);
|
|
113 |
*/
|
114 |
define('SUCURISCAN_GET_PLUGINS_LIFETIME', 1800);
|
115 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
116 |
/**
|
117 |
* Miscellaneous library.
|
118 |
*
|
@@ -128,6 +336,43 @@ class SucuriScan {
|
|
128 |
public function __construct(){
|
129 |
}
|
130 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
131 |
/**
|
132 |
* Generates a lowercase random string with an specific length.
|
133 |
*
|
@@ -176,165 +421,489 @@ class SucuriScan {
|
|
176 |
}
|
177 |
|
178 |
/**
|
179 |
-
* Check the
|
180 |
*
|
181 |
-
* @return boolean TRUE
|
182 |
*/
|
183 |
-
public static function
|
184 |
-
// Create the option_page value if permalink submission.
|
185 |
if(
|
186 |
-
|
187 |
-
&&
|
188 |
){
|
189 |
-
|
190 |
}
|
191 |
|
192 |
-
|
193 |
-
|
194 |
-
$nonce='_wpnonce';
|
195 |
-
$action = '';
|
196 |
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
209 |
}
|
210 |
|
211 |
-
//
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
){
|
217 |
-
return TRUE;
|
218 |
}
|
219 |
}
|
220 |
|
221 |
return FALSE;
|
222 |
}
|
223 |
|
224 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
225 |
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
|
|
|
|
235 |
|
236 |
/**
|
237 |
-
*
|
238 |
-
* be used to return the directory tree, this should be disabled when scanning a
|
239 |
-
* directory without the need to filter the items in the list.
|
240 |
*
|
241 |
-
* @
|
242 |
*/
|
243 |
-
public
|
|
|
|
|
244 |
|
245 |
/**
|
246 |
-
*
|
247 |
-
* be used to return the directory tree, this should be disabled when scanning a
|
248 |
-
* path without the need to filter the items in the list.
|
249 |
*
|
250 |
-
* @
|
251 |
*/
|
252 |
-
public
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
253 |
|
254 |
/**
|
255 |
-
*
|
256 |
*
|
257 |
-
* @
|
258 |
*/
|
259 |
-
public
|
|
|
|
|
|
|
|
|
|
|
|
|
260 |
|
261 |
/**
|
262 |
-
*
|
|
|
|
|
263 |
*/
|
264 |
-
public function
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
265 |
}
|
266 |
|
267 |
/**
|
268 |
-
*
|
269 |
-
* in the main and subdirectories of the folder specified, also the filesize
|
270 |
-
* and md5sum of that file. Some folders and files will be ignored depending
|
271 |
-
* on some rules defined by the developer.
|
272 |
*
|
273 |
-
* @param
|
274 |
-
* @
|
275 |
-
* @param boolean $as_array Whether the result of the operation will be returned as an array or string.
|
276 |
-
* @return array List of files in the main and subdirectories of the folder specified.
|
277 |
*/
|
278 |
-
public function
|
279 |
-
$
|
280 |
-
|
281 |
-
$files = $this->get_directory_tree($directory, $scan_with);
|
282 |
-
sort($files);
|
283 |
-
|
284 |
-
if( $as_array ){
|
285 |
-
$project_signatures = array();
|
286 |
}
|
287 |
|
288 |
-
|
289 |
-
$file_checksum = @md5_file($filepath);
|
290 |
-
$filesize = @filesize($filepath);
|
291 |
|
292 |
-
|
293 |
-
$basename = str_replace( $abs_path . '/', '', $filepath );
|
294 |
-
$project_signatures[$basename] = array(
|
295 |
-
'filepath' => $filepath,
|
296 |
-
'checksum' => $file_checksum,
|
297 |
-
'filesize' => $filesize,
|
298 |
-
'filetime' => filectime($filepath),
|
299 |
-
);
|
300 |
-
} else {
|
301 |
-
$filepath = str_replace( $abs_path, $abs_path . '/', $filepath );
|
302 |
-
$project_signatures .= sprintf(
|
303 |
-
"%s%s%s%s\n",
|
304 |
-
$file_checksum,
|
305 |
-
$filesize,
|
306 |
-
chr(32),
|
307 |
-
$filepath
|
308 |
-
);
|
309 |
-
}
|
310 |
-
}
|
311 |
|
312 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
313 |
}
|
314 |
|
315 |
/**
|
316 |
-
*
|
317 |
-
* of the folder specified. Some folders and files will be ignored depending
|
318 |
-
* on some rules defined by the developer.
|
319 |
*
|
320 |
-
* @
|
321 |
-
*
|
322 |
-
* @
|
|
|
323 |
*/
|
324 |
-
public function
|
325 |
-
|
326 |
-
|
|
|
327 |
|
328 |
-
|
329 |
-
|
330 |
-
if( $this->is_spl_available() ){
|
331 |
-
$tree = $this->get_directory_tree_with_spl($directory);
|
332 |
-
} else {
|
333 |
-
$tree = $this->get_directory_tree($directory, 'opendir');
|
334 |
-
}
|
335 |
-
break;
|
336 |
|
337 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
338 |
$tree = $this->get_directory_tree_with_glob($directory);
|
339 |
break;
|
340 |
|
@@ -613,339 +1182,99 @@ class SucuriScanFileInfo extends SucuriScan {
|
|
613 |
return $all_removed;
|
614 |
}
|
615 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
616 |
}
|
617 |
|
618 |
/**
|
619 |
-
*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
620 |
*
|
621 |
-
*
|
622 |
-
*
|
623 |
-
* the previous database prefix.
|
624 |
*/
|
625 |
-
class
|
626 |
|
627 |
/**
|
628 |
-
*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
629 |
*
|
630 |
-
* @
|
631 |
*/
|
632 |
-
|
633 |
-
global $wpdb;
|
634 |
-
|
635 |
-
$table_names = array();
|
636 |
-
$tables = $wpdb->get_results('SHOW TABLES', ARRAY_N);
|
637 |
-
|
638 |
-
foreach($tables as $table){
|
639 |
-
$table_names[] = $table[0];
|
640 |
-
}
|
641 |
|
642 |
-
|
643 |
-
|
|
|
|
|
|
|
|
|
644 |
|
645 |
/**
|
646 |
-
*
|
647 |
*
|
648 |
-
*
|
|
|
|
|
|
|
649 |
*/
|
650 |
-
|
651 |
-
$new_table_prefix = $this->random_char( rand(4,7) ).'_';
|
652 |
-
$this->set_table_prefix($new_table_prefix);
|
653 |
-
}
|
654 |
|
655 |
/**
|
656 |
-
*
|
657 |
*
|
|
|
658 |
* @return void
|
659 |
*/
|
660 |
-
public function
|
661 |
-
$this->
|
|
|
|
|
662 |
}
|
663 |
|
664 |
/**
|
665 |
-
*
|
666 |
*
|
667 |
-
* @
|
668 |
-
* @return void
|
669 |
*/
|
670 |
-
private function
|
671 |
-
$
|
672 |
-
|
673 |
-
|
674 |
-
|
675 |
-
|
676 |
-
// Update options table with the new table prefix.
|
677 |
-
$resp_parts[] = $this->new_table_prefix_optionstable($new_table_prefix);
|
678 |
-
|
679 |
-
// Update usermeta table with the new table prefix.
|
680 |
-
$resp_parts[] = $this->new_table_prefix_usermetatable($new_table_prefix);
|
681 |
-
|
682 |
-
// Rename table names with the new table prefix.
|
683 |
-
$resp_parts[] = $this->new_table_prefix_tablerename($new_table_prefix);
|
684 |
|
685 |
-
|
686 |
-
if( $response['process'] !== TRUE ){
|
687 |
-
sucuriscan_error( $response['message'] );
|
688 |
-
}
|
689 |
-
}
|
690 |
}
|
691 |
|
692 |
/**
|
693 |
-
*
|
694 |
*
|
695 |
-
* @param
|
696 |
-
* @return
|
697 |
-
*/
|
698 |
-
private function new_table_prefix_wpconfig( $new_table_prefix='' ){
|
699 |
-
global $wpdb;
|
700 |
-
|
701 |
-
$response = array( 'process'=>FALSE, 'message'=>'' );
|
702 |
-
$wp_config_path = sucuriscan_get_wpconfig_path();
|
703 |
-
|
704 |
-
if( file_exists($wp_config_path) ){
|
705 |
-
@chmod($wp_config_path, 0777);
|
706 |
-
|
707 |
-
if( is_writable($wp_config_path) ){
|
708 |
-
$new_wpconfig = '';
|
709 |
-
$wpconfig_lines = @file($wp_config_path);
|
710 |
-
|
711 |
-
foreach( $wpconfig_lines as $line ){
|
712 |
-
$line = str_replace("\n", '', $line);
|
713 |
-
|
714 |
-
if( preg_match('/.*\$table_prefix([ ]+)?=.*/', $line, $match) ){
|
715 |
-
$line = str_replace($wpdb->prefix, $new_table_prefix, $match[0]);
|
716 |
-
}
|
717 |
-
|
718 |
-
$new_wpconfig .= "{$line}\n";
|
719 |
-
}
|
720 |
-
|
721 |
-
$handle = fopen($wp_config_path, 'w');
|
722 |
-
@fwrite($handle, $new_wpconfig);
|
723 |
-
@fclose($handle);
|
724 |
-
@chmod($wp_config_path, 0644);
|
725 |
-
|
726 |
-
$response['process'] = TRUE;
|
727 |
-
$response['message'] = 'Main configuration file modified.';
|
728 |
-
} else {
|
729 |
-
$response['message'] = 'Main configuration file is not writable, you will need to put the new
|
730 |
-
table prefix <code>'.$new_table_prefix.'</code> manually in <code>wp-config.php</code>.';
|
731 |
-
}
|
732 |
-
} else {
|
733 |
-
$response['message'] = 'Main configuration file was not located: <code>'.$wp_config_path.'</code>.';
|
734 |
-
}
|
735 |
-
|
736 |
-
return $response;
|
737 |
-
}
|
738 |
-
|
739 |
-
/**
|
740 |
-
* Returns a list of all the tables in the selected database containing the same prefix.
|
741 |
-
*
|
742 |
-
* @param string $prefix A text string used to filter the tables with a specific prefix.
|
743 |
-
* @return array A list of all the tables with the prefix specified.
|
744 |
-
*/
|
745 |
-
public function get_prefixed_tables( $prefix='' ){
|
746 |
-
global $wpdb;
|
747 |
-
|
748 |
-
$tables = array();
|
749 |
-
$prefix = empty($prefix) ? $wpdb->prefix : $prefix;
|
750 |
-
$db_tables = $this->get_dbtables();
|
751 |
-
|
752 |
-
foreach( $db_tables as $table_name ){
|
753 |
-
if( preg_match("/^{$prefix}/", $table_name) ){
|
754 |
-
$tables[] = $table_name;
|
755 |
-
}
|
756 |
-
}
|
757 |
-
|
758 |
-
return $tables;
|
759 |
-
}
|
760 |
-
|
761 |
-
/**
|
762 |
-
* Using the new database table prefix, it modifies the name of all tables with the new value.
|
763 |
-
*
|
764 |
-
* @param string $new_table_prefix
|
765 |
-
* @return array An array with two default indexes containing the result of the operation and a message.
|
766 |
-
*/
|
767 |
-
private function new_table_prefix_tablerename( $new_table_prefix='' ){
|
768 |
-
global $wpdb;
|
769 |
-
|
770 |
-
$response = array( 'process'=>FALSE, 'message'=>'' );
|
771 |
-
$db_tables = $this->get_prefixed_tables();
|
772 |
-
|
773 |
-
$renamed_count = 0;
|
774 |
-
$total_tables = count($db_tables);
|
775 |
-
$tables_not_renamed = array();
|
776 |
-
|
777 |
-
foreach( $db_tables as $table_name ){
|
778 |
-
$table_new_name = $new_table_prefix . str_replace($wpdb->prefix, '', $table_name);
|
779 |
-
$sql = 'RENAME TABLE `%s` TO `%s`';
|
780 |
-
|
781 |
-
/* Don't use WPDB->Prepare() */
|
782 |
-
if( $wpdb->query(sprintf($sql, $table_name, $table_new_name))===FALSE ){
|
783 |
-
$tables_not_renamed[] = $table_name;
|
784 |
-
} else {
|
785 |
-
$renamed_count += 1;
|
786 |
-
}
|
787 |
-
}
|
788 |
-
|
789 |
-
$response['message'] = 'Database tables renamed: '.$renamed_count.' out of '.$total_tables;
|
790 |
-
|
791 |
-
if( $renamed_count>0 && $renamed_count==$total_tables ){
|
792 |
-
$response['process'] = TRUE;
|
793 |
-
$error = $wpdb->set_prefix($new_table_prefix);
|
794 |
-
|
795 |
-
if( is_wp_error($error) ){
|
796 |
-
foreach( $error->errors as $error_index=>$error_data ){
|
797 |
-
if( is_array($error_data) ){
|
798 |
-
foreach( $error_data as $error_data_value ){
|
799 |
-
$response['message'] .= chr(32) . $error_data_value . '.';
|
800 |
-
}
|
801 |
-
}
|
802 |
-
}
|
803 |
-
}
|
804 |
-
} else {
|
805 |
-
$response['message'] .= '<br>These tables were not renamed, you will need to do it manually:';
|
806 |
-
$response['message'] .= chr(32) . implode( ',' . chr(32), $table_not_renamed );
|
807 |
-
}
|
808 |
-
|
809 |
-
return $response;
|
810 |
-
}
|
811 |
-
|
812 |
-
/**
|
813 |
-
* Using the new database table prefix, it modifies the name of all options with the new value.
|
814 |
-
*
|
815 |
-
* @param string $new_table_prefix
|
816 |
-
* @return array An array with two default indexes containing the result of the operation and a message.
|
817 |
-
*/
|
818 |
-
private function new_table_prefix_optionstable( $new_table_prefix='' ){
|
819 |
-
global $wpdb;
|
820 |
-
|
821 |
-
$response = array( 'process'=>TRUE, 'message'=>'' );
|
822 |
-
$results = $wpdb->get_results("SELECT option_id, option_name FROM {$wpdb->prefix}options WHERE option_name LIKE '{$wpdb->prefix}%'");
|
823 |
-
|
824 |
-
foreach( $results as $row ){
|
825 |
-
$row->new_option_name = $new_table_prefix.str_replace($wpdb->prefix, '', $row->option_name);
|
826 |
-
$sql = "UPDATE {$wpdb->prefix}options SET option_name=%s WHERE option_id=%s LIMIT 1";
|
827 |
-
|
828 |
-
if( $wpdb->query($wpdb->prepare($sql, $row->new_option_name, $row->option_id))===FALSE ){
|
829 |
-
$response['process'] = FALSE;
|
830 |
-
}
|
831 |
-
}
|
832 |
-
|
833 |
-
$response['message'] = $response['process']
|
834 |
-
? 'Database table options updated.'
|
835 |
-
: 'Some entries in the database table <strong>Options</strong> were not updated';
|
836 |
-
|
837 |
-
return $response;
|
838 |
-
}
|
839 |
-
|
840 |
-
/**
|
841 |
-
* Using the new database table prefix, it modifies the name of all usermeta keys with the new value.
|
842 |
-
*
|
843 |
-
* @param string $new_table_prefix
|
844 |
-
* @return array An array with two default indexes containing the result of the operation and a message.
|
845 |
-
*/
|
846 |
-
private function new_table_prefix_usermetatable( $new_table_prefix='' ){
|
847 |
-
global $wpdb;
|
848 |
-
|
849 |
-
$response = array( 'process'=>TRUE, 'message'=>'' );
|
850 |
-
$results = $wpdb->get_results("SELECT umeta_id, meta_key FROM {$wpdb->prefix}usermeta WHERE meta_key LIKE '{$wpdb->prefix}%'");
|
851 |
-
|
852 |
-
foreach( $results as $row ){
|
853 |
-
$row->new_meta_key = $new_table_prefix.str_replace($wpdb->prefix, '', $row->meta_key);
|
854 |
-
$sql = "UPDATE {$wpdb->prefix}usermeta SET meta_key=%s WHERE umeta_id=%s LIMIT 1";
|
855 |
-
|
856 |
-
if( $wpdb->query($wpdb->prepare($sql, $row->new_meta_key, $row->umeta_id))===FALSE ){
|
857 |
-
$response['process'] = FALSE;
|
858 |
-
}
|
859 |
-
}
|
860 |
-
|
861 |
-
$response['message'] = $response['process']
|
862 |
-
? 'Database table usermeta updated.'
|
863 |
-
: 'Some entries in the database table <strong>UserMeta</strong> were not updated';
|
864 |
-
|
865 |
-
return $response;
|
866 |
-
}
|
867 |
-
|
868 |
-
}
|
869 |
-
|
870 |
-
/**
|
871 |
-
* File-based cache library.
|
872 |
-
*
|
873 |
-
* WP_Object_Cache [1] is WordPress' class for caching data which may be
|
874 |
-
* computationally expensive to regenerate, such as the result of complex
|
875 |
-
* database queries. However the object cache is non-persistent. This means that
|
876 |
-
* data stored in the cache resides in memory only and only for the duration of
|
877 |
-
* the request. Cached data will not be stored persistently across page loads
|
878 |
-
* unless of the installation of a 3party persistent caching plugin [2].
|
879 |
-
*
|
880 |
-
* [1] http://codex.wordpress.org/Class_Reference/WP_Object_Cache
|
881 |
-
* [2] http://codex.wordpress.org/Class_Reference/WP_Object_Cache#Persistent_Caching
|
882 |
-
*/
|
883 |
-
class SucuriScanCache extends SucuriScan {
|
884 |
-
|
885 |
-
/**
|
886 |
-
* The unique name (or identifier) of the file with the data.
|
887 |
-
*
|
888 |
-
* The file should be located in the same folder where the dynamic data
|
889 |
-
* generated by the plugin is stored, and using the following format [1], it
|
890 |
-
* most be a PHP file because it is expected to have an exit point in the first
|
891 |
-
* line of the file causing it to stop the execution if a unauthorized user
|
892 |
-
* tries to access it directly.
|
893 |
-
*
|
894 |
-
* [1] /public/data/sucuri-DATASTORE.php
|
895 |
-
*
|
896 |
-
* @var null|string
|
897 |
-
*/
|
898 |
-
private $datastore = NULL;
|
899 |
-
|
900 |
-
/**
|
901 |
-
* The full path of the datastore file.
|
902 |
-
*
|
903 |
-
* @var string
|
904 |
-
*/
|
905 |
-
private $datastore_path = '';
|
906 |
-
|
907 |
-
/**
|
908 |
-
* Whether the datastore file is usable or not.
|
909 |
-
*
|
910 |
-
* This variable will only be TRUE if the datastore file specified exists, is
|
911 |
-
* writable and readable, in any other case it will always be FALSE.
|
912 |
-
*
|
913 |
-
* @var boolean
|
914 |
-
*/
|
915 |
-
private $usable_datastore = FALSE;
|
916 |
-
|
917 |
-
/**
|
918 |
-
* Class constructor.
|
919 |
-
*
|
920 |
-
* @param string $datastore Unique name (or identifier) of the file with the data.
|
921 |
-
* @return void
|
922 |
-
*/
|
923 |
-
public function __construct( $datastore='' ){
|
924 |
-
$this->datastore = $datastore;
|
925 |
-
$this->datastore_path = $this->datastore_file_path();
|
926 |
-
$this->usable_datastore = (bool) $this->datastore_path;
|
927 |
-
}
|
928 |
-
|
929 |
-
/**
|
930 |
-
* Default attributes for every datastore file.
|
931 |
-
*
|
932 |
-
* @return string Default attributes for every datastore file.
|
933 |
-
*/
|
934 |
-
private function datastore_default_info(){
|
935 |
-
$attrs = array(
|
936 |
-
'datastore' => $this->datastore,
|
937 |
-
'created_on' => time(),
|
938 |
-
'updated_on' => time(),
|
939 |
-
);
|
940 |
-
|
941 |
-
return $attrs;
|
942 |
-
}
|
943 |
-
|
944 |
-
/**
|
945 |
-
* Default content of every datastore file.
|
946 |
-
*
|
947 |
-
* @param array $finfo Rainbow table with the key names and decoded values.
|
948 |
-
* @return string Default content of every datastore file.
|
949 |
*/
|
950 |
private function datastore_info( $finfo=array() ){
|
951 |
$attrs = $this->datastore_default_info();
|
@@ -1058,12 +1387,10 @@ class SucuriScanCache extends SucuriScan {
|
|
1058 |
);
|
1059 |
|
1060 |
if( $this->usable_datastore ){
|
1061 |
-
$data_lines =
|
1062 |
|
1063 |
if( !empty($data_lines) ){
|
1064 |
foreach( $data_lines as $line ){
|
1065 |
-
$line = trim($line);
|
1066 |
-
|
1067 |
if( preg_match('/^\/\/ ([a-z_]+)=(.*);$/', $line, $match) ){
|
1068 |
$data_object['info'][$match[1]] = $match[2];
|
1069 |
}
|
@@ -1073,7 +1400,7 @@ class SucuriScanCache extends SucuriScan {
|
|
1073 |
$this->valid_key_name($match[1])
|
1074 |
&& !array_key_exists($match[1], $data_object)
|
1075 |
){
|
1076 |
-
$data_object['entries'][$match[1]] = json_decode( $match[2], $assoc );
|
1077 |
}
|
1078 |
}
|
1079 |
}
|
@@ -1248,3206 +1575,3379 @@ class SucuriScanCache extends SucuriScan {
|
|
1248 |
}
|
1249 |
|
1250 |
/**
|
1251 |
-
*
|
1252 |
*
|
1253 |
-
*
|
1254 |
-
|
1255 |
-
|
1256 |
-
|
1257 |
-
|
1258 |
-
|
1259 |
-
|
1260 |
-
|
1261 |
-
*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1262 |
*
|
1263 |
-
* @
|
1264 |
-
* @
|
1265 |
*/
|
1266 |
-
|
1267 |
-
|
1268 |
-
|
1269 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1270 |
}
|
1271 |
|
1272 |
-
return
|
1273 |
}
|
1274 |
|
1275 |
-
return FALSE;
|
1276 |
-
}
|
1277 |
-
|
1278 |
-
if( !function_exists('sucuriscan_init') ){
|
1279 |
/**
|
1280 |
-
*
|
1281 |
*
|
1282 |
-
*
|
1283 |
-
*
|
1284 |
-
*
|
1285 |
-
* service like a Proxy.
|
1286 |
*
|
1287 |
-
*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1288 |
*/
|
1289 |
-
function
|
1290 |
-
|
1291 |
-
isset($_SERVER['HTTP_X_FORWARDED_FOR'])
|
1292 |
-
&& preg_match("/^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$/", $_SERVER['HTTP_X_FORWARDED_FOR'])
|
1293 |
-
&& sucuriscan_is_valid_ipv4($_SERVER['HTTP_X_FORWARDED_FOR'])
|
1294 |
-
){
|
1295 |
-
$_SERVER['SUCURIREAL_REMOTE_ADDR'] = $_SERVER['REMOTE_ADDR'];
|
1296 |
-
$_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_X_FORWARDED_FOR'];
|
1297 |
-
}
|
1298 |
-
}
|
1299 |
|
1300 |
-
|
1301 |
-
}
|
1302 |
|
1303 |
-
if( !function_exists('sucuriscan_create_uploaddir') ){
|
1304 |
/**
|
1305 |
-
*
|
1306 |
-
* store all the temporal or dynamic information.
|
1307 |
*
|
1308 |
-
*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1309 |
*/
|
1310 |
-
function
|
1311 |
-
|
|
|
1312 |
|
1313 |
-
|
1314 |
-
|
1315 |
-
// Create last-logins datastore file.
|
1316 |
-
sucuriscan_lastlogins_datastore_exists();
|
1317 |
|
1318 |
-
|
1319 |
-
|
1320 |
-
$plugin_upload_folder . '/.htaccess',
|
1321 |
-
"Order Deny,Allow\nDeny from all",
|
1322 |
-
LOCK_EX
|
1323 |
-
);
|
1324 |
|
1325 |
-
|
1326 |
-
|
1327 |
-
|
1328 |
-
|
1329 |
-
|
1330 |
-
|
1331 |
-
|
1332 |
-
|
1333 |
-
|
1334 |
-
|
1335 |
-
|
1336 |
-
|
1337 |
-
|
|
|
|
|
1338 |
}
|
1339 |
-
}
|
1340 |
|
1341 |
-
|
1342 |
-
}
|
1343 |
|
1344 |
-
if( !function_exists('sucuriscan_admin_script_style_registration') ){
|
1345 |
/**
|
1346 |
-
*
|
1347 |
-
*
|
|
|
|
|
|
|
|
|
|
|
1348 |
*/
|
1349 |
-
function
|
1350 |
-
$
|
1351 |
-
|
1352 |
-
if( strlen(SUCURISCAN_PLUGIN_CHECKSUM) >= 7 ){
|
1353 |
-
$asset_version = substr(SUCURISCAN_PLUGIN_CHECKSUM, 0, 7);
|
1354 |
}
|
1355 |
|
1356 |
-
|
1357 |
-
|
1358 |
|
1359 |
-
|
1360 |
-
|
|
|
|
|
|
|
1361 |
}
|
1362 |
|
1363 |
-
|
1364 |
-
|
1365 |
-
|
1366 |
-
|
1367 |
-
|
1368 |
-
|
1369 |
-
|
1370 |
-
|
1371 |
-
|
1372 |
-
*/
|
1373 |
-
function sucuriscan_dir_filepath($path = ''){
|
1374 |
-
return SucuriScan::datastore_folder_path($path);
|
1375 |
-
}
|
1376 |
-
|
1377 |
-
/**
|
1378 |
-
* List an associative array with the sub-pages of this plugin.
|
1379 |
-
*
|
1380 |
-
* @param boolean $for_navbar Either TRUE or FALSE indicanting that the first page will be named Dashboard.
|
1381 |
-
* @return array List of pages and sub-pages of this plugin.
|
1382 |
-
*/
|
1383 |
-
function sucuriscan_pages( $for_navbar=FALSE ){
|
1384 |
-
$pages = array(
|
1385 |
-
'sucuriscan' => 'Dashboard',
|
1386 |
-
'sucuriscan_scanner' => 'Malware Scan',
|
1387 |
-
'sucuriscan_monitoring' => 'Firewall (WAF)',
|
1388 |
-
'sucuriscan_hardening' => 'Hardening',
|
1389 |
-
'sucuriscan_posthack' => 'Post-Hack',
|
1390 |
-
'sucuriscan_lastlogins' => 'Last Logins',
|
1391 |
-
'sucuriscan_settings' => 'Settings',
|
1392 |
-
'sucuriscan_infosys' => 'Site Info',
|
1393 |
-
);
|
1394 |
-
|
1395 |
-
return $pages;
|
1396 |
-
}
|
1397 |
|
1398 |
-
|
1399 |
-
|
1400 |
-
|
1401 |
-
* @return void
|
1402 |
-
*/
|
1403 |
-
function sucuriscan_menu(){
|
1404 |
-
// Add main menu link.
|
1405 |
-
add_menu_page(
|
1406 |
-
'Sucuri Security',
|
1407 |
-
'Sucuri Security',
|
1408 |
-
'manage_options',
|
1409 |
-
'sucuriscan',
|
1410 |
-
'sucuriscan_page',
|
1411 |
-
SUCURI_URL . '/inc/images/menu-icon.png'
|
1412 |
-
);
|
1413 |
|
1414 |
-
|
|
|
|
|
|
|
1415 |
|
1416 |
-
|
1417 |
-
|
|
|
1418 |
|
1419 |
-
|
1420 |
-
'sucuriscan',
|
1421 |
-
$sub_page_title,
|
1422 |
-
$sub_page_title,
|
1423 |
-
'manage_options',
|
1424 |
-
$sub_page_func,
|
1425 |
-
$page_func
|
1426 |
-
);
|
1427 |
}
|
1428 |
-
}
|
1429 |
|
1430 |
-
if( !function_exists('sucuriscan_handle_old_plugin') ){
|
1431 |
/**
|
1432 |
-
*
|
1433 |
-
* 1.6.0) all the functionality of the others will be merged here, this will
|
1434 |
-
* remove duplicated functionality, duplicated bugs and/or duplicated
|
1435 |
-
* maintenance reports allowing us to focus in one unique project.
|
1436 |
*
|
1437 |
-
* @
|
|
|
1438 |
*/
|
1439 |
-
function
|
1440 |
-
$
|
1441 |
-
|
1442 |
-
|
1443 |
-
|
1444 |
-
|
1445 |
-
|
1446 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1447 |
);
|
1448 |
|
1449 |
-
|
1450 |
-
|
1451 |
-
|
1452 |
-
|
1453 |
-
if( is_plugin_active($plugin) ){
|
1454 |
-
deactivate_plugins($plugin);
|
1455 |
}
|
|
|
|
|
|
|
|
|
1456 |
|
1457 |
-
|
|
|
|
|
1458 |
}
|
1459 |
}
|
|
|
|
|
1460 |
}
|
1461 |
|
1462 |
-
|
1463 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1464 |
|
1465 |
-
|
1466 |
-
|
1467 |
-
|
1468 |
-
* This will load the menu options in the WordPress administrator panel, and
|
1469 |
-
* execute the bootstrap function of the plugin.
|
1470 |
-
*/
|
1471 |
-
add_action('admin_menu', 'sucuriscan_menu');
|
1472 |
-
add_action('sucuriscan_scheduled_scan', 'sucuriscan_filesystem_scan');
|
1473 |
-
remove_action('wp_head', 'wp_generator');
|
1474 |
|
1475 |
-
|
1476 |
-
* Validate email address.
|
1477 |
-
*
|
1478 |
-
* This use the native PHP function filter_var which is available in PHP >=
|
1479 |
-
* 5.2.0 if it is not found in the interpreter this function will sue regular
|
1480 |
-
* expressions to check whether the email address passed is valid or not.
|
1481 |
-
*
|
1482 |
-
* @see http://www.php.net/manual/en/function.filter-var.php
|
1483 |
-
*
|
1484 |
-
* @param string $email The string that will be validated as an email address.
|
1485 |
-
* @return boolean TRUE if the email address passed to the function is valid, FALSE if not.
|
1486 |
-
*/
|
1487 |
-
function is_valid_email( $email='' ){
|
1488 |
-
if( function_exists('filter_var') ){
|
1489 |
-
return (bool) filter_var($email, FILTER_VALIDATE_EMAIL);
|
1490 |
-
} else {
|
1491 |
-
$pattern = '/^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6}$/ix';
|
1492 |
-
return (bool) preg_match($pattern, $email);
|
1493 |
}
|
1494 |
-
}
|
1495 |
|
1496 |
-
/**
|
1497 |
-
|
1498 |
-
|
1499 |
-
|
1500 |
-
|
1501 |
-
|
1502 |
-
|
1503 |
-
function
|
1504 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1505 |
|
1506 |
-
|
1507 |
-
return substr( $text, 0, $length ) . '...';
|
1508 |
}
|
1509 |
|
1510 |
-
|
1511 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1512 |
|
1513 |
-
|
1514 |
-
|
1515 |
-
|
1516 |
-
|
1517 |
-
*/
|
1518 |
-
function sucuriscan_prettify_mails(){
|
1519 |
-
return ( sucuriscan_get_option('sucuriscan_prettify_mails') === 'enabled' );
|
1520 |
-
}
|
1521 |
|
1522 |
-
|
1523 |
-
|
1524 |
-
|
1525 |
-
|
1526 |
-
|
1527 |
-
|
1528 |
-
*/
|
1529 |
-
|
1530 |
-
|
1531 |
-
|
|
|
|
|
|
|
1532 |
|
1533 |
-
|
1534 |
-
|
1535 |
-
|
1536 |
-
|
1537 |
-
|
1538 |
-
|
1539 |
-
|
1540 |
-
|
1541 |
-
|
1542 |
-
function sucuriscan_send_mail( $email='', $subject='', $message='', $data_set=array() ){
|
1543 |
-
$headers = array();
|
1544 |
-
$subject = ucwords(strtolower($subject));
|
1545 |
-
$wp_domain = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : get_option('siteurl');
|
1546 |
-
$force = FALSE;
|
1547 |
-
$debug = FALSE;
|
1548 |
-
|
1549 |
-
// Check whether the mail will be printed in the site instead of sent.
|
1550 |
-
if(
|
1551 |
-
isset($data_set['Debug'])
|
1552 |
-
&& $data_set['Debug'] == TRUE
|
1553 |
-
){
|
1554 |
-
$debug = TRUE;
|
1555 |
-
unset($data_set['Debug']);
|
1556 |
-
}
|
1557 |
|
1558 |
-
|
1559 |
-
if(
|
1560 |
-
isset($data_set['Force'])
|
1561 |
-
&& $data_set['Force'] == TRUE
|
1562 |
-
){
|
1563 |
-
$force = TRUE;
|
1564 |
-
unset($data_set['Force']);
|
1565 |
}
|
1566 |
|
1567 |
-
|
1568 |
-
|
1569 |
-
|
1570 |
-
|
1571 |
-
|
|
|
|
|
|
|
|
|
1572 |
|
1573 |
-
|
1574 |
-
|
|
|
1575 |
|
1576 |
-
|
|
|
1577 |
|
1578 |
-
|
1579 |
-
|
1580 |
-
|
1581 |
-
|
1582 |
-
|
1583 |
-
|
|
|
|
|
1584 |
|
1585 |
-
|
1586 |
-
|
1587 |
-
update_option( 'sucuriscan_emails_sent', $emails_sent_num + 1 );
|
1588 |
-
update_option( 'sucuriscan_last_email_at', time() );
|
1589 |
|
1590 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1591 |
}
|
1592 |
-
} else {
|
1593 |
-
// sucuriscan_error( 'Cant send more emails for the next hour' );
|
1594 |
-
}
|
1595 |
|
1596 |
-
|
1597 |
-
}
|
1598 |
|
1599 |
-
/**
|
1600 |
-
|
1601 |
-
|
1602 |
-
|
1603 |
-
|
1604 |
-
|
1605 |
-
|
|
|
|
|
1606 |
|
1607 |
-
|
1608 |
-
|
1609 |
-
|
1610 |
-
$last_email_at = sucuriscan_get_option('sucuriscan_last_email_at');
|
1611 |
-
$diff_time = abs( $current_time - $last_email_at );
|
1612 |
|
1613 |
-
|
1614 |
-
|
1615 |
-
|
1616 |
-
|
1617 |
|
1618 |
-
|
1619 |
-
|
1620 |
}
|
1621 |
-
} else {
|
1622 |
-
// Reset the counter of emails sent.
|
1623 |
-
update_option( 'sucuriscan_emails_sent', 0 );
|
1624 |
}
|
|
|
|
|
1625 |
}
|
1626 |
|
1627 |
-
|
1628 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
1629 |
|
1630 |
-
|
1631 |
-
|
1632 |
-
|
1633 |
-
* @param string $subject The reason of the message that will be sent.
|
1634 |
-
* @param string $message Body of the message that will be sent.
|
1635 |
-
* @param array $data_set Optional parameter to add more information to the notification.
|
1636 |
-
* @return string The message formatted in a HTML template.
|
1637 |
-
*/
|
1638 |
-
function sucuriscan_prettify_mail( $subject='', $message='', $data_set=array() ){
|
1639 |
-
$prettify_type = isset($data_set['PrettifyType']) ? $data_set['PrettifyType'] : 'simple';
|
1640 |
-
$template_name = 'notification-' . $prettify_type;
|
1641 |
-
$remote_addr = sucuriscan_get_remoteaddr();
|
1642 |
-
$user = wp_get_current_user();
|
1643 |
-
$display_name = '';
|
1644 |
|
1645 |
-
|
1646 |
-
|
1647 |
-
|
1648 |
-
|
1649 |
-
){
|
1650 |
-
$display_name = sprintf( 'User: %s (%s)', $user->display_name, $user->user_login );
|
1651 |
}
|
1652 |
|
1653 |
-
|
1654 |
-
|
1655 |
-
|
1656 |
-
|
1657 |
-
|
1658 |
-
|
1659 |
-
|
1660 |
-
|
1661 |
-
|
|
|
|
|
|
|
|
|
1662 |
|
1663 |
-
|
1664 |
-
$mail_variables[$var_key] = $var_value;
|
1665 |
}
|
1666 |
|
1667 |
-
|
1668 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1669 |
|
1670 |
-
|
1671 |
-
|
1672 |
-
|
1673 |
-
* @param string $type The type of alert, it can be either Updated or Error.
|
1674 |
-
* @param string $message The message that will be printed in the alert.
|
1675 |
-
* @return void
|
1676 |
-
*/
|
1677 |
-
function sucuriscan_admin_notice($type='updated', $message=''){
|
1678 |
-
$alert_id = rand(100, 999);
|
1679 |
-
if( !empty($message) ): ?>
|
1680 |
-
<div id="sucuriscan-alert-<?php echo $alert_id; ?>" class="<?php echo $type; ?> sucuriscan-alert sucuriscan-alert-<?php echo $type; ?>">
|
1681 |
-
<a href="javascript:void(0)" class="close" onclick="sucuriscan_alert_close('<?php echo $alert_id; ?>')">×</a>
|
1682 |
-
<p><?php _e($message); ?></p>
|
1683 |
-
</div>
|
1684 |
-
<?php endif;
|
1685 |
-
}
|
1686 |
|
1687 |
-
|
1688 |
-
|
1689 |
-
|
1690 |
-
|
1691 |
-
|
1692 |
-
|
1693 |
-
|
1694 |
-
|
1695 |
-
}
|
1696 |
|
1697 |
-
|
1698 |
-
|
1699 |
-
*
|
1700 |
-
* @param string $info_msg The message that will be printed in the alert.
|
1701 |
-
* @return void
|
1702 |
-
*/
|
1703 |
-
function sucuriscan_info( $info_msg='' ){
|
1704 |
-
sucuriscan_admin_notice( 'updated', '<b>Sucuri:</b> ' . $info_msg );
|
1705 |
-
}
|
1706 |
|
1707 |
-
/**
|
1708 |
-
|
1709 |
-
|
1710 |
-
|
1711 |
-
|
1712 |
-
|
1713 |
-
|
1714 |
-
|
1715 |
-
if( !empty($_POST) ){
|
1716 |
-
$nonce_name = 'sucuriscan_page_nonce';
|
1717 |
|
1718 |
-
if(
|
1719 |
-
|
|
|
|
|
1720 |
|
1721 |
-
return
|
1722 |
}
|
1723 |
-
}
|
1724 |
|
1725 |
-
|
1726 |
-
|
1727 |
-
|
1728 |
-
/**
|
1729 |
-
* Replace all pseudo-variables from a string of characters.
|
1730 |
-
*
|
1731 |
-
* @param string $content The content of a template file which contains pseudo-variables.
|
1732 |
-
* @param array $params List of pseudo-variables that will be replaced in the template.
|
1733 |
-
* @return string The content of the template with the pseudo-variables replated.
|
1734 |
-
*/
|
1735 |
-
function sucuriscan_replace_pseudovars( $content='', $params=array() ){
|
1736 |
-
if( is_array($params) ){
|
1737 |
-
foreach( $params as $tpl_key => $tpl_value ){
|
1738 |
-
$tpl_key = '%%SUCURI.' . $tpl_key . '%%';
|
1739 |
-
$content = str_replace( $tpl_key, $tpl_value, $content );
|
1740 |
}
|
1741 |
|
1742 |
-
return
|
1743 |
}
|
1744 |
|
1745 |
-
return FALSE;
|
1746 |
}
|
1747 |
|
1748 |
/**
|
1749 |
-
*
|
1750 |
-
*
|
1751 |
-
*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1752 |
*
|
1753 |
-
* @
|
1754 |
-
* @return array A complementary list of pseudo-variables for the template files.
|
1755 |
*/
|
1756 |
-
|
1757 |
-
$params = is_array($params) ? $params : array();
|
1758 |
-
$sub_pages = sucuriscan_pages(TRUE);
|
1759 |
|
1760 |
-
|
1761 |
-
|
1762 |
-
|
1763 |
-
|
1764 |
-
|
|
|
|
|
1765 |
|
1766 |
-
if(
|
1767 |
-
|
1768 |
-
$pseudo_var = 'URL.' . ucwords($unique_name);
|
1769 |
-
} else {
|
1770 |
-
$unique_name = '';
|
1771 |
-
$pseudo_var = 'URL.Home';
|
1772 |
}
|
1773 |
|
1774 |
-
|
|
|
1775 |
|
1776 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1777 |
|
1778 |
-
|
1779 |
-
|
|
|
|
|
|
|
|
|
1780 |
}
|
1781 |
|
1782 |
-
|
1783 |
-
|
1784 |
-
$
|
1785 |
-
$params[$pseudo_var],
|
1786 |
-
$sub_page_title
|
1787 |
-
);
|
1788 |
-
}
|
1789 |
|
1790 |
-
|
1791 |
-
|
|
|
|
|
1792 |
|
1793 |
-
|
1794 |
-
* Generate a HTML code using a template and replacing all the pseudo-variables
|
1795 |
-
* by the dynamic variables provided by the developer through one of the parameters
|
1796 |
-
* of the function.
|
1797 |
-
*
|
1798 |
-
* @param string $template Filename of the template that will be used to generate the page.
|
1799 |
-
* @param array $params A hash containing the pseudo-variable name as the key and the value that will replace it.
|
1800 |
-
* @param boolean $type Either page, section or snippet indicating the type of template that will be retrieved.
|
1801 |
-
* @return string The formatted HTML page after replace all the pseudo-variables.
|
1802 |
-
*/
|
1803 |
-
function sucuriscan_get_template( $template='', $params=array(), $type='page' ){
|
1804 |
-
switch( $type ){
|
1805 |
-
case 'page': /* no_break */
|
1806 |
-
case 'section':
|
1807 |
-
$template_path_pattern = '%s/%s/inc/tpl/%s.html.tpl';
|
1808 |
-
break;
|
1809 |
-
case 'snippet':
|
1810 |
-
$template_path_pattern = '%s/%s/inc/tpl/%s.snippet.tpl';
|
1811 |
-
break;
|
1812 |
-
}
|
1813 |
|
1814 |
-
|
1815 |
-
|
1816 |
-
$params = is_array($params) ? $params : array();
|
1817 |
|
1818 |
-
|
1819 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1820 |
|
1821 |
-
$
|
1822 |
-
|
1823 |
-
|
1824 |
|
1825 |
-
|
1826 |
-
if(
|
1827 |
-
$template == 'base'
|
1828 |
-
&& isset($params['PageContent'])
|
1829 |
-
&& preg_match('/%%SUCURI\.(.+)%%/', $params['PageContent'])
|
1830 |
-
){
|
1831 |
-
$params['PageContent'] = sucuriscan_replace_pseudovars( $params['PageContent'], $params );
|
1832 |
}
|
1833 |
|
1834 |
-
|
1835 |
}
|
1836 |
|
1837 |
-
|
1838 |
-
|
1839 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1840 |
|
1841 |
-
|
1842 |
-
|
|
|
|
|
|
|
|
|
1843 |
|
1844 |
-
|
1845 |
-
|
1846 |
-
|
1847 |
-
* @param array $params A hash containing the pseudo-variable name as the key and the value that will replace it.
|
1848 |
-
* @return array A complementary list of pseudo-variables for the template files.
|
1849 |
-
*/
|
1850 |
-
function sucuriscan_shared_params( $params=array() ){
|
1851 |
-
$params = is_array($params) ? $params : array();
|
1852 |
|
1853 |
-
|
1854 |
-
|
1855 |
|
1856 |
-
|
1857 |
-
|
1858 |
-
|
1859 |
-
|
1860 |
-
|
1861 |
-
|
|
|
|
|
|
|
|
|
|
|
1862 |
|
1863 |
-
|
1864 |
-
}
|
1865 |
|
1866 |
-
/**
|
1867 |
-
|
1868 |
-
|
1869 |
-
|
1870 |
-
|
1871 |
-
|
1872 |
-
|
1873 |
-
|
1874 |
-
|
1875 |
-
|
1876 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1877 |
|
1878 |
-
|
1879 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1880 |
|
1881 |
-
|
1882 |
-
}
|
1883 |
|
1884 |
-
/**
|
1885 |
-
|
1886 |
-
|
1887 |
-
|
1888 |
-
|
1889 |
-
|
1890 |
-
|
1891 |
-
|
1892 |
-
|
1893 |
-
|
1894 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
1895 |
|
1896 |
-
|
1897 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
1898 |
|
1899 |
-
|
1900 |
-
|
1901 |
-
|
1902 |
-
|
1903 |
-
*
|
1904 |
-
* @param string $template Filename of the template that will be used to generate the page.
|
1905 |
-
* @param array $params A hash containing the pseudo-variable name as the key and the value that will replace it.
|
1906 |
-
* @return string The formatted HTML page after replace all the pseudo-variables.
|
1907 |
-
*/
|
1908 |
-
function sucuriscan_get_modal($template='', $params=array()){
|
1909 |
-
$required = array(
|
1910 |
-
'Title' => 'Lorem ipsum dolor sit amet',
|
1911 |
-
'CssClass' => '',
|
1912 |
-
'Content' => '<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do
|
1913 |
-
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
|
1914 |
-
veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
1915 |
-
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
1916 |
-
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
1917 |
-
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>',
|
1918 |
-
);
|
1919 |
|
1920 |
-
|
1921 |
-
|
1922 |
-
}
|
1923 |
|
1924 |
-
|
1925 |
-
if( !isset($params[$param_name]) ){
|
1926 |
-
$params[$param_name] = $param_value;
|
1927 |
}
|
1928 |
-
}
|
1929 |
|
1930 |
-
|
1931 |
-
|
1932 |
-
return sucuriscan_get_template( 'modalwindow', $params, 'section' );
|
1933 |
-
}
|
1934 |
|
1935 |
-
/**
|
1936 |
-
|
1937 |
-
|
1938 |
-
|
1939 |
-
|
1940 |
-
|
1941 |
-
|
1942 |
-
|
1943 |
-
*/
|
1944 |
-
function sucuriscan_get_snippet($template='', $params=array()){
|
1945 |
-
return sucuriscan_get_template( $template, $params, 'snippet' );
|
1946 |
-
}
|
1947 |
|
1948 |
-
|
1949 |
-
|
1950 |
-
* be loaded through the administrator panel.
|
1951 |
-
*
|
1952 |
-
* @param string $page Short name of the page that will be generated.
|
1953 |
-
* @return string Full string containing the link of the page.
|
1954 |
-
*/
|
1955 |
-
function sucuriscan_get_url($page=''){
|
1956 |
-
$url_path = admin_url('admin.php?page=sucuriscan');
|
1957 |
|
1958 |
-
|
1959 |
-
|
1960 |
-
}
|
1961 |
|
1962 |
-
|
1963 |
-
|
|
|
|
|
|
|
1964 |
|
1965 |
-
|
1966 |
-
|
1967 |
-
* official API provided by WordPress itself.
|
1968 |
-
*
|
1969 |
-
* @return array A list of the new set of keys generated by WordPress API.
|
1970 |
-
*/
|
1971 |
-
function sucuriscan_get_new_config_keys(){
|
1972 |
-
$request = wp_remote_get('https://api.wordpress.org/secret-key/1.1/salt/');
|
1973 |
|
1974 |
-
|
1975 |
-
if( preg_match_all("/define\('([A-Z_]+)',[ ]+'(.*)'\);/", $request['body'], $match) ){
|
1976 |
-
$new_keys = array();
|
1977 |
|
1978 |
-
|
1979 |
-
$new_keys[$value] = $match[2][$i];
|
1980 |
}
|
1981 |
-
|
1982 |
-
return $new_keys;
|
1983 |
}
|
1984 |
-
}
|
1985 |
|
1986 |
-
|
1987 |
-
}
|
1988 |
|
1989 |
-
/**
|
1990 |
-
|
1991 |
-
|
1992 |
-
|
1993 |
-
|
1994 |
-
|
1995 |
-
|
1996 |
-
|
1997 |
-
|
1998 |
-
function
|
1999 |
-
|
2000 |
-
|
2001 |
-
|
2002 |
-
|
2003 |
-
|
2004 |
-
|
2005 |
-
|
2006 |
-
|
2007 |
-
|
2008 |
-
|
2009 |
-
$
|
2010 |
-
|
2011 |
-
|
2012 |
-
$
|
2013 |
-
|
2014 |
-
|
2015 |
-
$
|
2016 |
-
|
2017 |
-
|
2018 |
-
|
2019 |
-
|
|
|
|
|
|
|
|
|
2020 |
}
|
|
|
|
|
2021 |
}
|
2022 |
|
2023 |
-
$
|
2024 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
2025 |
|
2026 |
-
|
2027 |
-
|
2028 |
-
|
2029 |
-
'old_keys_string' => $old_keys_string,
|
2030 |
-
'new_keys' => $new_keys,
|
2031 |
-
'new_keys_string' => $new_keys_string,
|
2032 |
-
'new_wpconfig' => $new_wpconfig,
|
2033 |
-
);
|
2034 |
|
2035 |
-
|
2036 |
-
file_put_contents($wp_config_path, $new_wpconfig, LOCK_EX);
|
2037 |
}
|
2038 |
-
|
|
|
2039 |
}
|
2040 |
-
|
2041 |
}
|
2042 |
|
2043 |
/**
|
2044 |
-
*
|
|
|
|
|
|
|
|
|
|
|
|
|
2045 |
*
|
2046 |
-
*
|
2047 |
-
*
|
|
|
|
|
|
|
2048 |
*/
|
2049 |
-
|
2050 |
-
$user_id = intval($user_id);
|
2051 |
-
$current_user = wp_get_current_user();
|
2052 |
|
2053 |
-
|
2054 |
-
|
2055 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
2056 |
|
2057 |
-
$
|
2058 |
-
|
2059 |
-
|
2060 |
-
|
2061 |
-
font-size:30px;margin:0;padding:15px;border:1px solid #999'>{$new_password}</div>";
|
2062 |
-
sucuriscan_send_mail($user->user_email, 'Changed password', $message, $data_set);
|
2063 |
|
2064 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2065 |
|
2066 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2067 |
}
|
2068 |
-
return FALSE;
|
2069 |
-
}
|
2070 |
|
2071 |
-
/**
|
2072 |
-
|
2073 |
-
|
2074 |
-
|
2075 |
-
|
2076 |
-
|
2077 |
-
$
|
2078 |
-
'
|
2079 |
-
'HTTP_CLIENT_IP',
|
2080 |
-
'HTTP_X_FORWARDED_FOR',
|
2081 |
-
'HTTP_X_FORWARDED',
|
2082 |
-
'HTTP_FORWARDED_FOR',
|
2083 |
-
'HTTP_FORWARDED',
|
2084 |
-
'REMOTE_ADDR',
|
2085 |
-
'SUCURI_RIP',
|
2086 |
-
);
|
2087 |
-
foreach($alternatives as $alternative){
|
2088 |
-
if( !isset($_SERVER[$alternative]) ){ continue; }
|
2089 |
|
2090 |
-
$
|
2091 |
-
|
|
|
2092 |
}
|
2093 |
|
2094 |
-
|
2095 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
2096 |
}
|
2097 |
|
2098 |
-
|
2099 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2100 |
|
2101 |
-
/**
|
2102 |
-
|
2103 |
-
|
2104 |
-
|
2105 |
-
|
2106 |
-
|
2107 |
-
|
2108 |
-
|
|
|
|
|
|
|
2109 |
}
|
2110 |
|
2111 |
-
|
2112 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2113 |
|
2114 |
-
|
2115 |
-
|
2116 |
-
|
2117 |
-
|
2118 |
-
|
2119 |
-
|
2120 |
-
|
2121 |
-
if( preg_match('/^(.*):([0-9]+)/', $http_host, $match) ){ $http_host = $match[1]; }
|
2122 |
-
$host_by_name = gethostbyname($http_host);
|
2123 |
-
$host_by_addr = gethostbyaddr($host_by_name);
|
2124 |
|
2125 |
-
|
2126 |
-
|
2127 |
-
|
2128 |
-
|
2129 |
-
|
|
|
2130 |
}
|
2131 |
|
2132 |
-
|
2133 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
2134 |
|
2135 |
-
|
2136 |
-
|
2137 |
-
|
2138 |
-
|
2139 |
-
|
2140 |
-
|
2141 |
-
|
2142 |
-
|
|
|
2143 |
|
2144 |
-
|
2145 |
-
|
2146 |
-
|
2147 |
-
if( isset($wp_version) ){ return $wp_version; }
|
2148 |
}
|
2149 |
|
2150 |
-
|
2151 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2152 |
|
2153 |
-
/**
|
2154 |
-
|
2155 |
-
|
2156 |
-
|
2157 |
-
|
2158 |
-
|
2159 |
-
$
|
|
|
|
|
2160 |
|
2161 |
-
|
2162 |
-
|
2163 |
-
|
|
|
|
|
|
|
|
|
|
|
2164 |
}
|
2165 |
|
2166 |
-
|
2167 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2168 |
|
2169 |
-
/**
|
2170 |
-
|
2171 |
-
|
2172 |
-
|
2173 |
-
|
2174 |
-
|
2175 |
-
|
2176 |
-
|
2177 |
-
|
2178 |
-
dirname(dirname(ABSPATH))
|
2179 |
-
);
|
2180 |
|
2181 |
-
|
2182 |
-
$htaccess_path = sprintf('%s/.htaccess', $base_dir);
|
2183 |
-
if( file_exists($htaccess_path) ){
|
2184 |
-
return $htaccess_path;
|
2185 |
-
}
|
2186 |
}
|
2187 |
|
2188 |
-
|
2189 |
-
|
2190 |
-
|
2191 |
-
|
2192 |
-
|
2193 |
-
|
2194 |
-
|
2195 |
-
|
2196 |
-
* @return string The administrator email address.
|
2197 |
-
*/
|
2198 |
-
function sucuriscan_get_site_email(){
|
2199 |
-
$email = get_option('admin_email');
|
2200 |
|
2201 |
-
|
2202 |
-
|
|
|
2203 |
}
|
2204 |
|
2205 |
-
|
2206 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2207 |
|
2208 |
-
|
2209 |
-
|
2210 |
-
|
2211 |
-
|
2212 |
-
*/
|
2213 |
-
function sucuriscan_get_domain(){
|
2214 |
-
$http_host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : '';
|
2215 |
-
$domain_name = preg_replace( '/^www\./', '', $http_host );
|
2216 |
|
2217 |
-
|
2218 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2219 |
|
2220 |
-
|
2221 |
-
|
2222 |
-
|
2223 |
-
|
2224 |
-
*/
|
2225 |
-
function sucuriscan_user_agent(){
|
2226 |
-
global $wp_version;
|
2227 |
|
2228 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2229 |
|
2230 |
-
|
2231 |
-
|
|
|
2232 |
|
2233 |
-
|
2234 |
-
|
2235 |
-
*
|
2236 |
-
* @param integer $timestamp The Unix time number of the date/time before now.
|
2237 |
-
* @return string The time passed since the timestamp specified.
|
2238 |
-
*/
|
2239 |
-
function sucuriscan_time_ago($timestamp=0){
|
2240 |
-
if( !is_numeric($timestamp) ){
|
2241 |
-
$timestamp = strtotime($timestamp);
|
2242 |
-
}
|
2243 |
|
2244 |
-
|
|
|
|
|
2245 |
|
2246 |
-
|
|
|
|
|
2247 |
|
2248 |
-
|
2249 |
-
|
2250 |
-
|
2251 |
-
|
2252 |
-
|
2253 |
-
|
2254 |
-
|
2255 |
-
|
2256 |
-
|
|
|
|
|
|
|
|
|
2257 |
|
2258 |
-
|
2259 |
-
|
2260 |
-
|
2261 |
-
|
2262 |
-
|
2263 |
-
|
2264 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2265 |
|
2266 |
-
|
2267 |
-
}
|
2268 |
|
2269 |
-
/**
|
2270 |
-
|
2271 |
-
|
2272 |
-
|
2273 |
-
|
2274 |
-
|
2275 |
-
|
2276 |
-
|
2277 |
-
function sucuriscan_str_human2var($string=''){
|
2278 |
-
$pattern = '/[^a-zA-Z0-9_]/';
|
2279 |
-
$var_name = preg_replace($pattern, '_', strtolower($string));
|
2280 |
|
2281 |
-
|
2282 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2283 |
|
2284 |
-
|
2285 |
-
|
2286 |
-
|
2287 |
-
|
2288 |
-
|
2289 |
-
|
2290 |
-
|
2291 |
-
* <ul>
|
2292 |
-
* <li>all_sucuriscan_options: Will retrieve all the option values created by this plugin in the main site (aka. network),</li>
|
2293 |
-
* <li>site_options: Will retrieve all the option values stored in the current site visited by the user (aka. sub-site) excluding the transient options,</li>
|
2294 |
-
* <li>sucuriscan_option: Will retrieve one specific option from the network site only if the option starts with the prefix <i>sucuri_<i>.</li>
|
2295 |
-
* </ul>
|
2296 |
-
*
|
2297 |
-
* @param string $filter_by Criteria to filter the results, valid values: all_sucuriscan_options, site_options, sucuri_option.
|
2298 |
-
* @param string $option_name Optional parameter with the name of the option that will be filtered.
|
2299 |
-
* @return array List of options retrieved from the query in the database.
|
2300 |
-
*/
|
2301 |
-
function sucuriscan_get_options_from_db( $filter_by='', $option_name='' ){
|
2302 |
-
global $wpdb;
|
2303 |
|
2304 |
-
|
2305 |
-
|
2306 |
-
|
2307 |
-
|
2308 |
-
|
2309 |
-
|
2310 |
-
|
2311 |
-
|
2312 |
-
case 'sucuriscan_option':
|
2313 |
-
$row = $wpdb->get_row( $wpdb->prepare("SELECT option_value FROM {$wpdb->base_prefix}options WHERE option_name = %s LIMIT 1", $option_name) );
|
2314 |
-
if( $row ){ $output = $row->option_value; }
|
2315 |
-
break;
|
2316 |
-
}
|
2317 |
|
2318 |
-
|
2319 |
-
|
2320 |
|
2321 |
-
|
2322 |
-
|
2323 |
-
|
2324 |
-
|
2325 |
-
|
2326 |
-
|
2327 |
-
|
2328 |
-
|
2329 |
-
|
2330 |
-
|
2331 |
-
|
2332 |
-
|
2333 |
-
|
|
|
|
|
|
|
|
|
2334 |
|
2335 |
-
|
2336 |
-
|
2337 |
-
|
2338 |
-
|
2339 |
-
|
2340 |
-
|
2341 |
-
|
2342 |
-
|
2343 |
-
|
2344 |
-
function sucuriscan_get_options( $option_name='' ){
|
2345 |
-
if( !empty($option_name) ){
|
2346 |
-
return sucuriscan_get_single_option($option_name);
|
2347 |
-
}
|
2348 |
|
2349 |
-
|
2350 |
-
|
2351 |
-
|
2352 |
-
|
2353 |
-
|
|
|
2354 |
|
2355 |
-
|
2356 |
-
|
|
|
|
|
|
|
|
|
|
|
2357 |
|
2358 |
-
|
2359 |
-
|
2360 |
-
*
|
2361 |
-
* @param string $option_name Name of the option that will be retrieved.
|
2362 |
-
* @return string Value of the option stored in the database, FALSE if not found.
|
2363 |
-
*/
|
2364 |
-
function sucuriscan_get_single_option( $option_name='' ){
|
2365 |
-
$is_sucuri_option = preg_match('/^sucuriscan_/', $option_name) ? TRUE : FALSE;
|
2366 |
|
2367 |
-
|
2368 |
-
|
2369 |
-
|
2370 |
-
|
2371 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2372 |
|
2373 |
-
|
2374 |
-
|
2375 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
2376 |
|
2377 |
-
|
2378 |
-
}
|
2379 |
|
2380 |
-
|
2381 |
-
|
2382 |
-
|
2383 |
-
|
2384 |
-
|
2385 |
-
|
2386 |
-
|
2387 |
-
|
2388 |
-
|
2389 |
-
|
2390 |
-
|
2391 |
-
|
2392 |
-
|
2393 |
-
|
2394 |
-
|
2395 |
-
'sucuriscan_notify_to' => $admin_email,
|
2396 |
-
'sucuriscan_emails_sent' => 0,
|
2397 |
-
'sucuriscan_emails_per_hour' => 5,
|
2398 |
-
'sucuriscan_last_email_at' => time(),
|
2399 |
-
'sucuriscan_prettify_mails' => 'enabled',
|
2400 |
-
'sucuriscan_notify_success_login' => 'enabled',
|
2401 |
-
'sucuriscan_notify_failed_login' => 'enabled',
|
2402 |
-
'sucuriscan_notify_post_publication' => 'enabled',
|
2403 |
-
'sucuriscan_notify_theme_editor' => 'enabled',
|
2404 |
-
'sucuriscan_maximum_failed_logins' => 30,
|
2405 |
-
'sucuriscan_ignored_events' => '',
|
2406 |
-
'sucuriscan_verify_ssl_cert' => 'true',
|
2407 |
-
);
|
2408 |
|
2409 |
-
|
2410 |
-
|
2411 |
-
|
2412 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2413 |
}
|
2414 |
}
|
2415 |
-
return $settings;
|
2416 |
-
}
|
2417 |
|
2418 |
-
|
2419 |
-
|
2420 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2421 |
}
|
2422 |
-
}
|
2423 |
|
2424 |
-
|
2425 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2426 |
|
2427 |
-
|
2428 |
-
|
2429 |
-
|
2430 |
-
* is compatible with multisite instances.
|
2431 |
-
*
|
2432 |
-
* @return array All the options stored by Wordpress in the database, except the transient options.
|
2433 |
-
*/
|
2434 |
-
function sucuriscan_get_wp_options(){
|
2435 |
-
$settings = array();
|
2436 |
|
2437 |
-
|
2438 |
-
|
2439 |
-
|
2440 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
2441 |
|
2442 |
-
|
2443 |
-
|
|
|
|
|
2444 |
|
2445 |
-
|
2446 |
-
|
2447 |
-
|
2448 |
-
|
2449 |
-
|
2450 |
-
|
2451 |
-
*/
|
2452 |
-
function sucuriscan_what_options_were_changed( $request=array() ){
|
2453 |
-
$options_changed = array(
|
2454 |
-
'original' => array(),
|
2455 |
-
'changed' => array()
|
2456 |
-
);
|
2457 |
-
$wp_options = sucuriscan_get_wp_options();
|
2458 |
|
2459 |
-
|
2460 |
-
|
2461 |
-
|
2462 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
2463 |
){
|
2464 |
-
$
|
2465 |
-
|
|
|
2466 |
}
|
2467 |
-
}
|
2468 |
-
return $options_changed;
|
2469 |
-
}
|
2470 |
|
2471 |
-
|
2472 |
-
|
2473 |
-
|
2474 |
-
|
2475 |
-
|
2476 |
-
|
2477 |
-
|
2478 |
-
|
2479 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2480 |
|
2481 |
-
|
|
|
|
|
2482 |
|
2483 |
-
|
2484 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2485 |
|
2486 |
-
|
2487 |
-
|
2488 |
-
|
2489 |
-
|
2490 |
-
|
2491 |
-
|
2492 |
-
|
2493 |
-
|
|
|
|
|
2494 |
|
2495 |
-
|
2496 |
-
|
2497 |
-
|
2498 |
|
2499 |
-
|
2500 |
-
|
2501 |
-
|
2502 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2503 |
|
2504 |
-
|
|
|
|
|
|
|
|
|
2505 |
}
|
|
|
2506 |
}
|
2507 |
|
2508 |
-
return FALSE;
|
2509 |
}
|
2510 |
|
2511 |
/**
|
2512 |
-
*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2513 |
*
|
2514 |
-
* @
|
2515 |
-
* @return boolean Whether the event was removed from the list or not.
|
2516 |
*/
|
2517 |
-
|
2518 |
-
$ignored_events = sucuriscan_get_ignored_events();
|
2519 |
|
2520 |
-
|
2521 |
-
|
2522 |
-
|
2523 |
-
|
2524 |
-
|
|
|
|
|
|
|
|
|
2525 |
}
|
2526 |
|
2527 |
-
|
2528 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2529 |
|
2530 |
-
|
2531 |
-
|
2532 |
-
*
|
2533 |
-
* @param string $event_name Unique post-type name.
|
2534 |
-
* @return boolean Whether an event is being ignored or not.
|
2535 |
-
*/
|
2536 |
-
function sucuriscan_is_ignored_event( $event_name='' ){
|
2537 |
-
$event_name = strtolower($event_name);
|
2538 |
-
$ignored_events = sucuriscan_get_ignored_events();
|
2539 |
|
2540 |
-
if( array_key_exists($event_name, $ignored_events) ){
|
2541 |
-
return TRUE;
|
2542 |
-
}
|
2543 |
-
|
2544 |
-
return FALSE;
|
2545 |
-
}
|
2546 |
-
|
2547 |
-
if( !function_exists('sucuriscan_plugin_setup_notice') ){
|
2548 |
/**
|
2549 |
-
*
|
2550 |
-
*
|
2551 |
-
* to be done to fully activate this plugin.
|
2552 |
*
|
2553 |
-
* @
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2554 |
*/
|
2555 |
-
function
|
2556 |
-
if(
|
2557 |
-
|
2558 |
-
|
2559 |
-
|
2560 |
-
|
2561 |
-
|
2562 |
-
|
2563 |
-
|
2564 |
-
|
2565 |
-
|
2566 |
-
|
2567 |
-
|
2568 |
-
|
2569 |
-
|
2570 |
-
|
2571 |
-
* Check the plugins directory and retrieve all plugin files with plugin data.
|
2572 |
-
* This function will also retrieve the URL and name of the repository/page
|
2573 |
-
* where it is being published at the WordPress plugins market.
|
2574 |
-
*
|
2575 |
-
* @return array Key is the plugin file path and the value is an array of the plugin data.
|
2576 |
-
*/
|
2577 |
-
function sucuriscan_get_plugins(){
|
2578 |
-
$sucuri_cache = new SucuriScanCache('plugindata');
|
2579 |
-
$cached_data = $sucuri_cache->get( 'plugins', SUCURISCAN_GET_PLUGINS_LIFETIME, 'array' );
|
2580 |
|
2581 |
-
|
2582 |
-
|
2583 |
-
|
2584 |
-
|
|
|
|
|
2585 |
|
2586 |
-
|
2587 |
-
|
2588 |
-
|
2589 |
-
|
2590 |
|
2591 |
-
|
2592 |
-
|
2593 |
-
// Default values for the plugin extra attributes.
|
2594 |
-
$repository = '';
|
2595 |
-
$repository_name = '';
|
2596 |
-
$is_free_plugin = FALSE;
|
2597 |
|
2598 |
-
|
2599 |
-
|
2600 |
-
|
2601 |
-
&& preg_match($pattern, $plugin_data['PluginURI'], $match)
|
2602 |
-
){
|
2603 |
-
$repository = $match[0];
|
2604 |
-
$repository_name = $match[1];
|
2605 |
-
$is_free_plugin = TRUE;
|
2606 |
}
|
2607 |
|
2608 |
-
|
2609 |
-
|
2610 |
-
|
2611 |
-
|
|
|
|
|
|
|
2612 |
} else {
|
2613 |
-
$
|
2614 |
-
}
|
2615 |
-
|
2616 |
-
if( isset($plugin_path_parts[0]) ){
|
2617 |
-
$possible_repository = sprintf($wp_market, $plugin_path_parts[0]);
|
2618 |
-
$resp = wp_remote_head($possible_repository);
|
2619 |
|
|
|
2620 |
if(
|
2621 |
-
|
2622 |
-
&& $
|
2623 |
){
|
2624 |
-
$
|
2625 |
-
|
2626 |
-
|
|
|
|
|
|
|
2627 |
}
|
|
|
|
|
2628 |
}
|
|
|
|
|
2629 |
}
|
2630 |
|
2631 |
-
|
2632 |
-
|
2633 |
-
|
2634 |
-
|
2635 |
-
|
2636 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2637 |
|
2638 |
-
if(
|
2639 |
-
|
2640 |
}
|
|
|
|
|
2641 |
}
|
2642 |
|
2643 |
-
|
2644 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2645 |
|
2646 |
-
|
2647 |
-
}
|
2648 |
|
2649 |
-
/**
|
2650 |
-
|
2651 |
-
|
2652 |
-
|
2653 |
-
|
2654 |
-
|
2655 |
-
|
2656 |
-
|
2657 |
-
|
2658 |
-
|
2659 |
-
|
2660 |
-
|
2661 |
-
|
2662 |
-
|
2663 |
-
|
2664 |
-
|
2665 |
-
|
2666 |
-
|
2667 |
-
|
2668 |
-
|
2669 |
-
|
|
|
2670 |
|
2671 |
-
|
2672 |
-
$
|
2673 |
|
2674 |
-
if( $
|
2675 |
-
return
|
|
|
|
|
|
|
|
|
2676 |
}
|
|
|
|
|
2677 |
}
|
2678 |
|
2679 |
-
|
2680 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2681 |
|
2682 |
-
|
2683 |
-
|
2684 |
-
*
|
2685 |
-
* @return integer Page number of the link clicked in a pagination.
|
2686 |
-
*/
|
2687 |
-
function sucuriscan_get_page_number(){
|
2688 |
-
$page_number = 1;
|
2689 |
|
2690 |
-
|
2691 |
-
|
2692 |
-
|
2693 |
-
|
2694 |
-
&& $_GET['num'] <= 10
|
2695 |
-
){
|
2696 |
-
$page_number = intval($_GET['num']);
|
2697 |
}
|
2698 |
|
2699 |
-
|
2700 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2701 |
|
2702 |
-
|
2703 |
-
|
2704 |
-
*
|
2705 |
-
* @param string $base_url Base URL for the links before the page number.
|
2706 |
-
* @param integer $total_items Total quantity of items retrieved from a query.
|
2707 |
-
* @param integer $max_per_page Maximum number of items that will be shown per page.
|
2708 |
-
* @return string HTML code for a pagination generated using the provided data.
|
2709 |
-
*/
|
2710 |
-
function sucuriscan_generate_pagination( $base_url='', $total_items=0, $max_per_page=1 ){
|
2711 |
-
// Calculate the number of links for the pagination.
|
2712 |
-
$html_links = '';
|
2713 |
-
$page_number = sucuriscan_get_page_number();
|
2714 |
-
$max_pages = ceil($total_items / $max_per_page);
|
2715 |
|
2716 |
-
|
2717 |
-
for( $j=1; $j<=$max_pages; $j++ ){
|
2718 |
-
$link_class = 'sucuriscan-pagination-link';
|
2719 |
|
2720 |
-
|
2721 |
-
$link_class .= chr(32) . 'sucuriscan-pagination-active';
|
2722 |
}
|
2723 |
|
2724 |
-
$
|
2725 |
-
|
2726 |
-
|
2727 |
-
);
|
2728 |
}
|
2729 |
|
2730 |
-
|
2731 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2732 |
|
2733 |
-
|
2734 |
-
|
2735 |
-
|
2736 |
-
|
2737 |
-
*
|
2738 |
-
* @return void
|
2739 |
-
*/
|
2740 |
-
function sucuriscan_scanner_page(){
|
2741 |
-
if(
|
2742 |
-
sucuriscan_check_page_nonce()
|
2743 |
-
&& isset($_POST['sucuriscan_malware_scan'])
|
2744 |
-
){
|
2745 |
-
sucuriscan_sitecheck_info();
|
2746 |
-
} else {
|
2747 |
-
echo sucuriscan_get_template('malwarescan');
|
2748 |
-
}
|
2749 |
-
}
|
2750 |
|
2751 |
-
|
2752 |
-
|
2753 |
-
|
2754 |
-
|
2755 |
-
|
2756 |
-
|
2757 |
-
$sucuri_cache = new SucuriScanCache('sitecheck');
|
2758 |
-
$scan_results = $sucuri_cache->get( 'scan_results', SUCURISCAN_SITECHECK_LIFETIME, 'array' );
|
2759 |
-
$clean_domain = sucuriscan_get_domain();
|
2760 |
-
$display_results = FALSE;
|
2761 |
|
2762 |
-
|
|
|
|
|
2763 |
|
2764 |
-
|
2765 |
-
$remote_url = 'http://sitecheck.sucuri.net/scanner/?serialized&clear&fromwp&scan='.$clean_domain;
|
2766 |
-
$scan_results = wp_remote_get($remote_url, array('timeout' => 180));
|
2767 |
|
2768 |
-
|
2769 |
-
sucuriscan_error( $scan_results->get_error_message() );
|
2770 |
}
|
2771 |
|
2772 |
-
|
2773 |
-
|
2774 |
-
sucuriscan_error( 'The site <code>' . $clean_domain . '</code> was not scanned: ' . $error_m[1] );
|
2775 |
-
}
|
2776 |
-
|
2777 |
-
else {
|
2778 |
-
$scan_results = @unserialize($scan_results['body']);
|
2779 |
-
$display_results = TRUE;
|
2780 |
|
2781 |
-
|
2782 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2783 |
}
|
|
|
|
|
2784 |
}
|
2785 |
}
|
2786 |
-
|
2787 |
-
|
2788 |
-
// sucuriscan_info( 'SiteCheck results retrieved from cache.' );
|
2789 |
}
|
2790 |
-
?>
|
2791 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2792 |
|
2793 |
-
|
|
|
2794 |
|
2795 |
-
|
2796 |
-
|
2797 |
|
2798 |
-
|
2799 |
-
|
2800 |
-
|
2801 |
-
|
2802 |
-
|
|
|
|
|
2803 |
|
2804 |
-
|
2805 |
-
|
2806 |
-
|
2807 |
-
|
|
|
2808 |
|
2809 |
-
if(
|
2810 |
-
$
|
|
|
|
|
|
|
2811 |
}
|
2812 |
|
2813 |
-
|
2814 |
-
|
2815 |
-
$sucuriscan_css_blacklist = 'sucuriscan-border-good';
|
2816 |
-
$sucuriscan_css_malware = 'sucuriscan-border-good';
|
2817 |
-
$sitecheck_results_tab = '';
|
2818 |
-
$blacklist_status_tab = '';
|
2819 |
-
$website_details_tab = '';
|
2820 |
|
2821 |
-
|
2822 |
-
|
2823 |
-
|
2824 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2825 |
}
|
|
|
2826 |
|
2827 |
-
|
2828 |
-
|
2829 |
-
$sucuriscan_css_malware = 'sucuriscan-border-bad';
|
2830 |
-
$sitecheck_results_tab = 'sucuriscan-red-tab';
|
2831 |
-
}
|
2832 |
|
2833 |
-
|
2834 |
-
|
2835 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2836 |
}
|
2837 |
|
2838 |
-
|
2839 |
}
|
2840 |
-
?>
|
2841 |
|
2842 |
-
|
2843 |
-
|
2844 |
-
<h3>SiteCheck Scanner</h3>
|
2845 |
|
2846 |
-
|
2847 |
-
|
2848 |
-
|
2849 |
-
|
2850 |
-
|
2851 |
-
|
2852 |
-
|
2853 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2854 |
|
|
|
|
|
2855 |
|
2856 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2857 |
|
|
|
|
|
|
|
2858 |
|
2859 |
-
|
2860 |
-
<li class="<?php _e($sitecheck_results_tab) ?>">
|
2861 |
-
<a href="#" data-tabname="sitecheck-results">Remote Scanner Results</a>
|
2862 |
-
</li>
|
2863 |
-
<li class="<?php _e($website_details_tab) ?>">
|
2864 |
-
<a href="#" data-tabname="website-details">Website Details</a>
|
2865 |
-
</li>
|
2866 |
-
<li>
|
2867 |
-
<a href="#" data-tabname="website-links">IFrames / Links / Scripts</a>
|
2868 |
-
</li>
|
2869 |
-
<li class="<?php _e($blacklist_status_tab) ?>">
|
2870 |
-
<a href="#" data-tabname="blacklist-status">Blacklist Status</a>
|
2871 |
-
</li>
|
2872 |
-
<li>
|
2873 |
-
<a href="#" data-tabname="modified-files">Modified Files</a>
|
2874 |
-
</li>
|
2875 |
-
</ul>
|
2876 |
|
|
|
|
|
|
|
2877 |
|
2878 |
-
|
|
|
2879 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2880 |
|
2881 |
-
|
2882 |
-
|
2883 |
-
|
2884 |
-
<h3>
|
2885 |
-
<?php if( $malware_warns_exist ): ?>
|
2886 |
-
Site compromised (malware was identified)
|
2887 |
-
<?php else: ?>
|
2888 |
-
Site clean (no malware was identified)
|
2889 |
-
<?php endif; ?>
|
2890 |
-
</h3>
|
2891 |
|
2892 |
-
|
2893 |
|
2894 |
-
|
2895 |
-
|
2896 |
-
|
2897 |
-
<span><strong>Malicious javascript:</strong> Clean.</span><br>
|
2898 |
-
<span><strong>Malicious iframes:</strong> Clean.</span><br>
|
2899 |
-
<span><strong>Suspicious redirections (htaccess):</strong> Clean.</span><br>
|
2900 |
-
<span><strong>Blackhat SEO Spam:</strong> Clean.</span><br>
|
2901 |
-
<span><strong>Anomaly detection:</strong> Clean.</span>
|
2902 |
-
</p>
|
2903 |
-
<?php else: ?>
|
2904 |
-
<ul>
|
2905 |
-
<?php
|
2906 |
-
foreach( $res['MALWARE']['WARN'] as $malres ){
|
2907 |
-
if( !is_array($malres) ){
|
2908 |
-
echo '<li>' . htmlspecialchars($malres) . '</li>';
|
2909 |
-
} else {
|
2910 |
-
$mwdetails = explode("\n", htmlspecialchars($malres[1]));
|
2911 |
-
$mw_name_link = isset($mwdetails[0]) ? substr($mwdetails[0], 1) : '';
|
2912 |
|
2913 |
-
|
2914 |
-
|
2915 |
-
'%s. Details: <a href="%s" target="_blank">%s</a>',
|
2916 |
-
$mw_match[1], $mw_match[2], $mw_match[2]
|
2917 |
-
);
|
2918 |
-
}
|
2919 |
|
2920 |
-
|
2921 |
-
|
2922 |
-
|
2923 |
-
|
2924 |
-
|
2925 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2926 |
|
2927 |
-
|
2928 |
-
|
2929 |
-
|
2930 |
-
target="_blank">http://sitecheck.sucuri.net/results/<?php _e($clean_domain); ?></a>
|
2931 |
-
</i>
|
2932 |
-
</p>
|
2933 |
|
2934 |
-
|
|
|
|
|
2935 |
|
2936 |
-
|
2937 |
-
<i>
|
2938 |
-
If our free scanner did not detect any issue, you may have a more complicated
|
2939 |
-
and hidden problem. You can <a href="http://sucuri.net/signup" target="_blank">
|
2940 |
-
sign up</a> with Sucuri for a complete and in depth scan+cleanup (not included
|
2941 |
-
in the free checks).
|
2942 |
-
</i>
|
2943 |
-
</p>
|
2944 |
|
2945 |
-
|
2946 |
-
|
2947 |
-
|
2948 |
-
</div>
|
2949 |
|
|
|
|
|
2950 |
|
2951 |
-
|
2952 |
-
|
2953 |
-
|
2954 |
-
|
2955 |
-
|
2956 |
-
|
2957 |
-
|
2958 |
-
|
2959 |
-
|
2960 |
-
|
2961 |
-
|
2962 |
-
|
2963 |
-
|
2964 |
-
|
|
|
|
|
|
|
|
|
2965 |
|
2966 |
-
|
2967 |
-
|
2968 |
-
|
2969 |
-
|
2970 |
-
'DOMAIN' => 'Domain Scanned',
|
2971 |
-
'IP' => 'Site IP Address',
|
2972 |
-
'HOSTING' => 'Hosting Company',
|
2973 |
-
'CMS' => 'CMS Found',
|
2974 |
-
);
|
2975 |
-
$possible_url_keys = array(
|
2976 |
-
'IFRAME' => 'List of iframes found',
|
2977 |
-
'JSEXTERNAL' => 'List of external scripts included',
|
2978 |
-
'JSLOCAL' => 'List of scripts included',
|
2979 |
-
'URL' => 'List of links found',
|
2980 |
-
);
|
2981 |
-
?>
|
2982 |
|
2983 |
-
|
2984 |
-
|
2985 |
-
<?php $result_value = implode(', ', $res['SCAN'][$result_key]); ?>
|
2986 |
-
<tr>
|
2987 |
-
<td><?php _e($result_title) ?></td>
|
2988 |
-
<td><span class="sucuriscan-monospace"><?php _e($result_value) ?></span></td>
|
2989 |
-
</tr>
|
2990 |
-
<?php endif; ?>
|
2991 |
-
<?php endforeach; ?>
|
2992 |
|
2993 |
-
|
2994 |
-
|
2995 |
-
|
2996 |
-
|
2997 |
-
|
2998 |
-
|
2999 |
-
|
3000 |
-
|
|
|
3001 |
|
3002 |
-
|
3003 |
-
|
3004 |
-
<th colspan="2">Web application details</th>
|
3005 |
-
</tr>
|
3006 |
-
<?php foreach( $res['WEBAPP'] as $webapp_key=>$webapp_details ): ?>
|
3007 |
-
<?php if( is_array($webapp_details) ): ?>
|
3008 |
-
<?php foreach( $webapp_details as $i=>$details ): ?>
|
3009 |
-
<?php if( is_array($details) ){ $details = isset($details[0]) ? $details[0] : ''; } ?>
|
3010 |
-
<tr>
|
3011 |
-
<td colspan="2">
|
3012 |
-
<span class="sucuriscan-monospace"><?php _e($details) ?></span>
|
3013 |
-
</td>
|
3014 |
-
</tr>
|
3015 |
-
<?php endforeach; ?>
|
3016 |
-
<?php endif; ?>
|
3017 |
-
<?php endforeach; ?>
|
3018 |
|
3019 |
-
|
3020 |
-
|
3021 |
-
|
3022 |
-
<td colspan="2">
|
3023 |
-
<span class="sucuriscan-monospace"><?php _e($notice) ?></span>
|
3024 |
-
</td>
|
3025 |
-
</tr>
|
3026 |
-
<?php endforeach; ?>
|
3027 |
|
3028 |
-
|
3029 |
-
|
3030 |
-
<tr>
|
3031 |
-
<th colspan="2">Recommendations for the site</th>
|
3032 |
-
</tr>
|
3033 |
-
<?php endif; ?>
|
3034 |
|
3035 |
-
|
3036 |
-
|
3037 |
-
<?php foreach( $res['OUTDATEDSCAN'] as $outdated ): ?>
|
3038 |
-
<?php if( count($outdated) >= 3 ): ?>
|
3039 |
-
<tr>
|
3040 |
-
<td colspan="2" class="sucuriscan-border-bad">
|
3041 |
-
<strong><?php _e($outdated[0]) ?></strong>
|
3042 |
-
<em>(<?php _e($outdated[2]) ?>)</em>
|
3043 |
-
<span><?php _e($outdated[1]) ?></span>
|
3044 |
-
</td>
|
3045 |
-
</tr>
|
3046 |
-
<?php endif; ?>
|
3047 |
-
<?php endforeach; ?>
|
3048 |
-
<?php endif; ?>
|
3049 |
|
3050 |
-
|
3051 |
-
|
3052 |
-
|
3053 |
-
|
3054 |
-
|
3055 |
-
|
3056 |
-
|
3057 |
-
|
3058 |
-
|
3059 |
-
|
3060 |
-
|
3061 |
-
|
3062 |
-
|
3063 |
-
|
3064 |
-
</tr>
|
3065 |
-
<?php endif; ?>
|
3066 |
-
<?php endforeach; ?>
|
3067 |
-
<?php endif; ?>
|
3068 |
-
</tbody>
|
3069 |
-
</table>
|
3070 |
-
</div>
|
3071 |
|
|
|
|
|
|
|
|
|
|
|
|
|
3072 |
|
3073 |
-
|
3074 |
-
|
3075 |
-
|
3076 |
-
|
|
|
3077 |
|
3078 |
-
|
3079 |
-
|
3080 |
-
|
3081 |
-
|
3082 |
-
'%s (%d found)',
|
3083 |
-
__($result_url_title),
|
3084 |
-
count($res['LINKS'][$result_url_key])
|
3085 |
-
) ?>
|
3086 |
-
</th>
|
3087 |
-
</tr>
|
3088 |
|
3089 |
-
|
3090 |
-
|
3091 |
-
|
3092 |
-
<span class="sucuriscan-monospace sucuriscan-wraptext"><?php _e($url_path) ?></span>
|
3093 |
-
</td>
|
3094 |
-
</tr>
|
3095 |
-
<?php endforeach; ?>
|
3096 |
-
<?php endif; ?>
|
3097 |
|
3098 |
-
|
3099 |
-
|
3100 |
-
</table>
|
3101 |
-
</div>
|
3102 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3103 |
|
3104 |
-
|
3105 |
-
|
3106 |
-
|
3107 |
-
<h3>
|
3108 |
-
<?php if( $blacklist_warns_exist ): ?>
|
3109 |
-
Site blacklisted
|
3110 |
-
<?php else: ?>
|
3111 |
-
Site blacklist-free
|
3112 |
-
<?php endif; ?>
|
3113 |
-
</h3>
|
3114 |
|
3115 |
-
|
3116 |
-
|
3117 |
-
|
3118 |
-
|
3119 |
-
|
3120 |
-
'WARN' => 'WARNING'
|
3121 |
-
) as $type => $group_title){
|
3122 |
-
if( isset($res['BLACKLIST'][$type]) ){
|
3123 |
-
foreach( $res['BLACKLIST'][$type] as $blres ){
|
3124 |
-
$report_site = htmlspecialchars($blres[0]);
|
3125 |
-
$report_url = htmlspecialchars($blres[1]);
|
3126 |
-
printf(
|
3127 |
-
'<li><b>%s:</b> %s.<br>Details at <a href="%s" target="_blank">%s</a></li>',
|
3128 |
-
$group_title, $report_site, $report_url, $report_url
|
3129 |
-
);
|
3130 |
-
}
|
3131 |
-
}
|
3132 |
-
}
|
3133 |
-
?>
|
3134 |
-
</ul>
|
3135 |
-
</div>
|
3136 |
-
</div>
|
3137 |
-
</div>
|
3138 |
-
</div>
|
3139 |
-
|
3140 |
-
|
3141 |
-
<div id="sucuriscan-modified-files">
|
3142 |
-
<?php echo sucuriscan_modified_files(); ?>
|
3143 |
-
</div>
|
3144 |
-
|
3145 |
-
|
3146 |
-
</div>
|
3147 |
-
</div>
|
3148 |
-
|
3149 |
-
<?php if( $malware_warns_exist || $blacklist_warns_exist ): ?>
|
3150 |
-
<a href="http://sucuri.net/signup/" target="_blank" class="button button-primary button-hero sucuriscan-cleanup-btn">
|
3151 |
-
Get your site protected with Sucuri
|
3152 |
-
</a>
|
3153 |
-
<?php endif; ?>
|
3154 |
-
|
3155 |
-
<?php endif; ?>
|
3156 |
|
|
|
|
|
|
|
|
|
3157 |
|
3158 |
-
|
3159 |
-
|
3160 |
-
|
3161 |
-
|
3162 |
-
|
3163 |
-
|
3164 |
-
'PageStyleClass' => 'scanner-results',
|
3165 |
-
));
|
3166 |
-
return;
|
3167 |
-
}
|
3168 |
|
3169 |
-
|
3170 |
-
|
3171 |
-
|
3172 |
-
|
3173 |
-
|
3174 |
-
|
3175 |
-
|
3176 |
-
|
3177 |
-
|
3178 |
-
* @param array $params Parameters for the request defined in an associative array of key-value.
|
3179 |
-
* @param array $args Request arguments like the timeout, redirections, headers, cookies, etc.
|
3180 |
-
* @return array Array of results including HTTP headers or WP_Error if the request failed.
|
3181 |
-
*/
|
3182 |
-
function sucuriscan_api_call( $url='', $method='GET', $params=array(), $args=array() ){
|
3183 |
-
if( !$url ){ return FALSE; }
|
3184 |
-
|
3185 |
-
$req_args = array(
|
3186 |
-
'method' => $method,
|
3187 |
-
'timeout' => 90,
|
3188 |
-
'redirection' => 2,
|
3189 |
-
'httpversion' => '1.0',
|
3190 |
-
'user-agent' => sucuriscan_user_agent(),
|
3191 |
-
'blocking' => TRUE,
|
3192 |
-
'headers' => array(),
|
3193 |
-
'cookies' => array(),
|
3194 |
-
'compress' => FALSE,
|
3195 |
-
'decompress' => FALSE,
|
3196 |
-
'sslverify' => sucuriscan_verify_ssl_cert(),
|
3197 |
-
);
|
3198 |
|
3199 |
-
|
3200 |
-
|
3201 |
-
|
3202 |
-
|
3203 |
-
|
3204 |
-
|
|
|
3205 |
|
3206 |
-
|
3207 |
-
|
3208 |
-
|
3209 |
-
}
|
3210 |
|
3211 |
-
|
3212 |
-
|
3213 |
-
|
3214 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
3215 |
|
3216 |
-
|
3217 |
-
|
3218 |
-
|
3219 |
-
|
3220 |
-
|
3221 |
-
|
3222 |
-
));
|
3223 |
-
} else {
|
3224 |
-
$response['body_raw'] = $response['body'];
|
3225 |
|
3226 |
-
if(
|
3227 |
-
|
3228 |
-
&& $response['headers']['content-type'] = 'application/json'
|
3229 |
-
){
|
3230 |
-
$response['body'] = json_decode($response['body_raw']);
|
3231 |
}
|
3232 |
-
|
3233 |
-
return $response;
|
3234 |
}
|
3235 |
-
} else {
|
3236 |
-
sucuriscan_error( 'HTTP method not allowed: ' . $method );
|
3237 |
-
}
|
3238 |
-
|
3239 |
-
return FALSE;
|
3240 |
-
}
|
3241 |
|
3242 |
-
|
3243 |
-
|
3244 |
-
|
3245 |
-
* @param string $api_key An unique string of characters to identify this installation.
|
3246 |
-
* @param boolean $validate Whether the format of the key should be validated before store it.
|
3247 |
-
* @return boolean Either TRUE or FALSE if the key was saved successfully or not respectively.
|
3248 |
-
*/
|
3249 |
-
function sucuriscan_set_api_key( $api_key='', $validate=FALSE ){
|
3250 |
-
if( $validate ){
|
3251 |
-
if( !preg_match('/^([a-z0-9]{32})$/', $api_key) ){
|
3252 |
-
sucuriscan_error( 'Invalid API key format' );
|
3253 |
-
return FALSE;
|
3254 |
}
|
3255 |
-
}
|
3256 |
|
3257 |
-
|
3258 |
-
sucuriscan_notify_event( 'plugin_change', 'API key updated successfully: ' . $api_key );
|
3259 |
}
|
3260 |
|
3261 |
-
|
3262 |
-
|
3263 |
-
|
3264 |
-
|
3265 |
-
|
3266 |
-
|
3267 |
-
|
3268 |
-
|
3269 |
-
|
3270 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3271 |
|
3272 |
-
|
3273 |
-
return $api_key;
|
3274 |
}
|
3275 |
|
3276 |
-
return FALSE;
|
3277 |
}
|
3278 |
|
3279 |
/**
|
3280 |
-
*
|
3281 |
*
|
3282 |
-
*
|
3283 |
-
*
|
3284 |
-
*
|
|
|
3285 |
*/
|
3286 |
-
|
3287 |
-
$pattern = '/^([a-z0-9]{32})\/([a-z0-9]{32})$/';
|
3288 |
-
|
3289 |
-
if( $api_key && preg_match($pattern, $api_key, $match) ){
|
3290 |
-
if( $return_match ){ return $match; }
|
3291 |
|
3292 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
3293 |
}
|
3294 |
|
3295 |
-
|
3296 |
-
|
3297 |
-
|
3298 |
-
|
3299 |
-
|
3300 |
-
|
3301 |
-
|
3302 |
-
|
3303 |
-
|
3304 |
-
|
3305 |
-
|
3306 |
-
|
3307 |
-
|
3308 |
-
|
3309 |
-
|
3310 |
-
|
3311 |
-
|
3312 |
-
|
3313 |
-
|
|
|
|
|
|
|
|
|
|
|
3314 |
|
3315 |
-
if
|
3316 |
-
|
3317 |
-
|
|
|
|
|
|
|
|
|
3318 |
}
|
3319 |
-
}
|
3320 |
|
3321 |
-
|
3322 |
-
|
|
|
|
|
|
|
|
|
|
|
3323 |
|
3324 |
-
|
3325 |
-
|
3326 |
-
'string' => $match[1].'/'.$match[2],
|
3327 |
-
'k' => $match[1],
|
3328 |
-
's' => $match[2]
|
3329 |
-
);
|
3330 |
-
}
|
3331 |
|
3332 |
-
|
3333 |
-
}
|
3334 |
|
3335 |
-
|
3336 |
-
|
3337 |
-
|
3338 |
-
|
3339 |
-
|
3340 |
-
|
3341 |
-
* @param array $args Request arguments like the timeout, redirections, headers, cookies, etc.
|
3342 |
-
* @return array Array of results including HTTP headers or WP_Error if the request failed.
|
3343 |
-
*/
|
3344 |
-
function sucuriscan_api_call_wordpress( $method='GET', $params=array(), $send_api_key=TRUE, $args=array() ){
|
3345 |
-
$url = SUCURISCAN_API;
|
3346 |
-
$params[SUCURISCAN_API_VERSION] = 1;
|
3347 |
-
$params['p'] = 'wordpress';
|
3348 |
|
3349 |
-
|
3350 |
-
|
|
|
|
|
3351 |
|
3352 |
-
|
|
|
|
|
3353 |
|
3354 |
-
|
3355 |
}
|
3356 |
|
3357 |
-
|
3358 |
-
|
3359 |
-
|
3360 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3361 |
|
3362 |
-
|
3363 |
-
|
3364 |
-
|
3365 |
-
|
3366 |
-
|
3367 |
-
|
3368 |
-
|
3369 |
-
function sucuriscan_api_call_cloudproxy( $method='GET', $params=array() ){
|
3370 |
-
$send_request = FALSE;
|
3371 |
|
3372 |
-
|
3373 |
-
|
3374 |
-
|
3375 |
-
|
|
|
|
|
|
|
|
|
|
|
3376 |
|
3377 |
-
|
3378 |
-
$
|
3379 |
-
$params['k'] = $api_key['k'];
|
3380 |
-
$params['s'] = $api_key['s'];
|
3381 |
}
|
3382 |
-
}
|
3383 |
|
3384 |
-
|
3385 |
-
|
3386 |
-
$params[SUCURISCAN_CLOUDPROXY_API_VERSION] = 1;
|
3387 |
|
3388 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
3389 |
|
3390 |
-
|
3391 |
-
|
|
|
|
|
|
|
3392 |
|
3393 |
-
|
3394 |
-
|
|
|
|
|
3395 |
|
3396 |
-
|
3397 |
-
* Determine whether an API response was successful or not checking the expected
|
3398 |
-
* generic variables and types, in case of an error a notification will appears
|
3399 |
-
* in the administrator panel explaining the result of the operation.
|
3400 |
-
*
|
3401 |
-
* @param array $response Array of results including HTTP headers or WP_Error if the request failed.
|
3402 |
-
* @return boolean Either TRUE or FALSE in case of success or failure of the API response (respectively).
|
3403 |
-
*/
|
3404 |
-
function sucuriscan_handle_response( $response=array() ){
|
3405 |
-
if( $response ){
|
3406 |
-
if( $response['body'] instanceof stdClass ){
|
3407 |
-
if( isset($response['body']->status) ){
|
3408 |
-
if( $response['body']->status == 1 ){
|
3409 |
return TRUE;
|
3410 |
-
} else {
|
3411 |
-
sucuriscan_error( ucwords($response['body']->action) . ': ' . $response['body']->messages[0] );
|
3412 |
}
|
3413 |
} else {
|
3414 |
-
|
|
|
3415 |
}
|
3416 |
-
} else {
|
3417 |
-
sucuriscan_error( 'Unknown API content-type, it was not a JSON-encoded response.' );
|
3418 |
}
|
|
|
|
|
3419 |
}
|
3420 |
|
3421 |
-
return FALSE;
|
3422 |
}
|
3423 |
|
3424 |
/**
|
3425 |
-
*
|
3426 |
*
|
3427 |
-
*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3428 |
*/
|
3429 |
-
|
3430 |
-
$response = sucuriscan_api_call_wordpress( 'POST', array(
|
3431 |
-
'e' => sucuriscan_get_site_email(),
|
3432 |
-
's' => sucuriscan_get_domain(),
|
3433 |
-
'a' => 'register_site',
|
3434 |
-
), FALSE );
|
3435 |
-
|
3436 |
-
if( sucuriscan_handle_response($response) ){
|
3437 |
-
sucuriscan_set_api_key( $response['body']->output->api_key );
|
3438 |
-
sucuriscan_create_scheduled_task();
|
3439 |
-
sucuriscan_notify_event( 'plugin_change', 'Site registered and API key generated' );
|
3440 |
-
sucuriscan_info( 'The API key for your site was successfully generated and saved.');
|
3441 |
|
3442 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3443 |
}
|
3444 |
|
3445 |
-
|
3446 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
3447 |
|
3448 |
-
|
3449 |
-
|
3450 |
-
*
|
3451 |
-
* @return boolean TRUE if the API key was sent to the administrator email, FALSE otherwise.
|
3452 |
-
*/
|
3453 |
-
function sucuriscan_recover_api_key(){
|
3454 |
-
$clean_domain = sucuriscan_get_domain();
|
3455 |
|
3456 |
-
|
3457 |
-
'
|
3458 |
-
'
|
3459 |
-
'
|
3460 |
-
|
|
|
3461 |
|
3462 |
-
|
3463 |
-
|
3464 |
-
sucuriscan_info( $response['body']->output->message );
|
3465 |
|
3466 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3467 |
}
|
3468 |
|
3469 |
-
|
3470 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3471 |
|
3472 |
-
|
3473 |
-
|
3474 |
-
* event can be anything from a simple request, an internal modification of the
|
3475 |
-
* settings or files in the administrator panel, or a notification generated by
|
3476 |
-
* this plugin.
|
3477 |
-
*
|
3478 |
-
* @param string $event The information gathered through out the normal functioning of the site.
|
3479 |
-
* @return boolean TRUE if the event was logged in the monitoring service, FALSE otherwise.
|
3480 |
-
*/
|
3481 |
-
function sucuriscan_send_log( $event='' ){
|
3482 |
-
if( !empty($event) ){
|
3483 |
-
$response = sucuriscan_api_call_wordpress( 'POST', array(
|
3484 |
-
'a' => 'send_log',
|
3485 |
-
'm' => $event,
|
3486 |
-
), TRUE, array( 'timeout' => 20 ) );
|
3487 |
-
|
3488 |
-
if( sucuriscan_handle_response($response) ){
|
3489 |
-
return TRUE;
|
3490 |
}
|
|
|
|
|
3491 |
}
|
3492 |
|
3493 |
-
|
3494 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3495 |
|
3496 |
-
|
3497 |
-
|
3498 |
-
*
|
3499 |
-
* @param integer $lines How many lines from the log file will be retrieved.
|
3500 |
-
* @return string The response of the API service.
|
3501 |
-
*/
|
3502 |
-
function sucuriscan_get_logs( $lines=50 ){
|
3503 |
-
$response = sucuriscan_api_call_wordpress( 'GET', array(
|
3504 |
-
'a' => 'get_logs',
|
3505 |
-
'l' => $lines,
|
3506 |
-
) );
|
3507 |
-
|
3508 |
-
if( sucuriscan_handle_response($response) ){
|
3509 |
-
$response['body']->output_data = array();
|
3510 |
-
$log_pattern = '/^([0-9-: ]+) (.*) : (.*)/';
|
3511 |
-
$extra_pattern = '/(.+ \(multiple entries\):) (.+)/';
|
3512 |
-
|
3513 |
-
foreach( $response['body']->output as $log ){
|
3514 |
-
if( preg_match($log_pattern, $log, $log_match) ){
|
3515 |
-
$log_data = array(
|
3516 |
-
'datetime' => $log_match[1],
|
3517 |
-
'timestamp' => strtotime($log_match[1]),
|
3518 |
-
'account' => $log_match[2],
|
3519 |
-
'message' => $log_match[3],
|
3520 |
-
'extra' => FALSE,
|
3521 |
-
'extra_total' => 0,
|
3522 |
-
);
|
3523 |
|
3524 |
-
|
|
|
3525 |
|
3526 |
-
|
3527 |
-
|
3528 |
-
|
3529 |
-
$log_data['extra_total'] = count($log_data['extra']);
|
3530 |
-
}
|
3531 |
|
3532 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3533 |
}
|
3534 |
-
}
|
3535 |
|
3536 |
-
|
3537 |
-
}
|
3538 |
|
3539 |
-
|
3540 |
-
}
|
3541 |
|
3542 |
-
|
3543 |
-
|
3544 |
-
|
3545 |
-
* information of the audit logs alerting the administrator of suspicious
|
3546 |
-
* changes in the system.
|
3547 |
-
*
|
3548 |
-
* @param string $hashes The information gathered after the scanning of the site's files.
|
3549 |
-
* @return boolean TRUE if the hashes were stored, FALSE otherwise.
|
3550 |
-
*/
|
3551 |
-
function sucuriscan_send_hashes( $hashes='' ){
|
3552 |
-
if( !empty($hashes) ){
|
3553 |
-
$response = sucuriscan_api_call_wordpress( 'POST', array(
|
3554 |
-
'a' => 'send_hashes',
|
3555 |
-
'h' => $hashes,
|
3556 |
-
) );
|
3557 |
|
3558 |
-
|
3559 |
-
|
|
|
|
|
|
|
|
|
3560 |
}
|
|
|
|
|
3561 |
}
|
3562 |
|
3563 |
-
|
3564 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3565 |
|
3566 |
-
|
3567 |
-
|
3568 |
-
*
|
3569 |
-
* @param integer $runtime When the filesystem scan must be scheduled to run.
|
3570 |
-
* @param boolean $force_scan Whether the filesystem scan was forced by an administrator user or not.
|
3571 |
-
* @return boolean Either TRUE or FALSE representing the success or fail of the operation respectively.
|
3572 |
-
*/
|
3573 |
-
function sucuriscan_verify_run( $runtime=0, $force_scan=FALSE ){
|
3574 |
-
$runtime_name = 'sucuriscan_runtime';
|
3575 |
-
$last_run = sucuriscan_get_option($runtime_name);
|
3576 |
-
$current_time = time();
|
3577 |
|
3578 |
-
|
3579 |
-
|
3580 |
|
3581 |
-
|
3582 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3583 |
}
|
3584 |
-
}
|
3585 |
|
3586 |
-
|
3587 |
-
|
3588 |
-
|
3589 |
|
3590 |
-
|
3591 |
-
|
3592 |
-
* service or not, this is to avoid duplicated information in the audit logs.
|
3593 |
-
*
|
3594 |
-
* @return boolean TRUE if the current WordPress version must be reported, FALSE otherwise.
|
3595 |
-
*/
|
3596 |
-
function sucuriscan_report_wpversion(){
|
3597 |
-
$option_name = 'sucuriscan_wp_version';
|
3598 |
-
$reported_version = sucuriscan_get_option($option_name);
|
3599 |
-
$wp_version = sucuriscan_get_wpversion();
|
3600 |
|
3601 |
-
|
3602 |
-
sucuriscan_send_log( 'WordPress version: ' . $wp_version );
|
3603 |
-
update_option( $option_name, $wp_version );
|
3604 |
|
3605 |
-
|
3606 |
-
|
|
|
|
|
|
|
|
|
3607 |
|
3608 |
-
|
3609 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
3610 |
|
3611 |
-
|
3612 |
-
|
3613 |
-
*
|
3614 |
-
* @return void
|
3615 |
-
*/
|
3616 |
-
function sucuriscan_create_scheduled_task(){
|
3617 |
-
$task_name = 'sucuriscan_scheduled_scan';
|
3618 |
|
3619 |
-
|
3620 |
-
|
3621 |
-
|
3622 |
|
3623 |
-
|
3624 |
-
|
3625 |
-
}
|
3626 |
|
3627 |
-
/**
|
3628 |
-
|
3629 |
-
|
3630 |
-
|
3631 |
-
|
3632 |
-
|
3633 |
-
|
3634 |
-
|
3635 |
-
|
3636 |
-
$
|
|
|
3637 |
|
3638 |
-
|
3639 |
-
|
3640 |
-
&& class_exists('SucuriScanFileInfo')
|
3641 |
-
&& sucuriscan_verify_run( $minimum_runtime, $force_scan )
|
3642 |
-
){
|
3643 |
-
sucuriscan_report_wpversion();
|
3644 |
|
3645 |
-
|
3646 |
-
|
3647 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3648 |
|
3649 |
-
if( $
|
3650 |
-
$
|
|
|
3651 |
|
3652 |
-
|
3653 |
-
|
3654 |
-
|
3655 |
-
} else {
|
3656 |
-
sucuriscan_error( 'The file hashes could not be stored.' );
|
3657 |
}
|
3658 |
-
} else {
|
3659 |
-
sucuriscan_error( 'The file hashes could not be retrieved, the filesystem scan failed.' );
|
3660 |
}
|
3661 |
-
}
|
3662 |
|
3663 |
-
|
3664 |
-
}
|
3665 |
|
3666 |
-
|
3667 |
-
* Generates an audit event log (to be sent later).
|
3668 |
-
*
|
3669 |
-
* @param integer $severity Importance of the event that will be reported, values from one to five.
|
3670 |
-
* @param string $location In which part of the system was the event triggered.
|
3671 |
-
* @param string $message The explanation of the event.
|
3672 |
-
* @return boolean TRUE if the event was logged in the monitoring service, FALSE otherwise.
|
3673 |
-
*/
|
3674 |
-
function sucuriscan_report_event( $severity=0, $location='', $message='' ){
|
3675 |
-
$user = wp_get_current_user();
|
3676 |
-
$username = FALSE;
|
3677 |
-
$current_time = date( 'Y-m-d H:i:s' );
|
3678 |
-
$remote_ip = sucuriscan_get_remoteaddr();
|
3679 |
-
|
3680 |
-
// Fixing severity value.
|
3681 |
-
$severity = (int) $severity;
|
3682 |
-
if( $severity > 0 ){ $severity = 1; }
|
3683 |
-
elseif( $severity > 5 ){ $severity = 5; }
|
3684 |
-
|
3685 |
-
// Identify current user in session.
|
3686 |
-
if(
|
3687 |
-
$user instanceof WP_User
|
3688 |
-
&& isset($user->user_login)
|
3689 |
-
&& !empty($user->user_login)
|
3690 |
-
){
|
3691 |
-
if( $user->user_login != $user->display_name ){
|
3692 |
-
$username = sprintf( ' %s (%s),', $user->display_name, $user->user_login );
|
3693 |
-
} else {
|
3694 |
-
$username = sprintf( ' %s,', $user->user_login );
|
3695 |
-
}
|
3696 |
}
|
3697 |
|
3698 |
-
|
3699 |
-
|
3700 |
-
|
3701 |
-
|
3702 |
-
|
3703 |
-
|
3704 |
-
|
3705 |
-
|
3706 |
-
|
|
|
|
|
3707 |
}
|
3708 |
|
3709 |
-
|
3710 |
-
|
3711 |
-
|
3712 |
-
|
3713 |
-
|
3714 |
-
|
3715 |
-
|
3716 |
-
)
|
|
|
3717 |
|
3718 |
-
|
3719 |
-
|
3720 |
|
3721 |
-
|
3722 |
-
|
3723 |
-
|
3724 |
-
*
|
3725 |
-
* @param string $event The name of the event that was triggered.
|
3726 |
-
* @param string $content Body of the email that will be sent to the administrator.
|
3727 |
-
* @return void
|
3728 |
-
*/
|
3729 |
-
function sucuriscan_notify_event( $event='', $content='' ){
|
3730 |
-
$event_name = 'sucuriscan_notify_' . $event;
|
3731 |
-
$notify = sucuriscan_get_option($event_name);
|
3732 |
-
$email = sucuriscan_get_option('sucuriscan_notify_to');
|
3733 |
-
$email_params = array();
|
3734 |
|
3735 |
-
|
3736 |
-
|
3737 |
-
|
|
|
3738 |
}
|
3739 |
|
3740 |
-
|
3741 |
-
|
3742 |
-
are getting too many of these messages, it is likely your site is under a brute
|
3743 |
-
force attack. You can disable the notifications for failed logins from
|
3744 |
-
<a href="' . sucuriscan_get_url('settings') . '" target="_blank">here</a>.
|
3745 |
-
More details at <a href="http://kb.sucuri.net/definitions/attacks/brute-force/password-guessing"
|
3746 |
-
target="_blank">Password Guessing Brute Force Attacks</a>.</em>';
|
3747 |
-
}
|
3748 |
|
3749 |
-
|
3750 |
-
|
3751 |
-
|
3752 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3753 |
|
3754 |
-
|
3755 |
-
|
|
|
|
|
|
|
3756 |
|
3757 |
-
return $
|
3758 |
}
|
3759 |
|
3760 |
-
return FALSE;
|
3761 |
}
|
3762 |
|
3763 |
/**
|
3764 |
-
*
|
3765 |
-
* registered by the administrator of the site. This function will send a HTTP
|
3766 |
-
* request to the remote API service and process its response, when successful
|
3767 |
-
* it will return an array/object containing the public attributes of the site.
|
3768 |
*
|
3769 |
-
*
|
3770 |
-
*
|
|
|
|
|
|
|
3771 |
*/
|
3772 |
-
|
3773 |
-
$params = array( 'a' => 'show_settings' );
|
3774 |
|
3775 |
-
|
3776 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3777 |
}
|
3778 |
|
3779 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3780 |
|
3781 |
-
|
3782 |
-
|
3783 |
}
|
3784 |
|
3785 |
-
|
3786 |
-
|
|
|
|
|
|
|
|
|
|
|
3787 |
|
3788 |
-
|
3789 |
-
|
3790 |
-
|
3791 |
-
|
3792 |
-
|
3793 |
-
|
3794 |
-
|
3795 |
-
|
|
|
|
|
|
|
|
|
|
|
3796 |
|
3797 |
-
|
3798 |
-
$params = array_merge( $params, $api_key );
|
3799 |
-
}
|
3800 |
|
3801 |
-
|
|
|
3802 |
|
3803 |
-
|
3804 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3805 |
}
|
3806 |
|
3807 |
-
|
3808 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3809 |
|
3810 |
-
|
3811 |
-
|
3812 |
-
|
3813 |
-
|
3814 |
-
* it will return an array/object containing a list of requests blocked by our
|
3815 |
-
* CloudProxy.
|
3816 |
-
*
|
3817 |
-
* By default the logs that will be retrieved are from today, if you need to see
|
3818 |
-
* the logs of previous days you will need to add a new parameter to the request
|
3819 |
-
* URL named "date" with format yyyy-mm-dd.
|
3820 |
-
*
|
3821 |
-
* @param boolean $api_key The CloudProxy API key.
|
3822 |
-
* @param string $date An optional date to filter the result to a specific timespan: yyyy-mm-dd.
|
3823 |
-
* @return array A list of objects with the detailed version of each request blocked by our service.
|
3824 |
-
*/
|
3825 |
-
function sucuriscan_cloudproxy_logs( $api_key=FALSE, $date='' ){
|
3826 |
-
$params = array(
|
3827 |
-
'a' => 'audit_trails',
|
3828 |
-
'date' => date('Y-m-d'),
|
3829 |
-
);
|
3830 |
|
3831 |
-
|
3832 |
-
|
3833 |
-
}
|
3834 |
|
3835 |
-
|
3836 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3837 |
}
|
3838 |
|
3839 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3840 |
|
3841 |
-
|
3842 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3843 |
}
|
3844 |
|
3845 |
-
|
3846 |
-
|
|
|
|
|
|
|
|
|
|
|
3847 |
|
3848 |
-
|
3849 |
-
|
3850 |
-
|
3851 |
-
|
3852 |
-
|
3853 |
-
|
3854 |
-
|
3855 |
-
|
3856 |
-
'xmlrpc_publish_post',
|
3857 |
-
'add_link',
|
3858 |
-
'switch_theme',
|
3859 |
-
'delete_user',
|
3860 |
-
'retrieve_password',
|
3861 |
-
'user_register',
|
3862 |
-
'wp_login',
|
3863 |
-
'wp_login_failed',
|
3864 |
-
'login_form_resetpass',
|
3865 |
-
);
|
3866 |
|
3867 |
-
/**
|
3868 |
-
|
3869 |
-
|
3870 |
-
|
3871 |
-
|
3872 |
-
|
3873 |
-
|
3874 |
-
|
3875 |
-
|
|
|
|
|
3876 |
|
3877 |
-
|
3878 |
-
|
3879 |
-
sucuriscan_notify_event( 'post_publication', $message );
|
3880 |
-
}
|
3881 |
|
3882 |
-
|
3883 |
-
|
3884 |
-
|
3885 |
-
* @param integer $id The identifier of the category created.
|
3886 |
-
* @return void
|
3887 |
-
*/
|
3888 |
-
function sucuriscan_hook_create_category( $id=0 ){
|
3889 |
-
$title = ( is_int($id) ? get_cat_name($id) : 'Unknown' );
|
3890 |
|
3891 |
-
|
3892 |
-
|
3893 |
-
sucuriscan_notify_event( 'post_publication', $message );
|
3894 |
-
}
|
3895 |
|
3896 |
-
/**
|
3897 |
-
|
3898 |
-
|
3899 |
-
|
3900 |
-
|
3901 |
-
|
3902 |
-
|
3903 |
-
|
3904 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3905 |
|
3906 |
-
/**
|
3907 |
-
|
3908 |
-
|
3909 |
-
|
3910 |
-
|
3911 |
-
|
3912 |
-
|
3913 |
-
|
3914 |
-
|
3915 |
|
3916 |
-
|
3917 |
-
|
3918 |
-
|
3919 |
-
|
3920 |
-
|
3921 |
-
|
|
|
|
|
3922 |
}
|
3923 |
|
3924 |
-
|
3925 |
-
|
3926 |
-
|
3927 |
-
|
3928 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3929 |
}
|
|
|
3930 |
}
|
3931 |
|
3932 |
/**
|
3933 |
-
*
|
|
|
|
|
3934 |
*
|
3935 |
-
* @param integer $id The identifier of the post or page published.
|
3936 |
* @return void
|
3937 |
*/
|
3938 |
-
function
|
3939 |
-
|
3940 |
|
3941 |
-
if
|
3942 |
-
|
3943 |
-
|
3944 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3945 |
} else {
|
3946 |
-
|
3947 |
-
|
3948 |
-
|
|
|
3949 |
}
|
3950 |
-
|
3951 |
-
$message = $p_type.' was '.$action.' #'.$id.' ('.$title.')';
|
3952 |
-
sucuriscan_report_event( 2, 'core', $message );
|
3953 |
-
sucuriscan_notify_event( 'post_publication', $message );
|
3954 |
}
|
3955 |
|
3956 |
/**
|
3957 |
-
*
|
3958 |
*
|
3959 |
-
* @param
|
3960 |
* @return void
|
3961 |
*/
|
3962 |
-
function
|
|
|
|
|
|
|
3963 |
|
3964 |
-
|
3965 |
-
|
3966 |
-
|
3967 |
-
* @param integer $id The identifier of the post or page published.
|
3968 |
-
* @return void
|
3969 |
-
*/
|
3970 |
-
function sucuriscan_hook_publish_post( $id=0 ){ sucuriscan_hook_publish($id); }
|
3971 |
|
3972 |
-
|
3973 |
-
|
3974 |
-
|
3975 |
-
|
3976 |
-
* @return void
|
3977 |
-
*/
|
3978 |
-
function sucuriscan_hook_publish_phone( $id=0 ){ sucuriscan_hook_publish($id); }
|
3979 |
|
3980 |
-
|
3981 |
-
|
3982 |
-
|
3983 |
-
* @param integer $id The identifier of the post or page published.
|
3984 |
-
* @return void
|
3985 |
-
*/
|
3986 |
-
function sucuriscan_hook_xmlrpc_publish_post( $id=0 ){ sucuriscan_hook_publish($id); }
|
3987 |
-
|
3988 |
-
/**
|
3989 |
-
* Send to Sucuri servers an alert advising that a new link was added to the bookmarks.
|
3990 |
-
*
|
3991 |
-
* @param integer $id Identifier of the new link created;
|
3992 |
-
* @return void
|
3993 |
-
*/
|
3994 |
-
function sucuriscan_hook_add_link( $id=0 ){
|
3995 |
-
$data = ( is_int($id) ? get_bookmark($id) : FALSE );
|
3996 |
|
3997 |
-
|
3998 |
-
|
3999 |
-
|
4000 |
-
|
4001 |
-
|
4002 |
-
$url = 'undefined/url';
|
4003 |
}
|
4004 |
|
4005 |
-
|
4006 |
-
|
4007 |
-
sucuriscan_notify_event( 'post_publication', $message );
|
4008 |
-
}
|
4009 |
-
|
4010 |
-
/**
|
4011 |
-
* Send to Sucuri servers an alert advising that the theme of the site was changed.
|
4012 |
-
*
|
4013 |
-
* @param string $title The name of the new theme selected to used through out the site.
|
4014 |
-
* @return void
|
4015 |
-
*/
|
4016 |
-
function sucuriscan_hook_switch_theme( $title='' ){
|
4017 |
-
if( empty($title) ){ $title = 'Unknown'; }
|
4018 |
|
4019 |
-
$message = 'Theme switched to: '.$title;
|
4020 |
-
sucuriscan_report_event( 3, 'core', $message );
|
4021 |
-
sucuriscan_notify_event( 'theme_switched', $message );
|
4022 |
-
}
|
4023 |
|
4024 |
-
|
4025 |
-
* Send to Sucuri servers an alert advising that a user account was deleted.
|
4026 |
-
*
|
4027 |
-
* @param integer $id The identifier of the user account deleted.
|
4028 |
-
* @return void
|
4029 |
-
*/
|
4030 |
-
function sucuriscan_hook_delete_user( $id=0 ){
|
4031 |
-
sucuriscan_report_event( 3, 'core', 'User account deleted #'.$id );
|
4032 |
-
}
|
4033 |
|
4034 |
-
|
4035 |
-
|
4036 |
-
|
4037 |
-
|
4038 |
-
|
4039 |
-
|
4040 |
-
*/
|
4041 |
-
function sucuriscan_hook_retrieve_password( $title='' ){
|
4042 |
-
if( empty($title) ){ $title = 'Unknown'; }
|
4043 |
|
4044 |
-
|
4045 |
-
|
|
|
|
|
4046 |
|
4047 |
-
|
4048 |
-
|
4049 |
-
|
4050 |
-
* @param integer $id The identifier of the new user account created.
|
4051 |
-
* @return void
|
4052 |
-
*/
|
4053 |
-
function sucuriscan_hook_user_register( $id=0 ){
|
4054 |
-
$data = ( is_int($id) ? get_userdata($id) : FALSE );
|
4055 |
-
$title = ( $data ? $data->display_name : 'Unknown' );
|
4056 |
|
4057 |
-
|
4058 |
-
|
4059 |
-
|
4060 |
-
|
|
|
|
|
|
|
4061 |
|
4062 |
-
|
4063 |
-
|
4064 |
-
|
4065 |
-
|
4066 |
-
|
4067 |
-
* @return void
|
4068 |
-
*/
|
4069 |
-
function sucuriscan_hook_wp_login( $title='' ){
|
4070 |
-
if( empty($title) ){ $title = 'Unknown'; }
|
4071 |
|
4072 |
-
|
4073 |
-
|
4074 |
-
|
4075 |
-
|
|
|
4076 |
|
4077 |
-
|
4078 |
-
|
4079 |
-
|
4080 |
-
|
4081 |
-
* @param string $title The name of the user account involved in the transaction.
|
4082 |
-
* @return void
|
4083 |
-
*/
|
4084 |
-
function sucuriscan_hook_wp_login_failed( $title='' ){
|
4085 |
-
if( empty($title) ){ $title = 'Unknown'; }
|
4086 |
|
4087 |
-
|
4088 |
-
|
4089 |
-
|
4090 |
|
4091 |
-
|
4092 |
-
|
|
|
4093 |
|
4094 |
-
|
4095 |
-
|
4096 |
-
|
|
|
|
|
|
|
|
|
|
|
4097 |
|
4098 |
-
if( $failed_logins ){
|
4099 |
-
$max_time = 3600;
|
4100 |
-
$maximum_failed_logins = sucuriscan_get_option('sucuriscan_maximum_failed_logins');
|
4101 |
|
4102 |
-
|
4103 |
-
* If the time passed is within the hour, and the quantity of failed logins
|
4104 |
-
* registered in the datastore file is bigger than the maximum quantity of
|
4105 |
-
* failed logins allowed per hour (value configured by the administrator in the
|
4106 |
-
* settings page), then send an email notification reporting the event and
|
4107 |
-
* specifying that it may be a brute-force attack against the login page.
|
4108 |
-
*/
|
4109 |
-
if(
|
4110 |
-
$failed_logins['diff_time'] <= $max_time
|
4111 |
-
&& $failed_logins['count'] >= $maximum_failed_logins
|
4112 |
-
){
|
4113 |
-
sucuriscan_report_failed_logins($failed_logins);
|
4114 |
-
}
|
4115 |
|
4116 |
-
/**
|
4117 |
-
* If there time passed is superior to the hour, then reset the content of the
|
4118 |
-
* datastore file containing the failed logins so far, any entry in that file
|
4119 |
-
* will not be considered as part of a brute-force attack (if it exists) because
|
4120 |
-
* the time passed between the first and last login attempt is big enough to
|
4121 |
-
* mitigate the attack. We will consider the current failed login event as the
|
4122 |
-
* first entry of that file in case of future attempts during the next sixty
|
4123 |
-
* minutes.
|
4124 |
-
*/
|
4125 |
-
elseif( $failed_logins['diff_time'] > $max_time ){
|
4126 |
-
sucuriscan_reset_failed_logins();
|
4127 |
-
sucuriscan_log_failed_login($title);
|
4128 |
-
}
|
4129 |
-
}
|
4130 |
-
}
|
4131 |
-
}
|
4132 |
|
4133 |
-
|
4134 |
-
|
4135 |
-
|
4136 |
-
|
4137 |
-
|
4138 |
-
|
4139 |
-
|
4140 |
-
|
4141 |
-
|
4142 |
-
|
4143 |
-
|
4144 |
-
|
|
|
|
|
|
|
|
|
|
|
4145 |
|
4146 |
-
// Configure the hooks defined above to be triggered automatically.
|
4147 |
-
if( isset($sucuriscan_hooks) ){
|
4148 |
-
foreach( $sucuriscan_hooks as $hook_name ){
|
4149 |
-
$hook_func = 'sucuriscan_hook_' . $hook_name;
|
4150 |
|
4151 |
-
|
4152 |
-
add_action( $hook_name, $hook_func, 50 );
|
4153 |
-
}
|
4154 |
-
}
|
4155 |
-
}
|
4156 |
|
4157 |
-
if( !function_exists('sucuriscan_hook_undefined_actions') ){
|
4158 |
|
4159 |
-
|
4160 |
-
|
4161 |
-
|
4162 |
-
|
4163 |
-
|
4164 |
-
|
4165 |
-
|
4166 |
-
|
|
|
|
|
4167 |
|
4168 |
-
|
4169 |
-
if(
|
4170 |
-
current_user_can('activate_plugins')
|
4171 |
-
&& (
|
4172 |
-
( isset($_GET['action']) && preg_match('/^(activate|deactivate)$/', $_GET['action']) ) ||
|
4173 |
-
( isset($_POST['action']) && preg_match('/^(activate|deactivate)-selected$/', $_POST['action']))
|
4174 |
-
)
|
4175 |
-
){
|
4176 |
-
$plugin_list = array();
|
4177 |
|
4178 |
-
|
4179 |
-
|
4180 |
-
|
4181 |
-
|
4182 |
-
|
4183 |
-
|
4184 |
-
|
4185 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4186 |
|
4187 |
-
|
4188 |
-
|
4189 |
-
|
4190 |
-
|
|
|
|
|
4191 |
|
4192 |
-
|
4193 |
-
|
4194 |
-
|
4195 |
-
|
4196 |
-
|
4197 |
-
|
4198 |
-
$plugin_info['Version'],
|
4199 |
-
esc_attr($plugin)
|
4200 |
-
);
|
4201 |
|
4202 |
-
|
4203 |
-
|
4204 |
-
|
4205 |
-
|
|
|
|
|
4206 |
|
4207 |
-
|
4208 |
-
elseif(
|
4209 |
-
current_user_can('update_plugins')
|
4210 |
-
&& (
|
4211 |
-
( isset($_GET['action']) && preg_match('/(upgrade-plugin|do-plugin-upgrade)/', $_GET['action']) ) ||
|
4212 |
-
( isset($_POST['action']) && $_POST['action'] == 'update-selected' )
|
4213 |
-
)
|
4214 |
-
){
|
4215 |
-
$plugin_list = array();
|
4216 |
|
4217 |
-
|
4218 |
-
|
4219 |
-
|
4220 |
-
|
4221 |
-
|
4222 |
-
|
4223 |
-
|
|
|
4224 |
|
4225 |
-
|
4226 |
-
|
4227 |
-
|
|
|
4228 |
|
4229 |
-
foreach( $plugin_list as $plugin ){
|
4230 |
-
$plugin_info = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin );
|
4231 |
-
$message = sprintf(
|
4232 |
-
'Plugin request to be updated: %s (v%s; %s)',
|
4233 |
-
$plugin_info['Name'],
|
4234 |
-
$plugin_info['Version'],
|
4235 |
-
esc_attr($plugin)
|
4236 |
-
);
|
4237 |
|
4238 |
-
|
4239 |
-
|
4240 |
-
|
4241 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4242 |
|
4243 |
-
|
4244 |
-
|
4245 |
-
|
4246 |
-
|
4247 |
-
|
4248 |
-
|
4249 |
-
|
4250 |
-
|
4251 |
-
|
4252 |
-
|
4253 |
-
|
4254 |
-
|
4255 |
-
|
4256 |
-
|
|
|
|
|
4257 |
|
4258 |
-
|
4259 |
-
|
4260 |
-
|
4261 |
-
|
|
|
|
|
|
|
|
|
|
|
4262 |
|
4263 |
-
|
4264 |
-
|
4265 |
-
|
4266 |
-
|
4267 |
-
|
4268 |
-
|
4269 |
-
|
4270 |
-
|
4271 |
-
$plugin_list = (array) $_POST['checked'];
|
4272 |
|
4273 |
-
|
4274 |
-
|
4275 |
-
|
4276 |
-
|
4277 |
-
|
4278 |
-
|
4279 |
-
|
4280 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4281 |
|
4282 |
-
|
4283 |
-
|
4284 |
-
|
4285 |
-
|
|
|
|
|
|
|
|
|
4286 |
|
4287 |
-
|
4288 |
-
|
4289 |
-
|
4290 |
-
|
4291 |
-
|
4292 |
-
|
4293 |
-
&& isset($_POST['plugin'])
|
4294 |
-
&& strpos($_SERVER['REQUEST_URI'], 'plugin-editor.php') !== FALSE
|
4295 |
-
){
|
4296 |
-
$message = 'Plugin editor modification: ' . esc_attr($_POST['file']);
|
4297 |
-
sucuriscan_report_event( 3, 'core', $message );
|
4298 |
-
sucuriscan_notify_event( 'theme_editor', $message );
|
4299 |
-
}
|
4300 |
|
4301 |
-
|
4302 |
-
|
4303 |
-
|
4304 |
-
|
4305 |
-
|
4306 |
-
|
4307 |
-
|
4308 |
-
|
4309 |
-
|
4310 |
-
|
4311 |
-
|
4312 |
-
|
4313 |
-
|
|
|
4314 |
|
4315 |
-
|
4316 |
-
|
4317 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4318 |
|
4319 |
-
// Theme update request.
|
4320 |
-
elseif(
|
4321 |
-
current_user_can('update_themes')
|
4322 |
-
&& isset($_GET['action'])
|
4323 |
-
&& preg_match('/^(upgrade-theme|do-theme-upgrade)$/', $_GET['action'])
|
4324 |
-
&& isset($_POST['checked'])
|
4325 |
-
){
|
4326 |
-
$theme_list = (array) $_POST['checked'];
|
4327 |
|
4328 |
-
|
4329 |
-
|
4330 |
-
|
4331 |
-
|
4332 |
|
4333 |
-
|
4334 |
-
|
4335 |
-
|
4336 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
4337 |
|
4338 |
-
|
4339 |
-
|
4340 |
-
|
4341 |
-
|
4342 |
-
|
4343 |
-
|
|
|
|
|
4344 |
|
4345 |
-
|
4346 |
-
|
4347 |
-
|
4348 |
-
|
4349 |
|
4350 |
-
// WordPress update request.
|
4351 |
-
elseif(
|
4352 |
-
current_user_can('update_core')
|
4353 |
-
&& isset($_GET['action'])
|
4354 |
-
&& $_GET['action'] == 'do-core-reinstall'
|
4355 |
-
&& isset($_POST['upgrade'])
|
4356 |
-
&& isset($_POST['version'])
|
4357 |
-
){
|
4358 |
-
$message = 'WordPress updated (or re-installed) to version: ' . esc_attr($_POST['version']);
|
4359 |
-
sucuriscan_report_event( 3, 'core', $message );
|
4360 |
-
sucuriscan_notify_event( 'website_updated', $message );
|
4361 |
-
}
|
4362 |
|
4363 |
-
|
4364 |
-
|
4365 |
-
|
4366 |
-
|
4367 |
-
|
4368 |
-
|
4369 |
-
|
4370 |
-
|
4371 |
-
|
4372 |
-
|
4373 |
-
&& $_POST['delete_widget'] == 1
|
4374 |
-
){
|
4375 |
-
$action_d = 'deleted';
|
4376 |
-
$action_text = 'deleted from';
|
4377 |
-
} else {
|
4378 |
-
$action_d = 'added';
|
4379 |
-
$action_text = 'added to';
|
4380 |
-
}
|
4381 |
|
4382 |
-
|
4383 |
-
|
4384 |
-
|
4385 |
-
|
4386 |
-
|
4387 |
-
|
4388 |
-
|
4389 |
-
|
4390 |
-
|
4391 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4392 |
|
4393 |
-
sucuriscan_report_event( 3, 'core', $message );
|
4394 |
-
sucuriscan_notify_event( 'widget_' . $action_d, $message );
|
4395 |
-
}
|
4396 |
|
4397 |
-
|
4398 |
-
|
4399 |
-
|
4400 |
-
&& current_user_can('manage_options')
|
4401 |
-
&& SucuriScan::sucuriscan_check_options_wpnonce()
|
4402 |
-
){
|
4403 |
-
// Get the settings available in the database and compare them with the submission.
|
4404 |
-
$all_options = sucuriscan_get_wp_options();
|
4405 |
-
$options_changed = sucuriscan_what_options_were_changed($_POST);
|
4406 |
-
$options_changed_str = '';
|
4407 |
-
$options_changed_count = 0;
|
4408 |
|
4409 |
-
// Generate the list of options changed.
|
4410 |
-
foreach( $options_changed['original'] as $option_name => $option_value ){
|
4411 |
-
$options_changed_count += 1;
|
4412 |
-
$options_changed_str .= sprintf(
|
4413 |
-
"The value of the option <b>%s</b> was changed from <b>'%s'</b> to <b>'%s'</b>.<br>\n",
|
4414 |
-
$option_name, $option_value, $options_changed['changed'][$option_name]
|
4415 |
-
);
|
4416 |
-
}
|
4417 |
|
4418 |
-
|
4419 |
-
|
4420 |
-
$page_referer = FALSE;
|
4421 |
|
4422 |
-
|
4423 |
-
|
4424 |
-
|
4425 |
-
|
4426 |
-
|
4427 |
-
case 'general': /* no_break */
|
4428 |
-
case 'writing': /* no_break */
|
4429 |
-
case 'reading': /* no_break */
|
4430 |
-
case 'discussion': /* no_break */
|
4431 |
-
case 'media': /* no_break */
|
4432 |
-
case 'permalink':
|
4433 |
-
$page_referer = ucwords($option_page);
|
4434 |
-
break;
|
4435 |
-
default:
|
4436 |
-
$page_referer = 'Common';
|
4437 |
-
break;
|
4438 |
-
}
|
4439 |
|
4440 |
-
|
4441 |
-
$message = $page_referer.' settings changed';
|
4442 |
-
sucuriscan_report_event( 3, 'core', $message );
|
4443 |
-
sucuriscan_notify_event( 'settings_updated', $message . "<br>\n" . $options_changed_str );
|
4444 |
-
}
|
4445 |
-
}
|
4446 |
|
4447 |
-
}
|
4448 |
|
4449 |
-
|
4450 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4451 |
}
|
4452 |
|
4453 |
/**
|
@@ -4460,15 +4960,13 @@ if( !function_exists('sucuriscan_hook_undefined_actions') ){
|
|
4460 |
* @return void
|
4461 |
*/
|
4462 |
function sucuriscan_monitoring_page(){
|
4463 |
-
|
4464 |
-
wp_die(__('You do not have sufficient permissions to access this page: Firewall (WAF)') );
|
4465 |
-
}
|
4466 |
|
4467 |
// Process all form submissions.
|
4468 |
sucuriscan_monitoring_form_submissions();
|
4469 |
|
4470 |
// Get the dynamic values for the template variables.
|
4471 |
-
$api_key =
|
4472 |
|
4473 |
// Page pseudo-variables initialization.
|
4474 |
$template_variables = array(
|
@@ -4490,49 +4988,48 @@ function sucuriscan_monitoring_page(){
|
|
4490 |
$template_variables['Monitoring.InstructionsVisibility'] = 'hidden';
|
4491 |
}
|
4492 |
|
4493 |
-
echo
|
4494 |
}
|
4495 |
|
4496 |
/**
|
4497 |
* Process the requests sent by the form submissions originated in the monitoring
|
4498 |
-
* page, all forms must have a nonce field that will be checked
|
4499 |
* generated in the template render function.
|
4500 |
*
|
4501 |
* @return void
|
4502 |
*/
|
4503 |
function sucuriscan_monitoring_form_submissions(){
|
4504 |
|
4505 |
-
if(
|
4506 |
|
4507 |
// Add and/or Update the Sucuri WAF API Key (do it before anything else).
|
4508 |
-
$option_name = '
|
4509 |
-
|
4510 |
-
if( isset($_POST[$option_name]) ){
|
4511 |
-
$api_key = $_POST[$option_name];
|
4512 |
|
4513 |
-
|
4514 |
-
|
4515 |
-
|
|
|
4516 |
} elseif( empty($api_key) ){
|
4517 |
-
delete_option($option_name);
|
4518 |
-
|
4519 |
} else {
|
4520 |
-
|
4521 |
}
|
4522 |
}
|
4523 |
|
4524 |
// Flush the cache of the site(s) associated with the API key.
|
4525 |
-
if(
|
4526 |
-
$clear_cache_resp =
|
4527 |
|
4528 |
if( $clear_cache_resp ){
|
4529 |
if( isset($clear_cache_resp->messages[0]) ){
|
4530 |
-
|
4531 |
} else {
|
4532 |
-
|
4533 |
}
|
4534 |
} else {
|
4535 |
-
|
4536 |
}
|
4537 |
}
|
4538 |
|
@@ -4554,7 +5051,7 @@ function sucuriscan_monitoring_settings( $api_key='' ){
|
|
4554 |
);
|
4555 |
|
4556 |
if( $api_key ){
|
4557 |
-
$settings =
|
4558 |
|
4559 |
$template_variables['Monitoring.APIKey'] = $api_key['string'];
|
4560 |
|
@@ -4586,7 +5083,7 @@ function sucuriscan_monitoring_settings( $api_key='' ){
|
|
4586 |
}
|
4587 |
|
4588 |
// Parse the snippet template and replace the pseudo-variables.
|
4589 |
-
$template_variables['Monitoring.SettingOptions'] .=
|
4590 |
'Monitoring.OptionCssClass' => $css_class,
|
4591 |
'Monitoring.OptionName' => $option_title,
|
4592 |
'Monitoring.OptionValue' => $option_value,
|
@@ -4596,7 +5093,7 @@ function sucuriscan_monitoring_settings( $api_key='' ){
|
|
4596 |
}
|
4597 |
}
|
4598 |
|
4599 |
-
return
|
4600 |
}
|
4601 |
|
4602 |
/**
|
@@ -4634,10 +5131,10 @@ function sucuriscan_explain_monitoring_settings( $settings=array() ){
|
|
4634 |
}
|
4635 |
|
4636 |
/**
|
4637 |
-
* Get an
|
4638 |
*
|
4639 |
* @param string $mode The value set for the cache settings of the site.
|
4640 |
-
* @return string
|
4641 |
*/
|
4642 |
function sucuriscan_cache_mode_title( $mode='' ){
|
4643 |
$title = '';
|
@@ -4645,8 +5142,8 @@ function sucuriscan_cache_mode_title( $mode='' ){
|
|
4645 |
switch( $mode ){
|
4646 |
case 'docache': $title = 'Enabled (recommended)'; break;
|
4647 |
case 'sitecache': $title = 'Site caching (using your site headers)'; break;
|
4648 |
-
case 'nocache': $title = '
|
4649 |
-
case 'nocacheatall': $title = 'Caching
|
4650 |
default: $title = 'Unknown'; break;
|
4651 |
}
|
4652 |
|
@@ -4668,33 +5165,29 @@ function sucuriscan_monitoring_logs( $api_key='' ){
|
|
4668 |
'AuditLogs.PaginationVisibility' => 'hidden',
|
4669 |
'AuditLogs.AuditPagination' => '',
|
4670 |
'AuditLogs.TargetDate' => '',
|
4671 |
-
'AuditLogs.DateYears' =>
|
4672 |
-
'AuditLogs.DateMonths' =>
|
4673 |
-
'AuditLogs.DateDays' =>
|
4674 |
);
|
4675 |
|
4676 |
$date = date('Y-m-d');
|
4677 |
|
4678 |
if( $api_key ){
|
4679 |
-
// Retrieve the date filter from the request (if any).
|
4680 |
-
if(
|
4681 |
-
$date = $
|
4682 |
}
|
4683 |
|
4684 |
-
|
4685 |
-
|
4686 |
-
|
4687 |
-
|
4688 |
-
|
4689 |
-
|
4690 |
-
|
4691 |
-
$_POST['sucuriscan_year'],
|
4692 |
-
$_POST['sucuriscan_month'],
|
4693 |
-
$_POST['sucuriscan_day']
|
4694 |
-
);
|
4695 |
}
|
4696 |
|
4697 |
-
$logs_data =
|
4698 |
|
4699 |
if( $logs_data ){
|
4700 |
add_thickbox(); /* Include the Thickbox library. */
|
@@ -4706,8 +5199,11 @@ function sucuriscan_monitoring_logs( $api_key='' ){
|
|
4706 |
}
|
4707 |
|
4708 |
$template_variables['AuditLogs.TargetDate'] = htmlentities($date);
|
|
|
|
|
|
|
4709 |
|
4710 |
-
return
|
4711 |
}
|
4712 |
|
4713 |
/**
|
@@ -4741,14 +5237,14 @@ function sucuriscan_monitoring_access_logs( $access_logs=array() ){
|
|
4741 |
$filter_by_keyword = FALSE;
|
4742 |
$filter_query = FALSE;
|
4743 |
|
4744 |
-
if(
|
4745 |
$filter_by_denial_type = TRUE;
|
4746 |
-
$filter_query =
|
4747 |
}
|
4748 |
|
4749 |
-
if(
|
4750 |
$filter_by_keyword = TRUE;
|
4751 |
-
$filter_query =
|
4752 |
}
|
4753 |
|
4754 |
foreach( $access_logs as $access_log ){
|
@@ -4761,7 +5257,7 @@ function sucuriscan_monitoring_access_logs( $access_logs=array() ){
|
|
4761 |
// If there is a filter, check the access_log data and break the operation if needed.
|
4762 |
if( $filter_query ){
|
4763 |
if( $filter_by_denial_type ){
|
4764 |
-
$denial_type_slug =
|
4765 |
|
4766 |
if( $denial_type_slug != $filter_query ){ continue; }
|
4767 |
}
|
@@ -4791,7 +5287,7 @@ function sucuriscan_monitoring_access_logs( $access_logs=array() ){
|
|
4791 |
$audit_log_snippet[$attr_title] = $attr_value;
|
4792 |
}
|
4793 |
|
4794 |
-
$logs_html .=
|
4795 |
$counter += 1;
|
4796 |
}
|
4797 |
}
|
@@ -4810,12 +5306,11 @@ function sucuriscan_monitoring_access_logs( $access_logs=array() ){
|
|
4810 |
*/
|
4811 |
function sucuriscan_monitoring_denial_types( $access_logs=array(), $in_html=TRUE ){
|
4812 |
$types = array();
|
4813 |
-
$selected = '';
|
4814 |
|
4815 |
if( $access_logs && !empty($access_logs) ){
|
4816 |
foreach( $access_logs as $access_log ){
|
4817 |
if( !array_key_exists($access_log->sucuri_block_reason, $types) ){
|
4818 |
-
$denial_type_k =
|
4819 |
$types[$denial_type_k] = $access_log->sucuri_block_reason;
|
4820 |
}
|
4821 |
}
|
@@ -4823,14 +5318,16 @@ function sucuriscan_monitoring_denial_types( $access_logs=array(), $in_html=TRUE
|
|
4823 |
|
4824 |
if( $in_html ){
|
4825 |
$html_types = '<option value="">Filter</option>';
|
4826 |
-
|
4827 |
-
if( isset($_REQUEST['sucuriscan_monitoring_denial_type']) ){
|
4828 |
-
$selected = htmlentities($_REQUEST['sucuriscan_monitoring_denial_type']);
|
4829 |
-
}
|
4830 |
|
4831 |
foreach( $types as $type_key => $type_value ){
|
4832 |
-
$selected_tag = ( $type_key
|
4833 |
-
$html_types .= sprintf(
|
|
|
|
|
|
|
|
|
|
|
4834 |
}
|
4835 |
|
4836 |
return $html_types;
|
@@ -4843,24 +5340,33 @@ function sucuriscan_monitoring_denial_types( $access_logs=array(), $in_html=TRUE
|
|
4843 |
* Get a list of years, months or days depending of the type specified.
|
4844 |
*
|
4845 |
* @param string $type Either years, months or days.
|
|
|
4846 |
* @param boolean $in_html Whether the list should be converted to a HTML select options or not.
|
4847 |
* @return array Either an array with the expected values, or a HTML code.
|
4848 |
*/
|
4849 |
-
function sucuriscan_monitoring_dates( $type='', $in_html=TRUE ){
|
4850 |
$options = array();
|
4851 |
$selected = '';
|
4852 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4853 |
switch( $type ){
|
4854 |
case 'years':
|
|
|
4855 |
$current_year = (int) date('Y');
|
4856 |
$max_years = 5; /* Maximum number of years to keep the logs. */
|
4857 |
$options = range( ($current_year - $max_years), $current_year );
|
4858 |
-
|
4859 |
-
if( isset($_REQUEST['sucuriscan_year']) ){
|
4860 |
-
$selected = $_REQUEST['sucuriscan_year'];
|
4861 |
-
}
|
4862 |
break;
|
4863 |
case 'months':
|
|
|
4864 |
$options = array(
|
4865 |
'01' => 'January',
|
4866 |
'02' => 'February',
|
@@ -4875,17 +5381,10 @@ function sucuriscan_monitoring_dates( $type='', $in_html=TRUE ){
|
|
4875 |
'11' => 'November',
|
4876 |
'12' => 'December'
|
4877 |
);
|
4878 |
-
|
4879 |
-
if( isset($_REQUEST['sucuriscan_month']) ){
|
4880 |
-
$selected = $_REQUEST['sucuriscan_month'];
|
4881 |
-
}
|
4882 |
break;
|
4883 |
case 'days':
|
4884 |
$options = range(1, 31);
|
4885 |
-
|
4886 |
-
if( isset($_REQUEST['sucuriscan_day']) ){
|
4887 |
-
$selected = $_REQUEST['sucuriscan_day'];
|
4888 |
-
}
|
4889 |
break;
|
4890 |
}
|
4891 |
|
@@ -4916,15 +5415,13 @@ function sucuriscan_monitoring_dates( $type='', $in_html=TRUE ){
|
|
4916 |
* @return void
|
4917 |
*/
|
4918 |
function sucuriscan_hardening_page(){
|
|
|
4919 |
|
4920 |
-
if(
|
4921 |
-
|
4922 |
-
|
4923 |
-
|
4924 |
-
|
4925 |
-
if( !wp_verify_nonce($_POST['sucuriscan_hardening_nonce'], 'sucuriscan_hardening_nonce') ){
|
4926 |
-
unset($_POST['wpsucuri-doharden']);
|
4927 |
-
}
|
4928 |
}
|
4929 |
|
4930 |
ob_start();
|
@@ -4932,8 +5429,8 @@ function sucuriscan_hardening_page(){
|
|
4932 |
|
4933 |
<div id="poststuff">
|
4934 |
<form method="post">
|
4935 |
-
<input type="hidden" name="
|
4936 |
-
<input type="hidden" name="
|
4937 |
|
4938 |
<?php
|
4939 |
sucuriscan_harden_version();
|
@@ -4955,7 +5452,7 @@ function sucuriscan_hardening_page(){
|
|
4955 |
<?php
|
4956 |
$_html = ob_get_contents();
|
4957 |
ob_end_clean();
|
4958 |
-
echo
|
4959 |
'PageTitle' => 'Hardening',
|
4960 |
'PageContent' => $_html,
|
4961 |
'PageStyleClass' => 'hardening'
|
@@ -5019,8 +5516,7 @@ function sucuriscan_harden_status( $title='', $status=0, $type='', $messageok=''
|
|
5019 |
* @return void
|
5020 |
*/
|
5021 |
function sucuriscan_harden_version(){
|
5022 |
-
|
5023 |
-
|
5024 |
$updates = get_core_updates();
|
5025 |
$cp = ( !is_array($updates) || empty($updates) ? 1 : 0 );
|
5026 |
|
@@ -5033,21 +5529,20 @@ function sucuriscan_harden_version(){
|
|
5033 |
}
|
5034 |
}
|
5035 |
|
5036 |
-
if( strcmp($
|
5037 |
$cp = 0;
|
5038 |
}
|
5039 |
|
5040 |
-
$wp_version = htmlspecialchars($wp_version);
|
5041 |
$initial_msg = 'Why keep your site updated? WordPress is an open-source
|
5042 |
project which means that with every update the details of the changes made
|
5043 |
to the source code are made public, if there were security fixes then
|
5044 |
someone with malicious intent can use this information to attack any site
|
5045 |
that has not been upgraded.';
|
5046 |
-
$messageok = sprintf('Your WordPress installation (%s) is current.', $
|
5047 |
$messagewarn = sprintf(
|
5048 |
'Your current version (%s) is not current.<br>
|
5049 |
<a href="update-core.php" class="button-primary">Update now!</a>',
|
5050 |
-
$
|
5051 |
);
|
5052 |
|
5053 |
sucuriscan_harden_status( 'Verify WordPress version', $cp, NULL, $messageok, $messagewarn, $initial_msg );
|
@@ -5084,33 +5579,34 @@ function sucuriscan_harden_removegenerator(){
|
|
5084 |
function sucuriscan_harden_upload(){
|
5085 |
$cp = 1;
|
5086 |
$upmsg = NULL;
|
5087 |
-
$
|
|
|
5088 |
|
5089 |
if( !is_readable($htaccess_upload) ){
|
5090 |
$cp = 0;
|
5091 |
} else {
|
5092 |
$cp = 0;
|
5093 |
-
$fcontent =
|
5094 |
|
5095 |
foreach( $fcontent as $fline ){
|
5096 |
-
if(
|
5097 |
$cp = 1;
|
5098 |
break;
|
5099 |
}
|
5100 |
}
|
5101 |
}
|
5102 |
|
5103 |
-
if(
|
5104 |
-
if(
|
5105 |
if( @file_put_contents($htaccess_upload, "\n<Files *.php>\ndeny from all\n</Files>") === FALSE ){
|
5106 |
-
$upmsg =
|
5107 |
} else {
|
5108 |
-
$upmsg =
|
5109 |
$cp = 1;
|
5110 |
}
|
5111 |
}
|
5112 |
|
5113 |
-
elseif(
|
5114 |
$htaccess_upload_writable = ( file_exists($htaccess_upload) && is_writable($htaccess_upload) ) ? TRUE : FALSE;
|
5115 |
$htaccess_content = $htaccess_upload_writable ? file_get_contents($htaccess_upload) : '';
|
5116 |
|
@@ -5122,11 +5618,11 @@ function sucuriscan_harden_upload(){
|
|
5122 |
@file_put_contents($htaccess_upload, $htaccess_content, LOCK_EX);
|
5123 |
}
|
5124 |
|
5125 |
-
|
5126 |
} else {
|
5127 |
-
|
5128 |
-
'<code
|
5129 |
-
writable, you will need to remove the following code (manually):
|
5130 |
<code><Files *.php>deny from all</Files></code>'
|
5131 |
);
|
5132 |
}
|
@@ -5162,27 +5658,27 @@ function sucuriscan_harden_wpcontent(){
|
|
5162 |
$cp = 0;
|
5163 |
} else {
|
5164 |
$cp = 0;
|
5165 |
-
$fcontent =
|
5166 |
|
5167 |
foreach( $fcontent as $fline ){
|
5168 |
-
if(
|
5169 |
$cp = 1;
|
5170 |
break;
|
5171 |
}
|
5172 |
}
|
5173 |
}
|
5174 |
|
5175 |
-
if(
|
5176 |
-
if(
|
5177 |
if( @file_put_contents($htaccess_upload, "\n<Files *.php>\ndeny from all\n</Files>") === FALSE ){
|
5178 |
-
$upmsg =
|
5179 |
} else {
|
5180 |
-
$upmsg =
|
5181 |
$cp = 1;
|
5182 |
}
|
5183 |
}
|
5184 |
|
5185 |
-
elseif(
|
5186 |
$htaccess_upload_writable = ( file_exists($htaccess_upload) && is_writable($htaccess_upload) ) ? TRUE : FALSE;
|
5187 |
$htaccess_content = $htaccess_upload_writable ? file_get_contents($htaccess_upload) : '';
|
5188 |
|
@@ -5194,11 +5690,11 @@ function sucuriscan_harden_wpcontent(){
|
|
5194 |
@file_put_contents($htaccess_upload, $htaccess_content, LOCK_EX);
|
5195 |
}
|
5196 |
|
5197 |
-
|
5198 |
} else {
|
5199 |
-
|
5200 |
-
'<code
|
5201 |
-
you will need to remove the following code manually there:
|
5202 |
<code><Files *.php>deny from all</Files></code>'
|
5203 |
);
|
5204 |
}
|
@@ -5237,27 +5733,27 @@ function sucuriscan_harden_wpincludes(){
|
|
5237 |
$cp = 0;
|
5238 |
} else {
|
5239 |
$cp = 0;
|
5240 |
-
$fcontent =
|
5241 |
|
5242 |
foreach( $fcontent as $fline ){
|
5243 |
-
if(
|
5244 |
$cp = 1;
|
5245 |
break;
|
5246 |
}
|
5247 |
}
|
5248 |
}
|
5249 |
|
5250 |
-
if(
|
5251 |
-
if(
|
5252 |
if( @file_put_contents($htaccess_upload, "\n<Files *.php>\ndeny from all\n</Files>\n<Files wp-tinymce.php>\nallow from all\n</Files>\n")===FALSE ){
|
5253 |
-
$upmsg =
|
5254 |
} else {
|
5255 |
-
$upmsg =
|
5256 |
$cp = 1;
|
5257 |
}
|
5258 |
}
|
5259 |
|
5260 |
-
elseif(
|
5261 |
$htaccess_upload_writable = ( file_exists($htaccess_upload) && is_writable($htaccess_upload) ) ? TRUE : FALSE;
|
5262 |
$htaccess_content = $htaccess_upload_writable ? file_get_contents($htaccess_upload) : '';
|
5263 |
|
@@ -5270,11 +5766,11 @@ function sucuriscan_harden_wpincludes(){
|
|
5270 |
|
5271 |
@file_put_contents($htaccess_upload, $htaccess_content, LOCK_EX);
|
5272 |
}
|
5273 |
-
|
5274 |
} else {
|
5275 |
-
|
5276 |
-
'<code>wp-includes/.htaccess</code> does not exists or is not
|
5277 |
-
writable, you will need to remove the following code manually
|
5278 |
there: <code><Files *.php>deny from all</Files></code>'
|
5279 |
);
|
5280 |
}
|
@@ -5320,7 +5816,7 @@ function sucuriscan_harden_phpversion(){
|
|
5320 |
*/
|
5321 |
function sucuriscan_cloudproxy_enabled(){
|
5322 |
$btn_string = '';
|
5323 |
-
$enabled =
|
5324 |
$status = 1;
|
5325 |
|
5326 |
if( $enabled !== TRUE ){
|
@@ -5352,40 +5848,22 @@ function sucuriscan_cloudproxy_enabled(){
|
|
5352 |
* @return void
|
5353 |
*/
|
5354 |
function sucuriscan_harden_secretkeys(){
|
5355 |
-
$wp_config_path =
|
|
|
5356 |
|
5357 |
if( $wp_config_path ){
|
5358 |
$cp = 1;
|
5359 |
$message = 'The main configuration file was found at: <code>'.$wp_config_path.'</code><br>';
|
5360 |
|
5361 |
-
|
5362 |
-
'
|
5363 |
-
'
|
5364 |
-
|
5365 |
-
|
5366 |
-
'AUTH_SALT',
|
5367 |
-
'SECURE_AUTH_SALT',
|
5368 |
-
'LOGGED_IN_SALT',
|
5369 |
-
'NONCE_SALT',
|
5370 |
-
);
|
5371 |
-
|
5372 |
-
foreach( $secret_key_names as $key_name){
|
5373 |
-
if( !defined($key_name) ){
|
5374 |
-
$cp = 0;
|
5375 |
-
$message .= 'The secret key <strong>'.$key_name.'</strong> is not defined.<br>';
|
5376 |
-
} elseif( constant($key_name) == 'put your unique phrase here' ){
|
5377 |
-
$cp = 0;
|
5378 |
-
$message .= 'The secret key <strong>'.$key_name.'</strong> is not properly set.<br>';
|
5379 |
-
}
|
5380 |
-
}
|
5381 |
-
|
5382 |
-
if( $cp == 0 ){
|
5383 |
-
$admin_url = admin_url('admin.php?page=sucuriscan_posthack');
|
5384 |
-
$message .= '<br><a href="'.$admin_url.'" class="button button-primary">Update WP-Config Keys</a><br>';
|
5385 |
}
|
5386 |
}else{
|
5387 |
$cp = 0;
|
5388 |
-
$message = 'The <code>wp-config</code> file was not found.<br>';
|
5389 |
}
|
5390 |
|
5391 |
$message .= '<br>It checks whether you have proper random keys/salts created for WordPress. A
|
@@ -5394,13 +5872,16 @@ function sucuriscan_harden_secretkeys(){
|
|
5394 |
random elements to the password. In simple terms, a secret key is a password with
|
5395 |
elements that make it harder to generate enough options to break through your
|
5396 |
security barriers.';
|
|
|
|
|
|
|
5397 |
|
5398 |
sucuriscan_harden_status(
|
5399 |
-
'
|
5400 |
$cp,
|
5401 |
NULL,
|
5402 |
-
'
|
5403 |
-
|
5404 |
$message,
|
5405 |
NULL
|
5406 |
);
|
@@ -5417,18 +5898,19 @@ function sucuriscan_harden_readme(){
|
|
5417 |
$upmsg = NULL;
|
5418 |
$cp = is_readable(ABSPATH.'/readme.html') ? 0 : 1;
|
5419 |
|
5420 |
-
|
5421 |
-
|
|
|
5422 |
if( @unlink(ABSPATH.'/readme.html') === FALSE ){
|
5423 |
-
$upmsg =
|
5424 |
} else {
|
5425 |
$cp = 1;
|
5426 |
-
$upmsg =
|
5427 |
}
|
5428 |
}
|
5429 |
|
5430 |
-
elseif(
|
5431 |
-
|
5432 |
}
|
5433 |
}
|
5434 |
|
@@ -5453,14 +5935,19 @@ function sucuriscan_harden_adminuser(){
|
|
5453 |
global $wpdb;
|
5454 |
|
5455 |
$upmsg = NULL;
|
5456 |
-
$
|
5457 |
-
|
|
|
|
|
|
|
|
|
|
|
5458 |
|
5459 |
-
if( $account_removed
|
5460 |
-
$upmsg = '<i><strong>We do not offer
|
5461 |
Go to the <a href="'.admin_url('users.php').'" target="_blank">user list</a> and create a new
|
5462 |
-
|
5463 |
-
(make sure to assign all the admin posts to the new user too
|
5464 |
}
|
5465 |
|
5466 |
sucuriscan_harden_status(
|
@@ -5482,14 +5969,14 @@ function sucuriscan_harden_adminuser(){
|
|
5482 |
function sucuriscan_harden_fileeditor(){
|
5483 |
$file_editor_disabled = defined('DISALLOW_FILE_EDIT') ? DISALLOW_FILE_EDIT : FALSE;
|
5484 |
|
5485 |
-
if(
|
5486 |
$current_time = date('r');
|
5487 |
-
$wp_config_path =
|
5488 |
|
5489 |
$wp_config_writable = ( file_exists($wp_config_path) && is_writable($wp_config_path) ) ? TRUE : FALSE;
|
5490 |
$new_wpconfig = $wp_config_writable ? file_get_contents($wp_config_path) : '';
|
5491 |
|
5492 |
-
if(
|
5493 |
if( $wp_config_writable ){
|
5494 |
if( preg_match('/(.*define\(.DB_COLLATE..*)/', $new_wpconfig, $match) ){
|
5495 |
$disallow_fileedit_definition = "\n\ndefine('DISALLOW_FILE_EDIT', TRUE); // Sucuri Security: {$current_time}\n";
|
@@ -5497,37 +5984,37 @@ function sucuriscan_harden_fileeditor(){
|
|
5497 |
}
|
5498 |
|
5499 |
@file_put_contents($wp_config_path, $new_wpconfig, LOCK_EX);
|
5500 |
-
|
5501 |
$file_editor_disabled = TRUE;
|
5502 |
} else {
|
5503 |
-
|
5504 |
or is not writable, you will need to put the following code manually there:
|
5505 |
<code>define("DISALLOW_FILE_EDIT", TRUE);</code>' );
|
5506 |
}
|
5507 |
}
|
5508 |
|
5509 |
-
elseif(
|
5510 |
if( preg_match("/(.*define\('DISALLOW_FILE_EDIT', TRUE\);.*)/", $new_wpconfig, $match) ){
|
5511 |
if( $wp_config_writable ){
|
5512 |
$new_wpconfig = str_replace("\n{$match[1]}", '', $new_wpconfig);
|
5513 |
file_put_contents($wp_config_path, $new_wpconfig, LOCK_EX);
|
5514 |
-
|
5515 |
$file_editor_disabled = FALSE;
|
5516 |
} else {
|
5517 |
-
|
5518 |
or is not writable, you will need to remove the following code manually from there:
|
5519 |
<code>define("DISALLOW_FILE_EDIT", TRUE);</code>' );
|
5520 |
}
|
5521 |
} else {
|
5522 |
-
|
5523 |
}
|
5524 |
}
|
5525 |
}
|
5526 |
|
5527 |
-
$message = 'Occasionally you may wish to disable the plugin or theme editor to prevent overzealous
|
5528 |
-
from being able to edit sensitive files and potentially crash the site. Disabling these
|
5529 |
-
provides an additional layer of security if a hacker gains access to a well-privileged
|
5530 |
-
account.';
|
5531 |
|
5532 |
sucuriscan_harden_status(
|
5533 |
'Plugin & Theme editor',
|
@@ -5573,11 +6060,15 @@ function sucuriscan_harden_dbtables(){
|
|
5573 |
* @return void
|
5574 |
*/
|
5575 |
function sucuriscan_page(){
|
5576 |
-
|
5577 |
-
wp_die(__('You do not have sufficient permissions to access this page: Sucuri Integrity Check') );
|
5578 |
-
}
|
5579 |
|
5580 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
5581 |
|
5582 |
$template_variables = array(
|
5583 |
'WordpressVersion' => sucuriscan_wordpress_outdated(),
|
@@ -5585,30 +6076,7 @@ function sucuriscan_page(){
|
|
5585 |
'CoreFiles' => sucuriscan_core_files(),
|
5586 |
);
|
5587 |
|
5588 |
-
echo
|
5589 |
-
}
|
5590 |
-
|
5591 |
-
/**
|
5592 |
-
* Process the requests sent by the form submissions originated in the integrity
|
5593 |
-
* page, all forms must have a nonce field that will be checked agains the one
|
5594 |
-
* generated in the template render function.
|
5595 |
-
*
|
5596 |
-
* @return void
|
5597 |
-
*/
|
5598 |
-
function sucuriscan_integrity_form_submissions(){
|
5599 |
-
if( sucuriscan_check_page_nonce() ){
|
5600 |
-
|
5601 |
-
// Manually force a filesystem scan (by an administrator user).
|
5602 |
-
if( isset($_POST['sucuriscan_force_scan']) ){
|
5603 |
-
if( current_user_can('manage_options') ){
|
5604 |
-
sucuriscan_notify_event( 'plugin_change', 'Filesystem scan forced at: ' . date('r') );
|
5605 |
-
sucuriscan_filesystem_scan(TRUE);
|
5606 |
-
} else {
|
5607 |
-
sucuriscan_error( 'Your privileges are not sufficient to execute this action.' );
|
5608 |
-
}
|
5609 |
-
}
|
5610 |
-
|
5611 |
-
}
|
5612 |
}
|
5613 |
|
5614 |
/**
|
@@ -5645,9 +6113,9 @@ function sucuriscan_auditlogs(){
|
|
5645 |
|
5646 |
// Initialize the values for the pagination.
|
5647 |
$max_per_page = SUCURISCAN_AUDITLOGS_PER_PAGE;
|
5648 |
-
$page_number =
|
5649 |
$logs_limit = $page_number * $max_per_page;
|
5650 |
-
$audit_logs =
|
5651 |
|
5652 |
$show_all = TRUE;
|
5653 |
|
@@ -5696,7 +6164,7 @@ function sucuriscan_auditlogs(){
|
|
5696 |
$snippet_data['AuditLog.Extra'] .= '<small>For Mac users, this is a scrollable container</small>';
|
5697 |
}
|
5698 |
|
5699 |
-
$template_variables['AuditLogs.List'] .=
|
5700 |
$counter_i += 1;
|
5701 |
}
|
5702 |
}
|
@@ -5706,15 +6174,15 @@ function sucuriscan_auditlogs(){
|
|
5706 |
|
5707 |
if( $total_items > 0 ){
|
5708 |
$template_variables['AuditLogs.PaginationVisibility'] = 'visible';
|
5709 |
-
$template_variables['AuditLogs.PaginationLinks'] =
|
5710 |
'%%SUCURI.URL.Home%%',
|
5711 |
-
$max_per_page * 5, /* Temporary value while we get the total logs. */
|
5712 |
$max_per_page
|
5713 |
);
|
5714 |
}
|
5715 |
}
|
5716 |
|
5717 |
-
return
|
5718 |
}
|
5719 |
|
5720 |
/**
|
@@ -5723,13 +6191,12 @@ function sucuriscan_auditlogs(){
|
|
5723 |
* @return string Panel with a warning advising that WordPress is outdated.
|
5724 |
*/
|
5725 |
function sucuriscan_wordpress_outdated(){
|
5726 |
-
|
5727 |
-
|
5728 |
$updates = get_core_updates();
|
5729 |
$cp = ( !is_array($updates) || empty($updates) ? 1 : 0 );
|
5730 |
|
5731 |
$template_variables = array(
|
5732 |
-
'WordPress.Version' =>
|
5733 |
'WordPress.UpgradeURL' => admin_url('update-core.php'),
|
5734 |
'WordPress.UpdateVisibility' => 'hidden',
|
5735 |
'WordPressBeta.Visibility' => 'hidden',
|
@@ -5751,7 +6218,7 @@ function sucuriscan_wordpress_outdated(){
|
|
5751 |
}
|
5752 |
}
|
5753 |
|
5754 |
-
if( strcmp($
|
5755 |
$cp = 0;
|
5756 |
}
|
5757 |
|
@@ -5759,7 +6226,7 @@ function sucuriscan_wordpress_outdated(){
|
|
5759 |
$template_variables['WordPress.UpdateVisibility'] = 'visible';
|
5760 |
}
|
5761 |
|
5762 |
-
return
|
5763 |
}
|
5764 |
|
5765 |
/**
|
@@ -5770,7 +6237,7 @@ function sucuriscan_wordpress_outdated(){
|
|
5770 |
* @return void
|
5771 |
*/
|
5772 |
function sucuriscan_core_files(){
|
5773 |
-
|
5774 |
|
5775 |
$template_variables = array(
|
5776 |
'CoreFiles.List' => '',
|
@@ -5779,8 +6246,8 @@ function sucuriscan_core_files(){
|
|
5779 |
'CoreFiles.BadVisibility' => 'hidden',
|
5780 |
);
|
5781 |
|
5782 |
-
if( $
|
5783 |
-
$latest_hashes = sucuriscan_check_wp_integrity($
|
5784 |
|
5785 |
if( $latest_hashes ){
|
5786 |
$counter = 0;
|
@@ -5813,7 +6280,7 @@ function sucuriscan_core_files(){
|
|
5813 |
}
|
5814 |
|
5815 |
$css_class = ( $counter % 2 == 0 ) ? '' : 'alternate';
|
5816 |
-
$template_variables['CoreFiles.List'] .=
|
5817 |
'CoreFiles.CssClass' => $css_class,
|
5818 |
'CoreFiles.StatusType' => $list_type,
|
5819 |
'CoreFiles.StatusAbbr' => substr($list_type, 0, 1),
|
@@ -5829,41 +6296,11 @@ function sucuriscan_core_files(){
|
|
5829 |
$template_variables['CoreFiles.BadVisibility'] = 'visible';
|
5830 |
}
|
5831 |
} else {
|
5832 |
-
|
5833 |
-
}
|
5834 |
-
}
|
5835 |
-
|
5836 |
-
return sucuriscan_get_section('integrity-corefiles', $template_variables);
|
5837 |
-
}
|
5838 |
-
|
5839 |
-
/**
|
5840 |
-
* Retrieve a list with the checksums of the files in a specific version of WordPress.
|
5841 |
-
*
|
5842 |
-
* @see Release Archive http://wordpress.org/download/release-archive/
|
5843 |
-
*
|
5844 |
-
* @param integer $version Valid version number of the WordPress project.
|
5845 |
-
* @return object Associative object with the relative filepath and the checksums of the project files.
|
5846 |
-
*/
|
5847 |
-
function sucuriscan_get_official_checksums( $version=0 ){
|
5848 |
-
$api_url = sprintf('http://api.wordpress.org/core/checksums/1.0/?version=%s&locale=en_US', $version);
|
5849 |
-
$request = wp_remote_get($api_url);
|
5850 |
-
|
5851 |
-
if( !is_wp_error($request) || wp_remote_retrieve_response_code($request) === 200 ){
|
5852 |
-
$json_data = json_decode($request['body']);
|
5853 |
-
|
5854 |
-
if( $json_data->checksums !== FALSE ){
|
5855 |
-
$checksums = $json_data->checksums;
|
5856 |
-
|
5857 |
-
// Convert the object list to an array for better handle of the data.
|
5858 |
-
if( $checksums instanceof stdClass ){
|
5859 |
-
$checksums = (array) $checksums;
|
5860 |
-
}
|
5861 |
-
|
5862 |
-
return $checksums;
|
5863 |
}
|
5864 |
}
|
5865 |
|
5866 |
-
return
|
5867 |
}
|
5868 |
|
5869 |
/**
|
@@ -5882,7 +6319,7 @@ function sucuriscan_get_official_checksums( $version=0 ){
|
|
5882 |
* @return array Associative array with these keys: modified, stable, removed, added.
|
5883 |
*/
|
5884 |
function sucuriscan_check_wp_integrity( $version=0 ){
|
5885 |
-
$latest_hashes =
|
5886 |
|
5887 |
if( !$latest_hashes ){ return FALSE; }
|
5888 |
|
@@ -5941,27 +6378,29 @@ function sucuriscan_check_wp_integrity( $version=0 ){
|
|
5941 |
function sucuriscan_ignore_integrity_filepath( $filepath='' ){
|
5942 |
// List of files that will be ignored from the integrity checking.
|
5943 |
$ignore_files = array(
|
5944 |
-
'
|
5945 |
-
'
|
5946 |
-
'
|
5947 |
-
'
|
5948 |
-
'wp-
|
5949 |
-
'wp-
|
5950 |
-
'wp-rss
|
5951 |
-
'wp-
|
5952 |
-
'
|
5953 |
-
'
|
5954 |
-
'
|
5955 |
-
'
|
5956 |
-
'
|
|
|
|
|
|
|
|
|
5957 |
);
|
5958 |
|
5959 |
-
|
5960 |
-
|
5961 |
-
|
5962 |
-
|
5963 |
-
){
|
5964 |
-
return TRUE;
|
5965 |
}
|
5966 |
|
5967 |
return FALSE;
|
@@ -5984,9 +6423,9 @@ function sucuriscan_modified_files(){
|
|
5984 |
// Find files modified in the last days.
|
5985 |
$back_days = 7;
|
5986 |
|
5987 |
-
//
|
5988 |
-
if(
|
5989 |
-
$back_days =
|
5990 |
if ( $back_days <= 0 ){ $back_days = 1; }
|
5991 |
elseif( $back_days >= 60 ){ $back_days = 60; }
|
5992 |
}
|
@@ -6000,32 +6439,41 @@ function sucuriscan_modified_files(){
|
|
6000 |
);
|
6001 |
}
|
6002 |
|
6003 |
-
//
|
6004 |
-
|
6005 |
-
|
6006 |
-
|
6007 |
-
$counter = 0;
|
6008 |
|
6009 |
-
|
6010 |
-
|
6011 |
-
$
|
6012 |
-
$
|
6013 |
|
6014 |
-
$
|
6015 |
-
|
6016 |
-
|
6017 |
-
|
6018 |
-
|
6019 |
-
|
6020 |
-
|
6021 |
-
|
6022 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6023 |
|
6024 |
-
|
6025 |
-
|
|
|
|
|
6026 |
}
|
6027 |
|
6028 |
-
return
|
6029 |
}
|
6030 |
|
6031 |
/**
|
@@ -6034,9 +6482,7 @@ function sucuriscan_modified_files(){
|
|
6034 |
* @return void
|
6035 |
*/
|
6036 |
function sucuriscan_posthack_page(){
|
6037 |
-
|
6038 |
-
wp_die(__('You do not have sufficient permissions to access this page: Sucuri Post-Hack') );
|
6039 |
-
}
|
6040 |
|
6041 |
$process_form = sucuriscan_posthack_process_form();
|
6042 |
|
@@ -6048,7 +6494,7 @@ function sucuriscan_posthack_page(){
|
|
6048 |
'ResetPlugins' => sucuriscan_posthack_plugins($process_form),
|
6049 |
);
|
6050 |
|
6051 |
-
echo
|
6052 |
}
|
6053 |
|
6054 |
/**
|
@@ -6057,11 +6503,16 @@ function sucuriscan_posthack_page(){
|
|
6057 |
* @return boolean TRUE if a form submission should be processed, FALSE otherwise.
|
6058 |
*/
|
6059 |
function sucuriscan_posthack_process_form(){
|
6060 |
-
|
6061 |
-
|
|
|
|
|
|
|
|
|
|
|
6062 |
return TRUE;
|
6063 |
} else {
|
6064 |
-
|
6065 |
}
|
6066 |
}
|
6067 |
|
@@ -6078,32 +6529,74 @@ function sucuriscan_update_secret_keys( $process_form=FALSE ){
|
|
6078 |
$template_variables = array(
|
6079 |
'WPConfigUpdate.Visibility' => 'hidden',
|
6080 |
'WPConfigUpdate.NewConfig' => '',
|
|
|
6081 |
);
|
6082 |
|
6083 |
// Update all WordPress secret keys.
|
6084 |
-
if( $process_form &&
|
6085 |
-
$wpconfig_process =
|
6086 |
|
6087 |
if( $wpconfig_process ){
|
6088 |
$template_variables['WPConfigUpdate.Visibility'] = 'visible';
|
6089 |
|
6090 |
if( $wpconfig_process['updated'] === TRUE ){
|
6091 |
-
|
6092 |
$template_variables['WPConfigUpdate.NewConfig'] .= "// Old Keys\n";
|
6093 |
$template_variables['WPConfigUpdate.NewConfig'] .= $wpconfig_process['old_keys_string'];
|
6094 |
$template_variables['WPConfigUpdate.NewConfig'] .= "//\n";
|
6095 |
$template_variables['WPConfigUpdate.NewConfig'] .= "// New Keys\n";
|
6096 |
$template_variables['WPConfigUpdate.NewConfig'] .= $wpconfig_process['new_keys_string'];
|
6097 |
} else {
|
6098 |
-
|
|
|
|
|
|
|
6099 |
$template_variables['WPConfigUpdate.NewConfig'] = $wpconfig_process['new_wpconfig'];
|
6100 |
}
|
6101 |
} else {
|
6102 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6103 |
}
|
6104 |
}
|
6105 |
|
6106 |
-
return
|
6107 |
}
|
6108 |
|
6109 |
/**
|
@@ -6132,22 +6625,21 @@ function sucuriscan_posthack_users( $process_form=FALSE ){
|
|
6132 |
$user->user_registered_formatted = date('D, M/Y H:i', $user->user_registered_timestamp);
|
6133 |
$css_class = ( $counter % 2 == 0 ) ? '' : 'alternate';
|
6134 |
|
6135 |
-
$
|
6136 |
'ResetPassword.UserId' => $user->ID,
|
6137 |
-
'ResetPassword.Username' => $user->user_login,
|
6138 |
-
'ResetPassword.Displayname' => $user->display_name,
|
6139 |
-
'ResetPassword.Email' => $user->user_email,
|
6140 |
'ResetPassword.Registered' => $user->user_registered_formatted,
|
6141 |
'ResetPassword.Roles' => implode(', ', $user->roles),
|
6142 |
-
'ResetPassword.CssClass' => $css_class
|
6143 |
));
|
6144 |
|
6145 |
-
$template_variables['ResetPassword.UserList'] .= $user_snippet;
|
6146 |
$counter += 1;
|
6147 |
}
|
6148 |
}
|
6149 |
|
6150 |
-
return
|
6151 |
}
|
6152 |
|
6153 |
/**
|
@@ -6157,15 +6649,16 @@ function sucuriscan_posthack_users( $process_form=FALSE ){
|
|
6157 |
* @return void
|
6158 |
*/
|
6159 |
function sucuriscan_reset_user_password( $process_form=FALSE ){
|
6160 |
-
if( $process_form &&
|
6161 |
-
$user_identifiers =
|
6162 |
-
$pwd_changed =
|
|
|
6163 |
|
6164 |
if( is_array($user_identifiers) && !empty($user_identifiers) ){
|
6165 |
arsort($user_identifiers);
|
6166 |
|
6167 |
foreach( $user_identifiers as $user_id ){
|
6168 |
-
if(
|
6169 |
$pwd_changed[] = $user_id;
|
6170 |
} else {
|
6171 |
$pwd_not_changed[] = $user_id;
|
@@ -6173,14 +6666,14 @@ function sucuriscan_reset_user_password( $process_form=FALSE ){
|
|
6173 |
}
|
6174 |
|
6175 |
if( !empty($pwd_changed) ){
|
6176 |
-
|
6177 |
}
|
6178 |
|
6179 |
if( !empty($pwd_not_changed) ){
|
6180 |
-
|
6181 |
}
|
6182 |
} else {
|
6183 |
-
|
6184 |
}
|
6185 |
}
|
6186 |
}
|
@@ -6197,7 +6690,7 @@ function sucuriscan_posthack_plugins( $process_form=FALSE ){
|
|
6197 |
);
|
6198 |
|
6199 |
sucuriscan_posthack_reinstall_plugins($process_form);
|
6200 |
-
$all_plugins =
|
6201 |
$counter = 0;
|
6202 |
|
6203 |
foreach( $all_plugins as $plugin_path => $plugin_data ){
|
@@ -6207,11 +6700,11 @@ function sucuriscan_posthack_plugins( $process_form=FALSE ){
|
|
6207 |
$plugin_status = $plugin_data['IsPluginActive'] ? 'active' : 'not active';
|
6208 |
$plugin_status_class = $plugin_data['IsPluginActive'] ? 'success' : 'default';
|
6209 |
|
6210 |
-
$template_variables['ResetPlugin.PluginList'] .=
|
6211 |
'ResetPlugin.CssClass' => $css_class,
|
6212 |
'ResetPlugin.Disabled' => $input_disabled,
|
6213 |
-
'ResetPlugin.PluginPath' => $plugin_path,
|
6214 |
-
'ResetPlugin.Plugin' =>
|
6215 |
'ResetPlugin.Version' => $plugin_data['Version'],
|
6216 |
'ResetPlugin.Type' => $plugin_data['PluginType'],
|
6217 |
'ResetPlugin.TypeClass' => $plugin_type_class,
|
@@ -6222,7 +6715,7 @@ function sucuriscan_posthack_plugins( $process_form=FALSE ){
|
|
6222 |
$counter += 1;
|
6223 |
}
|
6224 |
|
6225 |
-
return
|
6226 |
}
|
6227 |
|
6228 |
/**
|
@@ -6239,17 +6732,14 @@ function sucuriscan_posthack_reinstall_plugins( $process_form=FALSE ){
|
|
6239 |
include_once( ABSPATH . 'wp-admin/includes/class-wp-upgrader.php' );
|
6240 |
include_once( ABSPATH . 'wp-admin/includes/plugin-install.php' ); // For plugins_api.
|
6241 |
|
6242 |
-
if(
|
6243 |
-
isset($_POST['plugin_path'])
|
6244 |
-
&& !empty($_POST['plugin_path'])
|
6245 |
-
){
|
6246 |
// Create an instance of the FileInfo interface.
|
6247 |
$sucuri_fileinfo = new SucuriScanFileInfo();
|
6248 |
$sucuri_fileinfo->ignore_files = FALSE;
|
6249 |
$sucuri_fileinfo->ignore_directories = FALSE;
|
6250 |
|
6251 |
// Get (possible) cached information from the installed plugins.
|
6252 |
-
$all_plugins =
|
6253 |
|
6254 |
// Loop through all the installed plugins.
|
6255 |
foreach( $_POST['plugin_path'] as $plugin_path ){
|
@@ -6258,7 +6748,7 @@ function sucuriscan_posthack_reinstall_plugins( $process_form=FALSE ){
|
|
6258 |
|
6259 |
// Check if the plugin can be downloaded from the free market.
|
6260 |
if( $plugin_data['IsFreePlugin'] === TRUE ){
|
6261 |
-
$plugin_info =
|
6262 |
|
6263 |
if( $plugin_info ){
|
6264 |
// First, remove all files/sub-folders from the plugin's directory.
|
@@ -6270,13 +6760,13 @@ function sucuriscan_posthack_reinstall_plugins( $process_form=FALSE ){
|
|
6270 |
$upgrader = new Plugin_Upgrader($upgrader_skin);
|
6271 |
$upgrader->install($plugin_info->download_link);
|
6272 |
} else {
|
6273 |
-
|
6274 |
}
|
6275 |
}
|
6276 |
}
|
6277 |
}
|
6278 |
} else {
|
6279 |
-
|
6280 |
}
|
6281 |
}
|
6282 |
}
|
@@ -6289,9 +6779,7 @@ function sucuriscan_posthack_reinstall_plugins( $process_form=FALSE ){
|
|
6289 |
* @return string Last-logings for the administrator accounts.
|
6290 |
*/
|
6291 |
function sucuriscan_lastlogins_page(){
|
6292 |
-
|
6293 |
-
wp_die(__('You do not have sufficient permissions to access this page: Sucuri Last-Logins') );
|
6294 |
-
}
|
6295 |
|
6296 |
// Page pseudo-variables initialization.
|
6297 |
$template_variables = array(
|
@@ -6302,7 +6790,7 @@ function sucuriscan_lastlogins_page(){
|
|
6302 |
'FailedLogins' => sucuriscan_failed_logins_panel(),
|
6303 |
);
|
6304 |
|
6305 |
-
echo
|
6306 |
}
|
6307 |
|
6308 |
/**
|
@@ -6326,8 +6814,8 @@ function sucuriscan_lastlogins_admins(){
|
|
6326 |
$admin->lastlogins = $last_logins['entries'];
|
6327 |
|
6328 |
$user_snippet = array(
|
6329 |
-
'AdminUsers.Username' => $admin->user_login,
|
6330 |
-
'AdminUsers.Email' => $admin->user_email,
|
6331 |
'AdminUsers.LastLogins' => '',
|
6332 |
'AdminUsers.RegisteredAt' => 'Undefined',
|
6333 |
'AdminUsers.UserURL' => admin_url('user-edit.php?user_id='.$admin->ID),
|
@@ -6343,19 +6831,19 @@ function sucuriscan_lastlogins_admins(){
|
|
6343 |
|
6344 |
foreach( $admin->lastlogins as $lastlogin ){
|
6345 |
$css_class = ( $counter % 2 == 0 ) ? '' : 'alternate';
|
6346 |
-
$user_snippet['AdminUsers.LastLogins'] .=
|
6347 |
-
'AdminUsers.RemoteAddr' => $lastlogin->user_remoteaddr,
|
6348 |
-
'AdminUsers.Datetime' => $lastlogin->user_lastlogin,
|
6349 |
'AdminUsers.CssClass' => $css_class,
|
6350 |
));
|
6351 |
$counter += 1;
|
6352 |
}
|
6353 |
}
|
6354 |
|
6355 |
-
$template_variables['AdminUsers.List'] .=
|
6356 |
}
|
6357 |
|
6358 |
-
return
|
6359 |
}
|
6360 |
|
6361 |
/**
|
@@ -6367,7 +6855,7 @@ function sucuriscan_lastlogins_admins(){
|
|
6367 |
*/
|
6368 |
function sucuriscan_lastlogins_all(){
|
6369 |
$max_per_page = SUCURISCAN_LASTLOGINS_USERSLIMIT;
|
6370 |
-
$page_number =
|
6371 |
$offset = ($max_per_page * $page_number) - $max_per_page;
|
6372 |
|
6373 |
$template_variables = array(
|
@@ -6380,7 +6868,7 @@ function sucuriscan_lastlogins_all(){
|
|
6380 |
);
|
6381 |
|
6382 |
if( !sucuriscan_lastlogins_datastore_is_writable() ){
|
6383 |
-
|
6384 |
}
|
6385 |
|
6386 |
$counter = 0;
|
@@ -6389,6 +6877,9 @@ function sucuriscan_lastlogins_all(){
|
|
6389 |
|
6390 |
if( $last_logins['total'] > $max_per_page ){
|
6391 |
$template_variables['UserList.PaginationVisibility'] = 'visible';
|
|
|
|
|
|
|
6392 |
$template_variables['UserList.NoItemsVisibility'] = 'hidden';
|
6393 |
}
|
6394 |
|
@@ -6403,32 +6894,32 @@ function sucuriscan_lastlogins_all(){
|
|
6403 |
'UserList.Displayname' => '',
|
6404 |
'UserList.Email' => '',
|
6405 |
'UserList.Registered' => '',
|
6406 |
-
'UserList.RemoteAddr' => $user->user_remoteaddr,
|
6407 |
-
'UserList.Hostname' => $user->user_hostname,
|
6408 |
-
'UserList.Datetime' => $user->user_lastlogin,
|
6409 |
-
'UserList.TimeAgo' =>
|
6410 |
'UserList.UserURL' => admin_url('user-edit.php?user_id='.$user->user_id),
|
6411 |
'UserList.CssClass' => $css_class,
|
6412 |
);
|
6413 |
|
6414 |
if( $user->user_exists ){
|
6415 |
-
$user_dataset['UserList.Username'] = $user->user_login;
|
6416 |
-
$user_dataset['UserList.Displayname'] = $user->display_name;
|
6417 |
-
$user_dataset['UserList.Email'] = $user->user_email;
|
6418 |
-
$user_dataset['UserList.Registered'] = $user->user_registered;
|
6419 |
}
|
6420 |
|
6421 |
-
$template_variables['UserList'] .=
|
6422 |
}
|
6423 |
|
6424 |
// Generate the pagination for the list.
|
6425 |
-
$template_variables['UserList.Pagination'] =
|
6426 |
'%%SUCURI.URL.Lastlogins%%',
|
6427 |
$last_logins['total'],
|
6428 |
$max_per_page
|
6429 |
);
|
6430 |
|
6431 |
-
return
|
6432 |
}
|
6433 |
|
6434 |
/**
|
@@ -6437,7 +6928,7 @@ function sucuriscan_lastlogins_all(){
|
|
6437 |
* @return string Absolute filepath where the user's last login information is stored.
|
6438 |
*/
|
6439 |
function sucuriscan_lastlogins_datastore_filepath(){
|
6440 |
-
return
|
6441 |
}
|
6442 |
|
6443 |
/**
|
@@ -6466,12 +6957,17 @@ function sucuriscan_lastlogins_datastore_exists(){
|
|
6466 |
*/
|
6467 |
function sucuriscan_lastlogins_datastore_is_writable(){
|
6468 |
$datastore_filepath = sucuriscan_lastlogins_datastore_exists();
|
|
|
6469 |
if($datastore_filepath){
|
6470 |
if( !is_writable($datastore_filepath) ){
|
6471 |
@chmod($datastore_filepath, 0644);
|
6472 |
}
|
6473 |
-
|
|
|
|
|
|
|
6474 |
}
|
|
|
6475 |
return FALSE;
|
6476 |
}
|
6477 |
|
@@ -6483,9 +6979,11 @@ function sucuriscan_lastlogins_datastore_is_writable(){
|
|
6483 |
*/
|
6484 |
function sucuriscan_lastlogins_datastore_is_readable(){
|
6485 |
$datastore_filepath = sucuriscan_lastlogins_datastore_exists();
|
|
|
6486 |
if( $datastore_filepath && is_readable($datastore_filepath) ){
|
6487 |
return $datastore_filepath;
|
6488 |
}
|
|
|
6489 |
return FALSE;
|
6490 |
}
|
6491 |
|
@@ -6501,7 +6999,7 @@ if( !function_exists('sucuri_set_lastlogin') ){
|
|
6501 |
|
6502 |
if($datastore_filepath){
|
6503 |
$current_user = get_user_by('login', $user_login);
|
6504 |
-
$remote_addr =
|
6505 |
|
6506 |
$login_info = array(
|
6507 |
'user_id' => $current_user->ID,
|
@@ -6537,7 +7035,7 @@ function sucuriscan_get_logins( $limit=10, $offset=0, $user_id=0 ){
|
|
6537 |
|
6538 |
if( $datastore_filepath ){
|
6539 |
$parsed_lines = 0;
|
6540 |
-
$data_lines =
|
6541 |
|
6542 |
if( $data_lines ){
|
6543 |
/**
|
@@ -6566,7 +7064,7 @@ function sucuriscan_get_logins( $limit=10, $offset=0, $user_id=0 ){
|
|
6566 |
for( $i=$offset; $i<$total_lines; $i++ ){
|
6567 |
$line = $reversed_lines[$i] ? trim($reversed_lines[$i]) : '';
|
6568 |
|
6569 |
-
if( preg_match('/^a
|
6570 |
$last_login = @unserialize($line);
|
6571 |
|
6572 |
// Only administrators can see all login stats.
|
@@ -6596,7 +7094,7 @@ function sucuriscan_get_logins( $limit=10, $offset=0, $user_id=0 ){
|
|
6596 |
$parsed_lines += 1;
|
6597 |
}
|
6598 |
|
6599 |
-
if( preg_match('/^
|
6600 |
if( $parsed_lines >= $limit ){ break; }
|
6601 |
}
|
6602 |
}
|
@@ -6626,8 +7124,7 @@ if( !function_exists('sucuri_login_redirect') ){
|
|
6626 |
return $login_url;
|
6627 |
}
|
6628 |
|
6629 |
-
|
6630 |
-
if( $lastlogin_redirection == 'enabled' ){
|
6631 |
add_filter('login_redirect', 'sucuriscan_login_redirect', 10, 3);
|
6632 |
}
|
6633 |
}
|
@@ -6639,7 +7136,10 @@ if( !function_exists('sucuri_get_user_lastlogin') ){
|
|
6639 |
* @return void
|
6640 |
*/
|
6641 |
function sucuriscan_get_user_lastlogin(){
|
6642 |
-
if(
|
|
|
|
|
|
|
6643 |
$current_user = wp_get_current_user();
|
6644 |
|
6645 |
// Select the penultimate entry, not the last one.
|
@@ -6648,10 +7148,10 @@ if( !function_exists('sucuri_get_user_lastlogin') ){
|
|
6648 |
if( isset($last_logins['entries'][1]) ){
|
6649 |
$row = $last_logins['entries'][1];
|
6650 |
|
6651 |
-
$message_tpl
|
6652 |
$lastlogin_message = sprintf( $message_tpl, date('d/M/Y H:i'), $row->user_remoteaddr, $row->user_hostname );
|
6653 |
-
$lastlogin_message .= chr(32).'(<a href="'.
|
6654 |
-
|
6655 |
}
|
6656 |
}
|
6657 |
}
|
@@ -6672,6 +7172,7 @@ function sucuriscan_loggedin_users_panel(){
|
|
6672 |
);
|
6673 |
|
6674 |
$logged_in_users = sucuriscan_get_online_users(TRUE);
|
|
|
6675 |
if( is_array($logged_in_users) && !empty($logged_in_users) ){
|
6676 |
$template_variables['LoggedInUsers.Total'] = count($logged_in_users);
|
6677 |
$counter = 0;
|
@@ -6681,20 +7182,20 @@ function sucuriscan_loggedin_users_panel(){
|
|
6681 |
$logged_in_user['last_activity_datetime'] = date('d/M/Y H:i', $logged_in_user['last_activity']);
|
6682 |
$logged_in_user['user_registered_datetime'] = date('d/M/Y H:i', strtotime($logged_in_user['user_registered']));
|
6683 |
|
6684 |
-
$template_variables['LoggedInUsers.List'] .=
|
6685 |
-
'LoggedInUsers.Id' => $logged_in_user['user_id'],
|
6686 |
'LoggedInUsers.UserURL' => admin_url('user-edit.php?user_id='.$logged_in_user['user_id']),
|
6687 |
-
'LoggedInUsers.UserLogin' => $logged_in_user['user_login'],
|
6688 |
-
'LoggedInUsers.UserEmail' => $logged_in_user['user_email'],
|
6689 |
-
'LoggedInUsers.LastActivity' => $logged_in_user['last_activity_datetime'],
|
6690 |
-
'LoggedInUsers.Registered' => $logged_in_user['user_registered_datetime'],
|
6691 |
-
'LoggedInUsers.RemoveAddr' => $logged_in_user['remote_addr'],
|
6692 |
'LoggedInUsers.CssClass' => ( $counter % 2 == 0 ) ? '' : 'alternate'
|
6693 |
));
|
6694 |
}
|
6695 |
}
|
6696 |
|
6697 |
-
return
|
6698 |
}
|
6699 |
|
6700 |
/**
|
@@ -6706,7 +7207,7 @@ function sucuriscan_loggedin_users_panel(){
|
|
6706 |
function sucuriscan_get_online_users( $add_current_user=FALSE ){
|
6707 |
$users = array();
|
6708 |
|
6709 |
-
if(
|
6710 |
$users = get_site_transient('online_users');
|
6711 |
} else {
|
6712 |
$users = get_transient('online_users');
|
@@ -6737,7 +7238,7 @@ function sucuriscan_get_online_users( $add_current_user=FALSE ){
|
|
6737 |
function sucuriscan_save_online_users( $logged_in_users=array() ){
|
6738 |
$expiration = 30 * 60;
|
6739 |
|
6740 |
-
if(
|
6741 |
return set_site_transient('online_users', $logged_in_users, $expiration);
|
6742 |
} else {
|
6743 |
return set_transient('online_users', $logged_in_users, $expiration);
|
@@ -6752,7 +7253,7 @@ if( !function_exists('sucuriscan_unset_online_user_on_logout') ){
|
|
6752 |
* @return void
|
6753 |
*/
|
6754 |
function sucuriscan_unset_online_user_on_logout(){
|
6755 |
-
$remote_addr =
|
6756 |
$current_user = wp_get_current_user();
|
6757 |
$user_id = $current_user->ID;
|
6758 |
|
@@ -6802,7 +7303,7 @@ if( !function_exists('sucuriscan_set_online_user') ){
|
|
6802 |
// Get logged in user information.
|
6803 |
$current_user = ($user instanceof WP_User) ? $user : wp_get_current_user();
|
6804 |
$current_user_id = $current_user->ID;
|
6805 |
-
$remote_addr =
|
6806 |
$current_time = current_time('timestamp');
|
6807 |
$logged_in_users = sucuriscan_get_online_users();
|
6808 |
|
@@ -6813,7 +7314,7 @@ if( !function_exists('sucuriscan_set_online_user') ){
|
|
6813 |
'user_email' => $current_user->user_email,
|
6814 |
'user_registered' => $current_user->user_registered,
|
6815 |
'last_activity' => $current_time,
|
6816 |
-
'remote_addr' => $remote_addr
|
6817 |
);
|
6818 |
|
6819 |
if( !is_array($logged_in_users) || empty($logged_in_users) ){
|
@@ -6871,8 +7372,8 @@ function sucuriscan_failed_logins_panel(){
|
|
6871 |
'FailedLogins.WarningVisibility' => 'visible',
|
6872 |
);
|
6873 |
|
6874 |
-
$max_failed_logins =
|
6875 |
-
$notify_bruteforce_attack =
|
6876 |
$failed_logins = sucuriscan_get_failed_logins();
|
6877 |
|
6878 |
if( $failed_logins ){
|
@@ -6881,13 +7382,13 @@ function sucuriscan_failed_logins_panel(){
|
|
6881 |
foreach( $failed_logins['entries'] as $login_data ){
|
6882 |
$css_class = ( $counter % 2 == 0 ) ? '' : 'alternate';
|
6883 |
|
6884 |
-
$template_variables['FailedLogins.List'] .=
|
6885 |
'FailedLogins.CssClass' => $css_class,
|
6886 |
'FailedLogins.Num' => ($counter + 1),
|
6887 |
-
'FailedLogins.Username' => $login_data['user_login'],
|
6888 |
-
'FailedLogins.RemoteAddr' => $login_data['remote_addr'],
|
6889 |
'FailedLogins.Datetime' => date('d/M/Y H:i', $login_data['attempt_time']),
|
6890 |
-
'FailedLogins.UserAgent' =>
|
6891 |
));
|
6892 |
|
6893 |
$counter += 1;
|
@@ -6904,7 +7405,7 @@ function sucuriscan_failed_logins_panel(){
|
|
6904 |
$template_variables['FailedLogins.WarningVisibility'] = 'hidden';
|
6905 |
}
|
6906 |
|
6907 |
-
return
|
6908 |
}
|
6909 |
|
6910 |
/**
|
@@ -6919,7 +7420,7 @@ function sucuriscan_failed_logins_panel(){
|
|
6919 |
* @return string The full (relative) path where the file is located.
|
6920 |
*/
|
6921 |
function sucuriscan_failed_logins_datastore_path( $reset=FALSE ){
|
6922 |
-
$datastore_path =
|
6923 |
$default_content = sucuriscan_failed_logins_default_content();
|
6924 |
|
6925 |
// Create the file if it does not exists.
|
@@ -6965,7 +7466,7 @@ function sucuriscan_get_failed_logins(){
|
|
6965 |
$default_content_n = substr_count($default_content, "\n");
|
6966 |
|
6967 |
if( $datastore_path ){
|
6968 |
-
$lines =
|
6969 |
|
6970 |
if( $lines ){
|
6971 |
$failed_logins = array(
|
@@ -6979,7 +7480,7 @@ function sucuriscan_get_failed_logins(){
|
|
6979 |
// Read and parse all the entries found in the datastore file.
|
6980 |
foreach( $lines as $i => $line ){
|
6981 |
if( $i >= $default_content_n ){
|
6982 |
-
$login_data = json_decode( trim($line), TRUE );
|
6983 |
$login_data['attempt_date'] = date('r', $login_data['attempt_time']);
|
6984 |
|
6985 |
if( !$login_data['user_agent'] ){
|
@@ -7022,8 +7523,8 @@ function sucuriscan_log_failed_login( $user_login='' ){
|
|
7022 |
$login_data = json_encode(array(
|
7023 |
'user_login' => $user_login,
|
7024 |
'attempt_time' => time(),
|
7025 |
-
'remote_addr' =>
|
7026 |
-
'user_agent' =>
|
7027 |
));
|
7028 |
|
7029 |
$logged = @file_put_contents( $datastore_path, $login_data . "\n", FILE_APPEND );
|
@@ -7045,7 +7546,7 @@ function sucuriscan_log_failed_login( $user_login='' ){
|
|
7045 |
*/
|
7046 |
function sucuriscan_report_failed_logins( $failed_logins=array() ){
|
7047 |
if( $failed_logins && $failed_logins['count'] > 0 ){
|
7048 |
-
$prettify_mails =
|
7049 |
$mail_content = '';
|
7050 |
|
7051 |
if( $prettify_mails ){
|
@@ -7081,32 +7582,482 @@ function sucuriscan_report_failed_logins( $failed_logins=array() ){
|
|
7081 |
}
|
7082 |
}
|
7083 |
|
7084 |
-
if( $prettify_mails ){
|
7085 |
-
$table_html .= '</tbody>';
|
7086 |
-
$table_html .= '</table>';
|
7087 |
-
$mail_content = $table_html;
|
7088 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
7089 |
|
7090 |
-
|
7091 |
-
|
|
|
|
|
7092 |
|
7093 |
-
|
7094 |
-
|
|
|
|
|
|
|
|
|
|
|
7095 |
}
|
7096 |
|
7097 |
-
return
|
7098 |
}
|
7099 |
|
7100 |
/**
|
7101 |
-
*
|
7102 |
-
* being kept. The execution of this function will not delete the file (which is
|
7103 |
-
* likely the best move) but rather will clean its content and append the
|
7104 |
-
* default code defined by another function above.
|
7105 |
*
|
7106 |
-
* @return
|
7107 |
*/
|
7108 |
-
function
|
7109 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
7110 |
}
|
7111 |
|
7112 |
/**
|
@@ -7119,9 +8070,10 @@ function sucuriscan_reset_failed_logins(){
|
|
7119 |
* @return void
|
7120 |
*/
|
7121 |
function sucuriscan_infosys_page(){
|
7122 |
-
|
7123 |
-
|
7124 |
-
|
|
|
7125 |
|
7126 |
// Page pseudo-variables initialization.
|
7127 |
$template_variables = array(
|
@@ -7132,7 +8084,7 @@ function sucuriscan_infosys_page(){
|
|
7132 |
'WordpressConfig' => sucuriscan_infosys_wpconfig(),
|
7133 |
);
|
7134 |
|
7135 |
-
echo
|
7136 |
}
|
7137 |
|
7138 |
/**
|
@@ -7142,7 +8094,7 @@ function sucuriscan_infosys_page(){
|
|
7142 |
* @return string The HTML code displaying the information about the HTAccess rules.
|
7143 |
*/
|
7144 |
function sucuriscan_infosys_htaccess(){
|
7145 |
-
$htaccess_path =
|
7146 |
|
7147 |
$template_variables = array(
|
7148 |
'HTAccess.Content' => '',
|
@@ -7177,7 +8129,7 @@ function sucuriscan_infosys_htaccess(){
|
|
7177 |
$template_variables['HTAccess.MessageVisible'] = 'visible';
|
7178 |
}
|
7179 |
|
7180 |
-
return
|
7181 |
}
|
7182 |
|
7183 |
/**
|
@@ -7189,7 +8141,7 @@ function sucuriscan_infosys_htaccess(){
|
|
7189 |
*/
|
7190 |
function sucuriscan_htaccess_is_standard($rules=FALSE){
|
7191 |
if( $rules===FALSE ){
|
7192 |
-
$htaccess_path =
|
7193 |
$rules = $htaccess_path ? file_get_contents($htaccess_path) : '';
|
7194 |
}
|
7195 |
|
@@ -7236,687 +8188,268 @@ function sucuriscan_infosys_wpconfig(){
|
|
7236 |
$template_variables = array(
|
7237 |
'WordpressConfig.Rules' => '',
|
7238 |
'WordpressConfig.Total' => 0,
|
7239 |
-
'WordpressConfig.Content' => '',
|
7240 |
-
'WordpressConfig.ThickboxURL' => '#TB_inline?',
|
7241 |
-
);
|
7242 |
-
$ignore_wp_rules = array('DB_PASSWORD');
|
7243 |
-
$template_variables['WordpressConfig.ThickboxURL'] .= http_build_query(array(
|
7244 |
-
'width' => '800',
|
7245 |
-
'height' => '550',
|
7246 |
-
'inlineId' => 'sucuriscan-wpconfig-content',
|
7247 |
-
));
|
7248 |
-
|
7249 |
-
$wp_config_path = sucuriscan_get_wpconfig_path();
|
7250 |
-
if( $wp_config_path ){
|
7251 |
-
add_thickbox();
|
7252 |
-
$wp_config_content = file($wp_config_path);
|
7253 |
-
$template_variables['WordpressConfig.Content'] = file_get_contents($wp_config_path);
|
7254 |
-
|
7255 |
-
// Read WordPress main configuration file as text plain.
|
7256 |
-
$wp_config_rules = array();
|
7257 |
-
foreach( (array)$wp_config_content as $line ){
|
7258 |
-
$line = str_replace("\n", '', $line);
|
7259 |
-
|
7260 |
-
// Ignore useless lines and append to the clean string the important lines.
|
7261 |
-
if( preg_match('/^define\(/', $line) ){
|
7262 |
-
$line = str_replace('define(', '', $line);
|
7263 |
-
$line = preg_replace('/\);.*/', '', $line);
|
7264 |
-
$line_parts = explode(',', $line, 2);
|
7265 |
-
}
|
7266 |
-
else if( preg_match('/^\$[a-zA-Z_]+/', $line) ){
|
7267 |
-
$line_parts = explode('=', $line, 2);
|
7268 |
-
}
|
7269 |
-
else{ continue; }
|
7270 |
-
|
7271 |
-
// Clean and append the rule to the wp_config_rules variable.
|
7272 |
-
if( isset($line_parts) && count($line_parts)==2 ){
|
7273 |
-
$key_name = $key_value = '';
|
7274 |
-
foreach($line_parts as $i=>$line_part){
|
7275 |
-
$line_part = trim($line_part);
|
7276 |
-
$line_part = ltrim($line_part, '$');
|
7277 |
-
$line_part = rtrim($line_part, ';');
|
7278 |
-
|
7279 |
-
// Remove single/double quotes at the beginning and end of the string.
|
7280 |
-
$line_part = ltrim($line_part, "'");
|
7281 |
-
$line_part = rtrim($line_part, "'");
|
7282 |
-
$line_part = ltrim($line_part, '"');
|
7283 |
-
$line_part = rtrim($line_part, '"');
|
7284 |
-
|
7285 |
-
// Assign the clean strings to specific variables.
|
7286 |
-
if( $i==0 ){ $key_name = $line_part; }
|
7287 |
-
if( $i==1 ){ $key_value = $line_part; }
|
7288 |
-
}
|
7289 |
-
|
7290 |
-
if( !in_array($key_name, $ignore_wp_rules) ){
|
7291 |
-
$wp_config_rules[$key_name] = $key_value;
|
7292 |
-
}
|
7293 |
-
}
|
7294 |
-
}
|
7295 |
-
|
7296 |
-
// Pass the WordPress configuration rules to the template and show them.
|
7297 |
-
$counter = 0;
|
7298 |
-
foreach( $wp_config_rules as $var_name=>$var_value ){
|
7299 |
-
$counter += 1;
|
7300 |
-
$template_variables['WordpressConfig.Total'] += 1;
|
7301 |
-
$template_variables['WordpressConfig.Rules'] .= sucuriscan_get_snippet('infosys-wpconfig', array(
|
7302 |
-
'WordpressConfig.VariableName' => $var_name,
|
7303 |
-
'WordpressConfig.VariableValue' => htmlentities($var_value),
|
7304 |
-
'WordpressConfig.CssClass' => ( $counter%2 == 0 ) ? '' : 'alternate'
|
7305 |
-
));
|
7306 |
-
}
|
7307 |
-
}
|
7308 |
-
|
7309 |
-
return sucuriscan_get_section('infosys-wpconfig', $template_variables);
|
7310 |
-
}
|
7311 |
-
|
7312 |
-
/**
|
7313 |
-
* Retrieve a list with the scheduled tasks configured for the site.
|
7314 |
-
*
|
7315 |
-
* @return array A list of pseudo-variables and values that will replace them in the HTML template.
|
7316 |
-
*/
|
7317 |
-
function sucuriscan_show_cronjobs(){
|
7318 |
-
$template_variables = array(
|
7319 |
-
'Cronjobs.List' => '',
|
7320 |
-
'Cronjobs.Total' => 0,
|
7321 |
-
);
|
7322 |
-
|
7323 |
-
$cronjobs = _get_cron_array();
|
7324 |
-
$schedules = wp_get_schedules();
|
7325 |
-
$date_format = _x('M j, Y - H:i', 'Publish box date format', 'cron-view' );
|
7326 |
-
$counter = 0;
|
7327 |
-
|
7328 |
-
foreach( $cronjobs as $timestamp=>$cronhooks ){
|
7329 |
-
foreach( (array)$cronhooks as $hook=>$events ){
|
7330 |
-
foreach( (array)$events as $key=>$event ){
|
7331 |
-
$counter += 1;
|
7332 |
-
$cronjob_snippet = '';
|
7333 |
-
$template_variables['Cronjobs.Total'] += 1;
|
7334 |
-
$template_variables['Cronjobs.List'] .= sucuriscan_get_snippet('infosys-cronjobs', array(
|
7335 |
-
'Cronjob.Task' => ucwords(str_replace('_',chr(32),$hook)),
|
7336 |
-
'Cronjob.Schedule' => $event['schedule'],
|
7337 |
-
'Cronjob.Nexttime' => date_i18n($date_format, $timestamp),
|
7338 |
-
'Cronjob.Hook' => $hook,
|
7339 |
-
'Cronjob.Arguments' => implode(', ', $event['args']),
|
7340 |
-
'Cronjob.CssClass' => ( $counter%2 == 0 ) ? '' : 'alternate'
|
7341 |
-
));
|
7342 |
-
}
|
7343 |
-
}
|
7344 |
-
}
|
7345 |
-
|
7346 |
-
return sucuriscan_get_section('infosys-cronjobs', $template_variables);
|
7347 |
-
}
|
7348 |
-
|
7349 |
-
/**
|
7350 |
-
* Gather information from the server, database engine, and PHP interpreter.
|
7351 |
-
*
|
7352 |
-
* @return array A list of pseudo-variables and values that will replace them in the HTML template.
|
7353 |
-
*/
|
7354 |
-
function sucuriscan_server_info(){
|
7355 |
-
global $wpdb;
|
7356 |
-
|
7357 |
-
if( current_user_can('manage_options') ){
|
7358 |
-
$memory_usage = function_exists('memory_get_usage') ? round(memory_get_usage()/1024/1024,2).' MB' : 'N/A';
|
7359 |
-
$mysql_version = $wpdb->get_var('SELECT VERSION() AS version');
|
7360 |
-
$mysql_info = $wpdb->get_results('SHOW VARIABLES LIKE "sql_mode"');
|
7361 |
-
$sql_mode = ( is_array($mysql_info) && !empty($mysql_info[0]->Value) ) ? $mysql_info[0]->Value : 'Not set';
|
7362 |
-
$runtime_scan = sucuriscan_get_option('sucuriscan_runtime');
|
7363 |
-
$runtime_scan_human = date( 'd/M/Y H:i:s', $runtime_scan );
|
7364 |
-
|
7365 |
-
$template_variables = array(
|
7366 |
-
'PluginVersion' => SUCURISCAN_VERSION,
|
7367 |
-
'PluginMD5' => SUCURISCAN_PLUGIN_CHECKSUM,
|
7368 |
-
'PluginRuntimeDatetime' => $runtime_scan_human,
|
7369 |
-
'OperatingSystem' => sprintf('%s (%d Bit)', PHP_OS, PHP_INT_SIZE*8),
|
7370 |
-
'Server' => isset($_SERVER['SERVER_SOFTWARE']) ? $_SERVER['SERVER_SOFTWARE'] : 'Unknown',
|
7371 |
-
'MemoryUsage' => $memory_usage,
|
7372 |
-
'MySQLVersion' => $mysql_version,
|
7373 |
-
'SQLMode' => $sql_mode,
|
7374 |
-
'PHPVersion' => PHP_VERSION,
|
7375 |
-
);
|
7376 |
-
|
7377 |
-
$field_names = array(
|
7378 |
-
'safe_mode',
|
7379 |
-
'allow_url_fopen',
|
7380 |
-
'memory_limit',
|
7381 |
-
'upload_max_filesize',
|
7382 |
-
'post_max_size',
|
7383 |
-
'max_execution_time',
|
7384 |
-
'max_input_time',
|
7385 |
-
);
|
7386 |
-
|
7387 |
-
foreach( $field_names as $php_flag ){
|
7388 |
-
$php_flag_name = ucwords(str_replace('_', chr(32), $php_flag) );
|
7389 |
-
$tpl_varname = str_replace(chr(32), '', $php_flag_name);
|
7390 |
-
$php_flag_value = ini_get($php_flag);
|
7391 |
-
$template_variables[$tpl_varname] = $php_flag_value ? $php_flag_value : 'N/A';
|
7392 |
-
}
|
7393 |
-
}
|
7394 |
-
|
7395 |
-
return sucuriscan_get_section('infosys-serverinfo', $template_variables);
|
7396 |
-
}
|
7397 |
-
|
7398 |
-
/**
|
7399 |
-
* Global variables used by the functions bellow.
|
7400 |
-
*
|
7401 |
-
* These are lists of options allowed to use in the execution of the monitoring
|
7402 |
-
* tool, and the administrator can select among them in the settings page.
|
7403 |
-
*
|
7404 |
-
* @var array
|
7405 |
-
*/
|
7406 |
-
$sucuriscan_notify_options = array(
|
7407 |
-
'sucuriscan_notify_user_registration' => 'Enable email alerts for new user registration',
|
7408 |
-
'sucuriscan_notify_success_login' => 'Enable email alerts for successful logins',
|
7409 |
-
'sucuriscan_notify_failed_login' => 'Enable email alerts for failed logins',
|
7410 |
-
'sucuriscan_notify_bruteforce_attack' => 'Enable email alerts for login brute-force attack',
|
7411 |
-
'sucuriscan_notify_post_publication' => 'Enable email alerts for new site content',
|
7412 |
-
'sucuriscan_notify_theme_editor' => 'Enable email alerts when a file is modified via the theme/plugin editor',
|
7413 |
-
'sucuriscan_notify_website_updated' => 'Enable email alerts when your website is updated',
|
7414 |
-
'sucuriscan_notify_settings_updated' => 'Enable email alerts when your website settings are updated',
|
7415 |
-
'sucuriscan_notify_theme_switched' => 'Enable email alerts when the website theme is switched',
|
7416 |
-
'sucuriscan_notify_theme_updated' => 'Enable email alerts when a theme is updated',
|
7417 |
-
'sucuriscan_notify_widget_added' => 'Enable email alerts when a widget is added to a sidebar',
|
7418 |
-
'sucuriscan_notify_widget_deleted' => 'Enable email alerts when a widget is deleted from a sidebar',
|
7419 |
-
'sucuriscan_notify_plugin_change' => 'Enable email alerts for Sucuri plugin changes',
|
7420 |
-
'sucuriscan_notify_plugin_activated' => 'Enable email alerts when a plugin is activated',
|
7421 |
-
'sucuriscan_notify_plugin_deactivated' => 'Enable email alerts when a plugin is deactivated',
|
7422 |
-
'sucuriscan_notify_plugin_updated' => 'Enable email alerts when a plugin is updated',
|
7423 |
-
'sucuriscan_notify_plugin_installed' => 'Enable email alerts when a plugin is installed',
|
7424 |
-
'sucuriscan_notify_plugin_deleted' => 'Enable email alerts when a plugin is deleted',
|
7425 |
-
'sucuriscan_prettify_mails' => 'Enable email alerts in HTML (uncheck to get email in text/plain)',
|
7426 |
-
'sucuriscan_lastlogin_redirection' => 'Allow redirection after login to report the last-login information',
|
7427 |
-
);
|
7428 |
-
|
7429 |
-
$sucuriscan_schedule_allowed = array(
|
7430 |
-
'hourly' => 'Every three hours (3 hours)',
|
7431 |
-
'twicedaily' => 'Twice daily (12 hours)',
|
7432 |
-
'daily' => 'Once daily (24 hours)',
|
7433 |
-
'_oneoff' => 'Never',
|
7434 |
-
);
|
7435 |
-
|
7436 |
-
$sucuriscan_interface_allowed = array(
|
7437 |
-
'spl' => 'SPL (high performance)',
|
7438 |
-
'opendir' => 'OpenDir (medium)',
|
7439 |
-
'glob' => 'Glob (low)',
|
7440 |
-
);
|
7441 |
-
|
7442 |
-
$sucuriscan_emails_per_hour = array(
|
7443 |
-
'5' => 'Maximum 5 per hour',
|
7444 |
-
'10' => 'Maximum 10 per hour',
|
7445 |
-
'20' => 'Maximum 20 per hour',
|
7446 |
-
'40' => 'Maximum 40 per hour',
|
7447 |
-
'80' => 'Maximum 80 per hour',
|
7448 |
-
'160' => 'Maximum 160 per hour',
|
7449 |
-
'unlimited' => 'Unlimited',
|
7450 |
-
);
|
7451 |
-
|
7452 |
-
$sucuriscan_maximum_failed_logins = array(
|
7453 |
-
'30' => '30 failed logins per hour',
|
7454 |
-
'60' => '60 failed logins per hour',
|
7455 |
-
'120' => '120 failed logins per hour',
|
7456 |
-
'240' => '240 failed logins per hour',
|
7457 |
-
'480' => '480 failed logins per hour',
|
7458 |
-
);
|
7459 |
-
|
7460 |
-
$sucuriscan_verify_ssl_cert = array(
|
7461 |
-
'true' => 'Verify peer\'s cert',
|
7462 |
-
'false' => 'Stop peer\'s cert verification',
|
7463 |
-
);
|
7464 |
-
|
7465 |
-
/**
|
7466 |
-
* Print a HTML code with the settings of the plugin.
|
7467 |
-
*
|
7468 |
-
* @return void
|
7469 |
-
*/
|
7470 |
-
function sucuriscan_settings_page(){
|
7471 |
-
$template_variables = array(
|
7472 |
-
'PageTitle' => 'Settings',
|
7473 |
-
'Settings.General' => sucuriscan_settings_general(),
|
7474 |
-
'Settings.Notifications' => sucuriscan_settings_notifications(),
|
7475 |
-
'Settings.IgnoreRules' => sucuriscan_settings_ignore_rules(),
|
7476 |
);
|
7477 |
|
7478 |
-
|
7479 |
-
|
7480 |
-
|
7481 |
-
/**
|
7482 |
-
* Process the requests sent by the form submissions originated in the settings
|
7483 |
-
* page, all forms must have a nonce field that will be checked against the one
|
7484 |
-
* generated in the template render function.
|
7485 |
-
*
|
7486 |
-
* @param boolean $page_nonce True if the nonce is valid, False otherwise.
|
7487 |
-
* @return void
|
7488 |
-
*/
|
7489 |
-
function sucuriscan_settings_form_submissions( $page_nonce=NULL ){
|
7490 |
-
|
7491 |
-
global $sucuriscan_schedule_allowed,
|
7492 |
-
$sucuriscan_interface_allowed,
|
7493 |
-
$sucuriscan_notify_options,
|
7494 |
-
$sucuriscan_emails_per_hour,
|
7495 |
-
$sucuriscan_maximum_failed_logins,
|
7496 |
-
$sucuriscan_verify_ssl_cert;
|
7497 |
-
|
7498 |
-
// Use this conditional to avoid double checking.
|
7499 |
-
if( is_null($page_nonce) ){
|
7500 |
-
$page_nonce = sucuriscan_check_page_nonce();
|
7501 |
-
}
|
7502 |
-
|
7503 |
-
if( $page_nonce ){
|
7504 |
-
|
7505 |
-
// Recover API key through the email registered previously.
|
7506 |
-
if( isset($_POST['sucuriscan_recover_api_key']) ){
|
7507 |
-
sucuriscan_recover_api_key();
|
7508 |
-
}
|
7509 |
-
|
7510 |
-
// Save API key after it was recovered by the administrator.
|
7511 |
-
if( isset($_POST['sucuriscan_manual_api_key']) ){
|
7512 |
-
sucuriscan_set_api_key( $_POST['sucuriscan_manual_api_key'], TRUE );
|
7513 |
-
sucuriscan_create_scheduled_task();
|
7514 |
-
}
|
7515 |
-
|
7516 |
-
// Remove API key from the local storage.
|
7517 |
-
if( isset($_POST['sucuriscan_remove_api_key']) ){
|
7518 |
-
sucuriscan_set_api_key('');
|
7519 |
-
wp_clear_scheduled_hook('sucuriscan_scheduled_scan');
|
7520 |
-
sucuriscan_notify_event( 'plugin_change', 'Sucuri API key removed' );
|
7521 |
-
}
|
7522 |
-
|
7523 |
-
// Modify the schedule of the filesystem scanner.
|
7524 |
-
if(
|
7525 |
-
isset($_POST['sucuriscan_scan_frequency'])
|
7526 |
-
&& isset($sucuriscan_schedule_allowed)
|
7527 |
-
){
|
7528 |
-
$frequency = $_POST['sucuriscan_scan_frequency'];
|
7529 |
-
$current_frequency = sucuriscan_get_option('sucuriscan_scan_frequency');
|
7530 |
-
$allowed_frequency = array_keys($sucuriscan_schedule_allowed);
|
7531 |
-
|
7532 |
-
if( in_array($frequency, $allowed_frequency) && $current_frequency != $frequency ){
|
7533 |
-
update_option('sucuriscan_scan_frequency', $frequency);
|
7534 |
-
wp_clear_scheduled_hook('sucuriscan_scheduled_scan');
|
7535 |
-
|
7536 |
-
if( $frequency != '_oneoff' ){
|
7537 |
-
wp_schedule_event( time()+10, $frequency, 'sucuriscan_scheduled_scan' );
|
7538 |
-
}
|
7539 |
-
|
7540 |
-
sucuriscan_notify_event( 'plugin_change', 'Filesystem scanning frequency changed to: ' . $frequency );
|
7541 |
-
sucuriscan_info( 'Filesystem scan scheduled to run <code>'.$frequency.'</code>' );
|
7542 |
-
}
|
7543 |
-
}
|
7544 |
-
|
7545 |
-
// Set the method (aka. interface) that will be used to scan the site.
|
7546 |
-
if(
|
7547 |
-
isset($_POST['sucuriscan_scan_interface'])
|
7548 |
-
&& isset($sucuriscan_interface_allowed)
|
7549 |
-
){
|
7550 |
-
$interface = trim($_POST['sucuriscan_scan_interface']);
|
7551 |
-
$allowed_values = array_keys($sucuriscan_interface_allowed);
|
7552 |
-
|
7553 |
-
if( in_array($interface, $allowed_values) ){
|
7554 |
-
update_option('sucuriscan_scan_interface', $interface);
|
7555 |
-
sucuriscan_notify_event( 'plugin_change', 'Filesystem scanning interface changed to: ' . $interface );
|
7556 |
-
sucuriscan_info( 'Filesystem scan interface set to <code>'.$interface.'</code>' );
|
7557 |
-
}
|
7558 |
-
}
|
7559 |
|
7560 |
-
|
7561 |
-
|
7562 |
-
|
7563 |
|
7564 |
-
|
7565 |
-
|
7566 |
-
|
7567 |
-
|
7568 |
-
|
7569 |
-
|
7570 |
-
sucuriscan_error( 'Invalid value for the maximum emails per hour.' );
|
7571 |
}
|
7572 |
-
}
|
7573 |
-
|
7574 |
-
// Update the email where the event notifications will be sent.
|
7575 |
-
if( isset($_POST['sucuriscan_notify_to']) ){
|
7576 |
-
$new_email = esc_attr($_POST['sucuriscan_notify_to']);
|
7577 |
|
7578 |
-
|
7579 |
-
|
7580 |
-
|
7581 |
-
sucuriscan_info( 'All the event notifications will be sent to the email specified.' );
|
7582 |
-
} else {
|
7583 |
-
sucuriscan_error( 'Email format not supported.' );
|
7584 |
}
|
7585 |
-
}
|
7586 |
|
7587 |
-
|
7588 |
-
|
7589 |
-
$failed_logins = esc_attr($_POST['sucuriscan_maximum_failed_logins']);
|
7590 |
|
7591 |
-
|
7592 |
-
|
7593 |
-
|
7594 |
-
|
7595 |
-
'A brute-force attack event will be reported if there are more than '
|
7596 |
-
. '<code>' . $failed_logins . '</code> failed logins per hour.'
|
7597 |
-
);
|
7598 |
-
} else {
|
7599 |
-
sucuriscan_error( 'Invalid value for the maximum failed logins per hour before consider it a brute-force attack.' );
|
7600 |
-
}
|
7601 |
-
}
|
7602 |
|
7603 |
-
|
7604 |
-
|
7605 |
-
|
|
|
|
|
7606 |
|
7607 |
-
|
7608 |
-
|
7609 |
-
|
7610 |
-
|
7611 |
-
|
7612 |
-
sucuriscan_notify_event( 'plugin_change', $message );
|
7613 |
-
sucuriscan_info( $message );
|
7614 |
-
} else {
|
7615 |
-
sucuriscan_error( 'Invalid value for the SSL certificate verification.' );
|
7616 |
-
}
|
7617 |
-
}
|
7618 |
|
7619 |
-
|
7620 |
-
|
7621 |
-
|
7622 |
-
|
7623 |
-
|
7624 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
7625 |
|
7626 |
-
|
7627 |
-
if(
|
7628 |
-
$
|
7629 |
-
update_option( $alert_type, $option_value );
|
7630 |
-
$options_updated_counter += 1;
|
7631 |
}
|
7632 |
-
}
|
7633 |
|
7634 |
-
|
7635 |
-
|
7636 |
-
sucuriscan_info( 'Notification settings updated.' );
|
7637 |
}
|
7638 |
}
|
7639 |
|
7640 |
-
//
|
7641 |
-
|
7642 |
-
|
7643 |
-
$
|
7644 |
-
|
7645 |
-
sucuriscan_notify_event( 'plugin_change', $event_msg );
|
7646 |
-
|
7647 |
-
// Remove all plugin's options from the database.
|
7648 |
-
$options = sucuriscan_get_options_from_db('all_sucuriscan_options');
|
7649 |
|
7650 |
-
|
7651 |
-
|
|
|
7652 |
}
|
7653 |
|
7654 |
-
|
7655 |
-
|
|
|
7656 |
|
7657 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
7658 |
}
|
|
|
7659 |
|
7660 |
-
|
7661 |
-
|
7662 |
-
isset($_POST['sucuriscan_ignorerule_action'])
|
7663 |
-
&& isset($_POST['sucuriscan_ignorerule'])
|
7664 |
-
){
|
7665 |
-
if( $_POST['sucuriscan_ignorerule_action'] == 'add' ){
|
7666 |
-
$event_ignored = sucuriscan_add_ignored_event( $_POST['sucuriscan_ignorerule'] );
|
7667 |
|
7668 |
-
|
7669 |
-
|
7670 |
-
|
7671 |
-
|
7672 |
-
|
7673 |
-
|
7674 |
-
|
7675 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
7676 |
}
|
7677 |
}
|
7678 |
-
|
7679 |
}
|
7680 |
|
|
|
7681 |
}
|
7682 |
|
7683 |
/**
|
7684 |
-
*
|
|
|
|
|
7685 |
*
|
7686 |
-
* @
|
|
|
7687 |
*/
|
7688 |
-
function
|
7689 |
-
|
7690 |
-
global $sucuriscan_schedule_allowed,
|
7691 |
-
$sucuriscan_interface_allowed,
|
7692 |
-
$sucuriscan_emails_per_hour,
|
7693 |
-
$sucuriscan_maximum_failed_logins,
|
7694 |
-
$sucuriscan_verify_ssl_cert;
|
7695 |
-
|
7696 |
-
// Check the nonce here to populate the value through other functions.
|
7697 |
-
$page_nonce = sucuriscan_check_page_nonce();
|
7698 |
-
|
7699 |
-
// Process all form submissions.
|
7700 |
-
sucuriscan_settings_form_submissions($page_nonce);
|
7701 |
|
7702 |
-
|
7703 |
-
|
7704 |
|
7705 |
-
|
7706 |
-
|
7707 |
|
7708 |
-
|
7709 |
-
|
7710 |
|
7711 |
-
|
7712 |
-
|
7713 |
-
|
7714 |
-
|
7715 |
-
|
7716 |
-
|
7717 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
7718 |
}
|
7719 |
-
}
|
7720 |
-
|
7721 |
-
// Get initial variables to decide some things bellow.
|
7722 |
-
$api_key = sucuriscan_wordpress_apikey();
|
7723 |
-
$scan_freq = sucuriscan_get_option('sucuriscan_scan_frequency');
|
7724 |
-
$scan_interface = sucuriscan_get_option('sucuriscan_scan_interface');
|
7725 |
-
$emails_per_hour = sucuriscan_get_option('sucuriscan_emails_per_hour');
|
7726 |
-
$maximum_failed_logins = sucuriscan_get_option('sucuriscan_maximum_failed_logins');
|
7727 |
-
$verify_ssl_cert = sucuriscan_get_option('sucuriscan_verify_ssl_cert');
|
7728 |
-
$runtime_scan = sucuriscan_get_option('sucuriscan_runtime');
|
7729 |
-
$runtime_scan_human = date( 'd/M/Y H:i:s', $runtime_scan );
|
7730 |
-
|
7731 |
-
// Generate HTML code to configure the scanning frequency from the plugin settings.
|
7732 |
-
$scan_freq_options = '';
|
7733 |
-
foreach( $sucuriscan_schedule_allowed as $schedule => $schedule_label ){
|
7734 |
-
$selected = ( $scan_freq==$schedule ? 'selected="selected"' : '' );
|
7735 |
-
$scan_freq_options .= sprintf(
|
7736 |
-
'<option value="%s" %s>%s</option>',
|
7737 |
-
$schedule, $selected, $schedule_label
|
7738 |
-
);
|
7739 |
-
}
|
7740 |
|
7741 |
-
// Generate HTML code to configure the scanning interface from the plugin settings.
|
7742 |
-
$scan_interface_options = '';
|
7743 |
-
foreach( $sucuriscan_interface_allowed as $interface_name => $interface_desc ){
|
7744 |
-
$selected = ( $scan_interface == $interface_name ? 'selected="selected"' : '' );
|
7745 |
-
$scan_interface_options .= sprintf(
|
7746 |
-
'<option value="%s" %s>%s</option>',
|
7747 |
-
$interface_name,
|
7748 |
-
$selected,
|
7749 |
-
$interface_desc
|
7750 |
-
);
|
7751 |
-
}
|
7752 |
-
|
7753 |
-
// Generate the HTML code to configure the emails per hour.
|
7754 |
-
$emails_per_hour_options = '';
|
7755 |
-
foreach( $sucuriscan_emails_per_hour as $per_hour => $per_hour_label ){
|
7756 |
-
$selected = ( $emails_per_hour == $per_hour ? 'selected="selected"' : '' );
|
7757 |
-
$emails_per_hour_options .= sprintf(
|
7758 |
-
'<option value="%s" %s>%s</option>',
|
7759 |
-
$per_hour,
|
7760 |
-
$selected,
|
7761 |
-
$per_hour_label
|
7762 |
-
);
|
7763 |
-
}
|
7764 |
-
|
7765 |
-
// Generate the HTML code to configure the emails per hour.
|
7766 |
-
$maximum_failed_logins_options = '';
|
7767 |
-
foreach( $sucuriscan_maximum_failed_logins as $per_hour => $per_hour_label ){
|
7768 |
-
$selected = ( $maximum_failed_logins == $per_hour ? 'selected="selected"' : '' );
|
7769 |
-
$maximum_failed_logins_options .= sprintf(
|
7770 |
-
'<option value="%s" %s>%s</option>',
|
7771 |
-
$per_hour,
|
7772 |
-
$selected,
|
7773 |
-
$per_hour_label
|
7774 |
-
);
|
7775 |
}
|
|
|
7776 |
|
7777 |
-
|
7778 |
-
|
7779 |
-
|
7780 |
-
|
7781 |
-
|
7782 |
-
|
7783 |
-
|
7784 |
-
$selected,
|
7785 |
-
$verify_label
|
7786 |
-
);
|
7787 |
-
}
|
7788 |
|
7789 |
$template_variables = array(
|
7790 |
-
'
|
7791 |
-
'APIKey.RecoverVisibility' => ( $api_key || $display_manual_key_form ? 'hidden' : 'visible' ),
|
7792 |
-
'APIKey.ManualKeyFormVisibility' => ( $display_manual_key_form ? 'visible' : 'hidden' ),
|
7793 |
-
'APIKey.RemoveVisibility' => ( $api_key ? 'visible' : 'hidden' ),
|
7794 |
-
'ScanningFrequency' => 'Undefined',
|
7795 |
-
'ScanningFrequencyOptions' => $scan_freq_options,
|
7796 |
-
'ScanningInterface' => ( $scan_interface ? $sucuriscan_interface_allowed[$scan_interface] : 'Undefined' ),
|
7797 |
-
'ScanningInterfaceOptions' => $scan_interface_options,
|
7798 |
-
'ScanningInterfaceVisibility' => ( SucuriScanFileInfo::is_spl_available() ? 'hidden' : 'visible' ),
|
7799 |
-
'ScanningRuntime' => $runtime_scan,
|
7800 |
-
'ScanningRuntimeHuman' => $runtime_scan_human,
|
7801 |
-
'ModalWhenAPIRegistered' => $api_registered_modal,
|
7802 |
-
'NotifyTo' => sucuriscan_get_option('sucuriscan_notify_to'),
|
7803 |
-
'EmailsPerHour' => 'Undefined',
|
7804 |
-
'EmailsPerHourOptions' => $emails_per_hour_options,
|
7805 |
-
'MaximumFailedLogins' => 'Undefined',
|
7806 |
-
'MaximumFailedLoginsOptions' => $maximum_failed_logins_options,
|
7807 |
-
'VerifySSLCert' => 'Undefined',
|
7808 |
-
'VerifySSLCertOptions' => $verify_ssl_cert_options,
|
7809 |
-
'ModalWhenAPIRegistered' => $api_registered_modal,
|
7810 |
);
|
7811 |
|
7812 |
-
|
7813 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
7814 |
}
|
7815 |
|
7816 |
-
if(
|
7817 |
-
$
|
7818 |
}
|
7819 |
|
7820 |
-
if(
|
7821 |
-
$
|
7822 |
}
|
7823 |
|
7824 |
-
if(
|
7825 |
-
$
|
7826 |
}
|
7827 |
|
7828 |
-
|
7829 |
-
|
7830 |
|
7831 |
-
|
7832 |
-
|
7833 |
-
|
7834 |
-
|
7835 |
-
|
7836 |
-
function sucuriscan_settings_notifications(){
|
7837 |
-
global $sucuriscan_notify_options;
|
7838 |
|
7839 |
-
$
|
7840 |
-
'
|
|
|
|
|
|
|
|
|
|
|
|
|
7841 |
);
|
7842 |
|
|
|
|
|
|
|
|
|
|
|
|
|
7843 |
$counter = 0;
|
7844 |
|
7845 |
-
foreach( $
|
7846 |
-
$
|
7847 |
-
$
|
7848 |
-
$css_class = ( $counter % 2 == 0 ) ? 'alternate' : '';
|
7849 |
|
7850 |
-
$template_variables['
|
7851 |
-
'
|
7852 |
-
'
|
7853 |
-
'
|
7854 |
-
'Notification.Label' => $alert_label,
|
7855 |
));
|
7856 |
$counter += 1;
|
7857 |
}
|
7858 |
|
7859 |
-
return
|
7860 |
-
}
|
7861 |
-
|
7862 |
-
/**
|
7863 |
-
* Read and parse the content of the ignored-rules settings template.
|
7864 |
-
*
|
7865 |
-
* @return string Parsed HTML code for the ignored-rules settings panel.
|
7866 |
-
*/
|
7867 |
-
function sucuriscan_settings_ignore_rules(){
|
7868 |
-
$notify_new_site_content = sucuriscan_get_option('sucuriscan_notify_post_publication');
|
7869 |
-
|
7870 |
-
$template_variables = array(
|
7871 |
-
'IgnoreRules.MessageVisibility' => 'visible',
|
7872 |
-
'IgnoreRules.TableVisibility' => 'hidden',
|
7873 |
-
'IgnoreRules.PostTypes' => '',
|
7874 |
-
);
|
7875 |
-
|
7876 |
-
if( $notify_new_site_content == 'enabled' ){
|
7877 |
-
$post_types = get_post_types();
|
7878 |
-
$ignored_events = sucuriscan_get_ignored_events();
|
7879 |
-
|
7880 |
-
$template_variables['IgnoreRules.MessageVisibility'] = 'hidden';
|
7881 |
-
$template_variables['IgnoreRules.TableVisibility'] = 'visible';
|
7882 |
-
$counter = 0;
|
7883 |
-
|
7884 |
-
foreach( $post_types as $post_type => $post_type_object ){
|
7885 |
-
$counter += 1;
|
7886 |
-
$css_class = ( $counter % 2 == 0 ) ? 'alternate' : '';
|
7887 |
-
$post_type_title = ucwords( str_replace('_', chr(32), $post_type) );
|
7888 |
-
|
7889 |
-
if( array_key_exists($post_type, $ignored_events) ){
|
7890 |
-
$is_ignored_text = 'YES';
|
7891 |
-
$was_ignored_at = @date('d/M/Y - H:i:s', $ignored_events[$post_type]);
|
7892 |
-
$is_ignored_class = 'danger';
|
7893 |
-
$button_action = 'remove';
|
7894 |
-
$button_class = 'button-primary';
|
7895 |
-
$button_text = 'Allow';
|
7896 |
-
} else {
|
7897 |
-
$is_ignored_text = 'NO';
|
7898 |
-
$button_action = 'add';
|
7899 |
-
$was_ignored_at = 'Not ignored';
|
7900 |
-
$is_ignored_class = 'success';
|
7901 |
-
$button_class = 'button-primary button-danger';
|
7902 |
-
$button_text = 'Ignore';
|
7903 |
-
}
|
7904 |
-
|
7905 |
-
$template_variables['IgnoreRules.PostTypes'] .= sucuriscan_get_snippet('settings-ignorerules', array(
|
7906 |
-
'IgnoreRules.CssClass' => $css_class,
|
7907 |
-
'IgnoreRules.Num' => $counter,
|
7908 |
-
'IgnoreRules.PostTypeTitle' => $post_type_title,
|
7909 |
-
'IgnoreRules.IsIgnored' => $is_ignored_text,
|
7910 |
-
'IgnoreRules.WasIgnoredAt' => $was_ignored_at,
|
7911 |
-
'IgnoreRules.IsIgnoredClass' => $is_ignored_class,
|
7912 |
-
'IgnoreRules.PostType' => $post_type,
|
7913 |
-
'IgnoreRules.Action' => $button_action,
|
7914 |
-
'IgnoreRules.ButtonClass' => 'button ' . $button_class,
|
7915 |
-
'IgnoreRules.ButtonText' => $button_text,
|
7916 |
-
));
|
7917 |
-
}
|
7918 |
-
}
|
7919 |
-
|
7920 |
-
return sucuriscan_get_section('settings-ignorerules', $template_variables);
|
7921 |
}
|
7922 |
|
4 |
Plugin URI: http://wordpress.sucuri.net/
|
5 |
Description: The <a href="http://sucuri.net/" target="_blank">Sucuri Security</a> <em>(Auditing, Malware Scanner and Hardening)</em> plugin enables you to scan your WordPress site using <a href="http://sitecheck.sucuri.net/" target="_blank">Sucuri SiteCheck</a> right in your dashboard. SiteCheck will check for malware, spam, blacklisting and other security issues like .htaccess redirects, hidden eval code, etc. The best thing about it is it's completely free.
|
6 |
Author: Sucuri, INC
|
7 |
+
Version: 1.6.6
|
8 |
Author URI: http://sucuri.net
|
9 |
*/
|
10 |
|
12 |
/**
|
13 |
* Main file to control the plugin.
|
14 |
*
|
15 |
+
* @package Sucuri Security
|
16 |
* @author Yorman Arias <yorman.arias@sucuri.net>
|
17 |
* @author Daniel Cid <dcid@sucuri.net>
|
18 |
* @copyright Since 2010-2014 Sucuri Inc.
|
22 |
*/
|
23 |
|
24 |
|
25 |
+
/**
|
26 |
+
* Plugin dependencies.
|
27 |
+
*
|
28 |
+
* List of required functions for the execution of this plugin, we are assuming
|
29 |
+
* that this site was built on top of the WordPress project, and that it is
|
30 |
+
* being loaded through a pluggable system, these functions most be defined
|
31 |
+
* before to continue.
|
32 |
+
*
|
33 |
+
* @var array
|
34 |
+
*/
|
35 |
+
$sucuriscan_dependencies = array(
|
36 |
+
'wp',
|
37 |
+
'wp_die',
|
38 |
+
'add_action',
|
39 |
+
'remove_action',
|
40 |
+
'wp_remote_get',
|
41 |
+
'wp_remote_post',
|
42 |
+
);
|
43 |
+
|
44 |
+
// Terminate execution if any of the functions mentioned above is not defined.
|
45 |
+
foreach( $sucuriscan_dependencies as $dependency ){
|
46 |
+
if( !function_exists($dependency) ){
|
47 |
+
exit(0);
|
48 |
+
}
|
49 |
}
|
50 |
|
51 |
/**
|
52 |
+
* Plugin's constants.
|
53 |
+
*
|
54 |
+
* These constants will hold the basic information of the plugin, file/folder
|
55 |
+
* paths, version numbers, read-only variables that will affect the functioning
|
56 |
+
* of the rest of the code. The conditional will act as a container helping in
|
57 |
+
* the readability of the code considering the total number of lines that this
|
58 |
+
* file will have.
|
59 |
*/
|
|
|
60 |
|
61 |
/**
|
62 |
+
* Unique name of the plugin through out all the code.
|
63 |
*/
|
64 |
+
define('SUCURISCAN', 'sucuriscan');
|
65 |
|
66 |
/**
|
67 |
+
* Current version of the plugin's code.
|
68 |
*/
|
69 |
+
define('SUCURISCAN_VERSION', '1.6.6');
|
70 |
|
71 |
/**
|
72 |
* The name of the Sucuri plugin main file.
|
88 |
*/
|
89 |
define('SUCURISCAN_PLUGIN_FILEPATH', SUCURISCAN_PLUGIN_PATH.'/'.SUCURISCAN_PLUGIN_FILE);
|
90 |
|
91 |
+
/**
|
92 |
+
* The local URL where the plugin's files and assets are served.
|
93 |
+
*/
|
94 |
+
define('SUCURISCAN_URL', rtrim(plugin_dir_url(SUCURISCAN_PLUGIN_FILEPATH), '/') );
|
95 |
+
|
96 |
/**
|
97 |
* Checksum of this file to check the integrity of the plugin.
|
98 |
*/
|
143 |
*/
|
144 |
define('SUCURISCAN_GET_PLUGINS_LIFETIME', 1800);
|
145 |
|
146 |
+
/**
|
147 |
+
* Plugin's global variables.
|
148 |
+
*
|
149 |
+
* These variables will be defined globally to allow the inclusion in multiple
|
150 |
+
* functions and classes defined in the libraries loaded by this plugin. The
|
151 |
+
* conditional will act as a container helping in the readability of the code
|
152 |
+
* considering the total number of lines that this file will have.
|
153 |
+
*/
|
154 |
+
if( defined('SUCURISCAN') ){
|
155 |
+
|
156 |
+
/**
|
157 |
+
* List an associative array with the sub-pages of this plugin.
|
158 |
+
*
|
159 |
+
* @return array
|
160 |
+
*/
|
161 |
+
$sucuriscan_pages = array(
|
162 |
+
'sucuriscan' => 'Dashboard',
|
163 |
+
'sucuriscan_scanner' => 'Malware Scan',
|
164 |
+
'sucuriscan_monitoring' => 'Firewall (WAF)',
|
165 |
+
'sucuriscan_hardening' => 'Hardening',
|
166 |
+
'sucuriscan_posthack' => 'Post-Hack',
|
167 |
+
'sucuriscan_lastlogins' => 'Last Logins',
|
168 |
+
'sucuriscan_settings' => 'Settings',
|
169 |
+
'sucuriscan_infosys' => 'Site Info',
|
170 |
+
);
|
171 |
+
|
172 |
+
/**
|
173 |
+
* Settings options.
|
174 |
+
*
|
175 |
+
* The following global variables are mostly associative arrays where the key is
|
176 |
+
* linked to an option that will be stored in the database, and their
|
177 |
+
* correspondent values are the description of the option. These variables will
|
178 |
+
* be used in the settings page to offer the user a way to configure the
|
179 |
+
* behaviour of the plugin.
|
180 |
+
*
|
181 |
+
* @var array
|
182 |
+
*/
|
183 |
+
|
184 |
+
$sucuriscan_notify_options = array(
|
185 |
+
'sucuriscan_notify_user_registration' => 'Enable email alerts for new user registration',
|
186 |
+
'sucuriscan_notify_success_login' => 'Enable email alerts for successful logins',
|
187 |
+
'sucuriscan_notify_failed_login' => 'Enable email alerts for failed logins',
|
188 |
+
'sucuriscan_notify_bruteforce_attack' => 'Enable email alerts for login brute-force attack',
|
189 |
+
'sucuriscan_notify_post_publication' => 'Enable email alerts for new site content',
|
190 |
+
'sucuriscan_notify_theme_editor' => 'Enable email alerts when a file is modified via the theme/plugin editor',
|
191 |
+
'sucuriscan_notify_website_updated' => 'Enable email alerts when your website is updated',
|
192 |
+
'sucuriscan_notify_settings_updated' => 'Enable email alerts when your website settings are updated',
|
193 |
+
'sucuriscan_notify_theme_switched' => 'Enable email alerts when the website theme is switched',
|
194 |
+
'sucuriscan_notify_theme_updated' => 'Enable email alerts when a theme is updated',
|
195 |
+
'sucuriscan_notify_widget_added' => 'Enable email alerts when a widget is added to a sidebar',
|
196 |
+
'sucuriscan_notify_widget_deleted' => 'Enable email alerts when a widget is deleted from a sidebar',
|
197 |
+
'sucuriscan_notify_plugin_change' => 'Enable email alerts for Sucuri plugin changes',
|
198 |
+
'sucuriscan_notify_plugin_activated' => 'Enable email alerts when a plugin is activated',
|
199 |
+
'sucuriscan_notify_plugin_deactivated' => 'Enable email alerts when a plugin is deactivated',
|
200 |
+
'sucuriscan_notify_plugin_updated' => 'Enable email alerts when a plugin is updated',
|
201 |
+
'sucuriscan_notify_plugin_installed' => 'Enable email alerts when a plugin is installed',
|
202 |
+
'sucuriscan_notify_plugin_deleted' => 'Enable email alerts when a plugin is deleted',
|
203 |
+
'sucuriscan_prettify_mails' => 'Enable email alerts in HTML (uncheck to get email in text/plain)',
|
204 |
+
'sucuriscan_lastlogin_redirection' => 'Allow redirection after login to report the last-login information',
|
205 |
+
);
|
206 |
+
|
207 |
+
$sucuriscan_schedule_allowed = array(
|
208 |
+
'hourly' => 'Every three hours (3 hours)',
|
209 |
+
'twicedaily' => 'Twice daily (12 hours)',
|
210 |
+
'daily' => 'Once daily (24 hours)',
|
211 |
+
'_oneoff' => 'Never',
|
212 |
+
);
|
213 |
+
|
214 |
+
$sucuriscan_interface_allowed = array(
|
215 |
+
'spl' => 'SPL (high performance)',
|
216 |
+
'opendir' => 'OpenDir (medium)',
|
217 |
+
'glob' => 'Glob (low)',
|
218 |
+
);
|
219 |
+
|
220 |
+
$sucuriscan_emails_per_hour = array(
|
221 |
+
'5' => 'Maximum 5 per hour',
|
222 |
+
'10' => 'Maximum 10 per hour',
|
223 |
+
'20' => 'Maximum 20 per hour',
|
224 |
+
'40' => 'Maximum 40 per hour',
|
225 |
+
'80' => 'Maximum 80 per hour',
|
226 |
+
'160' => 'Maximum 160 per hour',
|
227 |
+
'unlimited' => 'Unlimited',
|
228 |
+
);
|
229 |
+
|
230 |
+
$sucuriscan_maximum_failed_logins = array(
|
231 |
+
'30' => '30 failed logins per hour',
|
232 |
+
'60' => '60 failed logins per hour',
|
233 |
+
'120' => '120 failed logins per hour',
|
234 |
+
'240' => '240 failed logins per hour',
|
235 |
+
'480' => '480 failed logins per hour',
|
236 |
+
);
|
237 |
+
|
238 |
+
$sucuriscan_verify_ssl_cert = array(
|
239 |
+
'true' => 'Verify peer\'s cert',
|
240 |
+
'false' => 'Stop peer\'s cert verification',
|
241 |
+
);
|
242 |
+
|
243 |
+
/**
|
244 |
+
* Remove the WordPress generator meta-tag from the source code.
|
245 |
+
*/
|
246 |
+
remove_action( 'wp_head', 'wp_generator' );
|
247 |
+
|
248 |
+
/**
|
249 |
+
* Run a specific function defined in the plugin's code to locate every
|
250 |
+
* directory and file, collect their checksum and file size, and send this
|
251 |
+
* information to the Sucuri API service where a security and integrity scan
|
252 |
+
* will be performed against the hashes provided and the official versions.
|
253 |
+
*/
|
254 |
+
add_action('sucuriscan_scheduled_scan', 'SucuriScanEvent::filesystem_scan');
|
255 |
+
|
256 |
+
/**
|
257 |
+
* Initialize the execute of the main plugin's functions.
|
258 |
+
*
|
259 |
+
* This will load the menu options in the WordPress administrator panel, and
|
260 |
+
* execute the bootstrap function of the plugin.
|
261 |
+
*/
|
262 |
+
add_action( 'init', 'SucuriScanInterface::initialize', 1 );
|
263 |
+
add_action( 'admin_init', 'SucuriScanInterface::create_datastore_folder' );
|
264 |
+
add_action( 'admin_init', 'SucuriScanInterface::handle_old_plugins' );
|
265 |
+
add_action( 'admin_enqueue_scripts', 'SucuriScanInterface::enqueue_scripts', 1 );
|
266 |
+
add_action( 'admin_menu', 'SucuriScanInterface::add_interface_menu' );
|
267 |
+
|
268 |
+
/**
|
269 |
+
* Function call interceptors.
|
270 |
+
*
|
271 |
+
* Define the names for the hooks that will intercept specific function calls in
|
272 |
+
* the admin interface and parts of the external site, an event report will be
|
273 |
+
* sent to the API service and an email notification to the administrator of the
|
274 |
+
* site.
|
275 |
+
*
|
276 |
+
* @see Class SucuriScanHook
|
277 |
+
*/
|
278 |
+
if( class_exists('SucuriScanHook') ){
|
279 |
+
$sucuriscan_hooks = array(
|
280 |
+
// Passes.
|
281 |
+
'add_attachment',
|
282 |
+
'add_link',
|
283 |
+
'create_category',
|
284 |
+
'delete_post',
|
285 |
+
'delete_user',
|
286 |
+
'login_form_resetpass',
|
287 |
+
'private_to_published',
|
288 |
+
'publish_page',
|
289 |
+
'publish_post',
|
290 |
+
'publish_phone',
|
291 |
+
'xmlrpc_publish_post',
|
292 |
+
'retrieve_password',
|
293 |
+
'switch_theme',
|
294 |
+
'user_register',
|
295 |
+
'wp_login',
|
296 |
+
'wp_login_failed',
|
297 |
+
);
|
298 |
+
|
299 |
+
foreach( $sucuriscan_hooks as $hook_name ){
|
300 |
+
$hook_func = 'SucuriScanHook::hook_' . $hook_name;
|
301 |
+
add_action( $hook_name, $hook_func, 50 );
|
302 |
+
}
|
303 |
+
|
304 |
+
add_action( 'admin_init', 'SucuriScanHook::hook_undefined_actions' );
|
305 |
+
add_action( 'login_form', 'SucuriScanHook::hook_undefined_actions' );
|
306 |
+
} else {
|
307 |
+
SucuriScanInterface::error( 'Function call interceptors are not working properly.' );
|
308 |
+
}
|
309 |
+
|
310 |
+
/**
|
311 |
+
* Display a message if the plugin is not activated.
|
312 |
+
*
|
313 |
+
* Display a message at the top of the administration panel with a button that
|
314 |
+
* once clicked will send the site's email and domain name to the Sucuri API
|
315 |
+
* service where an API key will be generated for the site, this key will allow
|
316 |
+
* the plugin to execute the filesystem scans, the project integrity, and the
|
317 |
+
* email notifications.
|
318 |
+
*/
|
319 |
+
$sucuriscan_admin_notice_name = SucuriScan::is_multisite() ? 'network_admin_notices' : 'admin_notices';
|
320 |
+
add_action( $sucuriscan_admin_notice_name, 'SucuriScanInterface::setup_notice' );
|
321 |
+
|
322 |
+
}
|
323 |
+
|
324 |
/**
|
325 |
* Miscellaneous library.
|
326 |
*
|
336 |
public function __construct(){
|
337 |
}
|
338 |
|
339 |
+
/**
|
340 |
+
* Return name of a variable with the plugin's prefix (if needed).
|
341 |
+
*
|
342 |
+
* To facilitate the development, you can prefix the name of the key in the
|
343 |
+
* request (when accessing it) with a single colon, this function will
|
344 |
+
* automatically replace that character with the unique identifier of the
|
345 |
+
* plugin.
|
346 |
+
*
|
347 |
+
* @param string $var_name Name of a variable with an optional colon at the beginning.
|
348 |
+
* @return string Full name of the variable with the extra characters (if needed).
|
349 |
+
*/
|
350 |
+
public static function variable_prefix( $var_name='' ){
|
351 |
+
if( preg_match('/^:(.*)/', $var_name, $match) ){
|
352 |
+
$var_name = sprintf( '%s_%s', SUCURISCAN, $match[1] );
|
353 |
+
}
|
354 |
+
|
355 |
+
return $var_name;
|
356 |
+
}
|
357 |
+
|
358 |
+
/**
|
359 |
+
* Encodes the less-than, greater-than, ampersand, double quote and single quote
|
360 |
+
* characters, will never double encode entities.
|
361 |
+
*
|
362 |
+
* @param string $text The text which is to be encoded.
|
363 |
+
* @return string The encoded text with HTML entities.
|
364 |
+
*/
|
365 |
+
public static function escape( $text='' ){
|
366 |
+
// Escape the value of the variable using a built-in function if possible.
|
367 |
+
if( function_exists('esc_attr') ){
|
368 |
+
$text = esc_attr($text);
|
369 |
+
} else {
|
370 |
+
$text = htmlspecialchars($text);
|
371 |
+
}
|
372 |
+
|
373 |
+
return $text;
|
374 |
+
}
|
375 |
+
|
376 |
/**
|
377 |
* Generates a lowercase random string with an specific length.
|
378 |
*
|
421 |
}
|
422 |
|
423 |
/**
|
424 |
+
* Check whether the current site is working as a multi-site instance.
|
425 |
*
|
426 |
+
* @return boolean Either TRUE or FALSE in case WordPress is being used as a multi-site instance.
|
427 |
*/
|
428 |
+
public static function is_multisite(){
|
|
|
429 |
if(
|
430 |
+
function_exists('is_multisite')
|
431 |
+
&& is_multisite()
|
432 |
){
|
433 |
+
return TRUE;
|
434 |
}
|
435 |
|
436 |
+
return FALSE;
|
437 |
+
}
|
|
|
|
|
438 |
|
439 |
+
/**
|
440 |
+
* Find and retrieve the current version of Wordpress installed.
|
441 |
+
*
|
442 |
+
* @return string The version number of Wordpress installed.
|
443 |
+
*/
|
444 |
+
public static function site_version(){
|
445 |
+
// Maybe the version number is in the database.
|
446 |
+
$version = get_option('version');
|
447 |
+
if( $version ){ return $version; }
|
448 |
+
|
449 |
+
// If not, then check for a specific file.
|
450 |
+
$wp_version_path = ABSPATH . WPINC . '/version.php';
|
451 |
+
if( file_exists($wp_version_path) ){
|
452 |
+
include($wp_version_path);
|
453 |
+
if( isset($wp_version) ){ return $wp_version; }
|
454 |
+
}
|
455 |
+
|
456 |
+
// At last, use the checksum of the main framework class.
|
457 |
+
return md5_file(ABSPATH . WPINC . '/class-wp.php');
|
458 |
+
}
|
459 |
+
|
460 |
+
/**
|
461 |
+
* Find and retrieve the absolute path of the WordPress configuration file.
|
462 |
+
*
|
463 |
+
* @return string Absolute path of the WordPress configuration file.
|
464 |
+
*/
|
465 |
+
public static function get_wpconfig_path(){
|
466 |
+
if( defined('ABSPATH') ){
|
467 |
+
$file_path = ABSPATH . '/wp-config.php';
|
468 |
+
|
469 |
+
// if wp-config.php doesn't exist, or is not readable check one directory up.
|
470 |
+
if( !file_exists($file_path) ){
|
471 |
+
$file_path = ABSPATH . '/../wp-config.php';
|
472 |
}
|
473 |
|
474 |
+
// Remove duplicated double slashes.
|
475 |
+
$file_path = realpath($file_path);
|
476 |
+
|
477 |
+
if( $file_path ){
|
478 |
+
return $file_path;
|
|
|
|
|
479 |
}
|
480 |
}
|
481 |
|
482 |
return FALSE;
|
483 |
}
|
484 |
|
485 |
+
/**
|
486 |
+
* Find and retrieve the absolute path of the main WordPress htaccess file.
|
487 |
+
*
|
488 |
+
* @return string Absolute path of the main WordPress htaccess file.
|
489 |
+
*/
|
490 |
+
public static function get_htaccess_path(){
|
491 |
+
if( defined('ABSPATH') ){
|
492 |
+
$base_dirs = array(
|
493 |
+
rtrim(ABSPATH, '/'),
|
494 |
+
dirname(ABSPATH),
|
495 |
+
dirname(dirname(ABSPATH))
|
496 |
+
);
|
497 |
|
498 |
+
foreach( $base_dirs as $base_dir ){
|
499 |
+
$htaccess_path = sprintf('%s/.htaccess', $base_dir);
|
500 |
+
|
501 |
+
if( file_exists($htaccess_path) ){
|
502 |
+
return $htaccess_path;
|
503 |
+
}
|
504 |
+
}
|
505 |
+
}
|
506 |
+
|
507 |
+
return FALSE;
|
508 |
+
}
|
509 |
|
510 |
/**
|
511 |
+
* Get the pattern of the definition related with a WordPress secret key.
|
|
|
|
|
512 |
*
|
513 |
+
* @return string Secret key definition pattern.
|
514 |
*/
|
515 |
+
public static function secret_key_pattern(){
|
516 |
+
return '/define\(\'([A-Z_]+)\',([ ]+)\'(.*)\'\);/';
|
517 |
+
}
|
518 |
|
519 |
/**
|
520 |
+
* Retrieve the real ip address of the user in the current request.
|
|
|
|
|
521 |
*
|
522 |
+
* @return string The real ip address of the user in the current request.
|
523 |
*/
|
524 |
+
public static function get_remote_addr(){
|
525 |
+
$alternatives = array(
|
526 |
+
'HTTP_X_REAL_IP',
|
527 |
+
'HTTP_CLIENT_IP',
|
528 |
+
'HTTP_X_FORWARDED_FOR',
|
529 |
+
'HTTP_X_FORWARDED',
|
530 |
+
'HTTP_FORWARDED_FOR',
|
531 |
+
'HTTP_FORWARDED',
|
532 |
+
'REMOTE_ADDR',
|
533 |
+
'SUCURI_RIP',
|
534 |
+
);
|
535 |
+
|
536 |
+
foreach( $alternatives as $alternative ){
|
537 |
+
if( isset($_SERVER[$alternative]) ){
|
538 |
+
$remote_addr = preg_replace('/[^0-9a-z.,: ]/', '', $_SERVER[$alternative]);
|
539 |
+
|
540 |
+
if( $remote_addr ){ break; }
|
541 |
+
}
|
542 |
+
}
|
543 |
+
|
544 |
+
if( $remote_addr == '::1' ){
|
545 |
+
$remote_addr = '127.0.0.1';
|
546 |
+
}
|
547 |
+
|
548 |
+
return $remote_addr;
|
549 |
+
}
|
550 |
|
551 |
/**
|
552 |
+
* Retrieve the user-agent from the current request.
|
553 |
*
|
554 |
+
* @return string The user-agent from the current request.
|
555 |
*/
|
556 |
+
public static function get_user_agent(){
|
557 |
+
if( isset($_SERVER['HTTP_USER_AGENT']) ){
|
558 |
+
return self::escape($_SERVER['HTTP_USER_AGENT']);
|
559 |
+
}
|
560 |
+
|
561 |
+
return FALSE;
|
562 |
+
}
|
563 |
|
564 |
/**
|
565 |
+
* Check whether the site is behing the Sucuri CloudProxy network.
|
566 |
+
*
|
567 |
+
* @return boolean Either TRUE or FALSE if the site is behind CloudProxy.
|
568 |
*/
|
569 |
+
public static function is_behind_cloudproxy(){
|
570 |
+
if( isset($_SERVER['HTTP_HOST']) ){
|
571 |
+
$http_host = preg_replace('/^(.*):[0-9]+/', '$1', $_SERVER['HTTP_HOST']);
|
572 |
+
} else {
|
573 |
+
$http_host = 'localhost';
|
574 |
+
}
|
575 |
+
|
576 |
+
$host_by_name = gethostbyname($http_host);
|
577 |
+
$host_by_addr = gethostbyaddr($host_by_name);
|
578 |
+
|
579 |
+
return (bool) preg_match('/^cloudproxy[0-9]+\.sucuri\.net$/', $host_by_addr);
|
580 |
}
|
581 |
|
582 |
/**
|
583 |
+
* Return the time passed since the specified timestamp until now.
|
|
|
|
|
|
|
584 |
*
|
585 |
+
* @param integer $timestamp The Unix time number of the date/time before now.
|
586 |
+
* @return string The time passed since the timestamp specified.
|
|
|
|
|
587 |
*/
|
588 |
+
public static function time_ago( $timestamp=0 ){
|
589 |
+
if( !is_numeric($timestamp) ){
|
590 |
+
$timestamp = strtotime($timestamp);
|
|
|
|
|
|
|
|
|
|
|
591 |
}
|
592 |
|
593 |
+
$diff = abs( time() - intval($timestamp) );
|
|
|
|
|
594 |
|
595 |
+
if( $diff == 0 ){ return 'just now'; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
596 |
|
597 |
+
$intervals = array(
|
598 |
+
1 => array('year', 31556926),
|
599 |
+
$diff < 31556926 => array('month', 2628000),
|
600 |
+
$diff < 2629744 => array('week', 604800),
|
601 |
+
$diff < 604800 => array('day', 86400),
|
602 |
+
$diff < 86400 => array('hour', 3600),
|
603 |
+
$diff < 3600 => array('minute', 60),
|
604 |
+
$diff < 60 => array('second', 1)
|
605 |
+
);
|
606 |
+
|
607 |
+
$value = floor($diff/$intervals[1][1]);
|
608 |
+
$time_ago = sprintf(
|
609 |
+
'%s %s%s ago',
|
610 |
+
$value,
|
611 |
+
$intervals[1][0],
|
612 |
+
( $value > 1 ? 's' : '' )
|
613 |
+
);
|
614 |
+
|
615 |
+
return $time_ago;
|
616 |
}
|
617 |
|
618 |
/**
|
619 |
+
* Convert an string of characters into a valid variable name.
|
|
|
|
|
620 |
*
|
621 |
+
* @see http://www.php.net/manual/en/language.variables.basics.php
|
622 |
+
*
|
623 |
+
* @param string $text A text containing alpha-numeric and special characters.
|
624 |
+
* @return string A valid variable name.
|
625 |
*/
|
626 |
+
public static function human2var( $text='' ){
|
627 |
+
$text = strtolower($text);
|
628 |
+
$pattern = '/[^a-z0-9_]/';
|
629 |
+
$var_name = preg_replace($pattern, '_', $text);
|
630 |
|
631 |
+
return $var_name;
|
632 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
633 |
|
634 |
+
/**
|
635 |
+
* Check whether an IP address has a valid format or not.
|
636 |
+
*
|
637 |
+
* @param string $remote_addr The host IP address.
|
638 |
+
* @return boolean Whether the IP address specified is valid or not.
|
639 |
+
*/
|
640 |
+
public static function is_valid_ip( $remote_addr='' ){
|
641 |
+
// Check for IPv4 and IPv6.
|
642 |
+
if( function_exists('filter_var') ){
|
643 |
+
return (bool) filter_var( $remote_addr, FILTER_VALIDATE_IP );
|
644 |
+
}
|
645 |
+
|
646 |
+
// Assuming older version of PHP and server, so only will check for IPv4.
|
647 |
+
elseif( strlen($remote_addr) >= 7 ) {
|
648 |
+
$pattern = '/^([0-9]{1,3}\.){3}[0-9]{1,3}$/';
|
649 |
+
|
650 |
+
if( preg_match($pattern, $remote_addr, $match) ){
|
651 |
+
for( $i=0; $i<4; $i++ ){
|
652 |
+
if( $match[$i] > 255 ){ return FALSE; }
|
653 |
+
}
|
654 |
+
|
655 |
+
return TRUE;
|
656 |
+
}
|
657 |
+
}
|
658 |
+
|
659 |
+
return FALSE;
|
660 |
+
}
|
661 |
+
|
662 |
+
/**
|
663 |
+
* Validate email address.
|
664 |
+
*
|
665 |
+
* This use the native PHP function filter_var which is available in PHP >=
|
666 |
+
* 5.2.0 if it is not found in the interpreter this function will sue regular
|
667 |
+
* expressions to check whether the email address passed is valid or not.
|
668 |
+
*
|
669 |
+
* @see http://www.php.net/manual/en/function.filter-var.php
|
670 |
+
*
|
671 |
+
* @param string $email The string that will be validated as an email address.
|
672 |
+
* @return boolean TRUE if the email address passed to the function is valid, FALSE if not.
|
673 |
+
*/
|
674 |
+
public static function is_valid_email( $email='' ){
|
675 |
+
if( function_exists('filter_var') ){
|
676 |
+
return (bool) filter_var($email, FILTER_VALIDATE_EMAIL);
|
677 |
+
} else {
|
678 |
+
$pattern = '/^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6}$/ix';
|
679 |
+
return (bool) preg_match($pattern, $email);
|
680 |
+
}
|
681 |
+
}
|
682 |
+
|
683 |
+
/**
|
684 |
+
* Cut a long text to the length specified, and append suspensive points at the end.
|
685 |
+
*
|
686 |
+
* @param string $text String of characters that will be cut.
|
687 |
+
* @param integer $length Maximum length of the returned string, default is 10.
|
688 |
+
* @return string Short version of the text specified.
|
689 |
+
*/
|
690 |
+
public static function excerpt( $text='', $length=10 ){
|
691 |
+
$text_length = strlen($text);
|
692 |
+
|
693 |
+
if( $text_length > $length ){
|
694 |
+
return substr( $text, 0, $length ) . '...';
|
695 |
+
}
|
696 |
+
|
697 |
+
return $text;
|
698 |
+
}
|
699 |
+
|
700 |
+
}
|
701 |
+
|
702 |
+
/**
|
703 |
+
* HTTP request handler.
|
704 |
+
*
|
705 |
+
* Function definitions to retrieve, validate, and clean the parameters during a
|
706 |
+
* HTTP request, generally after a form submission or while loading a URL. Use
|
707 |
+
* these methods at most instead of accessing an index in the global PHP
|
708 |
+
* variables _POST, _GET, _REQUEST since they may come with insecure data.
|
709 |
+
*/
|
710 |
+
class SucuriScanRequest extends SucuriScan {
|
711 |
+
|
712 |
+
/**
|
713 |
+
* Returns the value stored in a specific index in the global _GET, _POST or
|
714 |
+
* _REQUEST variables, you can specify a pattern as the second argument to
|
715 |
+
* match allowed values.
|
716 |
+
*
|
717 |
+
* @param array $list The array where the specified key will be searched.
|
718 |
+
* @param string $key Name of the index where the requested variable is supposed to be.
|
719 |
+
* @param string $pattern Optional pattern to match allowed values in the requested key.
|
720 |
+
* @return string The value stored in the specified key inside the global _GET variable.
|
721 |
+
*/
|
722 |
+
public static function request( $list=array(), $key='', $pattern='' ){
|
723 |
+
$key = self::variable_prefix($key);
|
724 |
+
|
725 |
+
if( is_array($list) && isset($list[$key]) ){
|
726 |
+
// Select the key from the list and escape its content.
|
727 |
+
$key_value = $list[$key];
|
728 |
+
|
729 |
+
// Define regular expressions for specific value types.
|
730 |
+
if( $pattern === '' ){
|
731 |
+
$pattern = '/.*/';
|
732 |
+
} else {
|
733 |
+
switch( $pattern ){
|
734 |
+
case '_nonce': $pattern = '/^[a-z0-9]{10}$/'; break;
|
735 |
+
case '_page': $pattern = '/^[a-z_]+$/'; break;
|
736 |
+
case '_array': $pattern = '_array'; break;
|
737 |
+
case '_yyyymmdd': $pattern = '/^[0-9]{4}\-[0-9]{2}\-[0-9]{2}$/'; break;
|
738 |
+
default: $pattern = '/^'.$pattern.'$/'; break;
|
739 |
+
}
|
740 |
+
}
|
741 |
+
|
742 |
+
// If the request data is an array, then only cast the value.
|
743 |
+
if( $pattern == '_array' && is_array($key_value) ){
|
744 |
+
return (array) $key_value;
|
745 |
+
}
|
746 |
+
|
747 |
+
// Check the format of the request data with a regex defined above.
|
748 |
+
if( preg_match($pattern, $key_value) ){
|
749 |
+
return self::escape($key_value);
|
750 |
+
}
|
751 |
+
}
|
752 |
+
|
753 |
+
return FALSE;
|
754 |
+
}
|
755 |
+
|
756 |
+
/**
|
757 |
+
* Returns the value stored in a specific index in the global _GET variable,
|
758 |
+
* you can specify a pattern as the second argument to match allowed values.
|
759 |
+
*
|
760 |
+
* @param string $key Name of the index where the requested variable is supposed to be.
|
761 |
+
* @param string $pattern Optional pattern to match allowed values in the requested key.
|
762 |
+
* @return string The value stored in the specified key inside the global _GET variable.
|
763 |
+
*/
|
764 |
+
public static function get( $key='', $pattern='' ){
|
765 |
+
return self::request( $_GET, $key, $pattern );
|
766 |
+
}
|
767 |
+
|
768 |
+
/**
|
769 |
+
* Returns the value stored in a specific index in the global _POST variable,
|
770 |
+
* you can specify a pattern as the second argument to match allowed values.
|
771 |
+
*
|
772 |
+
* @param string $key Name of the index where the requested variable is supposed to be.
|
773 |
+
* @param string $pattern Optional pattern to match allowed values in the requested key.
|
774 |
+
* @return string The value stored in the specified key inside the global _POST variable.
|
775 |
+
*/
|
776 |
+
public static function post( $key='', $pattern='' ){
|
777 |
+
return self::request( $_POST, $key, $pattern );
|
778 |
+
}
|
779 |
+
|
780 |
+
/**
|
781 |
+
* Returns the value stored in a specific index in the global _REQUEST variable,
|
782 |
+
* you can specify a pattern as the second argument to match allowed values.
|
783 |
+
*
|
784 |
+
* @param string $key Name of the index where the requested variable is supposed to be.
|
785 |
+
* @param string $pattern Optional pattern to match allowed values in the requested key.
|
786 |
+
* @return string The value stored in the specified key inside the global _POST variable.
|
787 |
+
*/
|
788 |
+
public static function get_or_post( $key='', $pattern='' ){
|
789 |
+
return self::request( $_REQUEST, $key, $pattern );
|
790 |
+
}
|
791 |
+
|
792 |
+
}
|
793 |
+
|
794 |
+
/**
|
795 |
+
* Class to process files and folders.
|
796 |
+
*
|
797 |
+
* Here are implemented the functions needed to open, scan, read, create files
|
798 |
+
* and folders using the built-in PHP class SplFileInfo. The SplFileInfo class
|
799 |
+
* offers a high-level object oriented interface to information for an individual
|
800 |
+
* file.
|
801 |
+
*/
|
802 |
+
class SucuriScanFileInfo extends SucuriScan {
|
803 |
+
|
804 |
+
/**
|
805 |
+
* Whether the list of files that can be ignored from the filesystem scan will
|
806 |
+
* be used to return the directory tree, this should be disabled when scanning a
|
807 |
+
* directory without the need to filter the items in the list.
|
808 |
+
*
|
809 |
+
* @var boolean
|
810 |
+
*/
|
811 |
+
public $ignore_files = TRUE;
|
812 |
+
|
813 |
+
/**
|
814 |
+
* Whether the list of folders that can be ignored from the filesystem scan will
|
815 |
+
* be used to return the directory tree, this should be disabled when scanning a
|
816 |
+
* path without the need to filter the items in the list.
|
817 |
+
*
|
818 |
+
* @var boolean
|
819 |
+
*/
|
820 |
+
public $ignore_directories = TRUE;
|
821 |
+
|
822 |
+
/**
|
823 |
+
* Whether the filesystem scanner should run recursively or not.
|
824 |
+
*
|
825 |
+
* @var boolean
|
826 |
+
*/
|
827 |
+
public $run_recursively = TRUE;
|
828 |
+
|
829 |
+
/**
|
830 |
+
* Class constructor.
|
831 |
+
*/
|
832 |
+
public function __construct(){
|
833 |
+
}
|
834 |
+
|
835 |
+
/**
|
836 |
+
* Retrieve a long text string with signatures of all the files contained
|
837 |
+
* in the main and subdirectories of the folder specified, also the filesize
|
838 |
+
* and md5sum of that file. Some folders and files will be ignored depending
|
839 |
+
* on some rules defined by the developer.
|
840 |
+
*
|
841 |
+
* @param string $directory Parent directory where the filesystem scan will start.
|
842 |
+
* @param string $scan_with Set the tool used to scan the filesystem, SplFileInfo by default.
|
843 |
+
* @param boolean $as_array Whether the result of the operation will be returned as an array or string.
|
844 |
+
* @return array List of files in the main and subdirectories of the folder specified.
|
845 |
+
*/
|
846 |
+
public function get_directory_tree_md5( $directory='', $scan_with='spl', $as_array=FALSE ){
|
847 |
+
$project_signatures = '';
|
848 |
+
$abs_path = rtrim( ABSPATH, '/' );
|
849 |
+
$files = $this->get_directory_tree($directory, $scan_with);
|
850 |
+
sort($files);
|
851 |
+
|
852 |
+
if( $as_array ){
|
853 |
+
$project_signatures = array();
|
854 |
+
}
|
855 |
+
|
856 |
+
foreach( $files as $filepath){
|
857 |
+
$file_checksum = @md5_file($filepath);
|
858 |
+
$filesize = @filesize($filepath);
|
859 |
+
|
860 |
+
if( $as_array ){
|
861 |
+
$basename = str_replace( $abs_path . '/', '', $filepath );
|
862 |
+
$project_signatures[$basename] = array(
|
863 |
+
'filepath' => $filepath,
|
864 |
+
'checksum' => $file_checksum,
|
865 |
+
'filesize' => $filesize,
|
866 |
+
'created_at' => filectime($filepath),
|
867 |
+
'modified_at' => filemtime($filepath),
|
868 |
+
);
|
869 |
+
} else {
|
870 |
+
$filepath = str_replace( $abs_path, $abs_path . '/', $filepath );
|
871 |
+
$project_signatures .= sprintf(
|
872 |
+
"%s%s%s%s\n",
|
873 |
+
$file_checksum,
|
874 |
+
$filesize,
|
875 |
+
chr(32),
|
876 |
+
$filepath
|
877 |
+
);
|
878 |
+
}
|
879 |
+
}
|
880 |
+
|
881 |
+
return $project_signatures;
|
882 |
+
}
|
883 |
+
|
884 |
+
/**
|
885 |
+
* Retrieve a list with all the files contained in the main and subdirectories
|
886 |
+
* of the folder specified. Some folders and files will be ignored depending
|
887 |
+
* on some rules defined by the developer.
|
888 |
+
*
|
889 |
+
* @param string $directory Parent directory where the filesystem scan will start.
|
890 |
+
* @param string $scan_with Set the tool used to scan the filesystem, SplFileInfo by default.
|
891 |
+
* @return array List of files in the main and subdirectories of the folder specified.
|
892 |
+
*/
|
893 |
+
public function get_directory_tree($directory='', $scan_with='spl'){
|
894 |
+
if( file_exists($directory) && is_dir($directory) ){
|
895 |
+
$tree = array();
|
896 |
+
|
897 |
+
switch( $scan_with ){
|
898 |
+
case 'spl':
|
899 |
+
if( $this->is_spl_available() ){
|
900 |
+
$tree = $this->get_directory_tree_with_spl($directory);
|
901 |
+
} else {
|
902 |
+
$tree = $this->get_directory_tree($directory, 'opendir');
|
903 |
+
}
|
904 |
+
break;
|
905 |
+
|
906 |
+
case 'glob':
|
907 |
$tree = $this->get_directory_tree_with_glob($directory);
|
908 |
break;
|
909 |
|
1182 |
return $all_removed;
|
1183 |
}
|
1184 |
|
1185 |
+
/**
|
1186 |
+
* Return the lines of a file as an array, it will automatically remove the new
|
1187 |
+
* line characters from the end of each line, and skip empty lines from the
|
1188 |
+
* list.
|
1189 |
+
*
|
1190 |
+
* @param string $filepath Path to the file.
|
1191 |
+
* @return array An array where each element is a line in the file.
|
1192 |
+
*/
|
1193 |
+
public static function file_lines( $filepath='' ){
|
1194 |
+
return @file( $filepath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES );
|
1195 |
+
}
|
1196 |
+
|
1197 |
}
|
1198 |
|
1199 |
/**
|
1200 |
+
* File-based cache library.
|
1201 |
+
*
|
1202 |
+
* WP_Object_Cache [1] is WordPress' class for caching data which may be
|
1203 |
+
* computationally expensive to regenerate, such as the result of complex
|
1204 |
+
* database queries. However the object cache is non-persistent. This means that
|
1205 |
+
* data stored in the cache resides in memory only and only for the duration of
|
1206 |
+
* the request. Cached data will not be stored persistently across page loads
|
1207 |
+
* unless of the installation of a 3party persistent caching plugin [2].
|
1208 |
*
|
1209 |
+
* [1] http://codex.wordpress.org/Class_Reference/WP_Object_Cache
|
1210 |
+
* [2] http://codex.wordpress.org/Class_Reference/WP_Object_Cache#Persistent_Caching
|
|
|
1211 |
*/
|
1212 |
+
class SucuriScanCache extends SucuriScan {
|
1213 |
|
1214 |
/**
|
1215 |
+
* The unique name (or identifier) of the file with the data.
|
1216 |
+
*
|
1217 |
+
* The file should be located in the same folder where the dynamic data
|
1218 |
+
* generated by the plugin is stored, and using the following format [1], it
|
1219 |
+
* most be a PHP file because it is expected to have an exit point in the first
|
1220 |
+
* line of the file causing it to stop the execution if a unauthorized user
|
1221 |
+
* tries to access it directly.
|
1222 |
+
*
|
1223 |
+
* [1] /public/data/sucuri-DATASTORE.php
|
1224 |
*
|
1225 |
+
* @var null|string
|
1226 |
*/
|
1227 |
+
private $datastore = NULL;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1228 |
|
1229 |
+
/**
|
1230 |
+
* The full path of the datastore file.
|
1231 |
+
*
|
1232 |
+
* @var string
|
1233 |
+
*/
|
1234 |
+
private $datastore_path = '';
|
1235 |
|
1236 |
/**
|
1237 |
+
* Whether the datastore file is usable or not.
|
1238 |
*
|
1239 |
+
* This variable will only be TRUE if the datastore file specified exists, is
|
1240 |
+
* writable and readable, in any other case it will always be FALSE.
|
1241 |
+
*
|
1242 |
+
* @var boolean
|
1243 |
*/
|
1244 |
+
private $usable_datastore = FALSE;
|
|
|
|
|
|
|
1245 |
|
1246 |
/**
|
1247 |
+
* Class constructor.
|
1248 |
*
|
1249 |
+
* @param string $datastore Unique name (or identifier) of the file with the data.
|
1250 |
* @return void
|
1251 |
*/
|
1252 |
+
public function __construct( $datastore='' ){
|
1253 |
+
$this->datastore = $datastore;
|
1254 |
+
$this->datastore_path = $this->datastore_file_path();
|
1255 |
+
$this->usable_datastore = (bool) $this->datastore_path;
|
1256 |
}
|
1257 |
|
1258 |
/**
|
1259 |
+
* Default attributes for every datastore file.
|
1260 |
*
|
1261 |
+
* @return string Default attributes for every datastore file.
|
|
|
1262 |
*/
|
1263 |
+
private function datastore_default_info(){
|
1264 |
+
$attrs = array(
|
1265 |
+
'datastore' => $this->datastore,
|
1266 |
+
'created_on' => time(),
|
1267 |
+
'updated_on' => time(),
|
1268 |
+
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1269 |
|
1270 |
+
return $attrs;
|
|
|
|
|
|
|
|
|
1271 |
}
|
1272 |
|
1273 |
/**
|
1274 |
+
* Default content of every datastore file.
|
1275 |
*
|
1276 |
+
* @param array $finfo Rainbow table with the key names and decoded values.
|
1277 |
+
* @return string Default content of every datastore file.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1278 |
*/
|
1279 |
private function datastore_info( $finfo=array() ){
|
1280 |
$attrs = $this->datastore_default_info();
|
1387 |
);
|
1388 |
|
1389 |
if( $this->usable_datastore ){
|
1390 |
+
$data_lines = SucuriScanFileInfo::file_lines($this->datastore_path);
|
1391 |
|
1392 |
if( !empty($data_lines) ){
|
1393 |
foreach( $data_lines as $line ){
|
|
|
|
|
1394 |
if( preg_match('/^\/\/ ([a-z_]+)=(.*);$/', $line, $match) ){
|
1395 |
$data_object['info'][$match[1]] = $match[2];
|
1396 |
}
|
1400 |
$this->valid_key_name($match[1])
|
1401 |
&& !array_key_exists($match[1], $data_object)
|
1402 |
){
|
1403 |
+
$data_object['entries'][$match[1]] = @json_decode( $match[2], $assoc );
|
1404 |
}
|
1405 |
}
|
1406 |
}
|
1575 |
}
|
1576 |
|
1577 |
/**
|
1578 |
+
* Plugin options handler.
|
1579 |
*
|
1580 |
+
* Options are pieces of data that WordPress uses to store various preferences
|
1581 |
+
* and configuration settings. Listed below are the options, along with some of
|
1582 |
+
* the default values from the current WordPress install. By using the
|
1583 |
+
* appropriate function, options can be added, changed, removed, and retrieved,
|
1584 |
+
* from the wp_options table.
|
1585 |
+
*
|
1586 |
+
* The Options API is a simple and standardized way of storing data in the
|
1587 |
+
* database. The API makes it easy to create, access, update, and delete
|
1588 |
+
* options. All the data is stored in the wp_options table under a given custom
|
1589 |
+
* name. This page contains the technical documentation needed to use the
|
1590 |
+
* Options API. A list of default options can be found in the Option Reference.
|
1591 |
+
*
|
1592 |
+
* Note that the _site_ functions are essentially the same as their
|
1593 |
+
* counterparts. The only differences occur for WP Multisite, when the options
|
1594 |
+
* apply network-wide and the data is stored in the wp_sitemeta table under the
|
1595 |
+
* given custom name.
|
1596 |
*
|
1597 |
+
* @see http://codex.wordpress.org/Option_Reference
|
1598 |
+
* @see http://codex.wordpress.org/Options_API
|
1599 |
*/
|
1600 |
+
class SucuriScanOption extends SucuriScanRequest {
|
1601 |
+
|
1602 |
+
/**
|
1603 |
+
* Retrieve specific options from the database.
|
1604 |
+
*
|
1605 |
+
* Considering the case in which this plugin is installed in a multisite instance
|
1606 |
+
* of Wordpress, the allowed values for the first parameter of this function will
|
1607 |
+
* be treated like this:
|
1608 |
+
*
|
1609 |
+
* <ul>
|
1610 |
+
* <li>all_plugin_options: Will retrieve all the option values created by this plugin in the main site (aka. network),</li>
|
1611 |
+
* <li>site_options: Will retrieve all the option values stored in the current site visited by the user (aka. sub-site) excluding the transient options,</li>
|
1612 |
+
* <li>plugin_option: Will retrieve one specific option from the network site only if the option starts with the prefix <i>sucuri_<i>.</li>
|
1613 |
+
* </ul>
|
1614 |
+
*
|
1615 |
+
* @param string $filter_by Criteria to filter the results, valid values: all_plugin_options, site_options, sucuri_option.
|
1616 |
+
* @param string $option_name Optional parameter with the name of the option that will be filtered.
|
1617 |
+
* @return array List of options retrieved from the query in the database.
|
1618 |
+
*/
|
1619 |
+
public function get_options_from_db( $filter_by='', $option_name='' ){
|
1620 |
+
global $wpdb;
|
1621 |
+
|
1622 |
+
$output = FALSE;
|
1623 |
+
switch($filter_by){
|
1624 |
+
case 'all_plugin_options':
|
1625 |
+
$output = $wpdb->get_results("SELECT * FROM {$wpdb->options} WHERE option_name LIKE 'sucuriscan%' ORDER BY option_id ASC");
|
1626 |
+
break;
|
1627 |
+
case 'site_options':
|
1628 |
+
$output = $wpdb->get_results("SELECT * FROM {$wpdb->options} WHERE option_name NOT LIKE '%_transient_%' ORDER BY option_id ASC");
|
1629 |
+
break;
|
1630 |
+
case 'plugin_option':
|
1631 |
+
$row = $wpdb->get_row( $wpdb->prepare("SELECT option_value FROM {$wpdb->base_prefix}options WHERE option_name = %s LIMIT 1", $option_name) );
|
1632 |
+
if( $row ){ $output = $row->option_value; }
|
1633 |
+
break;
|
1634 |
}
|
1635 |
|
1636 |
+
return $output;
|
1637 |
}
|
1638 |
|
|
|
|
|
|
|
|
|
1639 |
/**
|
1640 |
+
* Alias function for the method Common::SucuriScan_Get_Options()
|
1641 |
*
|
1642 |
+
* This function search the specified option in the database, not only the options
|
1643 |
+
* set by the plugin but all the options set for the site. If the value retrieved
|
1644 |
+
* is FALSE the method tries to search for a default value.
|
|
|
1645 |
*
|
1646 |
+
* To facilitate the development, you can prefix the name of the key in the
|
1647 |
+
* request (when accessing it) with a single colon, this function will
|
1648 |
+
* automatically replace that character with the unique identifier of the
|
1649 |
+
* plugin.
|
1650 |
+
*
|
1651 |
+
* @see http://codex.wordpress.org/Function_Reference/get_option
|
1652 |
+
*
|
1653 |
+
* @param string $option_name Optional parameter that you can use to filter the results to one option.
|
1654 |
+
* @return string The value (or default value) of the option specified.
|
1655 |
*/
|
1656 |
+
public static function get_option( $option_name='' ){
|
1657 |
+
$option_name = self::variable_prefix($option_name);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1658 |
|
1659 |
+
return self::get_options($option_name);
|
1660 |
+
}
|
1661 |
|
|
|
1662 |
/**
|
1663 |
+
* Update the value of an database' option.
|
|
|
1664 |
*
|
1665 |
+
* Use the function to update a named option/value pair to the options database
|
1666 |
+
* table. The option name value is escaped with a special database method before
|
1667 |
+
* the insert SQL statement but not the option value, this value should always
|
1668 |
+
* be properly sanitized.
|
1669 |
+
*
|
1670 |
+
* @see http://codex.wordpress.org/Function_Reference/update_option
|
1671 |
+
*
|
1672 |
+
* @param string $option_name Name of the option to update which must not exceed 64 characters.
|
1673 |
+
* @param string $option_value The new value for the option, can be an integer, string, array, or object.
|
1674 |
+
* @return boolean True if option value has changed, false if not or if update failed.
|
1675 |
*/
|
1676 |
+
public static function update_option( $option_name='', $option_value='' ){
|
1677 |
+
if( function_exists('update_option') ){
|
1678 |
+
$option_name = self::variable_prefix($option_name);
|
1679 |
|
1680 |
+
return update_option( $option_name, $option_value );
|
1681 |
+
}
|
|
|
|
|
1682 |
|
1683 |
+
return FALSE;
|
1684 |
+
}
|
|
|
|
|
|
|
|
|
1685 |
|
1686 |
+
/**
|
1687 |
+
* Remove an option from the database.
|
1688 |
+
*
|
1689 |
+
* A safe way of removing a named option/value pair from the options database table.
|
1690 |
+
*
|
1691 |
+
* @see http://codex.wordpress.org/Function_Reference/delete_option
|
1692 |
+
*
|
1693 |
+
* @param string $option_name Name of the option to be deleted.
|
1694 |
+
* @return boolean True, if option is successfully deleted. False on failure, or option does not exist.
|
1695 |
+
*/
|
1696 |
+
public static function delete_option( $option_name='' ){
|
1697 |
+
if( function_exists('delete_option') ){
|
1698 |
+
$option_name = self::variable_prefix($option_name);
|
1699 |
+
|
1700 |
+
return delete_option( $option_name );
|
1701 |
}
|
|
|
1702 |
|
1703 |
+
return FALSE;
|
1704 |
+
}
|
1705 |
|
|
|
1706 |
/**
|
1707 |
+
* Retrieve all the options created by this Plugin from the Wordpress database.
|
1708 |
+
*
|
1709 |
+
* The function acts as an alias of WP::get_option() and if the returned value
|
1710 |
+
* is FALSE it tries to search for a default value to complement the information.
|
1711 |
+
*
|
1712 |
+
* @param string $option_name Optional parameter that you can use to filter the results to one option.
|
1713 |
+
* @return array Either FALSE or an Array containing all the sucuri options in the database.
|
1714 |
*/
|
1715 |
+
private static function get_options( $option_name='' ){
|
1716 |
+
if( !empty($option_name) ){
|
1717 |
+
return self::get_single_option($option_name);
|
|
|
|
|
1718 |
}
|
1719 |
|
1720 |
+
$settings = array();
|
1721 |
+
$results = self::get_options_from_db('all_plugin_options');
|
1722 |
|
1723 |
+
foreach( $results as $row ){
|
1724 |
+
$settings[$row->option_name] = $row->option_value;
|
1725 |
+
}
|
1726 |
+
|
1727 |
+
return self::get_default_options($settings);
|
1728 |
}
|
1729 |
|
1730 |
+
/**
|
1731 |
+
* Retrieve a single option from the database.
|
1732 |
+
*
|
1733 |
+
* @param string $option_name Name of the option that will be retrieved.
|
1734 |
+
* @return string Value of the option stored in the database, FALSE if not found.
|
1735 |
+
*/
|
1736 |
+
private static function get_single_option( $option_name='' ){
|
1737 |
+
$option_value = FALSE;
|
1738 |
+
$is_plugin_option = preg_match('/^sucuriscan_/', $option_name) ? TRUE : FALSE;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1739 |
|
1740 |
+
if( self::is_multisite() && $is_plugin_option ){
|
1741 |
+
$option_value = self::get_options_from_db('plugin_option', $option_name);
|
1742 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1743 |
|
1744 |
+
// Use framework built-in function.
|
1745 |
+
elseif( function_exists('get_option') ){
|
1746 |
+
$option_value = get_option($option_name);
|
1747 |
+
}
|
1748 |
|
1749 |
+
if( $option_value === FALSE && $is_plugin_option ){
|
1750 |
+
$option_value = self::get_default_options($option_name);
|
1751 |
+
}
|
1752 |
|
1753 |
+
return $option_value;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1754 |
}
|
|
|
1755 |
|
|
|
1756 |
/**
|
1757 |
+
* Retrieve the default values for some specific options.
|
|
|
|
|
|
|
1758 |
*
|
1759 |
+
* @param string|array $settings Either an array that will be complemented or a string with the name of the option.
|
1760 |
+
* @return string|array The default values for the specified options.
|
1761 |
*/
|
1762 |
+
private static function get_default_options( $settings='' ){
|
1763 |
+
$admin_email = '';
|
1764 |
+
|
1765 |
+
// Use framework built-in function.
|
1766 |
+
if( function_exists('get_option') ){
|
1767 |
+
$admin_email = get_option('admin_email');
|
1768 |
+
}
|
1769 |
+
|
1770 |
+
$default_options = array(
|
1771 |
+
'sucuriscan_api_key' => FALSE,
|
1772 |
+
'sucuriscan_account' => $admin_email,
|
1773 |
+
'sucuriscan_fs_scanner' => 'enabled',
|
1774 |
+
'sucuriscan_scan_frequency' => 'hourly',
|
1775 |
+
'sucuriscan_scan_interface' => 'spl',
|
1776 |
+
'sucuriscan_scan_modfiles' => 'enabled',
|
1777 |
+
'sucuriscan_scan_checksums' => 'enabled',
|
1778 |
+
'sucuriscan_runtime' => 0,
|
1779 |
+
'sucuriscan_lastlogin_redirection' => 'enabled',
|
1780 |
+
'sucuriscan_notify_to' => $admin_email,
|
1781 |
+
'sucuriscan_emails_sent' => 0,
|
1782 |
+
'sucuriscan_emails_per_hour' => 5,
|
1783 |
+
'sucuriscan_last_email_at' => time(),
|
1784 |
+
'sucuriscan_prettify_mails' => 'enabled',
|
1785 |
+
'sucuriscan_notify_success_login' => 'enabled',
|
1786 |
+
'sucuriscan_notify_failed_login' => 'enabled',
|
1787 |
+
'sucuriscan_notify_post_publication' => 'enabled',
|
1788 |
+
'sucuriscan_notify_theme_editor' => 'enabled',
|
1789 |
+
'sucuriscan_maximum_failed_logins' => 30,
|
1790 |
+
'sucuriscan_ignored_events' => '',
|
1791 |
+
'sucuriscan_verify_ssl_cert' => 'true',
|
1792 |
);
|
1793 |
|
1794 |
+
if( is_array($settings) ){
|
1795 |
+
foreach( $default_options as $option_name => $option_value ){
|
1796 |
+
if( !isset($settings[$option_name]) ){
|
1797 |
+
$settings[$option_name] = $option_value;
|
|
|
|
|
1798 |
}
|
1799 |
+
}
|
1800 |
+
|
1801 |
+
return $settings;
|
1802 |
+
}
|
1803 |
|
1804 |
+
if( is_string($settings) ){
|
1805 |
+
if( isset($default_options[$settings]) ){
|
1806 |
+
return $default_options[$settings];
|
1807 |
}
|
1808 |
}
|
1809 |
+
|
1810 |
+
return FALSE;
|
1811 |
}
|
1812 |
|
1813 |
+
/**
|
1814 |
+
* Retrieve all the options stored by Wordpress in the database. The options
|
1815 |
+
* containing the word "transient" are excluded from the results, this function
|
1816 |
+
* is compatible with multisite instances.
|
1817 |
+
*
|
1818 |
+
* @return array All the options stored by Wordpress in the database, except the transient options.
|
1819 |
+
*/
|
1820 |
+
public static function get_site_options(){
|
1821 |
+
$settings = array();
|
1822 |
+
$results = self::get_options_from_db('site_options');
|
1823 |
|
1824 |
+
foreach( $results as $row ){
|
1825 |
+
$settings[$row->option_name] = $row->option_value;
|
1826 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
1827 |
|
1828 |
+
return $settings;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1829 |
}
|
|
|
1830 |
|
1831 |
+
/**
|
1832 |
+
* Check what Wordpress options were changed comparing the values in the database
|
1833 |
+
* with the values sent through a simple request using a GET or POST method.
|
1834 |
+
*
|
1835 |
+
* @param array $request The content of the global variable GET or POST considering SERVER[REQUEST_METHOD].
|
1836 |
+
* @return array A list of all the options that were changes through this request.
|
1837 |
+
*/
|
1838 |
+
public static function what_options_were_changed( $request=array() ){
|
1839 |
+
$options_changed = array(
|
1840 |
+
'original' => array(),
|
1841 |
+
'changed' => array()
|
1842 |
+
);
|
1843 |
+
|
1844 |
+
$site_options = self::get_site_options();
|
1845 |
+
|
1846 |
+
foreach( $request as $req_name => $req_value ){
|
1847 |
+
if(
|
1848 |
+
array_key_exists($req_name, $site_options)
|
1849 |
+
&& $site_options[$req_name] != $req_value
|
1850 |
+
){
|
1851 |
+
$options_changed['original'][$req_name] = $site_options[$req_name];
|
1852 |
+
$options_changed['changed'][$req_name] = $req_value;
|
1853 |
+
}
|
1854 |
+
}
|
1855 |
|
1856 |
+
return $options_changed;
|
|
|
1857 |
}
|
1858 |
|
1859 |
+
/**
|
1860 |
+
* Check the nonce comming from any of the settings pages.
|
1861 |
+
*
|
1862 |
+
* @return boolean TRUE if the nonce is valid, FALSE otherwise.
|
1863 |
+
*/
|
1864 |
+
public static function check_options_nonce(){
|
1865 |
+
// Create the option_page value if permalink submission.
|
1866 |
+
if(
|
1867 |
+
!isset($_POST['option_page'])
|
1868 |
+
&& isset($_POST['permalink_structure'])
|
1869 |
+
){
|
1870 |
+
$_POST['option_page'] = 'permalink';
|
1871 |
+
}
|
1872 |
|
1873 |
+
// Check if the option_page has an allowed value.
|
1874 |
+
if( $option_page = SucuriScanRequest::post('option_page') ){
|
1875 |
+
$nonce='_wpnonce';
|
1876 |
+
$action = '';
|
|
|
|
|
|
|
|
|
1877 |
|
1878 |
+
switch( $option_page ){
|
1879 |
+
case 'general': /* no_break */
|
1880 |
+
case 'writing': /* no_break */
|
1881 |
+
case 'reading': /* no_break */
|
1882 |
+
case 'discussion': /* no_break */
|
1883 |
+
case 'media': /* no_break */
|
1884 |
+
case 'options': /* no_break */
|
1885 |
+
$action = $option_page . '-options';
|
1886 |
+
break;
|
1887 |
+
case 'permalink':
|
1888 |
+
$action = 'update-permalink';
|
1889 |
+
break;
|
1890 |
+
}
|
1891 |
|
1892 |
+
// Check the nonce validity.
|
1893 |
+
if(
|
1894 |
+
!empty($action)
|
1895 |
+
&& isset($_REQUEST[$nonce])
|
1896 |
+
&& wp_verify_nonce($_REQUEST[$nonce], $action)
|
1897 |
+
){
|
1898 |
+
return TRUE;
|
1899 |
+
}
|
1900 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1901 |
|
1902 |
+
return FALSE;
|
|
|
|
|
|
|
|
|
|
|
|
|
1903 |
}
|
1904 |
|
1905 |
+
/**
|
1906 |
+
* Get the email address set by the administrator to receive the notifications
|
1907 |
+
* sent by the plugin, if the email is missing the WordPress email address is
|
1908 |
+
* chosen by default.
|
1909 |
+
*
|
1910 |
+
* @return string The administrator email address.
|
1911 |
+
*/
|
1912 |
+
public static function get_site_email(){
|
1913 |
+
$email = self::get_option('admin_email');
|
1914 |
|
1915 |
+
if( self::is_valid_email($email) ){
|
1916 |
+
return $email;
|
1917 |
+
}
|
1918 |
|
1919 |
+
return FALSE;
|
1920 |
+
}
|
1921 |
|
1922 |
+
/**
|
1923 |
+
* Get the clean version of the current domain.
|
1924 |
+
*
|
1925 |
+
* @return string The domain of the current site.
|
1926 |
+
*/
|
1927 |
+
public static function get_domain(){
|
1928 |
+
$http_host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : '';
|
1929 |
+
$domain_name = preg_replace( '/^www\./', '', $http_host );
|
1930 |
|
1931 |
+
return $domain_name;
|
1932 |
+
}
|
|
|
|
|
1933 |
|
1934 |
+
/**
|
1935 |
+
* Get a list of the post types ignored to receive email notifications when the
|
1936 |
+
* "new site content" hook is triggered.
|
1937 |
+
*
|
1938 |
+
* @return array List of ignored posts-types to send notifications.
|
1939 |
+
*/
|
1940 |
+
public static function get_ignored_events(){
|
1941 |
+
$post_types = self::get_option(':ignored_events');
|
1942 |
+
$post_types_arr = @unserialize($post_types);
|
1943 |
+
|
1944 |
+
if( !is_array($post_types_arr) ){
|
1945 |
+
$post_types_arr = array();
|
1946 |
}
|
|
|
|
|
|
|
1947 |
|
1948 |
+
return $post_types_arr;
|
1949 |
+
}
|
1950 |
|
1951 |
+
/**
|
1952 |
+
* Add a new post type to the list of ignored events to send notifications.
|
1953 |
+
*
|
1954 |
+
* @param string $event_name Unique post-type name.
|
1955 |
+
* @return boolean Whether the event was ignored or not.
|
1956 |
+
*/
|
1957 |
+
public static function add_ignored_event( $event_name='' ){
|
1958 |
+
if( function_exists('get_post_types') ){
|
1959 |
+
$post_types = get_post_types();
|
1960 |
|
1961 |
+
// Check if the event is a registered post-type.
|
1962 |
+
if( array_key_exists($event_name, $post_types) ){
|
1963 |
+
$ignored_events = self::get_ignored_events();
|
|
|
|
|
1964 |
|
1965 |
+
// Check if the event is not ignored already.
|
1966 |
+
if( !array_key_exists($event_name, $ignored_events) ){
|
1967 |
+
$ignored_events[$event_name] = time();
|
1968 |
+
$saved = self::update_option( ':ignored_events', serialize($ignored_events) );
|
1969 |
|
1970 |
+
return $saved;
|
1971 |
+
}
|
1972 |
}
|
|
|
|
|
|
|
1973 |
}
|
1974 |
+
|
1975 |
+
return FALSE;
|
1976 |
}
|
1977 |
|
1978 |
+
/**
|
1979 |
+
* Remove a post type from the list of ignored events to send notifications.
|
1980 |
+
*
|
1981 |
+
* @param string $event_name Unique post-type name.
|
1982 |
+
* @return boolean Whether the event was removed from the list or not.
|
1983 |
+
*/
|
1984 |
+
public static function remove_ignored_event( $event_name='' ){
|
1985 |
+
$ignored_events = self::get_ignored_events();
|
1986 |
|
1987 |
+
if( array_key_exists($event_name, $ignored_events) ){
|
1988 |
+
unset( $ignored_events[$event_name] );
|
1989 |
+
$saved = self::update_option( ':ignored_events', serialize($ignored_events) );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1990 |
|
1991 |
+
return $saved;
|
1992 |
+
}
|
1993 |
+
|
1994 |
+
return FALSE;
|
|
|
|
|
1995 |
}
|
1996 |
|
1997 |
+
/**
|
1998 |
+
* Check whether an event is being ignored to send notifications or not.
|
1999 |
+
*
|
2000 |
+
* @param string $event_name Unique post-type name.
|
2001 |
+
* @return boolean Whether an event is being ignored or not.
|
2002 |
+
*/
|
2003 |
+
public static function is_ignored_event( $event_name='' ){
|
2004 |
+
$event_name = strtolower($event_name);
|
2005 |
+
$ignored_events = self::get_ignored_events();
|
2006 |
+
|
2007 |
+
if( array_key_exists($event_name, $ignored_events) ){
|
2008 |
+
return TRUE;
|
2009 |
+
}
|
2010 |
|
2011 |
+
return FALSE;
|
|
|
2012 |
}
|
2013 |
|
2014 |
+
/**
|
2015 |
+
* Retrieve a list of basic security keys and check whether their values were
|
2016 |
+
* randomized correctly.
|
2017 |
+
*
|
2018 |
+
* @return array Array with three keys: good, missing, bad.
|
2019 |
+
*/
|
2020 |
+
public static function get_security_keys(){
|
2021 |
+
$response = array(
|
2022 |
+
'good' => array(),
|
2023 |
+
'missing' => array(),
|
2024 |
+
'bad' => array(),
|
2025 |
+
);
|
2026 |
+
$key_names = array(
|
2027 |
+
'AUTH_KEY',
|
2028 |
+
'AUTH_SALT',
|
2029 |
+
'LOGGED_IN_KEY',
|
2030 |
+
'LOGGED_IN_SALT',
|
2031 |
+
'NONCE_KEY',
|
2032 |
+
'NONCE_SALT',
|
2033 |
+
'SECURE_AUTH_KEY',
|
2034 |
+
'SECURE_AUTH_SALT',
|
2035 |
+
);
|
2036 |
|
2037 |
+
foreach( $key_names as $key_name ){
|
2038 |
+
if( defined($key_name) ){
|
2039 |
+
$key_value = constant($key_name);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2040 |
|
2041 |
+
if( stripos( $key_value, 'unique phrase' ) !== FALSE ){
|
2042 |
+
$response['bad'][$key_name] = $key_value;
|
2043 |
+
} else {
|
2044 |
+
$response['good'][$key_name] = $key_value;
|
2045 |
+
}
|
2046 |
+
} else {
|
2047 |
+
$response['missing'][$key_name] = FALSE;
|
2048 |
+
}
|
2049 |
+
}
|
2050 |
|
2051 |
+
return $response;
|
2052 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2053 |
|
2054 |
+
/**
|
2055 |
+
* Retrieve the last time when the filesystem scan was ran.
|
2056 |
+
*
|
2057 |
+
* @param boolean $format Whether the timestamp must be formatted as date/time or not.
|
2058 |
+
* @return string The timestamp of the runtime, or an string with the date/time.
|
2059 |
+
*/
|
2060 |
+
public static function get_filesystem_runtime( $format=FALSE ){
|
2061 |
+
$runtime = self::get_option(':runtime');
|
|
|
|
|
2062 |
|
2063 |
+
if( $runtime > 0 ){
|
2064 |
+
if( $format ){
|
2065 |
+
return date( 'd/M/Y H:i:s', $runtime );
|
2066 |
+
}
|
2067 |
|
2068 |
+
return $runtime;
|
2069 |
}
|
|
|
2070 |
|
2071 |
+
if( $format ){
|
2072 |
+
return '<em>Unknown</em>';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2073 |
}
|
2074 |
|
2075 |
+
return FALSE;
|
2076 |
}
|
2077 |
|
|
|
2078 |
}
|
2079 |
|
2080 |
/**
|
2081 |
+
* System events, reports and actions.
|
2082 |
+
*
|
2083 |
+
* An event is an action or occurrence detected by the program that may be
|
2084 |
+
* handled by the program. Typically events are handled synchronously with the
|
2085 |
+
* program flow, that is, the program has one or more dedicated places where
|
2086 |
+
* events are handled, frequently an event loop. Typical sources of events
|
2087 |
+
* include the user; another source is a hardware device such as a timer. Any
|
2088 |
+
* program can trigger its own custom set of events as well, e.g. to communicate
|
2089 |
+
* the completion of a task. A computer program that changes its behavior in
|
2090 |
+
* response to events is said to be event-driven, often with the goal of being
|
2091 |
+
* interactive.
|
2092 |
*
|
2093 |
+
* @see http://en.wikipedia.org/wiki/Event_(computing)
|
|
|
2094 |
*/
|
2095 |
+
class SucuriScanEvent extends SucuriScan {
|
|
|
|
|
2096 |
|
2097 |
+
/**
|
2098 |
+
* Schedule the task to run the first filesystem scan.
|
2099 |
+
*
|
2100 |
+
* @return void
|
2101 |
+
*/
|
2102 |
+
public static function schedule_task(){
|
2103 |
+
$task_name = 'sucuriscan_scheduled_scan';
|
2104 |
|
2105 |
+
if( !wp_next_scheduled($task_name) ){
|
2106 |
+
wp_schedule_event( time() + 10, 'twicedaily', $task_name );
|
|
|
|
|
|
|
|
|
2107 |
}
|
2108 |
|
2109 |
+
wp_schedule_single_event( time() + 300, $task_name );
|
2110 |
+
}
|
2111 |
|
2112 |
+
/**
|
2113 |
+
* Checks last time we ran to avoid running twice (or too often).
|
2114 |
+
*
|
2115 |
+
* @param integer $runtime When the filesystem scan must be scheduled to run.
|
2116 |
+
* @param boolean $force_scan Whether the filesystem scan was forced by an administrator user or not.
|
2117 |
+
* @return boolean Either TRUE or FALSE representing the success or fail of the operation respectively.
|
2118 |
+
*/
|
2119 |
+
private function verify_run( $runtime=0, $force_scan=FALSE ){
|
2120 |
+
$option_name = ':runtime';
|
2121 |
+
$last_run = SucuriScanOption::get_option($option_name);
|
2122 |
+
$current_time = time();
|
2123 |
|
2124 |
+
// The filesystem scanner can be disabled from the settings page.
|
2125 |
+
if(
|
2126 |
+
SucuriScanOption::get_option(':fs_scanner') == 'disabled'
|
2127 |
+
&& $force_scan === FALSE
|
2128 |
+
){
|
2129 |
+
return FALSE;
|
2130 |
}
|
2131 |
|
2132 |
+
// Check if the last runtime is too near the current time.
|
2133 |
+
if( $last_run && !$force_scan ){
|
2134 |
+
$runtime_diff = $current_time - $runtime;
|
|
|
|
|
|
|
|
|
2135 |
|
2136 |
+
if( $last_run >= $runtime_diff ){
|
2137 |
+
return FALSE;
|
2138 |
+
}
|
2139 |
+
}
|
2140 |
|
2141 |
+
SucuriScanOption::update_option( $option_name, $current_time );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2142 |
|
2143 |
+
return TRUE;
|
2144 |
+
}
|
|
|
2145 |
|
2146 |
+
/**
|
2147 |
+
* Check whether the current WordPress version must be reported to the API
|
2148 |
+
* service or not, this is to avoid duplicated information in the audit logs.
|
2149 |
+
*
|
2150 |
+
* @return boolean TRUE if the current WordPress version must be reported, FALSE otherwise.
|
2151 |
+
*/
|
2152 |
+
private function report_site_version(){
|
2153 |
+
$option_name = ':site_version';
|
2154 |
+
$reported_version = SucuriScanOption::get_option($option_name);
|
2155 |
+
$wp_version = self::site_version();
|
2156 |
|
2157 |
+
if( $reported_version != $wp_version ){
|
2158 |
+
SucuriScanAPI::send_log( 'WordPress version: ' . $wp_version );
|
2159 |
+
SucuriScanOption::update_option( $option_name, $wp_version );
|
2160 |
|
2161 |
+
return TRUE;
|
|
|
|
|
|
|
|
|
|
|
|
|
2162 |
}
|
2163 |
|
2164 |
+
return FALSE;
|
2165 |
}
|
2166 |
|
2167 |
+
/**
|
2168 |
+
* Gather all the checksums (aka. file hashes) of this site, send them, and
|
2169 |
+
* analyze them using the Sucuri Monitoring service, this will generate the
|
2170 |
+
* audit logs for this site and be part of the integrity checks.
|
2171 |
+
*
|
2172 |
+
* @param boolean $force_scan Whether the filesystem scan was forced by an administrator user or not.
|
2173 |
+
* @return boolean TRUE if the filesystem scan was successful, FALSE otherwise.
|
2174 |
+
*/
|
2175 |
+
public static function filesystem_scan( $force_scan=FALSE ){
|
2176 |
+
$minimum_runtime = SUCURISCAN_MINIMUM_RUNTIME;
|
2177 |
|
2178 |
+
if(
|
2179 |
+
self::verify_run( $minimum_runtime, $force_scan )
|
2180 |
+
&& class_exists('SucuriScanFileInfo')
|
2181 |
+
&& SucuriScanAPI::get_plugin_key()
|
2182 |
+
){
|
2183 |
+
self::report_site_version();
|
2184 |
|
2185 |
+
$sucuri_fileinfo = new SucuriScanFileInfo();
|
2186 |
+
$scan_interface = SucuriScanOption::get_option(':scan_interface');
|
2187 |
+
$signatures = $sucuri_fileinfo->get_directory_tree_md5(ABSPATH, $scan_interface);
|
|
|
|
|
|
|
|
|
|
|
2188 |
|
2189 |
+
if( $signatures ){
|
2190 |
+
$hashes_sent = SucuriScanAPI::send_hashes( $signatures );
|
2191 |
|
2192 |
+
if( $hashes_sent ){
|
2193 |
+
SucuriScanInterface::info( 'Successful filesystem scan' );
|
2194 |
+
SucuriScanOption::update_option( ':runtime', time() );
|
2195 |
+
return TRUE;
|
2196 |
+
} else {
|
2197 |
+
SucuriScanInterface::error( 'The file hashes could not be stored.' );
|
2198 |
+
}
|
2199 |
+
} else {
|
2200 |
+
SucuriScanInterface::error( 'The file hashes could not be retrieved, the filesystem scan failed.' );
|
2201 |
+
}
|
2202 |
+
}
|
2203 |
|
2204 |
+
return FALSE;
|
2205 |
+
}
|
2206 |
|
2207 |
+
/**
|
2208 |
+
* Generates an audit event log (to be sent later).
|
2209 |
+
*
|
2210 |
+
* @param integer $severity Importance of the event that will be reported, values from one to five.
|
2211 |
+
* @param string $location In which part of the system was the event triggered.
|
2212 |
+
* @param string $message The explanation of the event.
|
2213 |
+
* @return boolean TRUE if the event was logged in the monitoring service, FALSE otherwise.
|
2214 |
+
*/
|
2215 |
+
public static function report_event( $severity=0, $location='', $message='' ){
|
2216 |
+
$user = wp_get_current_user();
|
2217 |
+
$username = FALSE;
|
2218 |
+
$current_time = date( 'Y-m-d H:i:s' );
|
2219 |
+
$remote_ip = self::get_remote_addr();
|
2220 |
+
|
2221 |
+
// Fixing severity value.
|
2222 |
+
$severity = (int) $severity;
|
2223 |
+
if( $severity > 0 ){ $severity = 1; }
|
2224 |
+
elseif( $severity > 5 ){ $severity = 5; }
|
2225 |
+
|
2226 |
+
// Identify current user in session.
|
2227 |
+
if(
|
2228 |
+
$user instanceof WP_User
|
2229 |
+
&& isset($user->user_login)
|
2230 |
+
&& !empty($user->user_login)
|
2231 |
+
){
|
2232 |
+
if( $user->user_login != $user->display_name ){
|
2233 |
+
$username = sprintf( ' %s (%s),', $user->display_name, $user->user_login );
|
2234 |
+
} else {
|
2235 |
+
$username = sprintf( ' %s,', $user->user_login );
|
2236 |
+
}
|
2237 |
+
}
|
2238 |
|
2239 |
+
// Convert the severity number into a readable string.
|
2240 |
+
switch( $severity ){
|
2241 |
+
case 0: $severity_name = 'Debug'; break;
|
2242 |
+
case 1: $severity_name = 'Notice'; break;
|
2243 |
+
case 2: $severity_name = 'Info'; break;
|
2244 |
+
case 3: $severity_name = 'Warning'; break;
|
2245 |
+
case 4: $severity_name = 'Error'; break;
|
2246 |
+
case 5: $severity_name = 'Critical'; break;
|
2247 |
+
default: $severity_name = 'Info'; break;
|
2248 |
+
}
|
2249 |
+
|
2250 |
+
$message = str_replace( array("\n", "\r"), array('', ''), $message );
|
2251 |
+
$event_message = sprintf(
|
2252 |
+
'%s:%s %s; %s',
|
2253 |
+
$severity_name,
|
2254 |
+
$username,
|
2255 |
+
$remote_ip,
|
2256 |
+
$message
|
2257 |
+
);
|
2258 |
|
2259 |
+
return SucuriScanAPI::send_log($event_message);
|
2260 |
+
}
|
2261 |
|
2262 |
+
/**
|
2263 |
+
* Send a notification to the administrator of the specified events, only if
|
2264 |
+
* the administrator accepted to receive alerts for this type of events.
|
2265 |
+
*
|
2266 |
+
* @param string $event The name of the event that was triggered.
|
2267 |
+
* @param string $content Body of the email that will be sent to the administrator.
|
2268 |
+
* @return void
|
2269 |
+
*/
|
2270 |
+
public static function notify_event( $event='', $content='' ){
|
2271 |
+
$notify = SucuriScanOption::get_option(':notify_' . $event);
|
2272 |
+
$email = SucuriScanOption::get_option(':notify_to');
|
2273 |
+
$email_params = array();
|
2274 |
+
|
2275 |
+
if( $notify == 'enabled' ){
|
2276 |
+
if( $event == 'post_publication' ){
|
2277 |
+
$event = 'post_update';
|
2278 |
+
}
|
2279 |
|
2280 |
+
elseif( $event == 'failed_login' ){
|
2281 |
+
$content .= '<br><br><em>Explanation: Someone failed to login to your site. If you
|
2282 |
+
are getting too many of these messages, it is likely your site is under a brute
|
2283 |
+
force attack. You can disable the notifications for failed logins from
|
2284 |
+
<a href="' . SucuriScanTemplate::get_url('settings') . '" target="_blank">here</a>.
|
2285 |
+
More details at <a href="http://kb.sucuri.net/definitions/attacks/brute-force/password-guessing"
|
2286 |
+
target="_blank">Password Guessing Brute Force Attacks</a>.</em>';
|
2287 |
+
}
|
2288 |
|
2289 |
+
// Send a notification even if the limit of emails per hour was reached.
|
2290 |
+
elseif( $event == 'bruteforce_attack' ){
|
2291 |
+
$email_params['Force'] = TRUE;
|
2292 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2293 |
|
2294 |
+
$title = sprintf( 'Sucuri notification (%s)', str_replace('_', chr(32), $event) );
|
2295 |
+
$mail_sent = SucuriScanMail::send_mail( $email, $title, $content, $email_params );
|
|
|
2296 |
|
2297 |
+
return $mail_sent;
|
|
|
|
|
2298 |
}
|
|
|
2299 |
|
2300 |
+
return FALSE;
|
2301 |
+
}
|
|
|
|
|
2302 |
|
2303 |
+
/**
|
2304 |
+
* Generate and set a new password for a specific user not in session.
|
2305 |
+
*
|
2306 |
+
* @param integer $user_id The user identifier that will be changed, this must be different than the user in session.
|
2307 |
+
* @return boolean Either TRUE or FALSE in case of success or error respectively.
|
2308 |
+
*/
|
2309 |
+
public static function set_new_password( $user_id=0 ){
|
2310 |
+
$user_id = intval($user_id);
|
|
|
|
|
|
|
|
|
2311 |
|
2312 |
+
if( $user_id > 0 && function_exists('wp_generate_password') ){
|
2313 |
+
$user = get_userdata($user_id);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2314 |
|
2315 |
+
if( $user instanceof WP_User ){
|
2316 |
+
$new_password = wp_generate_password(15, TRUE, FALSE);
|
|
|
2317 |
|
2318 |
+
$message .= 'The password for your user account <strong>"'. $user->display_name .'"</strong> '
|
2319 |
+
. 'in the website specified above was changed, this is the new password generated automatically '
|
2320 |
+
. 'by the system, please update as soon as possible.<br><div style="display:inline-block;'
|
2321 |
+
. 'background:#ddd;font-family:monaco,monospace,courier;font-size:30px;margin:0;padding:15px;'
|
2322 |
+
. 'border:1px solid #999">'. $new_password .'</div>';
|
2323 |
|
2324 |
+
$data_set = array( 'Force' => TRUE ); // Skip limit for emails per hour.
|
2325 |
+
SucuriScanMail::send_mail( $user->user_email, 'Password changed', $message, $data_set );
|
|
|
|
|
|
|
|
|
|
|
|
|
2326 |
|
2327 |
+
wp_set_password($new_password, $user_id);
|
|
|
|
|
2328 |
|
2329 |
+
return TRUE;
|
|
|
2330 |
}
|
|
|
|
|
2331 |
}
|
|
|
2332 |
|
2333 |
+
return FALSE;
|
2334 |
+
}
|
2335 |
|
2336 |
+
/**
|
2337 |
+
* Modify the WordPress configuration file and change the keys that were defined
|
2338 |
+
* by a new random-generated list of keys retrieved from the official WordPress
|
2339 |
+
* API. The result of the operation will be either FALSE in case of error, or an
|
2340 |
+
* array containing multiple indexes explaining the modification, among them you
|
2341 |
+
* will find the old and new keys.
|
2342 |
+
*
|
2343 |
+
* @return false|array Either FALSE in case of error, or an array with the old and new keys.
|
2344 |
+
*/
|
2345 |
+
public static function set_new_config_keys(){
|
2346 |
+
$new_wpconfig = '';
|
2347 |
+
$config_path = self::get_wpconfig_path();
|
2348 |
+
|
2349 |
+
if( $config_path ){
|
2350 |
+
$pattern = self::secret_key_pattern();
|
2351 |
+
$define_tpl = "define('%s',%s'%s');";
|
2352 |
+
$config_lines = SucuriScanFileInfo::file_lines($config_path);
|
2353 |
+
$new_keys = SucuriScanAPI::get_new_secret_keys();
|
2354 |
+
$old_keys = array();
|
2355 |
+
$old_keys_string = '';
|
2356 |
+
$new_keys_string = '';
|
2357 |
+
|
2358 |
+
foreach( (array) $config_lines as $config_line ){
|
2359 |
+
$config_line = str_replace("\n", '', $config_line);
|
2360 |
+
|
2361 |
+
if( preg_match($pattern, $config_line, $match) ){
|
2362 |
+
$key_name = $match[1];
|
2363 |
+
|
2364 |
+
if( array_key_exists($key_name, $new_keys) ){
|
2365 |
+
$white_spaces = $match[2];
|
2366 |
+
$old_keys[$key_name] = $match[3];
|
2367 |
+
$config_line = sprintf( $define_tpl, $key_name, $white_spaces, $new_keys[$key_name] );
|
2368 |
+
$old_keys_string .= sprintf( $define_tpl, $key_name, $white_spaces, $old_keys[$key_name] ) . "\n";
|
2369 |
+
$new_keys_string .= $config_line . "\n";
|
2370 |
+
}
|
2371 |
}
|
2372 |
+
|
2373 |
+
$new_wpconfig .= $config_line . "\n";
|
2374 |
}
|
2375 |
|
2376 |
+
$response = array(
|
2377 |
+
'updated' => is_writable($config_path),
|
2378 |
+
'old_keys' => $old_keys,
|
2379 |
+
'old_keys_string' => $old_keys_string,
|
2380 |
+
'new_keys' => $new_keys,
|
2381 |
+
'new_keys_string' => $new_keys_string,
|
2382 |
+
'new_wpconfig' => $new_wpconfig,
|
2383 |
+
);
|
2384 |
|
2385 |
+
if( $response['updated'] ){
|
2386 |
+
file_put_contents($config_path, $new_wpconfig, LOCK_EX);
|
2387 |
+
}
|
|
|
|
|
|
|
|
|
|
|
2388 |
|
2389 |
+
return $response;
|
|
|
2390 |
}
|
2391 |
+
|
2392 |
+
return FALSE;
|
2393 |
}
|
2394 |
+
|
2395 |
}
|
2396 |
|
2397 |
/**
|
2398 |
+
* Function call interceptors.
|
2399 |
+
*
|
2400 |
+
* The term hooking covers a range of techniques used to alter or augment the
|
2401 |
+
* behavior of an operating system, of applications, or of other software
|
2402 |
+
* components by intercepting function calls or messages or events passed
|
2403 |
+
* between software components. Code that handles such intercepted function
|
2404 |
+
* calls, events or messages is called a "hook".
|
2405 |
*
|
2406 |
+
* Hooking is used for many purposes, including debugging and extending
|
2407 |
+
* functionality. Examples might include intercepting keyboard or mouse event
|
2408 |
+
* messages before they reach an application, or intercepting operating system
|
2409 |
+
* calls in order to monitor behavior or modify the function of an application
|
2410 |
+
* or other component; it is also widely used in benchmarking programs.
|
2411 |
*/
|
2412 |
+
class SucuriScanHook extends SucuriScanEvent {
|
|
|
|
|
2413 |
|
2414 |
+
/**
|
2415 |
+
* Send to Sucuri servers an alert advising that an attachment was added to a post.
|
2416 |
+
*
|
2417 |
+
* @param integer $id The post identifier.
|
2418 |
+
* @return void
|
2419 |
+
*/
|
2420 |
+
public static function hook_add_attachment( $id=0 ){
|
2421 |
+
$data = ( is_int($id) ? get_post($id) : FALSE );
|
2422 |
+
$title = ( $data ? $data->post_title : 'Unknown' );
|
2423 |
|
2424 |
+
$message = 'Media file added #'.$id.' ('.$title.')';
|
2425 |
+
self::report_event( 1, 'core', $message );
|
2426 |
+
self::notify_event( 'post_publication', $message );
|
2427 |
+
}
|
|
|
|
|
2428 |
|
2429 |
+
/**
|
2430 |
+
* Send an alert advising that a new link was added to the bookmarks.
|
2431 |
+
*
|
2432 |
+
* @param integer $id Identifier of the new link created;
|
2433 |
+
* @return void
|
2434 |
+
*/
|
2435 |
+
public static function hook_add_link( $id=0 ){
|
2436 |
+
$data = ( is_int($id) ? get_bookmark($id) : FALSE );
|
2437 |
|
2438 |
+
if( $data ){
|
2439 |
+
$title = $data->link_name;
|
2440 |
+
$url = $data->link_url;
|
2441 |
+
} else {
|
2442 |
+
$title = 'Unknown';
|
2443 |
+
$url = 'undefined/url';
|
2444 |
+
}
|
2445 |
+
|
2446 |
+
$message = 'New link added #'.$id.' ('.$title.': '.$url.')';
|
2447 |
+
self::report_event( 2, 'core', $message );
|
2448 |
+
self::notify_event( 'post_publication', $message );
|
2449 |
}
|
|
|
|
|
2450 |
|
2451 |
+
/**
|
2452 |
+
* Send an alert advising that a category was created.
|
2453 |
+
*
|
2454 |
+
* @param integer $id The identifier of the category created.
|
2455 |
+
* @return void
|
2456 |
+
*/
|
2457 |
+
public static function hook_create_category( $id=0 ){
|
2458 |
+
$title = ( is_int($id) ? get_cat_name($id) : 'Unknown' );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2459 |
|
2460 |
+
$message = 'Category created #'.$id.' ('.$title.')';
|
2461 |
+
self::report_event( 1, 'core', $message );
|
2462 |
+
self::notify_event( 'post_publication', $message );
|
2463 |
}
|
2464 |
|
2465 |
+
/**
|
2466 |
+
* Send an alert advising that a post was deleted.
|
2467 |
+
*
|
2468 |
+
* @param integer $id The identifier of the post deleted.
|
2469 |
+
* @return void
|
2470 |
+
*/
|
2471 |
+
public static function hook_delete_post( $id=0 ){
|
2472 |
+
self::report_event( 3, 'core', 'Post deleted #'.$id );
|
2473 |
}
|
2474 |
|
2475 |
+
/**
|
2476 |
+
* Send an alert advising that a user account was deleted.
|
2477 |
+
*
|
2478 |
+
* @param integer $id The identifier of the user account deleted.
|
2479 |
+
* @return void
|
2480 |
+
*/
|
2481 |
+
public static function hook_delete_user( $id=0 ){
|
2482 |
+
self::report_event( 3, 'core', 'User account deleted #'.$id );
|
2483 |
+
}
|
2484 |
|
2485 |
+
/**
|
2486 |
+
* Send an alert advising that an attempt to reset the password
|
2487 |
+
* of an user account was executed.
|
2488 |
+
*
|
2489 |
+
* @return void
|
2490 |
+
*/
|
2491 |
+
public static function hook_login_form_resetpass(){
|
2492 |
+
// Detecting WordPress 2.8.3 vulnerability - $key is array.
|
2493 |
+
if( isset($_GET['key']) && is_array($_GET['key']) ){
|
2494 |
+
self::report_event( 3, 'core', 'Attempt to reset password by attacking WP/2.8.3 bug' );
|
2495 |
+
}
|
2496 |
}
|
2497 |
|
2498 |
+
/**
|
2499 |
+
* Send an alert advising that the state of a post was changed
|
2500 |
+
* from private to published. This will only applies for posts not pages.
|
2501 |
+
*
|
2502 |
+
* @param integer $id The identifier of the post changed.
|
2503 |
+
* @return void
|
2504 |
+
*/
|
2505 |
+
public static function hook_private_to_published( $id=0 ){
|
2506 |
+
$data = ( is_int($id) ? get_post($id) : FALSE );
|
2507 |
|
2508 |
+
if( $data ){
|
2509 |
+
$title = $data->post_title;
|
2510 |
+
$p_type = ucwords($data->post_type);
|
2511 |
+
} else {
|
2512 |
+
$title = 'Unknown';
|
2513 |
+
$p_type = 'Publication';
|
2514 |
+
}
|
|
|
|
|
|
|
2515 |
|
2516 |
+
// Check whether the post-type is being ignored to send notifications.
|
2517 |
+
if( !SucuriScanOption::is_ignored_event($p_type) ){
|
2518 |
+
$message = $p_type.' changed from private to published #'.$id.' ('.$title.')';
|
2519 |
+
self::report_event( 2, 'core', $message );
|
2520 |
+
self::notify_event( 'post_publication', $message );
|
2521 |
+
}
|
2522 |
}
|
2523 |
|
2524 |
+
/**
|
2525 |
+
* Send an alert advising that a post was published.
|
2526 |
+
*
|
2527 |
+
* @param integer $id The identifier of the post or page published.
|
2528 |
+
* @return void
|
2529 |
+
*/
|
2530 |
+
public static function hook_publish( $id=0 ){
|
2531 |
+
$data = ( is_int($id) ? get_post($id) : FALSE );
|
2532 |
|
2533 |
+
if( $data ){
|
2534 |
+
$title = $data->post_title;
|
2535 |
+
$p_type = ucwords($data->post_type);
|
2536 |
+
$action = ( $data->post_date == $data->post_modified ? 'created' : 'updated' );
|
2537 |
+
} else {
|
2538 |
+
$title = 'Unknown';
|
2539 |
+
$p_type = 'Publication';
|
2540 |
+
$action = 'published';
|
2541 |
+
}
|
2542 |
|
2543 |
+
$message = $p_type.' was '.$action.' #'.$id.' ('.$title.')';
|
2544 |
+
self::report_event( 2, 'core', $message );
|
2545 |
+
self::notify_event( 'post_publication', $message );
|
|
|
2546 |
}
|
2547 |
|
2548 |
+
/**
|
2549 |
+
* Alias function for hook_publish()
|
2550 |
+
*
|
2551 |
+
* @param integer $id The identifier of the post or page published.
|
2552 |
+
* @return void
|
2553 |
+
*/
|
2554 |
+
public static function hook_publish_page( $id=0 ){
|
2555 |
+
self::hook_publish($id);
|
2556 |
+
}
|
2557 |
|
2558 |
+
/**
|
2559 |
+
* Alias function for hook_publish()
|
2560 |
+
*
|
2561 |
+
* @param integer $id The identifier of the post or page published.
|
2562 |
+
* @return void
|
2563 |
+
*/
|
2564 |
+
public static function hook_publish_post( $id=0 ){
|
2565 |
+
self::hook_publish($id);
|
2566 |
+
}
|
2567 |
|
2568 |
+
/**
|
2569 |
+
* Alias function for hook_publish()
|
2570 |
+
*
|
2571 |
+
* @param integer $id The identifier of the post or page published.
|
2572 |
+
* @return void
|
2573 |
+
*/
|
2574 |
+
public static function hook_publish_phone( $id=0 ){
|
2575 |
+
self::hook_publish($id);
|
2576 |
}
|
2577 |
|
2578 |
+
/**
|
2579 |
+
* Alias function for hook_publish()
|
2580 |
+
*
|
2581 |
+
* @param integer $id The identifier of the post or page published.
|
2582 |
+
* @return void
|
2583 |
+
*/
|
2584 |
+
public static function hook_xmlrpc_publish_post( $id=0 ){
|
2585 |
+
self::hook_publish($id);
|
2586 |
+
}
|
2587 |
|
2588 |
+
/**
|
2589 |
+
* Send an alert advising that an attempt to retrieve the password
|
2590 |
+
* of an user account was tried.
|
2591 |
+
*
|
2592 |
+
* @param string $title The name of the user account involved in the trasaction.
|
2593 |
+
* @return void
|
2594 |
+
*/
|
2595 |
+
public static function hook_retrieve_password( $title='' ){
|
2596 |
+
if( empty($title) ){ $title = 'Unknown'; }
|
|
|
|
|
2597 |
|
2598 |
+
self::report_event( 3, 'core', 'Password retrieval attempt for user: '.$title );
|
|
|
|
|
|
|
|
|
2599 |
}
|
2600 |
|
2601 |
+
/**
|
2602 |
+
* Send an alert advising that the theme of the site was changed.
|
2603 |
+
*
|
2604 |
+
* @param string $title The name of the new theme selected to used through out the site.
|
2605 |
+
* @return void
|
2606 |
+
*/
|
2607 |
+
public static function hook_switch_theme( $title='' ){
|
2608 |
+
if( empty($title) ){ $title = 'Unknown'; }
|
|
|
|
|
|
|
|
|
2609 |
|
2610 |
+
$message = 'Theme switched to: '.$title;
|
2611 |
+
self::report_event( 3, 'core', $message );
|
2612 |
+
self::notify_event( 'theme_switched', $message );
|
2613 |
}
|
2614 |
|
2615 |
+
/**
|
2616 |
+
* Send an alert advising that a new user account was created.
|
2617 |
+
*
|
2618 |
+
* @param integer $id The identifier of the new user account created.
|
2619 |
+
* @return void
|
2620 |
+
*/
|
2621 |
+
public static function hook_user_register( $id=0 ){
|
2622 |
+
$data = ( is_int($id) ? get_userdata($id) : FALSE );
|
2623 |
+
$title = ( $data ? $data->display_name : 'Unknown' );
|
2624 |
|
2625 |
+
$message = 'New user account registered #'.$id.' ('.$title.')';
|
2626 |
+
self::report_event( 3, 'core', $message );
|
2627 |
+
self::notify_event( 'user_registration', $message );
|
2628 |
+
}
|
|
|
|
|
|
|
|
|
2629 |
|
2630 |
+
/**
|
2631 |
+
* Send an alert advising that an attempt to login into the
|
2632 |
+
* administration panel was successful.
|
2633 |
+
*
|
2634 |
+
* @param string $title The name of the user account involved in the transaction.
|
2635 |
+
* @return void
|
2636 |
+
*/
|
2637 |
+
public static function hook_wp_login( $title='' ){
|
2638 |
+
if( empty($title) ){ $title = 'Unknown'; }
|
2639 |
|
2640 |
+
$message = 'User logged in: '.$title;
|
2641 |
+
self::report_event( 2, 'core', $message );
|
2642 |
+
self::notify_event( 'success_login', $message );
|
2643 |
+
}
|
|
|
|
|
|
|
2644 |
|
2645 |
+
/**
|
2646 |
+
* Send an alert advising that an attempt to login into the
|
2647 |
+
* administration panel failed.
|
2648 |
+
*
|
2649 |
+
* @param string $title The name of the user account involved in the transaction.
|
2650 |
+
* @return void
|
2651 |
+
*/
|
2652 |
+
public static function hook_wp_login_failed( $title='' ){
|
2653 |
+
if( empty($title) ){ $title = 'Unknown'; }
|
2654 |
|
2655 |
+
$message = 'User authentication failed: '.$title;
|
2656 |
+
self::report_event( 2, 'core', $message );
|
2657 |
+
self::notify_event( 'failed_login', $message );
|
2658 |
|
2659 |
+
// Log the failed login in the internal datastore for future reports.
|
2660 |
+
$logged = sucuriscan_log_failed_login($title);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2661 |
|
2662 |
+
// Check if the quantity of failed logins will be considered as a brute-force attack.
|
2663 |
+
if( $logged ){
|
2664 |
+
$failed_logins = sucuriscan_get_failed_logins();
|
2665 |
|
2666 |
+
if( $failed_logins ){
|
2667 |
+
$max_time = 3600;
|
2668 |
+
$maximum_failed_logins = SucuriScanOption::get_option('sucuriscan_maximum_failed_logins');
|
2669 |
|
2670 |
+
/**
|
2671 |
+
* If the time passed is within the hour, and the quantity of failed logins
|
2672 |
+
* registered in the datastore file is bigger than the maximum quantity of
|
2673 |
+
* failed logins allowed per hour (value configured by the administrator in the
|
2674 |
+
* settings page), then send an email notification reporting the event and
|
2675 |
+
* specifying that it may be a brute-force attack against the login page.
|
2676 |
+
*/
|
2677 |
+
if(
|
2678 |
+
$failed_logins['diff_time'] <= $max_time
|
2679 |
+
&& $failed_logins['count'] >= $maximum_failed_logins
|
2680 |
+
){
|
2681 |
+
sucuriscan_report_failed_logins($failed_logins);
|
2682 |
+
}
|
2683 |
|
2684 |
+
/**
|
2685 |
+
* If there time passed is superior to the hour, then reset the content of the
|
2686 |
+
* datastore file containing the failed logins so far, any entry in that file
|
2687 |
+
* will not be considered as part of a brute-force attack (if it exists) because
|
2688 |
+
* the time passed between the first and last login attempt is big enough to
|
2689 |
+
* mitigate the attack. We will consider the current failed login event as the
|
2690 |
+
* first entry of that file in case of future attempts during the next sixty
|
2691 |
+
* minutes.
|
2692 |
+
*/
|
2693 |
+
elseif( $failed_logins['diff_time'] > $max_time ){
|
2694 |
+
sucuriscan_reset_failed_logins();
|
2695 |
+
sucuriscan_log_failed_login($title);
|
2696 |
+
}
|
2697 |
+
}
|
2698 |
+
}
|
2699 |
+
}
|
2700 |
|
2701 |
+
// TODO: Detect auto updates in core, themes, and plugin files.
|
|
|
2702 |
|
2703 |
+
/**
|
2704 |
+
* Send a notifications to the administrator of some specific events that are
|
2705 |
+
* not triggered through an hooked action, but through a simple request in the
|
2706 |
+
* admin interface.
|
2707 |
+
*
|
2708 |
+
* @return integer Either one or zero representing the success or fail of the operation.
|
2709 |
+
*/
|
2710 |
+
public static function hook_undefined_actions(){
|
|
|
|
|
|
|
2711 |
|
2712 |
+
// Plugin activation and/or deactivation.
|
2713 |
+
if(
|
2714 |
+
current_user_can('activate_plugins')
|
2715 |
+
&& (
|
2716 |
+
SucuriScanRequest::get('action', '(activate|deactivate)') ||
|
2717 |
+
SucuriScanRequest::post('action', '(activate|deactivate)-selected')
|
2718 |
+
)
|
2719 |
+
){
|
2720 |
+
$plugin_list = array();
|
2721 |
|
2722 |
+
if(
|
2723 |
+
SucuriScanRequest::get('plugin', '.+')
|
2724 |
+
&& strpos($_SERVER['REQUEST_URI'], 'plugins.php') !== FALSE
|
2725 |
+
){
|
2726 |
+
$action_d = $_GET['action'] . 'd';
|
2727 |
+
$plugin_list[] = $_GET['plugin'];
|
2728 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2729 |
|
2730 |
+
elseif(
|
2731 |
+
isset($_POST['checked'])
|
2732 |
+
&& is_array($_POST['checked'])
|
2733 |
+
&& !empty($_POST['checked'])
|
2734 |
+
){
|
2735 |
+
$action_d = str_replace('-selected', 'd', $_POST['action']);
|
2736 |
+
$plugin_list = $_POST['checked'];
|
2737 |
+
}
|
|
|
|
|
|
|
|
|
|
|
2738 |
|
2739 |
+
foreach( $plugin_list as $plugin ){
|
2740 |
+
$plugin_info = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin );
|
2741 |
|
2742 |
+
if(
|
2743 |
+
!empty($plugin_info['Name'])
|
2744 |
+
&& !empty($plugin_info['Version'])
|
2745 |
+
){
|
2746 |
+
$message = sprintf(
|
2747 |
+
'Plugin %s: %s (v%s; %s)',
|
2748 |
+
$action_d,
|
2749 |
+
self::escape($plugin_info['Name']),
|
2750 |
+
self::escape($plugin_info['Version']),
|
2751 |
+
self::escape($plugin)
|
2752 |
+
);
|
2753 |
+
|
2754 |
+
self::report_event( 3, 'core', $message );
|
2755 |
+
self::notify_event( 'plugin_' . $action_d, $message );
|
2756 |
+
}
|
2757 |
+
}
|
2758 |
+
}
|
2759 |
|
2760 |
+
// Plugin update request.
|
2761 |
+
elseif(
|
2762 |
+
current_user_can('update_plugins')
|
2763 |
+
&& (
|
2764 |
+
SucuriScanRequest::get('action', '(upgrade-plugin|do-plugin-upgrade)')
|
2765 |
+
|| SucuriScanRequest::post('action', 'update-selected')
|
2766 |
+
)
|
2767 |
+
){
|
2768 |
+
$plugin_list = array();
|
|
|
|
|
|
|
|
|
2769 |
|
2770 |
+
if(
|
2771 |
+
SucuriScanRequest::get('plugin', '.+')
|
2772 |
+
&& strpos($_SERVER['REQUEST_URI'], 'wp-admin/update.php') !== FALSE
|
2773 |
+
){
|
2774 |
+
$plugin_list[] = SucuriScanRequest::get('plugin', '.+');
|
2775 |
+
}
|
2776 |
|
2777 |
+
elseif(
|
2778 |
+
isset($_POST['checked'])
|
2779 |
+
&& is_array($_POST['checked'])
|
2780 |
+
&& !empty($_POST['checked'])
|
2781 |
+
){
|
2782 |
+
$plugin_list = $_POST['checked'];
|
2783 |
+
}
|
2784 |
|
2785 |
+
foreach( $plugin_list as $plugin ){
|
2786 |
+
$plugin_info = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin );
|
|
|
|
|
|
|
|
|
|
|
|
|
2787 |
|
2788 |
+
if(
|
2789 |
+
!empty($plugin_info['Name'])
|
2790 |
+
&& !empty($plugin_info['Version'])
|
2791 |
+
){
|
2792 |
+
$message = sprintf(
|
2793 |
+
'Plugin request to be updated: %s (v%s; %s)',
|
2794 |
+
self::escape($plugin_info['Name']),
|
2795 |
+
self::escape($plugin_info['Version']),
|
2796 |
+
self::escape($plugin)
|
2797 |
+
);
|
2798 |
+
|
2799 |
+
self::report_event( 3, 'core', $message );
|
2800 |
+
self::notify_event( 'plugin_updated', $message );
|
2801 |
+
}
|
2802 |
+
}
|
2803 |
+
}
|
2804 |
|
2805 |
+
// Plugin installation request.
|
2806 |
+
elseif(
|
2807 |
+
current_user_can('install_plugins')
|
2808 |
+
&& SucuriScanRequest::get('action', '(install|upload)-plugin')
|
2809 |
+
){
|
2810 |
+
if( isset($_FILES['pluginzip']) ){
|
2811 |
+
$plugin = self::escape($_FILES['pluginzip']['name']);
|
2812 |
+
} else {
|
2813 |
+
$plugin = SucuriScanRequest::get('plugin', '.+');
|
2814 |
|
2815 |
+
if( !$plugin ){ $plugin = 'Unknown'; }
|
2816 |
+
}
|
2817 |
|
2818 |
+
$message = 'Plugin request to be installed: ' . self::escape($plugin);
|
2819 |
+
self::report_event( 3, 'core', $message );
|
2820 |
+
self::notify_event( 'plugin_installed', $message );
|
2821 |
+
}
|
2822 |
+
|
2823 |
+
// Plugin deletion request.
|
2824 |
+
elseif(
|
2825 |
+
current_user_can('delete_plugins')
|
2826 |
+
&& SucuriScanRequest::post('action', 'delete-selected')
|
2827 |
+
&& SucuriScanRequest::post('verify-delete', '1')
|
2828 |
+
){
|
2829 |
+
$plugin_list = (array) $_POST['checked'];
|
2830 |
+
|
2831 |
+
foreach( $plugin_list as $plugin ){
|
2832 |
+
$plugin_info = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2833 |
|
2834 |
+
if(
|
2835 |
+
!empty($plugin_info['Name'])
|
2836 |
+
&& !empty($plugin_info['Version'])
|
2837 |
+
){
|
2838 |
+
$message = sprintf(
|
2839 |
+
'Plugin request to be deleted: %s (v%s; %s)',
|
2840 |
+
self::escape($plugin_info['Name']),
|
2841 |
+
self::escape($plugin_info['Version']),
|
2842 |
+
self::escape($plugin)
|
2843 |
+
);
|
2844 |
+
|
2845 |
+
self::report_event( 3, 'core', $message );
|
2846 |
+
self::notify_event( 'plugin_deleted', $message );
|
2847 |
+
}
|
2848 |
}
|
2849 |
}
|
|
|
|
|
2850 |
|
2851 |
+
// Plugin editor request.
|
2852 |
+
elseif(
|
2853 |
+
current_user_can('edit_plugins')
|
2854 |
+
&& SucuriScanRequest::post('action', 'update')
|
2855 |
+
&& SucuriScanRequest::post('plugin', '.+')
|
2856 |
+
&& SucuriScanRequest::post('file', '.+')
|
2857 |
+
&& strpos($_SERVER['REQUEST_URI'], 'plugin-editor.php') !== FALSE
|
2858 |
+
){
|
2859 |
+
$message = 'Plugin editor used on: ' . SucuriScanRequest::post('file');
|
2860 |
+
self::report_event( 3, 'core', $message );
|
2861 |
+
self::notify_event( 'theme_editor', $message );
|
2862 |
}
|
|
|
2863 |
|
2864 |
+
// Theme editor request.
|
2865 |
+
elseif(
|
2866 |
+
current_user_can('edit_themes')
|
2867 |
+
&& SucuriScanRequest::post('action', 'update')
|
2868 |
+
&& SucuriScanRequest::post('theme', '.+')
|
2869 |
+
&& SucuriScanRequest::post('file', '.+')
|
2870 |
+
&& strpos($_SERVER['REQUEST_URI'], 'theme-editor.php') !== FALSE
|
2871 |
+
){
|
2872 |
+
$message = 'Theme editor used on: ' . SucuriScanRequest::post('theme') . '/' . SucuriScanRequest::post('file');
|
2873 |
+
self::report_event( 3, 'core', $message );
|
2874 |
+
self::notify_event( 'theme_editor', $message );
|
2875 |
+
}
|
2876 |
|
2877 |
+
// Theme activation and/or deactivation (same hook for switch_theme).
|
2878 |
+
// Theme installation request (hook not available).
|
2879 |
+
// Theme deletion request (hook not available).
|
|
|
|
|
|
|
|
|
|
|
|
|
2880 |
|
2881 |
+
// Theme update request.
|
2882 |
+
elseif(
|
2883 |
+
current_user_can('update_themes')
|
2884 |
+
&& SucuriScanRequest::get('action', '(upgrade-theme|do-theme-upgrade)')
|
2885 |
+
&& SucuriScanRequest::post('checked')
|
2886 |
+
){
|
2887 |
+
foreach( (array) $_POST['checked'] as $theme ){
|
2888 |
+
$theme_info = wp_get_theme($theme);
|
2889 |
+
$theme_name = ucwords($theme);
|
2890 |
+
$theme_version = '0.0';
|
2891 |
|
2892 |
+
if( $theme_info->exists() ){
|
2893 |
+
$theme_name = $theme_info->get('Name');
|
2894 |
+
$theme_version = $theme_info->get('Version');
|
2895 |
+
}
|
2896 |
|
2897 |
+
$message = sprintf(
|
2898 |
+
'Theme updated: %s (v%s; %s)',
|
2899 |
+
self::escape($theme_name),
|
2900 |
+
self::escape($theme_version),
|
2901 |
+
self::escape($theme)
|
2902 |
+
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2903 |
|
2904 |
+
self::report_event( 3, 'core', $message );
|
2905 |
+
self::notify_event( 'theme_updated', $message );
|
2906 |
+
}
|
2907 |
+
}
|
2908 |
+
|
2909 |
+
// WordPress update request.
|
2910 |
+
elseif(
|
2911 |
+
current_user_can('update_core')
|
2912 |
+
&& SucuriScanRequest::get('action', '(do-core-upgrade|do-core-reinstall)')
|
2913 |
+
&& SucuriScanRequest::post('upgrade')
|
2914 |
){
|
2915 |
+
$message = 'WordPress updated to version: ' . SucuriScanRequest::post('version');
|
2916 |
+
self::report_event( 3, 'core', $message );
|
2917 |
+
self::notify_event( 'website_updated', $message );
|
2918 |
}
|
|
|
|
|
|
|
2919 |
|
2920 |
+
// Widget addition or deletion.
|
2921 |
+
elseif(
|
2922 |
+
current_user_can('edit_theme_options')
|
2923 |
+
&& SucuriScanRequest::post('action', 'save-widget')
|
2924 |
+
&& SucuriScanRequest::post('id_base') !== FALSE
|
2925 |
+
&& SucuriScanRequest::post('sidebar') !== FALSE
|
2926 |
+
){
|
2927 |
+
if( SucuriScanRequest::post('delete_widget', '1') ){
|
2928 |
+
$action_d = 'deleted';
|
2929 |
+
$action_text = 'deleted from';
|
2930 |
+
} else {
|
2931 |
+
$action_d = 'added';
|
2932 |
+
$action_text = 'added to';
|
2933 |
+
}
|
2934 |
+
|
2935 |
+
$message = sprintf(
|
2936 |
+
'Widget %s (%s) %s %s (#%d; size %dx%d)',
|
2937 |
+
SucuriScanRequest::post('id_base'),
|
2938 |
+
SucuriScanRequest::post('widget-id'),
|
2939 |
+
$action_text,
|
2940 |
+
SucuriScanRequest::post('sidebar'),
|
2941 |
+
SucuriScanRequest::post('widget_number'),
|
2942 |
+
SucuriScanRequest::post('widget-width'),
|
2943 |
+
SucuriScanRequest::post('widget-height')
|
2944 |
+
);
|
2945 |
|
2946 |
+
self::report_event( 3, 'core', $message );
|
2947 |
+
self::notify_event( 'widget_' . $action_d, $message );
|
2948 |
+
}
|
2949 |
|
2950 |
+
// Detect any Wordpress settings modification.
|
2951 |
+
elseif(
|
2952 |
+
current_user_can('manage_options')
|
2953 |
+
&& SucuriScanOption::check_options_nonce()
|
2954 |
+
){
|
2955 |
+
// Get the settings available in the database and compare them with the submission.
|
2956 |
+
$all_options = SucuriScanOption::get_site_options();
|
2957 |
+
$options_changed = SucuriScanOption::what_options_were_changed($_POST);
|
2958 |
+
$options_changed_str = '';
|
2959 |
+
$options_changed_count = 0;
|
2960 |
|
2961 |
+
// Generate the list of options changed.
|
2962 |
+
foreach( $options_changed['original'] as $option_name => $option_value ){
|
2963 |
+
$options_changed_count += 1;
|
2964 |
+
$options_changed_str .= sprintf(
|
2965 |
+
"The value of the option <b>%s</b> was changed from <b>'%s'</b> to <b>'%s'</b>.<br>\n",
|
2966 |
+
self::escape($option_name),
|
2967 |
+
self::escape($option_value),
|
2968 |
+
self::escape($options_changed['changed'][$option_name])
|
2969 |
+
);
|
2970 |
+
}
|
2971 |
|
2972 |
+
// Get the option group (name of the page where the request was originated).
|
2973 |
+
$option_page = isset($_POST['option_page']) ? $_POST['option_page'] : 'options';
|
2974 |
+
$page_referer = FALSE;
|
2975 |
|
2976 |
+
// Check which of these option groups where modified.
|
2977 |
+
switch( $option_page ){
|
2978 |
+
case 'options':
|
2979 |
+
$page_referer = 'Global';
|
2980 |
+
break;
|
2981 |
+
case 'general': /* no_break */
|
2982 |
+
case 'writing': /* no_break */
|
2983 |
+
case 'reading': /* no_break */
|
2984 |
+
case 'discussion': /* no_break */
|
2985 |
+
case 'media': /* no_break */
|
2986 |
+
case 'permalink':
|
2987 |
+
$page_referer = ucwords($option_page);
|
2988 |
+
break;
|
2989 |
+
default:
|
2990 |
+
$page_referer = 'Common';
|
2991 |
+
break;
|
2992 |
+
}
|
2993 |
|
2994 |
+
if( $page_referer && $options_changed_count > 0 ){
|
2995 |
+
$message = $page_referer.' settings changed';
|
2996 |
+
self::report_event( 3, 'core', $message );
|
2997 |
+
self::notify_event( 'settings_updated', $message . "<br>\n" . $options_changed_str );
|
2998 |
+
}
|
2999 |
}
|
3000 |
+
|
3001 |
}
|
3002 |
|
|
|
3003 |
}
|
3004 |
|
3005 |
/**
|
3006 |
+
* Plugin API library.
|
3007 |
+
*
|
3008 |
+
* When used in the context of web development, an API is typically defined as a
|
3009 |
+
* set of Hypertext Transfer Protocol (HTTP) request messages, along with a
|
3010 |
+
* definition of the structure of response messages, which is usually in an
|
3011 |
+
* Extensible Markup Language (XML) or JavaScript Object Notation (JSON) format.
|
3012 |
+
* While "web API" historically has been virtually synonymous for web service,
|
3013 |
+
* the recent trend (so-called Web 2.0) has been moving away from Simple Object
|
3014 |
+
* Access Protocol (SOAP) based web services and service-oriented architecture
|
3015 |
+
* (SOA) towards more direct representational state transfer (REST) style web
|
3016 |
+
* resources and resource-oriented architecture (ROA). Part of this trend is
|
3017 |
+
* related to the Semantic Web movement toward Resource Description Framework
|
3018 |
+
* (RDF), a concept to promote web-based ontology engineering technologies. Web
|
3019 |
+
* APIs allow the combination of multiple APIs into new applications known as
|
3020 |
+
* mashups.
|
3021 |
*
|
3022 |
+
* @see http://en.wikipedia.org/wiki/Application_programming_interface#Web_APIs
|
|
|
3023 |
*/
|
3024 |
+
class SucuriScanAPI extends SucuriScanOption {
|
|
|
3025 |
|
3026 |
+
/**
|
3027 |
+
* Check whether the SSL certificates will be verified while executing a HTTP
|
3028 |
+
* request or not. This is only for customization of the administrator, in fact
|
3029 |
+
* not verifying the SSL certificates can lead to a "Man in the Middle" attack.
|
3030 |
+
*
|
3031 |
+
* @return boolean Whether the SSL certs will be verified while sending a request.
|
3032 |
+
*/
|
3033 |
+
public static function verify_ssl_cert(){
|
3034 |
+
return ( self::get_option(':verify_ssl_cert') === 'true' );
|
3035 |
}
|
3036 |
|
3037 |
+
/**
|
3038 |
+
* Generate an user-agent for the HTTP requests.
|
3039 |
+
*
|
3040 |
+
* @return string An user-agent for the HTTP requests.
|
3041 |
+
*/
|
3042 |
+
private static function user_agent(){
|
3043 |
+
$user_agent = sprintf(
|
3044 |
+
'WordPress/%s; %s',
|
3045 |
+
self::site_version(),
|
3046 |
+
self::get_domain()
|
3047 |
+
);
|
3048 |
|
3049 |
+
return $user_agent;
|
3050 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3051 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3052 |
/**
|
3053 |
+
* Retrieves a URL using a changeable HTTP method, returning results in an
|
3054 |
+
* array. Results include HTTP headers and content.
|
|
|
3055 |
*
|
3056 |
+
* @see http://codex.wordpress.org/Function_Reference/wp_remote_post
|
3057 |
+
* @see http://codex.wordpress.org/Function_Reference/wp_remote_get
|
3058 |
+
*
|
3059 |
+
* @param string $url The target URL where the request will be sent.
|
3060 |
+
* @param string $method HTTP method that will be used to send the request.
|
3061 |
+
* @param array $params Parameters for the request defined in an associative array of key-value.
|
3062 |
+
* @param array $args Request arguments like the timeout, redirections, headers, cookies, etc.
|
3063 |
+
* @return array Array of results including HTTP headers or WP_Error if the request failed.
|
3064 |
*/
|
3065 |
+
private static function api_call( $url='', $method='GET', $params=array(), $args=array() ){
|
3066 |
+
if( !$url ){ return FALSE; }
|
3067 |
+
|
3068 |
+
$req_args = array(
|
3069 |
+
'method' => $method,
|
3070 |
+
'timeout' => 90,
|
3071 |
+
'redirection' => 2,
|
3072 |
+
'httpversion' => '1.0',
|
3073 |
+
'user-agent' => self::user_agent(),
|
3074 |
+
'blocking' => TRUE,
|
3075 |
+
'headers' => array(),
|
3076 |
+
'cookies' => array(),
|
3077 |
+
'compress' => FALSE,
|
3078 |
+
'decompress' => FALSE,
|
3079 |
+
'sslverify' => self::verify_ssl_cert(),
|
3080 |
+
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3081 |
|
3082 |
+
// Update the request arguments with the values passed tot he function.
|
3083 |
+
foreach( $args as $arg_name => $arg_value ){
|
3084 |
+
if( array_key_exists($arg_name, $req_args) ){
|
3085 |
+
$req_args[$arg_name] = $arg_value;
|
3086 |
+
}
|
3087 |
+
}
|
3088 |
|
3089 |
+
if( $method == 'GET' ){
|
3090 |
+
if( !empty($params) ){
|
3091 |
+
$url = sprintf( '%s?%s', $url, http_build_query($params) );
|
3092 |
+
}
|
3093 |
|
3094 |
+
$response = wp_remote_get( $url, $req_args );
|
3095 |
+
}
|
|
|
|
|
|
|
|
|
3096 |
|
3097 |
+
elseif( $method == 'POST' ){
|
3098 |
+
$req_args['body'] = $params;
|
3099 |
+
$response = wp_remote_post( $url, $req_args );
|
|
|
|
|
|
|
|
|
|
|
3100 |
}
|
3101 |
|
3102 |
+
if( isset($response) ){
|
3103 |
+
if( is_wp_error($response) ){
|
3104 |
+
SucuriScanInterface::error(sprintf(
|
3105 |
+
'Something went wrong with an API call (%s action): %s',
|
3106 |
+
( isset($params['a']) ? $params['a'] : 'unknown' ),
|
3107 |
+
$response->get_error_message()
|
3108 |
+
));
|
3109 |
} else {
|
3110 |
+
$response['body_raw'] = $response['body'];
|
|
|
|
|
|
|
|
|
|
|
3111 |
|
3112 |
+
// Check if the response data is JSON-encoded, then decode it.
|
3113 |
if(
|
3114 |
+
isset($response['headers']['content-type'])
|
3115 |
+
&& $response['headers']['content-type'] == 'application/json'
|
3116 |
){
|
3117 |
+
$response['body'] = @json_decode($response['body_raw']);
|
3118 |
+
}
|
3119 |
+
|
3120 |
+
// Check if the response data is serialized, then unserialize it.
|
3121 |
+
elseif( preg_match('/^(a|O):[0-9]+:.+/', $response['body']) ){
|
3122 |
+
$response['body'] = @unserialize($response['body']);
|
3123 |
}
|
3124 |
+
|
3125 |
+
return $response;
|
3126 |
}
|
3127 |
+
} else {
|
3128 |
+
SucuriScanInterface::error( 'HTTP method not allowed: ' . $method );
|
3129 |
}
|
3130 |
|
3131 |
+
return FALSE;
|
3132 |
+
}
|
3133 |
+
|
3134 |
+
/**
|
3135 |
+
* Store the API key locally.
|
3136 |
+
*
|
3137 |
+
* @param string $api_key An unique string of characters to identify this installation.
|
3138 |
+
* @param boolean $validate Whether the format of the key should be validated before store it.
|
3139 |
+
* @return boolean Either TRUE or FALSE if the key was saved successfully or not respectively.
|
3140 |
+
*/
|
3141 |
+
public static function set_plugin_key( $api_key='', $validate=FALSE ){
|
3142 |
+
if( $validate ){
|
3143 |
+
if( !preg_match('/^([a-z0-9]{32})$/', $api_key) ){
|
3144 |
+
SucuriScanInterface::error( 'Invalid API key format' );
|
3145 |
+
return FALSE;
|
3146 |
+
}
|
3147 |
+
}
|
3148 |
|
3149 |
+
if( !empty($api_key) ){
|
3150 |
+
SucuriScanEvent::notify_event( 'plugin_change', 'API key updated successfully: ' . $api_key );
|
3151 |
}
|
3152 |
+
|
3153 |
+
return self::update_option( ':api_key', $api_key );
|
3154 |
}
|
3155 |
|
3156 |
+
/**
|
3157 |
+
* Retrieve the API key from the local storage.
|
3158 |
+
*
|
3159 |
+
* @return string|boolean The API key or FALSE if it does not exists.
|
3160 |
+
*/
|
3161 |
+
public static function get_plugin_key(){
|
3162 |
+
$api_key = self::get_option(':api_key');
|
3163 |
+
|
3164 |
+
if( $api_key && strlen($api_key) > 10 ){
|
3165 |
+
return $api_key;
|
3166 |
+
}
|
3167 |
|
3168 |
+
return FALSE;
|
3169 |
+
}
|
3170 |
|
3171 |
+
/**
|
3172 |
+
* Check and return the API key for the plugin.
|
3173 |
+
*
|
3174 |
+
* In this plugin the key is a pair of two strings concatenated by a single
|
3175 |
+
* slash, the first part of it is in fact the key and the second part is the
|
3176 |
+
* unique identifier of the site in the remote server.
|
3177 |
+
*
|
3178 |
+
* @return array|boolean FALSE if the key is invalid or not present, an array otherwise.
|
3179 |
+
*/
|
3180 |
+
public static function get_cloudproxy_key(){
|
3181 |
+
$option_name = ':cloudproxy_apikey';
|
3182 |
+
$api_key = self::get_option($option_name);
|
3183 |
+
|
3184 |
+
// Check if the cloudproxy-waf plugin was previously installed.
|
3185 |
+
if( !$api_key ){
|
3186 |
+
$api_key = self::get_option('sucuriwaf_apikey');
|
3187 |
+
|
3188 |
+
if( $api_key ){
|
3189 |
+
self::update_option( $option_name, $api_key );
|
3190 |
+
self::delete_option('sucuriwaf_apikey');
|
3191 |
+
}
|
3192 |
+
}
|
3193 |
|
3194 |
+
// Check the validity of the API key.
|
3195 |
+
$match = self::is_valid_cloudproxy_key( $api_key, TRUE );
|
3196 |
|
3197 |
+
if( $match ){
|
3198 |
+
return array(
|
3199 |
+
'string' => $match[1].'/'.$match[2],
|
3200 |
+
'k' => $match[1],
|
3201 |
+
's' => $match[2]
|
3202 |
+
);
|
3203 |
}
|
3204 |
+
|
3205 |
+
return FALSE;
|
3206 |
}
|
3207 |
|
3208 |
+
/**
|
3209 |
+
* Check whether the CloudProxy API key is valid or not.
|
3210 |
+
*
|
3211 |
+
* @param string $api_key The CloudProxy API key.
|
3212 |
+
* @param boolean $return_match Whether the parts of the API key must be returned or not.
|
3213 |
+
* @return boolean TRUE if the API key specified is valid, FALSE otherwise.
|
3214 |
+
*/
|
3215 |
+
public static function is_valid_cloudproxy_key( $api_key='', $return_match=FALSE ){
|
3216 |
+
$pattern = '/^([a-z0-9]{32})\/([a-z0-9]{32})$/';
|
3217 |
|
3218 |
+
if( $api_key && preg_match($pattern, $api_key, $match) ){
|
3219 |
+
if( $return_match ){ return $match; }
|
|
|
|
|
|
|
|
|
|
|
3220 |
|
3221 |
+
return TRUE;
|
3222 |
+
}
|
3223 |
+
|
3224 |
+
return FALSE;
|
|
|
|
|
|
|
3225 |
}
|
3226 |
|
3227 |
+
/**
|
3228 |
+
* Call an action from the remote API interface of our WordPress service.
|
3229 |
+
*
|
3230 |
+
* @param string $method HTTP method that will be used to send the request.
|
3231 |
+
* @param array $params Parameters for the request defined in an associative array of key-value.
|
3232 |
+
* @param boolean $send_api_key Whether the API key should be added to the request parameters or not.
|
3233 |
+
* @param array $args Request arguments like the timeout, redirections, headers, cookies, etc.
|
3234 |
+
* @return array Array of results including HTTP headers or WP_Error if the request failed.
|
3235 |
+
*/
|
3236 |
+
public static function api_call_wordpress( $method='GET', $params=array(), $send_api_key=TRUE, $args=array() ){
|
3237 |
+
$url = SUCURISCAN_API;
|
3238 |
+
$params[SUCURISCAN_API_VERSION] = 1;
|
3239 |
+
$params['p'] = 'wordpress';
|
3240 |
|
3241 |
+
if( $send_api_key ){
|
3242 |
+
$api_key = self::get_plugin_key();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3243 |
|
3244 |
+
if( !$api_key ){ return FALSE; }
|
|
|
|
|
3245 |
|
3246 |
+
$params['k'] = $api_key;
|
|
|
3247 |
}
|
3248 |
|
3249 |
+
$response = self::api_call( $url, $method, $params, $args );
|
3250 |
+
|
3251 |
+
return $response;
|
|
|
3252 |
}
|
3253 |
|
3254 |
+
/**
|
3255 |
+
* Call an action from the remote API interface of our CloudProxy service.
|
3256 |
+
*
|
3257 |
+
* @param string $method HTTP method that will be used to send the request.
|
3258 |
+
* @param array $params Parameters for the request defined in an associative array of key-value.
|
3259 |
+
* @return array Array of results including HTTP headers or WP_Error if the request failed.
|
3260 |
+
*/
|
3261 |
+
public static function api_call_cloudproxy( $method='GET', $params=array() ){
|
3262 |
+
$send_request = FALSE;
|
3263 |
|
3264 |
+
if( isset($params['k']) && isset($params['s']) ){
|
3265 |
+
$send_request = TRUE;
|
3266 |
+
} else {
|
3267 |
+
$api_key = self::get_cloudproxy_key();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3268 |
|
3269 |
+
if( $api_key ){
|
3270 |
+
$send_request = TRUE;
|
3271 |
+
$params['k'] = $api_key['k'];
|
3272 |
+
$params['s'] = $api_key['s'];
|
3273 |
+
}
|
3274 |
+
}
|
|
|
|
|
|
|
|
|
3275 |
|
3276 |
+
if( $send_request ){
|
3277 |
+
$url = SUCURISCAN_CLOUDPROXY_API;
|
3278 |
+
$params[SUCURISCAN_CLOUDPROXY_API_VERSION] = 1;
|
3279 |
|
3280 |
+
$response = self::api_call( $url, $method, $params );
|
|
|
|
|
3281 |
|
3282 |
+
return $response;
|
|
|
3283 |
}
|
3284 |
|
3285 |
+
return FALSE;
|
3286 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
3287 |
|
3288 |
+
/**
|
3289 |
+
* Determine whether an API response was successful or not checking the expected
|
3290 |
+
* generic variables and types, in case of an error a notification will appears
|
3291 |
+
* in the administrator panel explaining the result of the operation.
|
3292 |
+
*
|
3293 |
+
* @param array $response Array of results including HTTP headers or WP_Error if the request failed.
|
3294 |
+
* @return boolean Either TRUE or FALSE in case of success or failure of the API response (respectively).
|
3295 |
+
*/
|
3296 |
+
private static function handle_response( $response=array() ){
|
3297 |
+
if( $response ){
|
3298 |
+
if( $response['body'] instanceof stdClass ){
|
3299 |
+
if( isset($response['body']->status) ){
|
3300 |
+
if( $response['body']->status == 1 ){
|
3301 |
+
return TRUE;
|
3302 |
+
} else {
|
3303 |
+
SucuriScanInterface::error( ucwords($response['body']->action) . ': ' . $response['body']->messages[0] );
|
3304 |
+
}
|
3305 |
+
} else {
|
3306 |
+
SucuriScanInterface::error( 'Could not determine the status of an API call.' );
|
3307 |
}
|
3308 |
+
} else {
|
3309 |
+
SucuriScanInterface::error( 'Unknown API content-type, it was not a JSON-encoded response.' );
|
3310 |
}
|
3311 |
}
|
3312 |
+
|
3313 |
+
return FALSE;
|
|
|
3314 |
}
|
|
|
3315 |
|
3316 |
+
/**
|
3317 |
+
* Send a request to the API to register this site.
|
3318 |
+
*
|
3319 |
+
* @return boolean TRUE if the API key was generated, FALSE otherwise.
|
3320 |
+
*/
|
3321 |
+
public static function register_site(){
|
3322 |
+
$response = self::api_call_wordpress( 'POST', array(
|
3323 |
+
'e' => self::get_site_email(),
|
3324 |
+
's' => self::get_domain(),
|
3325 |
+
'a' => 'register_site',
|
3326 |
+
), FALSE );
|
3327 |
+
|
3328 |
+
if( self::handle_response($response) ){
|
3329 |
+
self::set_plugin_key( $response['body']->output->api_key );
|
3330 |
+
SucuriScanEvent::schedule_task();
|
3331 |
+
SucuriScanEvent::notify_event( 'plugin_change', 'Site registered and API key generated' );
|
3332 |
+
SucuriScanInterface::info( 'The API key for your site was successfully generated and saved.');
|
3333 |
|
3334 |
+
return TRUE;
|
3335 |
+
}
|
3336 |
|
3337 |
+
return FALSE;
|
3338 |
+
}
|
3339 |
|
3340 |
+
/**
|
3341 |
+
* Send a request to recover a previously registered API key.
|
3342 |
+
*
|
3343 |
+
* @return boolean TRUE if the API key was sent to the administrator email, FALSE otherwise.
|
3344 |
+
*/
|
3345 |
+
public static function recover_key(){
|
3346 |
+
$clean_domain = self::get_domain();
|
3347 |
|
3348 |
+
$response = self::api_call_wordpress( 'GET', array(
|
3349 |
+
'e' => self::get_site_email(),
|
3350 |
+
's' => $clean_domain,
|
3351 |
+
'a' => 'recover_key',
|
3352 |
+
), FALSE );
|
3353 |
|
3354 |
+
if( self::handle_response($response) ){
|
3355 |
+
SucuriScanEvent::notify_event( 'plugin_change', 'API key recovered for domain: ' . $clean_domain );
|
3356 |
+
SucuriScanInterface::info( $response['body']->output->message );
|
3357 |
+
|
3358 |
+
return TRUE;
|
3359 |
}
|
3360 |
|
3361 |
+
return FALSE;
|
3362 |
+
}
|
|
|
|
|
|
|
|
|
|
|
3363 |
|
3364 |
+
/**
|
3365 |
+
* Send a request to the API to store and analyze the events of the site. An
|
3366 |
+
* event can be anything from a simple request, an internal modification of the
|
3367 |
+
* settings or files in the administrator panel, or a notification generated by
|
3368 |
+
* this plugin.
|
3369 |
+
*
|
3370 |
+
* @param string $event The information gathered through out the normal functioning of the site.
|
3371 |
+
* @return boolean TRUE if the event was logged in the monitoring service, FALSE otherwise.
|
3372 |
+
*/
|
3373 |
+
public static function send_log( $event='' ){
|
3374 |
+
if( !empty($event) ){
|
3375 |
+
$response = self::api_call_wordpress( 'POST', array(
|
3376 |
+
'a' => 'send_log',
|
3377 |
+
'm' => $event,
|
3378 |
+
), TRUE, array( 'timeout' => 20 ) );
|
3379 |
+
|
3380 |
+
if( self::handle_response($response) ){
|
3381 |
+
return TRUE;
|
3382 |
}
|
3383 |
+
}
|
3384 |
|
3385 |
+
return FALSE;
|
3386 |
+
}
|
|
|
|
|
|
|
3387 |
|
3388 |
+
/**
|
3389 |
+
* Retrieve the event logs registered by the API service.
|
3390 |
+
*
|
3391 |
+
* @param integer $lines How many lines from the log file will be retrieved.
|
3392 |
+
* @return string The response of the API service.
|
3393 |
+
*/
|
3394 |
+
public static function get_logs( $lines=50 ){
|
3395 |
+
$response = self::api_call_wordpress( 'GET', array(
|
3396 |
+
'a' => 'get_logs',
|
3397 |
+
'l' => $lines,
|
3398 |
+
) );
|
3399 |
+
|
3400 |
+
if( self::handle_response($response) ){
|
3401 |
+
$response['body']->output_data = array();
|
3402 |
+
$log_pattern = '/^([0-9-: ]+) (.*) : (.*)/';
|
3403 |
+
$extra_pattern = '/(.+ \(multiple entries\):) (.+)/';
|
3404 |
+
|
3405 |
+
foreach( $response['body']->output as $log ){
|
3406 |
+
if( preg_match($log_pattern, $log, $log_match) ){
|
3407 |
+
$log_data = array(
|
3408 |
+
'datetime' => $log_match[1],
|
3409 |
+
'timestamp' => strtotime($log_match[1]),
|
3410 |
+
'account' => $log_match[2],
|
3411 |
+
'message' => $log_match[3],
|
3412 |
+
'extra' => FALSE,
|
3413 |
+
'extra_total' => 0,
|
3414 |
+
);
|
3415 |
+
|
3416 |
+
$log_data['message'] = str_replace( ', new size', '; new size', $log_data['message'] );
|
3417 |
+
|
3418 |
+
if( preg_match($extra_pattern, $log_data['message'], $log_extra) ){
|
3419 |
+
$log_data['message'] = $log_extra[1];
|
3420 |
+
$log_data['extra'] = explode(',', $log_extra[2]);
|
3421 |
+
$log_data['extra_total'] = count($log_data['extra']);
|
3422 |
+
}
|
3423 |
+
|
3424 |
+
$response['body']->output_data[] = $log_data;
|
3425 |
+
}
|
3426 |
}
|
3427 |
|
3428 |
+
return $response['body'];
|
3429 |
}
|
|
|
3430 |
|
3431 |
+
return FALSE;
|
3432 |
+
}
|
|
|
3433 |
|
3434 |
+
/**
|
3435 |
+
* Send a request to the API to store and analyze the file's hashes of the site.
|
3436 |
+
* This will be the core of the monitoring tools and will enhance the
|
3437 |
+
* information of the audit logs alerting the administrator of suspicious
|
3438 |
+
* changes in the system.
|
3439 |
+
*
|
3440 |
+
* @param string $hashes The information gathered after the scanning of the site's files.
|
3441 |
+
* @return boolean TRUE if the hashes were stored, FALSE otherwise.
|
3442 |
+
*/
|
3443 |
+
public static function send_hashes( $hashes='' ){
|
3444 |
+
if( !empty($hashes) ){
|
3445 |
+
$response = self::api_call_wordpress( 'POST', array(
|
3446 |
+
'a' => 'send_hashes',
|
3447 |
+
'h' => $hashes,
|
3448 |
+
) );
|
3449 |
+
|
3450 |
+
if( self::handle_response($response) ){
|
3451 |
+
return TRUE;
|
3452 |
+
}
|
3453 |
+
}
|
3454 |
|
3455 |
+
return FALSE;
|
3456 |
+
}
|
3457 |
|
3458 |
+
/**
|
3459 |
+
* Retrieve the public settings of the account associated with the API keys
|
3460 |
+
* registered by the administrator of the site. This function will send a HTTP
|
3461 |
+
* request to the remote API service and process its response, when successful
|
3462 |
+
* it will return an array/object containing the public attributes of the site.
|
3463 |
+
*
|
3464 |
+
* @param boolean $api_key The CloudProxy API key.
|
3465 |
+
* @return array A hash with the settings of a CloudProxy account.
|
3466 |
+
*/
|
3467 |
+
public static function get_cloudproxy_settings( $api_key=FALSE ){
|
3468 |
+
$params = array( 'a' => 'show_settings' );
|
3469 |
|
3470 |
+
if( $api_key ){
|
3471 |
+
$params = array_merge( $params, $api_key );
|
3472 |
+
}
|
3473 |
|
3474 |
+
$response = self::api_call_cloudproxy( 'GET', $params );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3475 |
|
3476 |
+
if( self::handle_response($response) ){
|
3477 |
+
return $response['body']->output;
|
3478 |
+
}
|
3479 |
|
3480 |
+
return FALSE;
|
3481 |
+
}
|
3482 |
|
3483 |
+
/**
|
3484 |
+
* Flush the cache of the site(s) associated with the API key.
|
3485 |
+
*
|
3486 |
+
* @param boolean $api_key The CloudProxy API key.
|
3487 |
+
* @return string Message explaining the result of the operation.
|
3488 |
+
*/
|
3489 |
+
public static function clear_cloudproxy_cache( $api_key=FALSE ){
|
3490 |
+
$params = array( 'a' => 'clear_cache' );
|
3491 |
|
3492 |
+
if( $api_key ){
|
3493 |
+
$params = array_merge( $params, $api_key );
|
3494 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3495 |
|
3496 |
+
$response = self::api_call_cloudproxy( 'GET', $params );
|
3497 |
|
3498 |
+
if( self::handle_response($response) ){
|
3499 |
+
return $response['body'];
|
3500 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3501 |
|
3502 |
+
return FALSE;
|
3503 |
+
}
|
|
|
|
|
|
|
|
|
3504 |
|
3505 |
+
/**
|
3506 |
+
* Retrieve the audit logs of the account associated with the API keys
|
3507 |
+
* registered b the administrator of the site. This function will send a HTTP
|
3508 |
+
* request to the remote API service and process its response, when successful
|
3509 |
+
* it will return an array/object containing a list of requests blocked by our
|
3510 |
+
* CloudProxy.
|
3511 |
+
*
|
3512 |
+
* By default the logs that will be retrieved are from today, if you need to see
|
3513 |
+
* the logs of previous days you will need to add a new parameter to the request
|
3514 |
+
* URL named "date" with format yyyy-mm-dd.
|
3515 |
+
*
|
3516 |
+
* @param boolean $api_key The CloudProxy API key.
|
3517 |
+
* @param string $date An optional date to filter the result to a specific timespan: yyyy-mm-dd.
|
3518 |
+
* @return array A list of objects with the detailed version of each request blocked by our service.
|
3519 |
+
*/
|
3520 |
+
public static function get_cloudproxy_logs( $api_key=FALSE, $date='' ){
|
3521 |
+
$params = array(
|
3522 |
+
'a' => 'audit_trails',
|
3523 |
+
'date' => date('Y-m-d'),
|
3524 |
+
);
|
3525 |
|
3526 |
+
if( preg_match('/^([0-9]{4})\-([0-9]{2})\-([0-9]{2})$/', $date) ){
|
3527 |
+
$params['date'] = $date;
|
3528 |
+
}
|
|
|
|
|
|
|
3529 |
|
3530 |
+
if( $api_key ){
|
3531 |
+
$params = array_merge( $params, $api_key );
|
3532 |
+
}
|
3533 |
|
3534 |
+
$response = self::api_call_cloudproxy( 'GET', $params );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3535 |
|
3536 |
+
if( self::handle_response($response) ){
|
3537 |
+
return $response['body']->output;
|
3538 |
+
}
|
|
|
3539 |
|
3540 |
+
return FALSE;
|
3541 |
+
}
|
3542 |
|
3543 |
+
/**
|
3544 |
+
* Scan a website through the public SiteCheck API [1] for known malware,
|
3545 |
+
* blacklisting status, website errors, and out-of-date software.
|
3546 |
+
*
|
3547 |
+
* [1] http://sitecheck.sucuri.net/
|
3548 |
+
*
|
3549 |
+
* @param string $domain The clean version of the website's domain.
|
3550 |
+
* @return object Serialized data of the scanning results for the site specified.
|
3551 |
+
*/
|
3552 |
+
public static function get_sitecheck_results( $domain='' ){
|
3553 |
+
if( !empty($domain) ){
|
3554 |
+
$url = 'http://sitecheck.sucuri.net/scanner/';
|
3555 |
+
$response = self::api_call( $url, 'GET', array(
|
3556 |
+
'serialized' => 1,
|
3557 |
+
'clear' => 1,
|
3558 |
+
'fromwp' => 2,
|
3559 |
+
'scan' => $domain,
|
3560 |
+
));
|
3561 |
|
3562 |
+
if( $response ){
|
3563 |
+
return $response['body'];
|
3564 |
+
}
|
3565 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3566 |
|
3567 |
+
return FALSE;
|
3568 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3569 |
|
3570 |
+
/**
|
3571 |
+
* Retrieve a new set of keys for the WordPress configuration file using the
|
3572 |
+
* official API provided by WordPress itself.
|
3573 |
+
*
|
3574 |
+
* @return array A list of the new set of keys generated by WordPress API.
|
3575 |
+
*/
|
3576 |
+
public static function get_new_secret_keys(){
|
3577 |
+
$pattern = self::secret_key_pattern();
|
3578 |
+
$response = self::api_call( 'https://api.wordpress.org/secret-key/1.1/salt/', 'GET' );
|
3579 |
|
3580 |
+
if( $response && preg_match_all($pattern, $response['body'], $match) ){
|
3581 |
+
$new_keys = array();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3582 |
|
3583 |
+
foreach( $match[1] as $i => $value ){
|
3584 |
+
$new_keys[$value] = $match[3][$i];
|
3585 |
+
}
|
|
|
|
|
|
|
|
|
|
|
3586 |
|
3587 |
+
return $new_keys;
|
3588 |
+
}
|
|
|
|
|
|
|
|
|
3589 |
|
3590 |
+
return FALSE;
|
3591 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3592 |
|
3593 |
+
/**
|
3594 |
+
* Retrieve a list with the checksums of the files in a specific version of WordPress.
|
3595 |
+
*
|
3596 |
+
* @see Release Archive http://wordpress.org/download/release-archive/
|
3597 |
+
*
|
3598 |
+
* @param integer $version Valid version number of the WordPress project.
|
3599 |
+
* @return object Associative object with the relative filepath and the checksums of the project files.
|
3600 |
+
*/
|
3601 |
+
public static function get_official_checksums( $version=0 ){
|
3602 |
+
$url = 'http://api.wordpress.org/core/checksums/1.0/';
|
3603 |
+
$response = self::api_call( $url, 'GET', array(
|
3604 |
+
'version' => $version,
|
3605 |
+
'locale' => 'en_US',
|
3606 |
+
));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3607 |
|
3608 |
+
if( $response ){
|
3609 |
+
if( $response['body'] instanceof stdClass ){
|
3610 |
+
$json_data = $response['body'];
|
3611 |
+
} else {
|
3612 |
+
$json_data = @json_decode($response['body']);
|
3613 |
+
}
|
3614 |
|
3615 |
+
if(
|
3616 |
+
isset($json_data->checksums)
|
3617 |
+
&& !empty($json_data->checksums)
|
3618 |
+
){
|
3619 |
+
$checksums = $json_data->checksums;
|
3620 |
|
3621 |
+
// Convert the object list to an array for better handle of the data.
|
3622 |
+
if( $checksums instanceof stdClass ){
|
3623 |
+
$checksums = (array) $checksums;
|
3624 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
3625 |
|
3626 |
+
return $checksums;
|
3627 |
+
}
|
3628 |
+
}
|
|
|
|
|
|
|
|
|
|
|
3629 |
|
3630 |
+
return FALSE;
|
3631 |
+
}
|
|
|
|
|
3632 |
|
3633 |
+
/**
|
3634 |
+
* Check the plugins directory and retrieve all plugin files with plugin data.
|
3635 |
+
* This function will also retrieve the URL and name of the repository/page
|
3636 |
+
* where it is being published at the WordPress plugins market.
|
3637 |
+
*
|
3638 |
+
* @return array Key is the plugin file path and the value is an array of the plugin data.
|
3639 |
+
*/
|
3640 |
+
public static function get_plugins(){
|
3641 |
+
// Check if the cache library was loaded.
|
3642 |
+
$can_cache = class_exists('SucuriScanCache');
|
3643 |
|
3644 |
+
if( $can_cache ){
|
3645 |
+
$sucuri_cache = new SucuriScanCache('plugindata');
|
3646 |
+
$cached_data = $sucuri_cache->get( 'plugins', SUCURISCAN_GET_PLUGINS_LIFETIME, 'array' );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3647 |
|
3648 |
+
// Return the previously cached results of this function.
|
3649 |
+
if( $cached_data !== FALSE ){
|
3650 |
+
return $cached_data;
|
3651 |
+
}
|
3652 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3653 |
|
3654 |
+
// Get the plugin's basic information from WordPress transient data.
|
3655 |
+
$plugins = get_plugins();
|
3656 |
+
$pattern = '/^http:\/\/wordpress\.org\/plugins\/(.*)\/$/';
|
3657 |
+
$wp_market = 'http://wordpress.org/plugins/%s/';
|
3658 |
|
3659 |
+
// Loop through each plugin data and complement its information with more attributes.
|
3660 |
+
foreach( $plugins as $plugin_path => $plugin_data ){
|
3661 |
+
// Default values for the plugin extra attributes.
|
3662 |
+
$repository = '';
|
3663 |
+
$repository_name = '';
|
3664 |
+
$is_free_plugin = FALSE;
|
|
|
|
|
|
|
|
|
3665 |
|
3666 |
+
// If the plugin's info object has already a plugin_uri.
|
3667 |
+
if(
|
3668 |
+
isset($plugin_data['PluginURI'])
|
3669 |
+
&& preg_match($pattern, $plugin_data['PluginURI'], $match)
|
3670 |
+
){
|
3671 |
+
$repository = $match[0];
|
3672 |
+
$repository_name = $match[1];
|
3673 |
+
$is_free_plugin = TRUE;
|
3674 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3675 |
|
3676 |
+
// Retrieve the WordPress plugin page from the plugin's filename.
|
3677 |
+
else {
|
3678 |
+
if( strpos($plugin_path, '/') !== FALSE ){
|
3679 |
+
$plugin_path_parts = explode('/', $plugin_path, 2);
|
3680 |
+
} else {
|
3681 |
+
$plugin_path_parts = explode('.', $plugin_path, 2);
|
3682 |
+
}
|
3683 |
|
3684 |
+
if( isset($plugin_path_parts[0]) ){
|
3685 |
+
$possible_repository = sprintf($wp_market, $plugin_path_parts[0]);
|
3686 |
+
$resp = wp_remote_head($possible_repository);
|
|
|
3687 |
|
3688 |
+
if(
|
3689 |
+
!is_wp_error($resp)
|
3690 |
+
&& $resp['response']['code'] == 200
|
3691 |
+
){
|
3692 |
+
$repository = $possible_repository;
|
3693 |
+
$repository_name = $plugin_path_parts[0];
|
3694 |
+
$is_free_plugin = TRUE;
|
3695 |
+
}
|
3696 |
+
}
|
3697 |
+
}
|
3698 |
|
3699 |
+
// Complement the plugin's information with these attributes.
|
3700 |
+
$plugins[$plugin_path]['Repository'] = $repository;
|
3701 |
+
$plugins[$plugin_path]['RepositoryName'] = $repository_name;
|
3702 |
+
$plugins[$plugin_path]['IsFreePlugin'] = $is_free_plugin;
|
3703 |
+
$plugins[$plugin_path]['PluginType'] = ( $is_free_plugin ? 'free' : 'premium' );
|
3704 |
+
$plugins[$plugin_path]['IsPluginActive'] = FALSE;
|
|
|
|
|
|
|
3705 |
|
3706 |
+
if( is_plugin_active($plugin_path) ){
|
3707 |
+
$plugins[$plugin_path]['IsPluginActive'] = TRUE;
|
|
|
|
|
|
|
3708 |
}
|
|
|
|
|
3709 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
3710 |
|
3711 |
+
if( $can_cache ){
|
3712 |
+
// Add the information of the plugins to the file-based cache.
|
3713 |
+
$sucuri_cache->add( 'plugins', $plugins );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3714 |
}
|
|
|
3715 |
|
3716 |
+
return $plugins;
|
|
|
3717 |
}
|
3718 |
|
3719 |
+
/**
|
3720 |
+
* Retrieve plugin installer pages from WordPress Plugins API.
|
3721 |
+
*
|
3722 |
+
* It is possible for a plugin to override the Plugin API result with three
|
3723 |
+
* filters. Assume this is for plugins, which can extend on the Plugin Info to
|
3724 |
+
* offer more choices. This is very powerful and must be used with care, when
|
3725 |
+
* overriding the filters.
|
3726 |
+
*
|
3727 |
+
* The first filter, 'plugins_api_args', is for the args and gives the action as
|
3728 |
+
* the second parameter. The hook for 'plugins_api_args' must ensure that an
|
3729 |
+
* object is returned.
|
3730 |
+
*
|
3731 |
+
* The second filter, 'plugins_api', is the result that would be returned.
|
3732 |
+
*
|
3733 |
+
* @param string $plugin Frienly name of the plugin.
|
3734 |
+
* @return object Object on success, WP_Error on failure.
|
3735 |
+
*/
|
3736 |
+
public static function get_remote_plugin_data( $plugin='' ){
|
3737 |
+
if( !empty($plugin) ){
|
3738 |
+
$url = sprintf( 'http://api.wordpress.org/plugins/info/1.0/%s/', $plugin );
|
3739 |
+
$response = self::api_call( $url, 'GET' );
|
3740 |
+
|
3741 |
+
if( $response ){
|
3742 |
+
if( $response['body'] instanceof stdClass ){
|
3743 |
+
return $response['body'];
|
3744 |
+
}
|
3745 |
+
}
|
3746 |
+
}
|
3747 |
|
3748 |
+
return FALSE;
|
|
|
3749 |
}
|
3750 |
|
|
|
3751 |
}
|
3752 |
|
3753 |
/**
|
3754 |
+
* Process and send emails.
|
3755 |
*
|
3756 |
+
* One of the core features of the plugin is the event alerts, a list of rules
|
3757 |
+
* will check if the site is being compromised, in which case a notification
|
3758 |
+
* will be sent to the site email address (an address that can be configured in
|
3759 |
+
* the settings page).
|
3760 |
*/
|
3761 |
+
class SucuriScanMail extends SucuriScanOption {
|
|
|
|
|
|
|
|
|
3762 |
|
3763 |
+
/**
|
3764 |
+
* Check whether the email notifications will be sent in HTML or Plain/Text.
|
3765 |
+
*
|
3766 |
+
* @return boolean Whether the emails will be in HTML or Plain/Text.
|
3767 |
+
*/
|
3768 |
+
public static function prettify_mails(){
|
3769 |
+
return ( self::get_option(':prettify_mails') === 'enabled' );
|
3770 |
}
|
3771 |
|
3772 |
+
/**
|
3773 |
+
* Send a message to a specific email address.
|
3774 |
+
*
|
3775 |
+
* @param string $email The email address of the recipient that will receive the message.
|
3776 |
+
* @param string $subject The reason of the message that will be sent.
|
3777 |
+
* @param string $message Body of the message that will be sent.
|
3778 |
+
* @param array $data_set Optional parameter to add more information to the notification.
|
3779 |
+
* @return boolean Whether the email contents were sent successfully.
|
3780 |
+
*/
|
3781 |
+
public static function send_mail( $email='', $subject='', $message='', $data_set=array() ){
|
3782 |
+
$headers = array();
|
3783 |
+
$subject = ucwords(strtolower($subject));
|
3784 |
+
$wp_domain = SucuriScanOption::get_domain();
|
3785 |
+
$force = FALSE;
|
3786 |
+
$debug = FALSE;
|
3787 |
+
|
3788 |
+
// Check whether the mail will be printed in the site instead of sent.
|
3789 |
+
if(
|
3790 |
+
isset($data_set['Debug'])
|
3791 |
+
&& $data_set['Debug'] == TRUE
|
3792 |
+
){
|
3793 |
+
$debug = TRUE;
|
3794 |
+
unset($data_set['Debug']);
|
3795 |
+
}
|
3796 |
|
3797 |
+
// Check whether the mail will be even if the limit per hour was reached or not.
|
3798 |
+
if(
|
3799 |
+
isset($data_set['Force'])
|
3800 |
+
&& $data_set['Force'] == TRUE
|
3801 |
+
){
|
3802 |
+
$force = TRUE;
|
3803 |
+
unset($data_set['Force']);
|
3804 |
}
|
|
|
3805 |
|
3806 |
+
// Check whether the email notifications will be sent in HTML or Plain/Text.
|
3807 |
+
if( self::prettify_mails() ){
|
3808 |
+
$headers = array( 'Content-type: text/html' );
|
3809 |
+
$data_set['PrettifyType'] = 'pretty';
|
3810 |
+
} else {
|
3811 |
+
$message = strip_tags($message);
|
3812 |
+
}
|
3813 |
|
3814 |
+
if( !self::emails_per_hour_reached() || $force || $debug ){
|
3815 |
+
$message = self::prettify_mail($subject, $message, $data_set);
|
|
|
|
|
|
|
|
|
|
|
3816 |
|
3817 |
+
if( $debug ){ die($message); }
|
|
|
3818 |
|
3819 |
+
$email_sent = wp_mail(
|
3820 |
+
$email,
|
3821 |
+
"Sucuri WP Notification: {$wp_domain} - {$subject}",
|
3822 |
+
$message,
|
3823 |
+
$headers
|
3824 |
+
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3825 |
|
3826 |
+
if( $email_sent ){
|
3827 |
+
$emails_sent_num = (int) self::get_option(':emails_sent');
|
3828 |
+
self::update_option( ':emails_sent', $emails_sent_num + 1 );
|
3829 |
+
self::update_option( ':last_email_at', time() );
|
3830 |
|
3831 |
+
return TRUE;
|
3832 |
+
}
|
3833 |
+
}
|
3834 |
|
3835 |
+
return FALSE;
|
3836 |
}
|
3837 |
|
3838 |
+
/**
|
3839 |
+
* Generate a HTML version of the message that will be sent through an email.
|
3840 |
+
*
|
3841 |
+
* @param string $subject The reason of the message that will be sent.
|
3842 |
+
* @param string $message Body of the message that will be sent.
|
3843 |
+
* @param array $data_set Optional parameter to add more information to the notification.
|
3844 |
+
* @return string The message formatted in a HTML template.
|
3845 |
+
*/
|
3846 |
+
private static function prettify_mail( $subject='', $message='', $data_set=array() ){
|
3847 |
+
$prettify_type = isset($data_set['PrettifyType']) ? $data_set['PrettifyType'] : 'simple';
|
3848 |
+
$template_name = 'notification-' . $prettify_type;
|
3849 |
+
$remote_addr = self::get_remote_addr();
|
3850 |
+
$user = wp_get_current_user();
|
3851 |
+
$display_name = '';
|
3852 |
|
3853 |
+
if(
|
3854 |
+
$user instanceof WP_User
|
3855 |
+
&& isset($user->user_login)
|
3856 |
+
&& !empty($user->user_login)
|
3857 |
+
){
|
3858 |
+
$display_name = sprintf( 'User: %s (%s)', $user->display_name, $user->user_login );
|
3859 |
+
}
|
|
|
|
|
3860 |
|
3861 |
+
$mail_variables = array(
|
3862 |
+
'TemplateTitle' => 'Sucuri Alert',
|
3863 |
+
'Subject' => $subject,
|
3864 |
+
'Website' => self::get_option('siteurl'),
|
3865 |
+
'RemoteAddress' => $remote_addr,
|
3866 |
+
'Message' => $message,
|
3867 |
+
'User' => $display_name,
|
3868 |
+
'Time' => date('d/M/Y H:i:s'),
|
3869 |
+
);
|
3870 |
|
3871 |
+
foreach( $data_set as $var_key => $var_value ){
|
3872 |
+
$mail_variables[$var_key] = $var_value;
|
|
|
|
|
3873 |
}
|
|
|
3874 |
|
3875 |
+
return SucuriScanTemplate::get_section( $template_name, $mail_variables );
|
3876 |
+
}
|
|
|
3877 |
|
3878 |
+
/**
|
3879 |
+
* Check whether the maximum quantity of emails per hour was reached.
|
3880 |
+
*
|
3881 |
+
* @return boolean Whether the quota emails per hour was reached.
|
3882 |
+
*/
|
3883 |
+
private static function emails_per_hour_reached(){
|
3884 |
+
$max_per_hour = self::get_option(':emails_per_hour');
|
3885 |
|
3886 |
+
if( $max_per_hour != 'unlimited' ){
|
3887 |
+
// Check if we are still in that sixty minutes.
|
3888 |
+
$current_time = time();
|
3889 |
+
$last_email_at = self::get_option(':last_email_at');
|
3890 |
+
$diff_time = abs( $current_time - $last_email_at );
|
3891 |
|
3892 |
+
if( $diff_time <= 3600 ){
|
3893 |
+
// Check if the quantity of emails sent is bigger than the configured.
|
3894 |
+
$emails_sent = (int) self::get_option(':emails_sent');
|
3895 |
+
$max_per_hour = intval($max_per_hour);
|
3896 |
|
3897 |
+
if( $emails_sent >= $max_per_hour ){
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3898 |
return TRUE;
|
|
|
|
|
3899 |
}
|
3900 |
} else {
|
3901 |
+
// Reset the counter of emails sent.
|
3902 |
+
self::update_option( ':emails_sent', 0 );
|
3903 |
}
|
|
|
|
|
3904 |
}
|
3905 |
+
|
3906 |
+
return FALSE;
|
3907 |
}
|
3908 |
|
|
|
3909 |
}
|
3910 |
|
3911 |
/**
|
3912 |
+
* Read, parse and handle everything related with the templates.
|
3913 |
*
|
3914 |
+
* A web template system uses a template processor to combine web templates to
|
3915 |
+
* form finished web pages, possibly using some data source to customize the
|
3916 |
+
* pages or present a large amount of content on similar-looking pages. It is a
|
3917 |
+
* web publishing tool present in content management systems, web application
|
3918 |
+
* frameworks, and HTML editors.
|
3919 |
+
*
|
3920 |
+
* Web templates can be used like the template of a form letter to either
|
3921 |
+
* generate a large number of "static" (unchanging) web pages in advance, or to
|
3922 |
+
* produce "dynamic" web pages on demand.
|
3923 |
*/
|
3924 |
+
class SucuriScanTemplate extends SucuriScanRequest {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3925 |
|
3926 |
+
/**
|
3927 |
+
* Replace all pseudo-variables from a string of characters.
|
3928 |
+
*
|
3929 |
+
* @param string $content The content of a template file which contains pseudo-variables.
|
3930 |
+
* @param array $params List of pseudo-variables that will be replaced in the template.
|
3931 |
+
* @return string The content of the template with the pseudo-variables replated.
|
3932 |
+
*/
|
3933 |
+
private static function replace_pseudovars( $content='', $params=array() ){
|
3934 |
+
if( is_array($params) ){
|
3935 |
+
foreach( $params as $tpl_key => $tpl_value ){
|
3936 |
+
$tpl_key = '%%SUCURI.' . $tpl_key . '%%';
|
3937 |
+
$content = str_replace( $tpl_key, $tpl_value, $content );
|
3938 |
+
}
|
3939 |
+
|
3940 |
+
return $content;
|
3941 |
+
}
|
3942 |
+
|
3943 |
+
return FALSE;
|
3944 |
}
|
3945 |
|
3946 |
+
/**
|
3947 |
+
* Gather and generate the information required globally by all the template files.
|
3948 |
+
*
|
3949 |
+
* @param array $params A hash containing the pseudo-variable name as the key and the value that will replace it.
|
3950 |
+
* @return array A complementary list of pseudo-variables for the template files.
|
3951 |
+
*/
|
3952 |
+
private static function shared_params( $params=array() ){
|
3953 |
+
$params = is_array($params) ? $params : array();
|
3954 |
|
3955 |
+
// Base parameters, required to render all the pages.
|
3956 |
+
$params = self::links_and_navbar($params);
|
|
|
|
|
|
|
|
|
|
|
3957 |
|
3958 |
+
// Global parameters, used through out all the pages.
|
3959 |
+
$params['PageTitle'] = isset($params['PageTitle']) ? '('.$params['PageTitle'].')' : '';
|
3960 |
+
$params['PageNonce'] = wp_create_nonce('sucuriscan_page_nonce');
|
3961 |
+
$params['PageStyleClass'] = isset($params['PageStyleClass']) ? $params['PageStyleClass'] : 'base';
|
3962 |
+
$params['CleanDomain'] = SucuriScanOption::get_domain();
|
3963 |
+
$params['AdminEmail'] = SucuriScanOption::get_site_email();
|
3964 |
|
3965 |
+
return $params;
|
3966 |
+
}
|
|
|
3967 |
|
3968 |
+
/**
|
3969 |
+
* Return a string indicating the visibility of a HTML component.
|
3970 |
+
*
|
3971 |
+
* @param boolean $visible Whether the condition executed returned a positive value or not.
|
3972 |
+
* @return string A string indicating the visibility of a HTML component.
|
3973 |
+
*/
|
3974 |
+
public static function visibility( $visible=FALSE ){
|
3975 |
+
return ( $visible === TRUE ? 'visible' : 'hidden' );
|
3976 |
}
|
3977 |
|
3978 |
+
/**
|
3979 |
+
* Generate an URL pointing to the page indicated in the function and that must
|
3980 |
+
* be loaded through the administrator panel.
|
3981 |
+
*
|
3982 |
+
* @param string $page Short name of the page that will be generated.
|
3983 |
+
* @return string Full string containing the link of the page.
|
3984 |
+
*/
|
3985 |
+
public static function get_url( $page='' ){
|
3986 |
+
$url_path = admin_url('admin.php?page=sucuriscan');
|
3987 |
|
3988 |
+
if( !empty($page) ){
|
3989 |
+
$url_path .= '_' . strtolower($page);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3990 |
}
|
3991 |
+
|
3992 |
+
return $url_path;
|
3993 |
}
|
3994 |
|
3995 |
+
/**
|
3996 |
+
* Complement the list of pseudo-variables that will be used in the base
|
3997 |
+
* template files, this will also generate the navigation bar and detect which
|
3998 |
+
* items in it are selected by the current page.
|
3999 |
+
*
|
4000 |
+
* @param array $params A hash containing the pseudo-variable name as the key and the value that will replace it.
|
4001 |
+
* @return array A complementary list of pseudo-variables for the template files.
|
4002 |
+
*/
|
4003 |
+
private static function links_and_navbar( $params=array() ){
|
4004 |
+
global $sucuriscan_pages;
|
4005 |
|
4006 |
+
$params = is_array($params) ? $params : array();
|
4007 |
+
$sub_pages = is_array($sucuriscan_pages) ? $sucuriscan_pages : array();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4008 |
|
4009 |
+
$params['Navbar'] = '';
|
4010 |
+
$params['CurrentPageFunc'] = '';
|
4011 |
|
4012 |
+
if( $_page = self::get('page', '_page') ){
|
4013 |
+
$params['CurrentPageFunc'] = $_page;
|
4014 |
+
}
|
|
|
|
|
4015 |
|
4016 |
+
foreach( $sub_pages as $sub_page_func => $sub_page_title ){
|
4017 |
+
$func_parts = explode( '_', $sub_page_func, 2 );
|
4018 |
+
|
4019 |
+
if( isset($func_parts[1]) ){
|
4020 |
+
$unique_name = $func_parts[1];
|
4021 |
+
$pseudo_var = 'URL.' . ucwords($unique_name);
|
4022 |
+
} else {
|
4023 |
+
$unique_name = '';
|
4024 |
+
$pseudo_var = 'URL.Home';
|
4025 |
}
|
|
|
4026 |
|
4027 |
+
$params[$pseudo_var] = self::get_url($unique_name);
|
|
|
4028 |
|
4029 |
+
$navbar_item_css_class = 'nav-tab';
|
|
|
4030 |
|
4031 |
+
if( $params['CurrentPageFunc'] == $sub_page_func ){
|
4032 |
+
$navbar_item_css_class .= chr(32) . 'nav-tab-active';
|
4033 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4034 |
|
4035 |
+
$params['Navbar'] .= sprintf(
|
4036 |
+
'<a class="%s" href="%s">%s</a>' . "\n",
|
4037 |
+
$navbar_item_css_class,
|
4038 |
+
$params[$pseudo_var],
|
4039 |
+
$sub_page_title
|
4040 |
+
);
|
4041 |
}
|
4042 |
+
|
4043 |
+
return $params;
|
4044 |
}
|
4045 |
|
4046 |
+
/**
|
4047 |
+
* Generate a HTML code using a template and replacing all the pseudo-variables
|
4048 |
+
* by the dynamic variables provided by the developer through one of the parameters
|
4049 |
+
* of the function.
|
4050 |
+
*
|
4051 |
+
* @param string $html The HTML content of a template file with its pseudo-variables parsed.
|
4052 |
+
* @param array $params A hash containing the pseudo-variable name as the key and the value that will replace it.
|
4053 |
+
* @return string The formatted HTML content of the base template.
|
4054 |
+
*/
|
4055 |
+
public static function get_base_template( $html='', $params=array() ){
|
4056 |
+
$params = is_array($params) ? $params : array();
|
4057 |
|
4058 |
+
$params = self::shared_params($params);
|
4059 |
+
$params['PageContent'] = $html;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4060 |
|
4061 |
+
return self::get_template( 'base', $params );
|
4062 |
+
}
|
4063 |
|
4064 |
+
/**
|
4065 |
+
* Generate a HTML code using a template and replacing all the pseudo-variables
|
4066 |
+
* by the dynamic variables provided by the developer through one of the parameters
|
4067 |
+
* of the function.
|
4068 |
+
*
|
4069 |
+
* @param string $template Filename of the template that will be used to generate the page.
|
4070 |
+
* @param array $params A hash containing the pseudo-variable name as the key and the value that will replace it.
|
4071 |
+
* @param boolean $type Either page, section or snippet indicating the type of template that will be retrieved.
|
4072 |
+
* @return string The formatted HTML page after replace all the pseudo-variables.
|
4073 |
+
*/
|
4074 |
+
public static function get_template( $template='', $params=array(), $type='page' ){
|
4075 |
+
switch( $type ){
|
4076 |
+
case 'page': /* no_break */
|
4077 |
+
case 'section':
|
4078 |
+
$template_path_pattern = '%s/%s/inc/tpl/%s.html.tpl';
|
4079 |
+
break;
|
4080 |
+
case 'snippet':
|
4081 |
+
$template_path_pattern = '%s/%s/inc/tpl/%s.snippet.tpl';
|
4082 |
+
break;
|
4083 |
}
|
|
|
4084 |
|
4085 |
+
$template_content = '';
|
4086 |
+
$template_path = sprintf( $template_path_pattern, WP_PLUGIN_DIR, SUCURISCAN_PLUGIN_FOLDER, $template );
|
4087 |
+
$params = is_array($params) ? $params : array();
|
4088 |
|
4089 |
+
if( file_exists($template_path) && is_readable($template_path) ){
|
4090 |
+
$template_content = @file_get_contents($template_path);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4091 |
|
4092 |
+
$params['SucuriURL'] = SUCURISCAN_URL;
|
|
|
|
|
4093 |
|
4094 |
+
// Detect the current page URL.
|
4095 |
+
if( $_page = self::get('page', '_page') ){
|
4096 |
+
$params['CurrentURL'] = admin_url('admin.php?page=' . $_page);
|
4097 |
+
} else {
|
4098 |
+
$params['CurrentURL'] = admin_url();
|
4099 |
+
}
|
4100 |
|
4101 |
+
// Replace the global pseudo-variables in the section/snippets templates.
|
4102 |
+
if(
|
4103 |
+
$template == 'base'
|
4104 |
+
&& isset($params['PageContent'])
|
4105 |
+
&& preg_match('/%%SUCURI\.(.+)%%/', $params['PageContent'])
|
4106 |
+
){
|
4107 |
+
$params['PageContent'] = self::replace_pseudovars( $params['PageContent'], $params );
|
4108 |
+
}
|
4109 |
|
4110 |
+
$template_content = self::replace_pseudovars( $template_content, $params );
|
4111 |
+
}
|
|
|
|
|
|
|
|
|
|
|
4112 |
|
4113 |
+
if( $template == 'base' || $type != 'page' ){
|
4114 |
+
return $template_content;
|
4115 |
+
}
|
4116 |
|
4117 |
+
return self::get_base_template( $template_content, $params );
|
4118 |
+
}
|
|
|
4119 |
|
4120 |
+
/**
|
4121 |
+
* Generate a HTML code using a template and replacing all the pseudo-variables
|
4122 |
+
* by the dynamic variables provided by the developer through one of the parameters
|
4123 |
+
* of the function.
|
4124 |
+
*
|
4125 |
+
* @param string $template Filename of the template that will be used to generate the page.
|
4126 |
+
* @param array $params A hash containing the pseudo-variable name as the key and the value that will replace it.
|
4127 |
+
* @return string The formatted HTML page after replace all the pseudo-variables.
|
4128 |
+
*/
|
4129 |
+
public static function get_section($template='', $params=array()){
|
4130 |
+
$params = self::shared_params($params);
|
4131 |
|
4132 |
+
return self::get_template( $template, $params, 'section' );
|
4133 |
+
}
|
|
|
|
|
|
|
|
|
4134 |
|
4135 |
+
/**
|
4136 |
+
* Generate a HTML code using a template and replacing all the pseudo-variables
|
4137 |
+
* by the dynamic variables provided by the developer through one of the parameters
|
4138 |
+
* of the function.
|
4139 |
+
*
|
4140 |
+
* @param string $template Filename of the template that will be used to generate the page.
|
4141 |
+
* @param array $params A hash containing the pseudo-variable name as the key and the value that will replace it.
|
4142 |
+
* @return string The formatted HTML page after replace all the pseudo-variables.
|
4143 |
+
*/
|
4144 |
+
public static function get_modal($template='', $params=array()){
|
4145 |
+
$required = array(
|
4146 |
+
'Title' => 'Lorem ipsum dolor sit amet',
|
4147 |
+
'CssClass' => '',
|
4148 |
+
'Content' => '<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do
|
4149 |
+
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
|
4150 |
+
veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
4151 |
+
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
4152 |
+
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
4153 |
+
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>',
|
4154 |
+
);
|
4155 |
|
4156 |
+
if( !empty($template) && $template != 'none' ){
|
4157 |
+
$params['Content'] = self::get_section($template);
|
4158 |
+
}
|
4159 |
|
4160 |
+
foreach( $required as $param_name => $param_value ){
|
4161 |
+
if( !isset($params[$param_name]) ){
|
4162 |
+
$params[$param_name] = $param_value;
|
|
|
|
|
4163 |
}
|
|
|
|
|
4164 |
}
|
|
|
4165 |
|
4166 |
+
$params = self::shared_params($params);
|
|
|
4167 |
|
4168 |
+
return self::get_template( 'modalwindow', $params, 'section' );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4169 |
}
|
4170 |
|
4171 |
+
/**
|
4172 |
+
* Generate a HTML code using a template and replacing all the pseudo-variables
|
4173 |
+
* by the dynamic variables provided by the developer through one of the parameters
|
4174 |
+
* of the function.
|
4175 |
+
*
|
4176 |
+
* @param string $template Filename of the template that will be used to generate the page.
|
4177 |
+
* @param array $params A hash containing the pseudo-variable name as the key and the value that will replace it.
|
4178 |
+
* @return string The formatted HTML page after replace all the pseudo-variables.
|
4179 |
+
*/
|
4180 |
+
public static function get_snippet($template='', $params=array()){
|
4181 |
+
return self::get_template( $template, $params, 'snippet' );
|
4182 |
}
|
4183 |
|
4184 |
+
/**
|
4185 |
+
* Generate the HTML code necessary to render a list of options in a form.
|
4186 |
+
*
|
4187 |
+
* @param array $allowed_values List with keys and values allowed for the options.
|
4188 |
+
* @param string $selected_val Value of the option that will be selected by default.
|
4189 |
+
* @return string Option list for a select form field.
|
4190 |
+
*/
|
4191 |
+
public static function get_select_options( $allowed_values=array(), $selected_val='' ){
|
4192 |
+
$options = '';
|
4193 |
|
4194 |
+
foreach( $allowed_values as $option_name => $option_label ){
|
4195 |
+
$selected_str = '';
|
4196 |
|
4197 |
+
if( $option_name == $selected_val ){
|
4198 |
+
$selected_str = 'selected="selected"';
|
4199 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4200 |
|
4201 |
+
$options .= sprintf(
|
4202 |
+
'<option value="%s" %s>%s</option>',
|
4203 |
+
$option_name, $selected_str, $option_label
|
4204 |
+
);
|
4205 |
}
|
4206 |
|
4207 |
+
return $options;
|
4208 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
4209 |
|
4210 |
+
/**
|
4211 |
+
* Detect which number in a pagination was clicked.
|
4212 |
+
*
|
4213 |
+
* @return integer Page number of the link clicked in a pagination.
|
4214 |
+
*/
|
4215 |
+
public static function get_page_number(){
|
4216 |
+
$num = self::get( 'num', '[0-9]{1,2}' );
|
4217 |
+
|
4218 |
+
return ( $num ? intval($num) : 1 );
|
4219 |
+
}
|
4220 |
+
|
4221 |
+
/**
|
4222 |
+
* Generate the HTML code to display a pagination.
|
4223 |
+
*
|
4224 |
+
* @param string $base_url Base URL for the links before the page number.
|
4225 |
+
* @param integer $total_items Total quantity of items retrieved from a query.
|
4226 |
+
* @param integer $max_per_page Maximum number of items that will be shown per page.
|
4227 |
+
* @return string HTML code for a pagination generated using the provided data.
|
4228 |
+
*/
|
4229 |
+
public static function get_pagination( $base_url='', $total_items=0, $max_per_page=1 ){
|
4230 |
+
// Calculate the number of links for the pagination.
|
4231 |
+
$html_links = '';
|
4232 |
+
$page_number = self::get_page_number();
|
4233 |
+
$max_pages = ceil($total_items / $max_per_page);
|
4234 |
+
|
4235 |
+
// Generate the HTML links for the pagination.
|
4236 |
+
for( $j=1; $j<=$max_pages; $j++ ){
|
4237 |
+
$link_class = 'sucuriscan-pagination-link';
|
4238 |
+
|
4239 |
+
if( $page_number == $j ){
|
4240 |
+
$link_class .= chr(32) . 'sucuriscan-pagination-active';
|
4241 |
+
}
|
4242 |
|
4243 |
+
$html_links .= sprintf(
|
4244 |
+
'<li><a href="%s&num=%d" class="%s">%s</a></li>',
|
4245 |
+
$base_url, $j, $link_class, $j
|
4246 |
+
);
|
4247 |
+
}
|
4248 |
|
4249 |
+
return $html_links;
|
4250 |
}
|
4251 |
|
|
|
4252 |
}
|
4253 |
|
4254 |
/**
|
4255 |
+
* Plugin initializer.
|
|
|
|
|
|
|
4256 |
*
|
4257 |
+
* Define all the required variables, script, styles, and basic functions needed
|
4258 |
+
* when the site is loaded, not even the administrator panel but also the front
|
4259 |
+
* page, some bug-fixes will/are applied here for sites behind a proxy, and
|
4260 |
+
* sites with old versions of the premium plugin (that was deprecated at
|
4261 |
+
* July/2014).
|
4262 |
*/
|
4263 |
+
class SucuriScanInterface {
|
|
|
4264 |
|
4265 |
+
/**
|
4266 |
+
* Initialization code for the plugin.
|
4267 |
+
*
|
4268 |
+
* The initial variables and information needed by the plugin during the
|
4269 |
+
* execution of other functions will be generated. Things like the real IP
|
4270 |
+
* address of the client when it has been forwarded or it's behind an external
|
4271 |
+
* service like a Proxy.
|
4272 |
+
*
|
4273 |
+
* @return void
|
4274 |
+
*/
|
4275 |
+
public static function initialize(){
|
4276 |
+
if(
|
4277 |
+
isset($_SERVER['HTTP_X_FORWARDED_FOR'])
|
4278 |
+
&& SucuriScan::is_valid_ip($_SERVER['HTTP_X_FORWARDED_FOR'])
|
4279 |
+
&& SucuriScan::is_behind_cloudproxy()
|
4280 |
+
){
|
4281 |
+
$_SERVER['SUCURIREAL_REMOTE_ADDR'] = $_SERVER['REMOTE_ADDR'];
|
4282 |
+
$_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_X_FORWARDED_FOR'];
|
4283 |
+
}
|
4284 |
}
|
4285 |
|
4286 |
+
/**
|
4287 |
+
* Define which javascript and css files will be loaded in the header of the
|
4288 |
+
* plugin pages, only when the administrator panel is accessed.
|
4289 |
+
*
|
4290 |
+
* @return void
|
4291 |
+
*/
|
4292 |
+
public static function enqueue_scripts(){
|
4293 |
+
$asset_version = '';
|
4294 |
+
|
4295 |
+
if( strlen(SUCURISCAN_PLUGIN_CHECKSUM) >= 7 ){
|
4296 |
+
$asset_version = substr(SUCURISCAN_PLUGIN_CHECKSUM, 0, 7);
|
4297 |
+
}
|
4298 |
+
|
4299 |
+
wp_register_style( 'sucuriscan', SUCURISCAN_URL . '/inc/css/sucuriscan-default-css.css', array(), $asset_version );
|
4300 |
+
wp_register_script( 'sucuriscan', SUCURISCAN_URL . '/inc/js/sucuriscan-scripts.js', array(), $asset_version );
|
4301 |
|
4302 |
+
wp_enqueue_style( 'sucuriscan' );
|
4303 |
+
wp_enqueue_script( 'sucuriscan' );
|
4304 |
}
|
4305 |
|
4306 |
+
/**
|
4307 |
+
* Generate the menu and submenus for the plugin in the admin interface.
|
4308 |
+
*
|
4309 |
+
* @return void
|
4310 |
+
*/
|
4311 |
+
public static function add_interface_menu(){
|
4312 |
+
global $sucuriscan_pages;
|
4313 |
|
4314 |
+
if(
|
4315 |
+
function_exists('add_menu_page')
|
4316 |
+
&& $sucuriscan_pages
|
4317 |
+
){
|
4318 |
+
// Add main menu link.
|
4319 |
+
add_menu_page(
|
4320 |
+
'Sucuri Security',
|
4321 |
+
'Sucuri Security',
|
4322 |
+
'manage_options',
|
4323 |
+
'sucuriscan',
|
4324 |
+
'sucuriscan_page',
|
4325 |
+
SUCURISCAN_URL . '/inc/images/menu-icon.png'
|
4326 |
+
);
|
4327 |
|
4328 |
+
$sub_pages = is_array($sucuriscan_pages) ? $sucuriscan_pages : array();
|
|
|
|
|
4329 |
|
4330 |
+
foreach( $sub_pages as $sub_page_func => $sub_page_title ){
|
4331 |
+
$page_func = $sub_page_func . '_page';
|
4332 |
|
4333 |
+
add_submenu_page(
|
4334 |
+
'sucuriscan',
|
4335 |
+
$sub_page_title,
|
4336 |
+
$sub_page_title,
|
4337 |
+
'manage_options',
|
4338 |
+
$sub_page_func,
|
4339 |
+
$page_func
|
4340 |
+
);
|
4341 |
+
}
|
4342 |
+
}
|
4343 |
}
|
4344 |
|
4345 |
+
/**
|
4346 |
+
* Remove the old Sucuri plugins considering that with the new version (after
|
4347 |
+
* 1.6.0) all the functionality of the others will be merged here, this will
|
4348 |
+
* remove duplicated functionality, duplicated bugs and/or duplicated
|
4349 |
+
* maintenance reports allowing us to focus in one unique project.
|
4350 |
+
*
|
4351 |
+
* @return void
|
4352 |
+
*/
|
4353 |
+
public static function handle_old_plugins(){
|
4354 |
+
if( class_exists('SucuriScanFileInfo') ){
|
4355 |
+
$sucuri_fileinfo = new SucuriScanFileInfo();
|
4356 |
+
$sucuri_fileinfo->ignore_files = FALSE;
|
4357 |
+
$sucuri_fileinfo->ignore_directories = FALSE;
|
4358 |
|
4359 |
+
$plugins = array(
|
4360 |
+
'sucuri-wp-plugin/sucuri.php',
|
4361 |
+
'sucuri-cloudproxy-waf/cloudproxy.php',
|
4362 |
+
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4363 |
|
4364 |
+
foreach( $plugins as $plugin ){
|
4365 |
+
$plugin_directory = dirname( WP_PLUGIN_DIR . '/' . $plugin );
|
|
|
4366 |
|
4367 |
+
if( file_exists($plugin_directory) ){
|
4368 |
+
if( is_plugin_active($plugin) ){
|
4369 |
+
deactivate_plugins($plugin);
|
4370 |
+
}
|
4371 |
+
|
4372 |
+
$plugin_removed = $sucuri_fileinfo->remove_directory_tree($plugin_directory);
|
4373 |
+
}
|
4374 |
+
}
|
4375 |
+
}
|
4376 |
}
|
4377 |
|
4378 |
+
/**
|
4379 |
+
* Create a folder in the WordPress upload directory where the plugin will
|
4380 |
+
* store all the temporal or dynamic information.
|
4381 |
+
*
|
4382 |
+
* @return void
|
4383 |
+
*/
|
4384 |
+
public static function create_datastore_folder(){
|
4385 |
+
$plugin_upload_folder = SucuriScan::datastore_folder_path();
|
4386 |
+
|
4387 |
+
if( !file_exists($plugin_upload_folder) ){
|
4388 |
+
if( @mkdir($plugin_upload_folder) ){
|
4389 |
+
// Create last-logins datastore file.
|
4390 |
+
sucuriscan_lastlogins_datastore_exists();
|
4391 |
+
|
4392 |
+
// Create a htaccess file to deny access from all.
|
4393 |
+
@file_put_contents(
|
4394 |
+
$plugin_upload_folder . '/.htaccess',
|
4395 |
+
"Order Deny,Allow\nDeny from all\n",
|
4396 |
+
LOCK_EX
|
4397 |
+
);
|
4398 |
|
4399 |
+
// Create an index.html to avoid directory listing.
|
4400 |
+
@file_put_contents(
|
4401 |
+
$plugin_upload_folder . '/index.html',
|
4402 |
+
'<!-- Attemp to prevent the directory listing. -->',
|
4403 |
+
LOCK_EX
|
4404 |
+
);
|
4405 |
+
} else {
|
4406 |
+
SucuriScanInterface::error(
|
4407 |
+
'Data folder does not exists and could not be created. You will need to
|
4408 |
+
create this folder manually and give it write permissions:<br><br><code>'
|
4409 |
+
. $plugin_upload_folder . '</code>'
|
4410 |
+
);
|
4411 |
+
}
|
4412 |
+
}
|
4413 |
}
|
4414 |
|
4415 |
+
/**
|
4416 |
+
* Check whether a user has the permissions to see a page from the plugin.
|
4417 |
+
*
|
4418 |
+
* @return void
|
4419 |
+
*/
|
4420 |
+
public static function check_permissions(){
|
4421 |
+
global $sucuriscan_pages;
|
4422 |
|
4423 |
+
if(
|
4424 |
+
!function_exists('current_user_can')
|
4425 |
+
|| !current_user_can('manage_options')
|
4426 |
+
){
|
4427 |
+
$page = SucuriScanRequest::get('page', '_page');
|
4428 |
+
wp_die(__('Access denied by <b>Sucuri</b> to see <code>' . $page . '</code>') );
|
4429 |
+
}
|
4430 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4431 |
|
4432 |
+
/**
|
4433 |
+
* Verify the nonce of the previous page after a form submission. If the
|
4434 |
+
* validation fails the execution of the script will be stopped and a dead page
|
4435 |
+
* will be printed to the client using the official WordPress method.
|
4436 |
+
*
|
4437 |
+
* @return boolean Either TRUE or FALSE if the nonce is valid or not respectively.
|
4438 |
+
*/
|
4439 |
+
public static function check_nonce(){
|
4440 |
+
if( !empty($_POST) ){
|
4441 |
+
$nonce_name = 'sucuriscan_page_nonce';
|
4442 |
+
$nonce_value = SucuriScanRequest::post($nonce_name, '_nonce');
|
4443 |
|
4444 |
+
if( !$nonce_value || !wp_verify_nonce($nonce_value, $nonce_name) ){
|
4445 |
+
wp_die(__('WordPress Nonce verification failed, try again going back and checking the form.') );
|
|
|
|
|
4446 |
|
4447 |
+
return FALSE;
|
4448 |
+
}
|
4449 |
+
}
|
|
|
|
|
|
|
|
|
|
|
4450 |
|
4451 |
+
return TRUE;
|
4452 |
+
}
|
|
|
|
|
4453 |
|
4454 |
+
/**
|
4455 |
+
* Prints a HTML alert in the WordPress admin interface.
|
4456 |
+
*
|
4457 |
+
* @param string $type The type of alert, it can be either Updated or Error.
|
4458 |
+
* @param string $message The message that will be printed in the alert.
|
4459 |
+
* @return void
|
4460 |
+
*/
|
4461 |
+
private static function admin_notice( $type='updated', $message='' ){
|
4462 |
+
$alert_id = rand(100, 999);
|
4463 |
+
if( !empty($message) ): ?>
|
4464 |
+
<div id="sucuriscan-alert-<?php echo $alert_id; ?>" class="<?php echo $type; ?> sucuriscan-alert sucuriscan-alert-<?php echo $type; ?>">
|
4465 |
+
<a href="javascript:void(0)" class="close" onclick="sucuriscan_alert_close('<?php echo $alert_id; ?>')">×</a>
|
4466 |
+
<p><?php _e($message); ?></p>
|
4467 |
+
</div>
|
4468 |
+
<?php endif;
|
4469 |
+
}
|
4470 |
|
4471 |
+
/**
|
4472 |
+
* Prints a HTML alert of type ERROR in the WordPress admin interface.
|
4473 |
+
*
|
4474 |
+
* @param string $error_msg The message that will be printed in the alert.
|
4475 |
+
* @return void
|
4476 |
+
*/
|
4477 |
+
public static function error( $error_msg='' ){
|
4478 |
+
self::admin_notice( 'error', '<b>Sucuri:</b> ' . $error_msg );
|
4479 |
+
}
|
4480 |
|
4481 |
+
/**
|
4482 |
+
* Prints a HTML alert of type INFO in the WordPress admin interface.
|
4483 |
+
*
|
4484 |
+
* @param string $info_msg The message that will be printed in the alert.
|
4485 |
+
* @return void
|
4486 |
+
*/
|
4487 |
+
public static function info( $info_msg='' ){
|
4488 |
+
self::admin_notice( 'updated', '<b>Sucuri:</b> ' . $info_msg );
|
4489 |
}
|
4490 |
|
4491 |
+
/**
|
4492 |
+
* Display a notice message with instructions to continue the setup of the
|
4493 |
+
* plugin, this includes the generation of the API key and other steps that need
|
4494 |
+
* to be done to fully activate this plugin.
|
4495 |
+
*
|
4496 |
+
* @return void
|
4497 |
+
*/
|
4498 |
+
public static function setup_notice(){
|
4499 |
+
if(
|
4500 |
+
current_user_can('manage_options')
|
4501 |
+
&& !SucuriScanAPI::get_plugin_key()
|
4502 |
+
&& SucuriScanRequest::post(':plugin_api_key') === FALSE
|
4503 |
+
&& SucuriScanRequest::post(':recover_key') === FALSE
|
4504 |
+
&& !SucuriScanRequest::post(':manual_api_key')
|
4505 |
+
){
|
4506 |
+
echo SucuriScanTemplate::get_section('setup-notice');
|
4507 |
+
}
|
4508 |
}
|
4509 |
+
|
4510 |
}
|
4511 |
|
4512 |
/**
|
4513 |
+
* Display the page with a temporary message explaining the action that will be
|
4514 |
+
* performed once the hidden form is submitted to retrieve the scanning results
|
4515 |
+
* from the public SiteCheck API.
|
4516 |
*
|
|
|
4517 |
* @return void
|
4518 |
*/
|
4519 |
+
function sucuriscan_scanner_page(){
|
4520 |
+
SucuriScanInterface::check_permissions();
|
4521 |
|
4522 |
+
// Check if the information is already cached.
|
4523 |
+
$sucuri_cache = new SucuriScanCache('sitecheck');
|
4524 |
+
$scan_results = $sucuri_cache->get( 'scan_results', SUCURISCAN_SITECHECK_LIFETIME, 'array' );
|
4525 |
+
|
4526 |
+
if(
|
4527 |
+
(
|
4528 |
+
$scan_results
|
4529 |
+
&& !empty($scan_results)
|
4530 |
+
) || (
|
4531 |
+
SucuriScanInterface::check_nonce()
|
4532 |
+
&& SucuriScanRequest::post(':malware_scan', '1')
|
4533 |
+
)
|
4534 |
+
){
|
4535 |
+
sucuriscan_sitecheck_info($scan_results);
|
4536 |
} else {
|
4537 |
+
echo SucuriScanTemplate::get_template('malwarescan', array(
|
4538 |
+
'PageTitle' => 'Malware Scan',
|
4539 |
+
'PageStyleClass' => 'scanner-loading',
|
4540 |
+
));
|
4541 |
}
|
|
|
|
|
|
|
|
|
4542 |
}
|
4543 |
|
4544 |
/**
|
4545 |
+
* Display the result of site scan made through SiteCheck.
|
4546 |
*
|
4547 |
+
* @param array $res Array with information of the scanning.
|
4548 |
* @return void
|
4549 |
*/
|
4550 |
+
function sucuriscan_sitecheck_info( $res=array() ){
|
4551 |
+
// Will be TRUE only if the scanning results were retrieved from the cache.
|
4552 |
+
$display_results = (bool) $res;
|
4553 |
+
$clean_domain = SucuriScanOption::get_domain();
|
4554 |
|
4555 |
+
// If the results are not cached, then request a new scanning.
|
4556 |
+
if( $res === FALSE ){
|
4557 |
+
$res = SucuriScanAPI::get_sitecheck_results($clean_domain);
|
|
|
|
|
|
|
|
|
4558 |
|
4559 |
+
// Check for error messages in the request's response.
|
4560 |
+
if( is_string($res) && preg_match('/^ERROR:(.*)/', $res, $error_m) ){
|
4561 |
+
SucuriScanInterface::error( 'The site <code>' . $clean_domain . '</code> was not scanned: ' . $error_m[1] );
|
4562 |
+
}
|
|
|
|
|
|
|
4563 |
|
4564 |
+
else {
|
4565 |
+
$sucuri_cache = new SucuriScanCache('sitecheck');
|
4566 |
+
$display_results = TRUE;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4567 |
|
4568 |
+
// Cache the scanning results to reduce memory lose.
|
4569 |
+
if( !$sucuri_cache->add( 'scan_results', $res ) ){
|
4570 |
+
SucuriScanInterface::error( 'Could not cache the results of the SiteCheck scanning.' );
|
4571 |
+
}
|
4572 |
+
}
|
|
|
4573 |
}
|
4574 |
|
4575 |
+
ob_start();
|
4576 |
+
?>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4577 |
|
|
|
|
|
|
|
|
|
4578 |
|
4579 |
+
<?php if( $display_results ): ?>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4580 |
|
4581 |
+
<?php
|
4582 |
+
// Check for general warnings, and return the information for Infected/Clean site.
|
4583 |
+
$malware_warns_exist = isset($res['MALWARE']['WARN']) ? TRUE : FALSE;
|
4584 |
+
$blacklist_warns_exist = isset($res['BLACKLIST']['WARN']) ? TRUE : FALSE;
|
4585 |
+
$outdated_warns_exist = isset($res['OUTDATEDSCAN']) ? TRUE : FALSE;
|
4586 |
+
$recommendations_exist = isset($res['RECOMMENDATIONS']) ? TRUE : FALSE;
|
|
|
|
|
|
|
4587 |
|
4588 |
+
// Check whether this WordPress installation needs an update.
|
4589 |
+
global $wp_version;
|
4590 |
+
$wordpress_updated = FALSE;
|
4591 |
+
$updates = function_exists('get_core_updates') ? get_core_updates() : array();
|
4592 |
|
4593 |
+
if( !is_array($updates) || empty($updates) || $updates[0]->response=='latest' ){
|
4594 |
+
$wordpress_updated = TRUE;
|
4595 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
4596 |
|
4597 |
+
if( TRUE ){
|
4598 |
+
// Initialize the CSS classes with default values.
|
4599 |
+
$sucuriscan_css_blacklist = 'sucuriscan-border-good';
|
4600 |
+
$sucuriscan_css_malware = 'sucuriscan-border-good';
|
4601 |
+
$sitecheck_results_tab = '';
|
4602 |
+
$blacklist_status_tab = '';
|
4603 |
+
$website_details_tab = '';
|
4604 |
|
4605 |
+
// Generate the CSS classes for the blacklist status.
|
4606 |
+
if( $blacklist_warns_exist ){
|
4607 |
+
$sucuriscan_css_blacklist = 'sucuriscan-border-bad';
|
4608 |
+
$blacklist_status_tab = 'sucuriscan-red-tab';
|
4609 |
+
}
|
|
|
|
|
|
|
|
|
4610 |
|
4611 |
+
// Generate the CSS classes for the SiteCheck scanning results.
|
4612 |
+
if( $malware_warns_exist ){
|
4613 |
+
$sucuriscan_css_malware = 'sucuriscan-border-bad';
|
4614 |
+
$sitecheck_results_tab = 'sucuriscan-red-tab';
|
4615 |
+
}
|
4616 |
|
4617 |
+
// Generate the CSS classes for the outdated/recommendations panel.
|
4618 |
+
if( $outdated_warns_exist || $recommendations_exist ){
|
4619 |
+
$website_details_tab = 'sucuriscan-red-tab';
|
4620 |
+
}
|
|
|
|
|
|
|
|
|
|
|
4621 |
|
4622 |
+
$sucuriscan_css_wpupdate = $wordpress_updated ? 'sucuriscan-border-good' : 'sucuriscan-border-bad';
|
4623 |
+
}
|
4624 |
+
?>
|
4625 |
|
4626 |
+
<div id="poststuff">
|
4627 |
+
<div class="postbox sucuriscan-border sucuriscan-border-info sucuriscan-malwarescan-message">
|
4628 |
+
<h3>SiteCheck Scanner</h3>
|
4629 |
|
4630 |
+
<div class="inside">
|
4631 |
+
<p>
|
4632 |
+
If your site was recently hacked, you can see which files were modified to
|
4633 |
+
assist with any investigation.
|
4634 |
+
</p>
|
4635 |
+
</div>
|
4636 |
+
</div>
|
4637 |
+
</div>
|
4638 |
|
|
|
|
|
|
|
4639 |
|
4640 |
+
<div class="sucuriscan-tabs">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4641 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4642 |
|
4643 |
+
<ul>
|
4644 |
+
<li class="<?php _e($sitecheck_results_tab) ?>">
|
4645 |
+
<a href="#" data-tabname="sitecheck-results">Remote Scanner Results</a>
|
4646 |
+
</li>
|
4647 |
+
<li class="<?php _e($website_details_tab) ?>">
|
4648 |
+
<a href="#" data-tabname="website-details">Website Details</a>
|
4649 |
+
</li>
|
4650 |
+
<li>
|
4651 |
+
<a href="#" data-tabname="website-links">IFrames / Links / Scripts</a>
|
4652 |
+
</li>
|
4653 |
+
<li class="<?php _e($blacklist_status_tab) ?>">
|
4654 |
+
<a href="#" data-tabname="blacklist-status">Blacklist Status</a>
|
4655 |
+
</li>
|
4656 |
+
<li>
|
4657 |
+
<a href="#" data-tabname="modified-files">Modified Files</a>
|
4658 |
+
</li>
|
4659 |
+
</ul>
|
4660 |
|
|
|
|
|
|
|
|
|
4661 |
|
4662 |
+
<div class="sucuriscan-tab-containers">
|
|
|
|
|
|
|
|
|
4663 |
|
|
|
4664 |
|
4665 |
+
<div id="sucuriscan-sitecheck-results">
|
4666 |
+
<div id="poststuff">
|
4667 |
+
<div class="postbox sucuriscan-border <?php _e($sucuriscan_css_malware) ?>">
|
4668 |
+
<h3>
|
4669 |
+
<?php if( $malware_warns_exist ): ?>
|
4670 |
+
Site compromised (malware was identified)
|
4671 |
+
<?php else: ?>
|
4672 |
+
Site clean (no malware was identified)
|
4673 |
+
<?php endif; ?>
|
4674 |
+
</h3>
|
4675 |
|
4676 |
+
<div class="inside">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4677 |
|
4678 |
+
<?php if( !$malware_warns_exist ): ?>
|
4679 |
+
<p>
|
4680 |
+
<span><strong>Malware:</strong> Clean.</span><br>
|
4681 |
+
<span><strong>Malicious javascript:</strong> Clean.</span><br>
|
4682 |
+
<span><strong>Malicious iframes:</strong> Clean.</span><br>
|
4683 |
+
<span><strong>Suspicious redirections (htaccess):</strong> Clean.</span><br>
|
4684 |
+
<span><strong>Blackhat SEO Spam:</strong> Clean.</span><br>
|
4685 |
+
<span><strong>Anomaly detection:</strong> Clean.</span>
|
4686 |
+
</p>
|
4687 |
+
<?php else: ?>
|
4688 |
+
<ul>
|
4689 |
+
<?php
|
4690 |
+
foreach( $res['MALWARE']['WARN'] as $malres ){
|
4691 |
+
if( !is_array($malres) ){
|
4692 |
+
echo '<li>' . htmlspecialchars($malres) . '</li>';
|
4693 |
+
} else {
|
4694 |
+
$mwdetails = explode("\n", htmlspecialchars($malres[1]));
|
4695 |
+
$mw_name_link = isset($mwdetails[0]) ? substr($mwdetails[0], 1) : '';
|
4696 |
|
4697 |
+
if( preg_match('/(.*)\. Details: (.*)/', $mw_name_link, $mw_match) ){
|
4698 |
+
$mw_name_link = sprintf(
|
4699 |
+
'%s. Details: <a href="%s" target="_blank">%s</a>',
|
4700 |
+
$mw_match[1], $mw_match[2], $mw_match[2]
|
4701 |
+
);
|
4702 |
+
}
|
4703 |
|
4704 |
+
echo '<li>'. htmlspecialchars($malres[0]) . "\n<br>" . $mw_name_link . "</li>\n";
|
4705 |
+
}
|
4706 |
+
}
|
4707 |
+
?>
|
4708 |
+
</ul>
|
4709 |
+
<?php endif; ?>
|
|
|
|
|
|
|
4710 |
|
4711 |
+
<p>
|
4712 |
+
<i>
|
4713 |
+
More details here: <a href="http://sitecheck.sucuri.net/results/<?php _e($clean_domain); ?>"
|
4714 |
+
target="_blank">http://sitecheck.sucuri.net/results/<?php _e($clean_domain); ?></a>
|
4715 |
+
</i>
|
4716 |
+
</p>
|
4717 |
|
4718 |
+
<hr />
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4719 |
|
4720 |
+
<p>
|
4721 |
+
<i>
|
4722 |
+
If our free scanner did not detect any issue, you may have a more complicated
|
4723 |
+
and hidden problem. You can <a href="http://sucuri.net/signup" target="_blank">
|
4724 |
+
sign up</a> with Sucuri for a complete and in depth scan+cleanup (not included
|
4725 |
+
in the free checks).
|
4726 |
+
</i>
|
4727 |
+
</p>
|
4728 |
|
4729 |
+
</div>
|
4730 |
+
</div>
|
4731 |
+
</div>
|
4732 |
+
</div>
|
4733 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4734 |
|
4735 |
+
<div id="sucuriscan-website-details">
|
4736 |
+
<table class="wp-list-table widefat sucuriscan-table sucuriscan-scanner-details">
|
4737 |
+
<thead>
|
4738 |
+
<tr>
|
4739 |
+
<th colspan="2" class="thead-with-button">
|
4740 |
+
<span>System Information</span>
|
4741 |
+
<?php if( !$wordpress_updated ): ?>
|
4742 |
+
<a href="<?php echo admin_url('update-core.php'); ?>" class="button button-primary thead-topright-action">
|
4743 |
+
Update to <?php _e($updates[0]->version) ?>
|
4744 |
+
</a>
|
4745 |
+
<?php endif; ?>
|
4746 |
+
</th>
|
4747 |
+
</tr>
|
4748 |
+
</thead>
|
4749 |
|
4750 |
+
<tbody>
|
4751 |
+
<!-- List of generic information from the site. -->
|
4752 |
+
<?php
|
4753 |
+
$possible_keys = array(
|
4754 |
+
'DOMAIN' => 'Domain Scanned',
|
4755 |
+
'IP' => 'Site IP Address',
|
4756 |
+
'HOSTING' => 'Hosting Company',
|
4757 |
+
'CMS' => 'CMS Found',
|
4758 |
+
);
|
4759 |
+
$possible_url_keys = array(
|
4760 |
+
'IFRAME' => 'List of iframes found',
|
4761 |
+
'JSEXTERNAL' => 'List of external scripts included',
|
4762 |
+
'JSLOCAL' => 'List of scripts included',
|
4763 |
+
'URL' => 'List of links found',
|
4764 |
+
);
|
4765 |
+
?>
|
4766 |
|
4767 |
+
<?php foreach( $possible_keys as $result_key=>$result_title ): ?>
|
4768 |
+
<?php if( isset($res['SCAN'][$result_key]) ): ?>
|
4769 |
+
<?php $result_value = implode(', ', $res['SCAN'][$result_key]); ?>
|
4770 |
+
<tr>
|
4771 |
+
<td><?php _e($result_title) ?></td>
|
4772 |
+
<td><span class="sucuriscan-monospace"><?php _e($result_value) ?></span></td>
|
4773 |
+
</tr>
|
4774 |
+
<?php endif; ?>
|
4775 |
+
<?php endforeach; ?>
|
4776 |
|
4777 |
+
<tr>
|
4778 |
+
<td>WordPress Version</td>
|
4779 |
+
<td><span class="sucuriscan-monospace"><?php _e($wp_version) ?></span></td>
|
4780 |
+
</tr>
|
4781 |
+
<tr>
|
4782 |
+
<td>PHP Version</td>
|
4783 |
+
<td><span class="sucuriscan-monospace"><?php _e(phpversion()) ?></span></td>
|
4784 |
+
</tr>
|
|
|
4785 |
|
4786 |
+
<!-- List of application details from the site. -->
|
4787 |
+
<tr>
|
4788 |
+
<th colspan="2">Web application details</th>
|
4789 |
+
</tr>
|
4790 |
+
<?php foreach( $res['WEBAPP'] as $webapp_key=>$webapp_details ): ?>
|
4791 |
+
<?php if( is_array($webapp_details) ): ?>
|
4792 |
+
<?php foreach( $webapp_details as $i=>$details ): ?>
|
4793 |
+
<?php if( is_array($details) ){ $details = isset($details[0]) ? $details[0] : ''; } ?>
|
4794 |
+
<tr>
|
4795 |
+
<td colspan="2">
|
4796 |
+
<span class="sucuriscan-monospace"><?php _e($details) ?></span>
|
4797 |
+
</td>
|
4798 |
+
</tr>
|
4799 |
+
<?php endforeach; ?>
|
4800 |
+
<?php endif; ?>
|
4801 |
+
<?php endforeach; ?>
|
4802 |
|
4803 |
+
<?php foreach( $res['SYSTEM']['NOTICE'] as $j=>$notice ): ?>
|
4804 |
+
<?php if( is_array($notice) ){ $notice = implode(', ', $notice); } ?>
|
4805 |
+
<tr>
|
4806 |
+
<td colspan="2">
|
4807 |
+
<span class="sucuriscan-monospace"><?php _e($notice) ?></span>
|
4808 |
+
</td>
|
4809 |
+
</tr>
|
4810 |
+
<?php endforeach; ?>
|
4811 |
|
4812 |
+
<!-- Possible recommendations or outdated software on the site. -->
|
4813 |
+
<?php if( $outdated_warns_exist || $recommendations_exist ): ?>
|
4814 |
+
<tr>
|
4815 |
+
<th colspan="2">Recommendations for the site</th>
|
4816 |
+
</tr>
|
4817 |
+
<?php endif; ?>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4818 |
|
4819 |
+
<!-- Possible outdated software on the site. -->
|
4820 |
+
<?php if( $outdated_warns_exist ): ?>
|
4821 |
+
<?php foreach( $res['OUTDATEDSCAN'] as $outdated ): ?>
|
4822 |
+
<?php if( count($outdated) >= 3 ): ?>
|
4823 |
+
<tr>
|
4824 |
+
<td colspan="2" class="sucuriscan-border-bad">
|
4825 |
+
<strong><?php _e($outdated[0]) ?></strong>
|
4826 |
+
<em>(<?php _e($outdated[2]) ?>)</em>
|
4827 |
+
<span><?php _e($outdated[1]) ?></span>
|
4828 |
+
</td>
|
4829 |
+
</tr>
|
4830 |
+
<?php endif; ?>
|
4831 |
+
<?php endforeach; ?>
|
4832 |
+
<?php endif; ?>
|
4833 |
|
4834 |
+
<!-- Possible recommendations for the site. -->
|
4835 |
+
<?php if( $recommendations_exist ): ?>
|
4836 |
+
<?php foreach( $res['RECOMMENDATIONS'] as $recommendation ): ?>
|
4837 |
+
<?php if( count($recommendation) >= 3 ): ?>
|
4838 |
+
<tr>
|
4839 |
+
<td colspan="2" class="sucuriscan-border-bad">
|
4840 |
+
<?php printf(
|
4841 |
+
'<strong>%s</strong><br><span>%s</span><br><a href="%s" target="_blank">%s</a>',
|
4842 |
+
SucuriScan::escape($recommendation[0]),
|
4843 |
+
SucuriScan::escape($recommendation[1]),
|
4844 |
+
SucuriScan::escape($recommendation[2]),
|
4845 |
+
SucuriScan::escape($recommendation[2])
|
4846 |
+
); ?>
|
4847 |
+
</td>
|
4848 |
+
</tr>
|
4849 |
+
<?php endif; ?>
|
4850 |
+
<?php endforeach; ?>
|
4851 |
+
<?php endif; ?>
|
4852 |
+
</tbody>
|
4853 |
+
</table>
|
4854 |
+
</div>
|
4855 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4856 |
|
4857 |
+
<div id="sucuriscan-website-links">
|
4858 |
+
<table class="wp-list-table widefat sucuriscan-table sucuriscan-scanner-links">
|
4859 |
+
<tbody>
|
4860 |
+
<?php foreach( $possible_url_keys as $result_url_key=>$result_url_title ): ?>
|
4861 |
|
4862 |
+
<?php if( isset($res['LINKS'][$result_url_key]) ): ?>
|
4863 |
+
<tr>
|
4864 |
+
<th colspan="2">
|
4865 |
+
<?php printf(
|
4866 |
+
'%s (%d found)',
|
4867 |
+
__($result_url_title),
|
4868 |
+
count($res['LINKS'][$result_url_key])
|
4869 |
+
) ?>
|
4870 |
+
</th>
|
4871 |
+
</tr>
|
4872 |
|
4873 |
+
<?php foreach( $res['LINKS'][$result_url_key] as $url_path ): ?>
|
4874 |
+
<tr>
|
4875 |
+
<td colspan="2">
|
4876 |
+
<span class="sucuriscan-monospace sucuriscan-wraptext"><?php _e($url_path) ?></span>
|
4877 |
+
</td>
|
4878 |
+
</tr>
|
4879 |
+
<?php endforeach; ?>
|
4880 |
+
<?php endif; ?>
|
4881 |
|
4882 |
+
<?php endforeach; ?>
|
4883 |
+
</tbody>
|
4884 |
+
</table>
|
4885 |
+
</div>
|
4886 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4887 |
|
4888 |
+
<div id="sucuriscan-blacklist-status">
|
4889 |
+
<div id="poststuff">
|
4890 |
+
<div class="postbox sucuriscan-border <?php _e($sucuriscan_css_blacklist) ?>">
|
4891 |
+
<h3>
|
4892 |
+
<?php if( $blacklist_warns_exist ): ?>
|
4893 |
+
Site blacklisted
|
4894 |
+
<?php else: ?>
|
4895 |
+
Site blacklist-free
|
4896 |
+
<?php endif; ?>
|
4897 |
+
</h3>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4898 |
|
4899 |
+
<div class="inside">
|
4900 |
+
<ul>
|
4901 |
+
<?php
|
4902 |
+
foreach(array(
|
4903 |
+
'INFO' => 'CLEAN',
|
4904 |
+
'WARN' => 'WARNING'
|
4905 |
+
) as $type => $group_title){
|
4906 |
+
if( isset($res['BLACKLIST'][$type]) ){
|
4907 |
+
foreach( $res['BLACKLIST'][$type] as $blres ){
|
4908 |
+
$report_site = SucuriScan::escape($blres[0]);
|
4909 |
+
$report_url = SucuriScan::escape($blres[1]);
|
4910 |
+
printf(
|
4911 |
+
'<li><b>%s:</b> %s.<br>Details at <a href="%s" target="_blank">%s</a></li>',
|
4912 |
+
$group_title, $report_site, $report_url, $report_url
|
4913 |
+
);
|
4914 |
+
}
|
4915 |
+
}
|
4916 |
+
}
|
4917 |
+
?>
|
4918 |
+
</ul>
|
4919 |
+
</div>
|
4920 |
+
</div>
|
4921 |
+
</div>
|
4922 |
+
</div>
|
4923 |
|
|
|
|
|
|
|
4924 |
|
4925 |
+
<div id="sucuriscan-modified-files">
|
4926 |
+
<?php echo sucuriscan_modified_files(); ?>
|
4927 |
+
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4928 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4929 |
|
4930 |
+
</div>
|
4931 |
+
</div>
|
|
|
4932 |
|
4933 |
+
<?php if( $malware_warns_exist || $blacklist_warns_exist ): ?>
|
4934 |
+
<a href="http://sucuri.net/signup/" target="_blank" class="button button-primary button-hero sucuriscan-cleanup-btn">
|
4935 |
+
Get your site protected with Sucuri
|
4936 |
+
</a>
|
4937 |
+
<?php endif; ?>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4938 |
|
4939 |
+
<?php endif; ?>
|
|
|
|
|
|
|
|
|
|
|
4940 |
|
|
|
4941 |
|
4942 |
+
<?php
|
4943 |
+
$_html = ob_get_contents();
|
4944 |
+
ob_end_clean();
|
4945 |
+
echo SucuriScanTemplate::get_base_template($_html, array(
|
4946 |
+
'PageTitle' => 'Malware Scan',
|
4947 |
+
'PageContent' => $_html,
|
4948 |
+
'PageStyleClass' => 'scanner-results',
|
4949 |
+
));
|
4950 |
+
return;
|
4951 |
}
|
4952 |
|
4953 |
/**
|
4960 |
* @return void
|
4961 |
*/
|
4962 |
function sucuriscan_monitoring_page(){
|
4963 |
+
SucuriScanInterface::check_permissions();
|
|
|
|
|
4964 |
|
4965 |
// Process all form submissions.
|
4966 |
sucuriscan_monitoring_form_submissions();
|
4967 |
|
4968 |
// Get the dynamic values for the template variables.
|
4969 |
+
$api_key = SucuriScanAPI::get_cloudproxy_key();
|
4970 |
|
4971 |
// Page pseudo-variables initialization.
|
4972 |
$template_variables = array(
|
4988 |
$template_variables['Monitoring.InstructionsVisibility'] = 'hidden';
|
4989 |
}
|
4990 |
|
4991 |
+
echo SucuriScanTemplate::get_template('monitoring', $template_variables);
|
4992 |
}
|
4993 |
|
4994 |
/**
|
4995 |
* Process the requests sent by the form submissions originated in the monitoring
|
4996 |
+
* page, all forms must have a nonce field that will be checked against the one
|
4997 |
* generated in the template render function.
|
4998 |
*
|
4999 |
* @return void
|
5000 |
*/
|
5001 |
function sucuriscan_monitoring_form_submissions(){
|
5002 |
|
5003 |
+
if( SucuriScanInterface::check_nonce() ){
|
5004 |
|
5005 |
// Add and/or Update the Sucuri WAF API Key (do it before anything else).
|
5006 |
+
$option_name = ':cloudproxy_apikey';
|
5007 |
+
$api_key = SucuriScanRequest::post($option_name);
|
|
|
|
|
5008 |
|
5009 |
+
if( $api_key !== FALSE ){
|
5010 |
+
if( SucuriScanAPI::is_valid_cloudproxy_key($api_key) ){
|
5011 |
+
SucuriScanOption::update_option($option_name, $api_key);
|
5012 |
+
SucuriScanInterface::info( 'CloudProxy API key saved successfully' );
|
5013 |
} elseif( empty($api_key) ){
|
5014 |
+
SucuriScanOption::delete_option($option_name);
|
5015 |
+
SucuriScanInterface::info( 'CloudProxy API key removed successfully' );
|
5016 |
} else {
|
5017 |
+
SucuriScanInterface::error( 'Invalid CloudProxy API key, check your settings and try again.' );
|
5018 |
}
|
5019 |
}
|
5020 |
|
5021 |
// Flush the cache of the site(s) associated with the API key.
|
5022 |
+
if( SucuriScanRequest::post(':clear_cache', '1') ){
|
5023 |
+
$clear_cache_resp = SucuriScanAPI::clear_cloudproxy_cache();
|
5024 |
|
5025 |
if( $clear_cache_resp ){
|
5026 |
if( isset($clear_cache_resp->messages[0]) ){
|
5027 |
+
SucuriScanInterface::info($clear_cache_resp->messages[0]);
|
5028 |
} else {
|
5029 |
+
SucuriScanInterface::error('Could not clear the cache of your site, try later again.');
|
5030 |
}
|
5031 |
} else {
|
5032 |
+
SucuriScanInterface::error( 'CloudProxy is not enabled on your site, or your API key is invalid.' );
|
5033 |
}
|
5034 |
}
|
5035 |
|
5051 |
);
|
5052 |
|
5053 |
if( $api_key ){
|
5054 |
+
$settings = SucuriScanAPI::get_cloudproxy_settings($api_key);
|
5055 |
|
5056 |
$template_variables['Monitoring.APIKey'] = $api_key['string'];
|
5057 |
|
5083 |
}
|
5084 |
|
5085 |
// Parse the snippet template and replace the pseudo-variables.
|
5086 |
+
$template_variables['Monitoring.SettingOptions'] .= SucuriScanTemplate::get_snippet('monitoring-settings', array(
|
5087 |
'Monitoring.OptionCssClass' => $css_class,
|
5088 |
'Monitoring.OptionName' => $option_title,
|
5089 |
'Monitoring.OptionValue' => $option_value,
|
5093 |
}
|
5094 |
}
|
5095 |
|
5096 |
+
return SucuriScanTemplate::get_section( 'monitoring-settings', $template_variables );
|
5097 |
}
|
5098 |
|
5099 |
/**
|
5131 |
}
|
5132 |
|
5133 |
/**
|
5134 |
+
* Get an explanation of the meaning of the value set for the account's attribute cache_mode.
|
5135 |
*
|
5136 |
* @param string $mode The value set for the cache settings of the site.
|
5137 |
+
* @return string Explanation of the meaning of the cache_mode value.
|
5138 |
*/
|
5139 |
function sucuriscan_cache_mode_title( $mode='' ){
|
5140 |
$title = '';
|
5142 |
switch( $mode ){
|
5143 |
case 'docache': $title = 'Enabled (recommended)'; break;
|
5144 |
case 'sitecache': $title = 'Site caching (using your site headers)'; break;
|
5145 |
+
case 'nocache': $title = 'Minimal (only for a few minutes)'; break;
|
5146 |
+
case 'nocacheatall': $title = 'Caching disabled (use with caution)'; break;
|
5147 |
default: $title = 'Unknown'; break;
|
5148 |
}
|
5149 |
|
5165 |
'AuditLogs.PaginationVisibility' => 'hidden',
|
5166 |
'AuditLogs.AuditPagination' => '',
|
5167 |
'AuditLogs.TargetDate' => '',
|
5168 |
+
'AuditLogs.DateYears' => '',
|
5169 |
+
'AuditLogs.DateMonths' => '',
|
5170 |
+
'AuditLogs.DateDays' => '',
|
5171 |
);
|
5172 |
|
5173 |
$date = date('Y-m-d');
|
5174 |
|
5175 |
if( $api_key ){
|
5176 |
+
// Retrieve the date filter from the GET request (if any).
|
5177 |
+
if( $date_by_get = SucuriScanRequest::get('date', '_yyyymmdd') ){
|
5178 |
+
$date = $date_by_get;
|
5179 |
}
|
5180 |
|
5181 |
+
// Retrieve the date filter from the POST request (if any).
|
5182 |
+
$year = SucuriScanRequest::post(':year');
|
5183 |
+
$month = SucuriScanRequest::post(':month');
|
5184 |
+
$day = SucuriScanRequest::post(':day');
|
5185 |
+
|
5186 |
+
if( $year && $month && $day ){
|
5187 |
+
$date = sprintf( '%s-%s-%s', $year, $month, $day );
|
|
|
|
|
|
|
|
|
5188 |
}
|
5189 |
|
5190 |
+
$logs_data = SucuriScanAPI::get_cloudproxy_logs( $api_key, $date );
|
5191 |
|
5192 |
if( $logs_data ){
|
5193 |
add_thickbox(); /* Include the Thickbox library. */
|
5199 |
}
|
5200 |
|
5201 |
$template_variables['AuditLogs.TargetDate'] = htmlentities($date);
|
5202 |
+
$template_variables['AuditLogs.DateYears'] = sucuriscan_monitoring_dates('years', $date);
|
5203 |
+
$template_variables['AuditLogs.DateMonths'] = sucuriscan_monitoring_dates('months', $date);
|
5204 |
+
$template_variables['AuditLogs.DateDays'] = sucuriscan_monitoring_dates('days', $date);
|
5205 |
|
5206 |
+
return SucuriScanTemplate::get_section( 'monitoring-logs', $template_variables );
|
5207 |
}
|
5208 |
|
5209 |
/**
|
5237 |
$filter_by_keyword = FALSE;
|
5238 |
$filter_query = FALSE;
|
5239 |
|
5240 |
+
if( $q = SucuriScanRequest::post(':monitoring_denial_type') ){
|
5241 |
$filter_by_denial_type = TRUE;
|
5242 |
+
$filter_query = $q;
|
5243 |
}
|
5244 |
|
5245 |
+
if( $q = SucuriScanRequest::post(':monitoring_log_filter') ){
|
5246 |
$filter_by_keyword = TRUE;
|
5247 |
+
$filter_query = $q;
|
5248 |
}
|
5249 |
|
5250 |
foreach( $access_logs as $access_log ){
|
5257 |
// If there is a filter, check the access_log data and break the operation if needed.
|
5258 |
if( $filter_query ){
|
5259 |
if( $filter_by_denial_type ){
|
5260 |
+
$denial_type_slug = SucuriScan::human2var($access_log->sucuri_block_reason);
|
5261 |
|
5262 |
if( $denial_type_slug != $filter_query ){ continue; }
|
5263 |
}
|
5287 |
$audit_log_snippet[$attr_title] = $attr_value;
|
5288 |
}
|
5289 |
|
5290 |
+
$logs_html .= SucuriScanTemplate::get_snippet('monitoring-logs', $audit_log_snippet);
|
5291 |
$counter += 1;
|
5292 |
}
|
5293 |
}
|
5306 |
*/
|
5307 |
function sucuriscan_monitoring_denial_types( $access_logs=array(), $in_html=TRUE ){
|
5308 |
$types = array();
|
|
|
5309 |
|
5310 |
if( $access_logs && !empty($access_logs) ){
|
5311 |
foreach( $access_logs as $access_log ){
|
5312 |
if( !array_key_exists($access_log->sucuri_block_reason, $types) ){
|
5313 |
+
$denial_type_k = SucuriScan::human2var($access_log->sucuri_block_reason);
|
5314 |
$types[$denial_type_k] = $access_log->sucuri_block_reason;
|
5315 |
}
|
5316 |
}
|
5318 |
|
5319 |
if( $in_html ){
|
5320 |
$html_types = '<option value="">Filter</option>';
|
5321 |
+
$selected = SucuriScanRequest::post(':monitoring_denial_type', '.+');
|
|
|
|
|
|
|
5322 |
|
5323 |
foreach( $types as $type_key => $type_value ){
|
5324 |
+
$selected_tag = ( $type_key === $selected ) ? 'selected="selected"' : '';
|
5325 |
+
$html_types .= sprintf(
|
5326 |
+
'<option value="%s" %s>%s</option>',
|
5327 |
+
SucuriScan::escape($type_key),
|
5328 |
+
$selected_tag,
|
5329 |
+
SucuriScan::escape($type_value)
|
5330 |
+
);
|
5331 |
}
|
5332 |
|
5333 |
return $html_types;
|
5340 |
* Get a list of years, months or days depending of the type specified.
|
5341 |
*
|
5342 |
* @param string $type Either years, months or days.
|
5343 |
+
* @param string $date Year, month and day selected from the request.
|
5344 |
* @param boolean $in_html Whether the list should be converted to a HTML select options or not.
|
5345 |
* @return array Either an array with the expected values, or a HTML code.
|
5346 |
*/
|
5347 |
+
function sucuriscan_monitoring_dates( $type='', $date='', $in_html=TRUE ){
|
5348 |
$options = array();
|
5349 |
$selected = '';
|
5350 |
|
5351 |
+
if( preg_match('/^([0-9]{4})\-([0-9]{2})\-([0-9]{2})$/', $date, $date_m) ){
|
5352 |
+
$s_year = $date_m[1];
|
5353 |
+
$s_month = $date_m[2];
|
5354 |
+
$s_day = $date_m[3];
|
5355 |
+
} else {
|
5356 |
+
$s_year = '';
|
5357 |
+
$s_month = '';
|
5358 |
+
$s_day = '';
|
5359 |
+
}
|
5360 |
+
|
5361 |
switch( $type ){
|
5362 |
case 'years':
|
5363 |
+
$selected = $s_year;
|
5364 |
$current_year = (int) date('Y');
|
5365 |
$max_years = 5; /* Maximum number of years to keep the logs. */
|
5366 |
$options = range( ($current_year - $max_years), $current_year );
|
|
|
|
|
|
|
|
|
5367 |
break;
|
5368 |
case 'months':
|
5369 |
+
$selected = $s_month;
|
5370 |
$options = array(
|
5371 |
'01' => 'January',
|
5372 |
'02' => 'February',
|
5381 |
'11' => 'November',
|
5382 |
'12' => 'December'
|
5383 |
);
|
|
|
|
|
|
|
|
|
5384 |
break;
|
5385 |
case 'days':
|
5386 |
$options = range(1, 31);
|
5387 |
+
$selected = $s_day;
|
|
|
|
|
|
|
5388 |
break;
|
5389 |
}
|
5390 |
|
5415 |
* @return void
|
5416 |
*/
|
5417 |
function sucuriscan_hardening_page(){
|
5418 |
+
SucuriScanInterface::check_permissions();
|
5419 |
|
5420 |
+
if(
|
5421 |
+
SucuriScanRequest::post(':run_hardening')
|
5422 |
+
&& !SucuriScanInterface::check_nonce()
|
5423 |
+
){
|
5424 |
+
unset($_POST['sucuriscan_run_hardening']);
|
|
|
|
|
|
|
5425 |
}
|
5426 |
|
5427 |
ob_start();
|
5429 |
|
5430 |
<div id="poststuff">
|
5431 |
<form method="post">
|
5432 |
+
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
|
5433 |
+
<input type="hidden" name="sucuriscan_run_hardening" value="1" />
|
5434 |
|
5435 |
<?php
|
5436 |
sucuriscan_harden_version();
|
5452 |
<?php
|
5453 |
$_html = ob_get_contents();
|
5454 |
ob_end_clean();
|
5455 |
+
echo SucuriScanTemplate::get_base_template($_html, array(
|
5456 |
'PageTitle' => 'Hardening',
|
5457 |
'PageContent' => $_html,
|
5458 |
'PageStyleClass' => 'hardening'
|
5516 |
* @return void
|
5517 |
*/
|
5518 |
function sucuriscan_harden_version(){
|
5519 |
+
$site_version = SucuriScan::site_version();
|
|
|
5520 |
$updates = get_core_updates();
|
5521 |
$cp = ( !is_array($updates) || empty($updates) ? 1 : 0 );
|
5522 |
|
5529 |
}
|
5530 |
}
|
5531 |
|
5532 |
+
if( strcmp($site_version, '3.7') < 0 ){
|
5533 |
$cp = 0;
|
5534 |
}
|
5535 |
|
|
|
5536 |
$initial_msg = 'Why keep your site updated? WordPress is an open-source
|
5537 |
project which means that with every update the details of the changes made
|
5538 |
to the source code are made public, if there were security fixes then
|
5539 |
someone with malicious intent can use this information to attack any site
|
5540 |
that has not been upgraded.';
|
5541 |
+
$messageok = sprintf('Your WordPress installation (%s) is current.', $site_version);
|
5542 |
$messagewarn = sprintf(
|
5543 |
'Your current version (%s) is not current.<br>
|
5544 |
<a href="update-core.php" class="button-primary">Update now!</a>',
|
5545 |
+
$site_version
|
5546 |
);
|
5547 |
|
5548 |
sucuriscan_harden_status( 'Verify WordPress version', $cp, NULL, $messageok, $messagewarn, $initial_msg );
|
5579 |
function sucuriscan_harden_upload(){
|
5580 |
$cp = 1;
|
5581 |
$upmsg = NULL;
|
5582 |
+
$datastore_path = SucuriScan::datastore_folder_path();
|
5583 |
+
$htaccess_upload = dirname($datastore_path) . '/.htaccess';
|
5584 |
|
5585 |
if( !is_readable($htaccess_upload) ){
|
5586 |
$cp = 0;
|
5587 |
} else {
|
5588 |
$cp = 0;
|
5589 |
+
$fcontent = SucuriScanFileInfo::file_lines($htaccess_upload);
|
5590 |
|
5591 |
foreach( $fcontent as $fline ){
|
5592 |
+
if( stripos($fline, 'deny from all') !== FALSE ){
|
5593 |
$cp = 1;
|
5594 |
break;
|
5595 |
}
|
5596 |
}
|
5597 |
}
|
5598 |
|
5599 |
+
if( SucuriScanRequest::post(':run_hardening') ){
|
5600 |
+
if( SucuriScanRequest::post(':harden_upload') && $cp == 0 ){
|
5601 |
if( @file_put_contents($htaccess_upload, "\n<Files *.php>\ndeny from all\n</Files>") === FALSE ){
|
5602 |
+
$upmsg = SucuriScanInterface::error('Unable to create <code>.htaccess</code> file, folder destination is not writable.');
|
5603 |
} else {
|
5604 |
+
$upmsg = SucuriScanInterface::info('Hardening applied successfully to upload directory');
|
5605 |
$cp = 1;
|
5606 |
}
|
5607 |
}
|
5608 |
|
5609 |
+
elseif( SucuriScanRequest::post(':harden_upload_unharden') ){
|
5610 |
$htaccess_upload_writable = ( file_exists($htaccess_upload) && is_writable($htaccess_upload) ) ? TRUE : FALSE;
|
5611 |
$htaccess_content = $htaccess_upload_writable ? file_get_contents($htaccess_upload) : '';
|
5612 |
|
5618 |
@file_put_contents($htaccess_upload, $htaccess_content, LOCK_EX);
|
5619 |
}
|
5620 |
|
5621 |
+
SucuriScanInterface::info('Hardening reverted for upload directory <code>/wp-content/uploads/</code>');
|
5622 |
} else {
|
5623 |
+
SucuriScanInterface::error(
|
5624 |
+
'File <code>/wp-content/uploads/.htaccess</code> does not exists or
|
5625 |
+
is not writable, you will need to remove the following code (manually):
|
5626 |
<code><Files *.php>deny from all</Files></code>'
|
5627 |
);
|
5628 |
}
|
5658 |
$cp = 0;
|
5659 |
} else {
|
5660 |
$cp = 0;
|
5661 |
+
$fcontent = SucuriScanFileInfo::file_lines($htaccess_upload);
|
5662 |
|
5663 |
foreach( $fcontent as $fline ){
|
5664 |
+
if( stripos($fline, 'deny from all') !== FALSE ){
|
5665 |
$cp = 1;
|
5666 |
break;
|
5667 |
}
|
5668 |
}
|
5669 |
}
|
5670 |
|
5671 |
+
if( SucuriScanRequest::post(':run_hardening') ){
|
5672 |
+
if( SucuriScanRequest::post(':harden_wpcontent') && $cp == 0 ){
|
5673 |
if( @file_put_contents($htaccess_upload, "\n<Files *.php>\ndeny from all\n</Files>") === FALSE ){
|
5674 |
+
$upmsg = SucuriScanInterface::error('Unable to create <code>.htaccess</code> file, folder destination is not writable.');
|
5675 |
} else {
|
5676 |
+
$upmsg = SucuriScanInterface::info('Hardening applied successfully to content directory <code>/wp-content/</code>');
|
5677 |
$cp = 1;
|
5678 |
}
|
5679 |
}
|
5680 |
|
5681 |
+
elseif( SucuriScanRequest::post(':harden_wpcontent_unharden') ){
|
5682 |
$htaccess_upload_writable = ( file_exists($htaccess_upload) && is_writable($htaccess_upload) ) ? TRUE : FALSE;
|
5683 |
$htaccess_content = $htaccess_upload_writable ? file_get_contents($htaccess_upload) : '';
|
5684 |
|
5690 |
@file_put_contents($htaccess_upload, $htaccess_content, LOCK_EX);
|
5691 |
}
|
5692 |
|
5693 |
+
SucuriScanInterface::info('Hardening reverted for content directory <code>/wp-content/</code>');
|
5694 |
} else {
|
5695 |
+
SucuriScanInterface::info(
|
5696 |
+
'File <code>/wp-content/.htaccess</code> does not exists or is not writable,
|
5697 |
+
you will need to remove the following code manually from there:
|
5698 |
<code><Files *.php>deny from all</Files></code>'
|
5699 |
);
|
5700 |
}
|
5733 |
$cp = 0;
|
5734 |
} else {
|
5735 |
$cp = 0;
|
5736 |
+
$fcontent = SucuriScanFileInfo::file_lines($htaccess_upload);
|
5737 |
|
5738 |
foreach( $fcontent as $fline ){
|
5739 |
+
if( stripos($fline, 'deny from all') !== FALSE ){
|
5740 |
$cp = 1;
|
5741 |
break;
|
5742 |
}
|
5743 |
}
|
5744 |
}
|
5745 |
|
5746 |
+
if( SucuriScanRequest::post(':run_hardening') ){
|
5747 |
+
if( SucuriScanRequest::post(':harden_wpincludes') && $cp == 0 ){
|
5748 |
if( @file_put_contents($htaccess_upload, "\n<Files *.php>\ndeny from all\n</Files>\n<Files wp-tinymce.php>\nallow from all\n</Files>\n")===FALSE ){
|
5749 |
+
$upmsg = SucuriScanInterface::error('Unable to create <code>.htaccess</code> file, folder destination is not writable.');
|
5750 |
} else {
|
5751 |
+
$upmsg = SucuriScanInterface::info('Hardening applied successfully to library\'s directory <code>/wp-includes/</code>');
|
5752 |
$cp = 1;
|
5753 |
}
|
5754 |
}
|
5755 |
|
5756 |
+
elseif( SucuriScanRequest::post(':harden_wpincludes_unharden') ){
|
5757 |
$htaccess_upload_writable = ( file_exists($htaccess_upload) && is_writable($htaccess_upload) ) ? TRUE : FALSE;
|
5758 |
$htaccess_content = $htaccess_upload_writable ? file_get_contents($htaccess_upload) : '';
|
5759 |
|
5766 |
|
5767 |
@file_put_contents($htaccess_upload, $htaccess_content, LOCK_EX);
|
5768 |
}
|
5769 |
+
SucuriScanInterface::info('Hardening reverted for library\'s directory <code>/wp-includes/</code>');
|
5770 |
} else {
|
5771 |
+
SucuriScanInterface::error(
|
5772 |
+
'File <code>wp-includes/.htaccess</code> does not exists or is not
|
5773 |
+
writable, you will need to remove the following code manually from
|
5774 |
there: <code><Files *.php>deny from all</Files></code>'
|
5775 |
);
|
5776 |
}
|
5816 |
*/
|
5817 |
function sucuriscan_cloudproxy_enabled(){
|
5818 |
$btn_string = '';
|
5819 |
+
$enabled = SucuriScan::is_behind_cloudproxy();
|
5820 |
$status = 1;
|
5821 |
|
5822 |
if( $enabled !== TRUE ){
|
5848 |
* @return void
|
5849 |
*/
|
5850 |
function sucuriscan_harden_secretkeys(){
|
5851 |
+
$wp_config_path = SucuriScan::get_wpconfig_path();
|
5852 |
+
$current_keys = SucuriScanOption::get_security_keys();
|
5853 |
|
5854 |
if( $wp_config_path ){
|
5855 |
$cp = 1;
|
5856 |
$message = 'The main configuration file was found at: <code>'.$wp_config_path.'</code><br>';
|
5857 |
|
5858 |
+
if(
|
5859 |
+
!empty($current_keys['bad'])
|
5860 |
+
|| !empty($current_keys['missing'])
|
5861 |
+
){
|
5862 |
+
$cp = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5863 |
}
|
5864 |
}else{
|
5865 |
$cp = 0;
|
5866 |
+
$message = 'The <code>wp-config.php</code> file was not found.<br>';
|
5867 |
}
|
5868 |
|
5869 |
$message .= '<br>It checks whether you have proper random keys/salts created for WordPress. A
|
5872 |
random elements to the password. In simple terms, a secret key is a password with
|
5873 |
elements that make it harder to generate enough options to break through your
|
5874 |
security barriers.';
|
5875 |
+
$messageok = 'Security keys and salts not set, we recommend creating them for security reasons'
|
5876 |
+
. '<a href="' . SucuriScanTemplate::get_url('posthack') . '" class="button button-primary">'
|
5877 |
+
. 'Harden</a>';
|
5878 |
|
5879 |
sucuriscan_harden_status(
|
5880 |
+
'Security keys',
|
5881 |
$cp,
|
5882 |
NULL,
|
5883 |
+
'Security keys and salts properly created',
|
5884 |
+
$messageok,
|
5885 |
$message,
|
5886 |
NULL
|
5887 |
);
|
5898 |
$upmsg = NULL;
|
5899 |
$cp = is_readable(ABSPATH.'/readme.html') ? 0 : 1;
|
5900 |
|
5901 |
+
// TODO: After hardening create an option to automatically remove this after WP upgrade.
|
5902 |
+
if( SucuriScanRequest::post(':run_hardening') ){
|
5903 |
+
if( SucuriScanRequest::post(':harden_readme') && $cp == 0 ){
|
5904 |
if( @unlink(ABSPATH.'/readme.html') === FALSE ){
|
5905 |
+
$upmsg = SucuriScanInterface::error('Unable to remove <code>readme.html</code> file.');
|
5906 |
} else {
|
5907 |
$cp = 1;
|
5908 |
+
$upmsg = SucuriScanInterface::info('<code>readme.html</code> file removed successfully.');
|
5909 |
}
|
5910 |
}
|
5911 |
|
5912 |
+
elseif( SucuriScanRequest::post(':harden_readme_unharden') ){
|
5913 |
+
SucuriScanInterface::error('We can not revert this action, you must create the <code>readme.html</code> file by yourself.');
|
5914 |
}
|
5915 |
}
|
5916 |
|
5935 |
global $wpdb;
|
5936 |
|
5937 |
$upmsg = NULL;
|
5938 |
+
$user_query = new WP_User_Query(array(
|
5939 |
+
'search' => 'admin',
|
5940 |
+
'fields' => array( 'ID', 'user_login' ),
|
5941 |
+
'search_columns' => array( 'user_login' ),
|
5942 |
+
));
|
5943 |
+
$results = $user_query->get_results();
|
5944 |
+
$account_removed = ( count($results) === 0 ? 1 : 0 );
|
5945 |
|
5946 |
+
if( $account_removed === 0 ){
|
5947 |
+
$upmsg = '<i><strong>Notice.</strong> We do not offer an option to automatically change the user name.
|
5948 |
Go to the <a href="'.admin_url('users.php').'" target="_blank">user list</a> and create a new
|
5949 |
+
administrator user. Once created, log in as that user and remove the default <code>admin</code>
|
5950 |
+
(make sure to assign all the admin posts to the new user too).</i>';
|
5951 |
}
|
5952 |
|
5953 |
sucuriscan_harden_status(
|
5969 |
function sucuriscan_harden_fileeditor(){
|
5970 |
$file_editor_disabled = defined('DISALLOW_FILE_EDIT') ? DISALLOW_FILE_EDIT : FALSE;
|
5971 |
|
5972 |
+
if( SucuriScanRequest::post(':run_hardening') ){
|
5973 |
$current_time = date('r');
|
5974 |
+
$wp_config_path = SucuriScan::get_wpconfig_path();
|
5975 |
|
5976 |
$wp_config_writable = ( file_exists($wp_config_path) && is_writable($wp_config_path) ) ? TRUE : FALSE;
|
5977 |
$new_wpconfig = $wp_config_writable ? file_get_contents($wp_config_path) : '';
|
5978 |
|
5979 |
+
if( SucuriScanRequest::post(':harden_fileeditor') ){
|
5980 |
if( $wp_config_writable ){
|
5981 |
if( preg_match('/(.*define\(.DB_COLLATE..*)/', $new_wpconfig, $match) ){
|
5982 |
$disallow_fileedit_definition = "\n\ndefine('DISALLOW_FILE_EDIT', TRUE); // Sucuri Security: {$current_time}\n";
|
5984 |
}
|
5985 |
|
5986 |
@file_put_contents($wp_config_path, $new_wpconfig, LOCK_EX);
|
5987 |
+
SucuriScanInterface::info( 'Configuration file updated successfully, the plugin and theme editor were disabled.' );
|
5988 |
$file_editor_disabled = TRUE;
|
5989 |
} else {
|
5990 |
+
SucuriScanInterface::error( 'The <code>wp-config.php</code> file is not in the default location
|
5991 |
or is not writable, you will need to put the following code manually there:
|
5992 |
<code>define("DISALLOW_FILE_EDIT", TRUE);</code>' );
|
5993 |
}
|
5994 |
}
|
5995 |
|
5996 |
+
elseif( SucuriScanRequest::post(':harden_fileeditor_unharden') ){
|
5997 |
if( preg_match("/(.*define\('DISALLOW_FILE_EDIT', TRUE\);.*)/", $new_wpconfig, $match) ){
|
5998 |
if( $wp_config_writable ){
|
5999 |
$new_wpconfig = str_replace("\n{$match[1]}", '', $new_wpconfig);
|
6000 |
file_put_contents($wp_config_path, $new_wpconfig, LOCK_EX);
|
6001 |
+
SucuriScanInterface::info( 'Configuration file updated successfully, the plugin and theme editor were enabled.' );
|
6002 |
$file_editor_disabled = FALSE;
|
6003 |
} else {
|
6004 |
+
SucuriScanInterface::error( 'The <code>wp-config.php</code> file is not in the default location
|
6005 |
or is not writable, you will need to remove the following code manually from there:
|
6006 |
<code>define("DISALLOW_FILE_EDIT", TRUE);</code>' );
|
6007 |
}
|
6008 |
} else {
|
6009 |
+
SucuriScanInterface::error( 'The theme and plugin editor are not disabled from the configuration file.' );
|
6010 |
}
|
6011 |
}
|
6012 |
}
|
6013 |
|
6014 |
+
$message = 'Occasionally you may wish to disable the plugin or theme editor to prevent overzealous
|
6015 |
+
users from being able to edit sensitive files and potentially crash the site. Disabling these
|
6016 |
+
also provides an additional layer of security if a hacker gains access to a well-privileged
|
6017 |
+
user account.';
|
6018 |
|
6019 |
sucuriscan_harden_status(
|
6020 |
'Plugin & Theme editor',
|
6060 |
* @return void
|
6061 |
*/
|
6062 |
function sucuriscan_page(){
|
6063 |
+
SucuriScanInterface::check_permissions();
|
|
|
|
|
6064 |
|
6065 |
+
if(
|
6066 |
+
SucuriScanInterface::check_nonce()
|
6067 |
+
&& SucuriScanRequest::post(':force_scan')
|
6068 |
+
){
|
6069 |
+
SucuriScanEvent::notify_event( 'plugin_change', 'Filesystem scan forced at: ' . date('r') );
|
6070 |
+
SucuriScanEvent::filesystem_scan(TRUE);
|
6071 |
+
}
|
6072 |
|
6073 |
$template_variables = array(
|
6074 |
'WordpressVersion' => sucuriscan_wordpress_outdated(),
|
6076 |
'CoreFiles' => sucuriscan_core_files(),
|
6077 |
);
|
6078 |
|
6079 |
+
echo SucuriScanTemplate::get_template('integrity', $template_variables);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6080 |
}
|
6081 |
|
6082 |
/**
|
6113 |
|
6114 |
// Initialize the values for the pagination.
|
6115 |
$max_per_page = SUCURISCAN_AUDITLOGS_PER_PAGE;
|
6116 |
+
$page_number = SucuriScanTemplate::get_page_number();
|
6117 |
$logs_limit = $page_number * $max_per_page;
|
6118 |
+
$audit_logs = SucuriScanAPI::get_logs($logs_limit);
|
6119 |
|
6120 |
$show_all = TRUE;
|
6121 |
|
6164 |
$snippet_data['AuditLog.Extra'] .= '<small>For Mac users, this is a scrollable container</small>';
|
6165 |
}
|
6166 |
|
6167 |
+
$template_variables['AuditLogs.List'] .= SucuriScanTemplate::get_snippet('integrity-auditlogs', $snippet_data);
|
6168 |
$counter_i += 1;
|
6169 |
}
|
6170 |
}
|
6174 |
|
6175 |
if( $total_items > 0 ){
|
6176 |
$template_variables['AuditLogs.PaginationVisibility'] = 'visible';
|
6177 |
+
$template_variables['AuditLogs.PaginationLinks'] = SucuriScanTemplate::get_pagination(
|
6178 |
'%%SUCURI.URL.Home%%',
|
6179 |
+
$max_per_page * 5, /* TODO: Temporary value while we get the total logs. */
|
6180 |
$max_per_page
|
6181 |
);
|
6182 |
}
|
6183 |
}
|
6184 |
|
6185 |
+
return SucuriScanTemplate::get_section('integrity-auditlogs', $template_variables);
|
6186 |
}
|
6187 |
|
6188 |
/**
|
6191 |
* @return string Panel with a warning advising that WordPress is outdated.
|
6192 |
*/
|
6193 |
function sucuriscan_wordpress_outdated(){
|
6194 |
+
$site_version = SucuriScan::site_version();
|
|
|
6195 |
$updates = get_core_updates();
|
6196 |
$cp = ( !is_array($updates) || empty($updates) ? 1 : 0 );
|
6197 |
|
6198 |
$template_variables = array(
|
6199 |
+
'WordPress.Version' => $site_version,
|
6200 |
'WordPress.UpgradeURL' => admin_url('update-core.php'),
|
6201 |
'WordPress.UpdateVisibility' => 'hidden',
|
6202 |
'WordPressBeta.Visibility' => 'hidden',
|
6218 |
}
|
6219 |
}
|
6220 |
|
6221 |
+
if( strcmp($site_version, '3.7') < 0 ){
|
6222 |
$cp = 0;
|
6223 |
}
|
6224 |
|
6226 |
$template_variables['WordPress.UpdateVisibility'] = 'visible';
|
6227 |
}
|
6228 |
|
6229 |
+
return SucuriScanTemplate::get_section('integrity-wpoutdate', $template_variables);
|
6230 |
}
|
6231 |
|
6232 |
/**
|
6237 |
* @return void
|
6238 |
*/
|
6239 |
function sucuriscan_core_files(){
|
6240 |
+
$site_version = SucuriScan::site_version();
|
6241 |
|
6242 |
$template_variables = array(
|
6243 |
'CoreFiles.List' => '',
|
6246 |
'CoreFiles.BadVisibility' => 'hidden',
|
6247 |
);
|
6248 |
|
6249 |
+
if( $site_version && SucuriScanOption::get_option(':scan_checksums') == 'enabled' ){
|
6250 |
+
$latest_hashes = sucuriscan_check_wp_integrity($site_version);
|
6251 |
|
6252 |
if( $latest_hashes ){
|
6253 |
$counter = 0;
|
6280 |
}
|
6281 |
|
6282 |
$css_class = ( $counter % 2 == 0 ) ? '' : 'alternate';
|
6283 |
+
$template_variables['CoreFiles.List'] .= SucuriScanTemplate::get_snippet('integrity-corefiles', array(
|
6284 |
'CoreFiles.CssClass' => $css_class,
|
6285 |
'CoreFiles.StatusType' => $list_type,
|
6286 |
'CoreFiles.StatusAbbr' => substr($list_type, 0, 1),
|
6296 |
$template_variables['CoreFiles.BadVisibility'] = 'visible';
|
6297 |
}
|
6298 |
} else {
|
6299 |
+
SucuriScanInterface::error( 'Error retrieving the WordPress core hashes, try again.' );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6300 |
}
|
6301 |
}
|
6302 |
|
6303 |
+
return SucuriScanTemplate::get_section('integrity-corefiles', $template_variables);
|
6304 |
}
|
6305 |
|
6306 |
/**
|
6319 |
* @return array Associative array with these keys: modified, stable, removed, added.
|
6320 |
*/
|
6321 |
function sucuriscan_check_wp_integrity( $version=0 ){
|
6322 |
+
$latest_hashes = SucuriScanAPI::get_official_checksums($version);
|
6323 |
|
6324 |
if( !$latest_hashes ){ return FALSE; }
|
6325 |
|
6378 |
function sucuriscan_ignore_integrity_filepath( $filepath='' ){
|
6379 |
// List of files that will be ignored from the integrity checking.
|
6380 |
$ignore_files = array(
|
6381 |
+
'^sucuri-[0-9a-z]+\.php$',
|
6382 |
+
'^favicon\.ico$',
|
6383 |
+
'^php\.ini$',
|
6384 |
+
'^\.htaccess$',
|
6385 |
+
'^wp-includes\/\.htaccess$',
|
6386 |
+
'^wp-admin\/setup-config\.php$',
|
6387 |
+
'^wp-(config|pass|rss|feed|register|atom|commentsrss2|rss2|rdf)\.php$',
|
6388 |
+
'^wp-content\/(themes|plugins)\/.+', // TODO: Add the popular themes/plugins integrity checks.
|
6389 |
+
'^sitemap\.xml($|\.gz)$',
|
6390 |
+
'^readme\.html$',
|
6391 |
+
'^(503|404)\.php$',
|
6392 |
+
'^500\.(shtml|php)$',
|
6393 |
+
'^40[0-9]\.shtml$',
|
6394 |
+
'^([^\/]*)\.(pdf|css)$',
|
6395 |
+
'^google[0-9a-z]{16}\.html$',
|
6396 |
+
'^pinterest-[0-9a-z]{5}\.html$',
|
6397 |
+
'(^|\/)error_log$',
|
6398 |
);
|
6399 |
|
6400 |
+
foreach( $ignore_files as $ignore_pattern ){
|
6401 |
+
if( preg_match('/'.$ignore_pattern.'/', $filepath) ){
|
6402 |
+
return TRUE;
|
6403 |
+
}
|
|
|
|
|
6404 |
}
|
6405 |
|
6406 |
return FALSE;
|
6423 |
// Find files modified in the last days.
|
6424 |
$back_days = 7;
|
6425 |
|
6426 |
+
// Set the ranges of the search to be between one and sixty days.
|
6427 |
+
if( SucuriScanInterface::check_nonce() ){
|
6428 |
+
$back_days = (int) SucuriScanRequest::post(':last_days', '[0-9]+');
|
6429 |
if ( $back_days <= 0 ){ $back_days = 1; }
|
6430 |
elseif( $back_days >= 60 ){ $back_days = 60; }
|
6431 |
}
|
6439 |
);
|
6440 |
}
|
6441 |
|
6442 |
+
// The scanner for modified files can be disabled from the settings page.
|
6443 |
+
if( SucuriScanOption::get_option(':scan_modfiles') == 'enabled' ){
|
6444 |
+
// Search modified files among the project's files.
|
6445 |
+
$content_hashes = sucuriscan_get_integrity_tree( ABSPATH.'wp-content', true );
|
|
|
6446 |
|
6447 |
+
if( $content_hashes ){
|
6448 |
+
$template_variables['ModifiedFiles.Days'] = $back_days;
|
6449 |
+
$back_days = current_time('timestamp') - ( $back_days * 86400);
|
6450 |
+
$counter = 0;
|
6451 |
|
6452 |
+
foreach( $content_hashes as $file_path => $file_info ){
|
6453 |
+
if(
|
6454 |
+
isset($file_info['modified_at'])
|
6455 |
+
&& $file_info['modified_at'] >= $back_days
|
6456 |
+
){
|
6457 |
+
$css_class = ( $counter % 2 == 0 ) ? '' : 'alternate';
|
6458 |
+
$mod_date = date('d/M/Y H:i:s', $file_info['modified_at']);
|
6459 |
+
|
6460 |
+
$template_variables['ModifiedFiles.List'] .= SucuriScanTemplate::get_snippet('integrity-modifiedfiles', array(
|
6461 |
+
'ModifiedFiles.CssClass' => $css_class,
|
6462 |
+
'ModifiedFiles.CheckSum' => $file_info['checksum'],
|
6463 |
+
'ModifiedFiles.FilePath' => $file_path,
|
6464 |
+
'ModifiedFiles.DateTime' => $mod_date
|
6465 |
+
));
|
6466 |
+
$counter += 1;
|
6467 |
+
}
|
6468 |
+
}
|
6469 |
|
6470 |
+
if( $counter > 0 ){
|
6471 |
+
$template_variables['ModifiedFiles.NoFilesVisibility'] = 'hidden';
|
6472 |
+
}
|
6473 |
+
}
|
6474 |
}
|
6475 |
|
6476 |
+
return SucuriScanTemplate::get_section('integrity-modifiedfiles', $template_variables);
|
6477 |
}
|
6478 |
|
6479 |
/**
|
6482 |
* @return void
|
6483 |
*/
|
6484 |
function sucuriscan_posthack_page(){
|
6485 |
+
SucuriScanInterface::check_permissions();
|
|
|
|
|
6486 |
|
6487 |
$process_form = sucuriscan_posthack_process_form();
|
6488 |
|
6494 |
'ResetPlugins' => sucuriscan_posthack_plugins($process_form),
|
6495 |
);
|
6496 |
|
6497 |
+
echo SucuriScanTemplate::get_template('posthack', $template_variables);
|
6498 |
}
|
6499 |
|
6500 |
/**
|
6503 |
* @return boolean TRUE if a form submission should be processed, FALSE otherwise.
|
6504 |
*/
|
6505 |
function sucuriscan_posthack_process_form(){
|
6506 |
+
$process_form = SucuriScanRequest::post(':process_form', '(0|1)');
|
6507 |
+
|
6508 |
+
if(
|
6509 |
+
SucuriScanInterface::check_nonce()
|
6510 |
+
&& $process_form !== FALSE
|
6511 |
+
){
|
6512 |
+
if( $process_form === '1' ){
|
6513 |
return TRUE;
|
6514 |
} else {
|
6515 |
+
SucuriScanInterface::error('You need to confirm that you understand the risk of this operation.');
|
6516 |
}
|
6517 |
}
|
6518 |
|
6529 |
$template_variables = array(
|
6530 |
'WPConfigUpdate.Visibility' => 'hidden',
|
6531 |
'WPConfigUpdate.NewConfig' => '',
|
6532 |
+
'SecurityKeys.List' => '',
|
6533 |
);
|
6534 |
|
6535 |
// Update all WordPress secret keys.
|
6536 |
+
if( $process_form && SucuriScanRequest::post(':update_wpconfig', '1') ){
|
6537 |
+
$wpconfig_process = SucuriScanEvent::set_new_config_keys();
|
6538 |
|
6539 |
if( $wpconfig_process ){
|
6540 |
$template_variables['WPConfigUpdate.Visibility'] = 'visible';
|
6541 |
|
6542 |
if( $wpconfig_process['updated'] === TRUE ){
|
6543 |
+
SucuriScanInterface::info( 'Secret keys updated successfully (summary of the operation bellow).' );
|
6544 |
$template_variables['WPConfigUpdate.NewConfig'] .= "// Old Keys\n";
|
6545 |
$template_variables['WPConfigUpdate.NewConfig'] .= $wpconfig_process['old_keys_string'];
|
6546 |
$template_variables['WPConfigUpdate.NewConfig'] .= "//\n";
|
6547 |
$template_variables['WPConfigUpdate.NewConfig'] .= "// New Keys\n";
|
6548 |
$template_variables['WPConfigUpdate.NewConfig'] .= $wpconfig_process['new_keys_string'];
|
6549 |
} else {
|
6550 |
+
SucuriScanInterface::error(
|
6551 |
+
'<code>wp-config.php</code> file is not writable, replace the '
|
6552 |
+
. 'old configuration file with the new values shown bellow.'
|
6553 |
+
);
|
6554 |
$template_variables['WPConfigUpdate.NewConfig'] = $wpconfig_process['new_wpconfig'];
|
6555 |
}
|
6556 |
} else {
|
6557 |
+
SucuriScanInterface::error('<code>wp-config.php</code> file was not found in the default location.' );
|
6558 |
+
}
|
6559 |
+
}
|
6560 |
+
|
6561 |
+
// Display the current status of the security keys.
|
6562 |
+
$current_keys = SucuriScanOption::get_security_keys();
|
6563 |
+
$counter = 0;
|
6564 |
+
|
6565 |
+
foreach( $current_keys as $key_status => $key_list ){
|
6566 |
+
foreach( $key_list as $key_name => $key_value ){
|
6567 |
+
$css_class = ( $counter %2 == 0 ) ? '' : 'alternate';
|
6568 |
+
$key_value = SucuriScan::excerpt( $key_value, 50 );
|
6569 |
+
|
6570 |
+
switch( $key_status ){
|
6571 |
+
case 'good':
|
6572 |
+
$key_status_text = 'good';
|
6573 |
+
$key_status_css_class = 'success';
|
6574 |
+
break;
|
6575 |
+
case 'bad':
|
6576 |
+
$key_status_text = 'not randomized';
|
6577 |
+
$key_status_css_class = 'warning';
|
6578 |
+
break;
|
6579 |
+
case 'missing':
|
6580 |
+
$key_value = '';
|
6581 |
+
$key_status_text = 'not set';
|
6582 |
+
$key_status_css_class = 'danger';
|
6583 |
+
break;
|
6584 |
+
}
|
6585 |
+
|
6586 |
+
if( isset($key_status_text) ){
|
6587 |
+
$template_variables['SecurityKeys.List'] .= SucuriScanTemplate::get_snippet('posthack-updatesecretkeys', array(
|
6588 |
+
'SecurityKey.CssClass' => $css_class,
|
6589 |
+
'SecurityKey.KeyName' => SucuriScan::escape($key_name),
|
6590 |
+
'SecurityKey.KeyValue' => SucuriScan::escape($key_value),
|
6591 |
+
'SecurityKey.KeyStatusText' => $key_status_text,
|
6592 |
+
'SecurityKey.KeyStatusCssClass' => $key_status_css_class,
|
6593 |
+
));
|
6594 |
+
$counter += 1;
|
6595 |
+
}
|
6596 |
}
|
6597 |
}
|
6598 |
|
6599 |
+
return SucuriScanTemplate::get_section('posthack-updatesecretkeys', $template_variables);
|
6600 |
}
|
6601 |
|
6602 |
/**
|
6625 |
$user->user_registered_formatted = date('D, M/Y H:i', $user->user_registered_timestamp);
|
6626 |
$css_class = ( $counter % 2 == 0 ) ? '' : 'alternate';
|
6627 |
|
6628 |
+
$template_variables['ResetPassword.UserList'] .= SucuriScanTemplate::get_snippet('posthack-resetpassword', array(
|
6629 |
'ResetPassword.UserId' => $user->ID,
|
6630 |
+
'ResetPassword.Username' => SucuriScan::escape($user->user_login),
|
6631 |
+
'ResetPassword.Displayname' => SucuriScan::escape($user->display_name),
|
6632 |
+
'ResetPassword.Email' => SucuriScan::escape($user->user_email),
|
6633 |
'ResetPassword.Registered' => $user->user_registered_formatted,
|
6634 |
'ResetPassword.Roles' => implode(', ', $user->roles),
|
6635 |
+
'ResetPassword.CssClass' => $css_class,
|
6636 |
));
|
6637 |
|
|
|
6638 |
$counter += 1;
|
6639 |
}
|
6640 |
}
|
6641 |
|
6642 |
+
return SucuriScanTemplate::get_section('posthack-resetpassword', $template_variables);
|
6643 |
}
|
6644 |
|
6645 |
/**
|
6649 |
* @return void
|
6650 |
*/
|
6651 |
function sucuriscan_reset_user_password( $process_form=FALSE ){
|
6652 |
+
if( $process_form && SucuriScanRequest::post(':reset_password') ){
|
6653 |
+
$user_identifiers = SucuriScanRequest::post('user_ids', '_array');
|
6654 |
+
$pwd_changed = array();
|
6655 |
+
$pwd_not_changed = array();
|
6656 |
|
6657 |
if( is_array($user_identifiers) && !empty($user_identifiers) ){
|
6658 |
arsort($user_identifiers);
|
6659 |
|
6660 |
foreach( $user_identifiers as $user_id ){
|
6661 |
+
if( SucuriScanEvent::set_new_password($user_id) ){
|
6662 |
$pwd_changed[] = $user_id;
|
6663 |
} else {
|
6664 |
$pwd_not_changed[] = $user_id;
|
6666 |
}
|
6667 |
|
6668 |
if( !empty($pwd_changed) ){
|
6669 |
+
SucuriScanInterface::info( 'Password changed successfully for users: ' . implode(', ',$pwd_changed) );
|
6670 |
}
|
6671 |
|
6672 |
if( !empty($pwd_not_changed) ){
|
6673 |
+
SucuriScanInterface::error( 'Password change failed for users: ' . implode(', ',$pwd_not_changed) );
|
6674 |
}
|
6675 |
} else {
|
6676 |
+
SucuriScanInterface::error( 'You did not select a user from the list.' );
|
6677 |
}
|
6678 |
}
|
6679 |
}
|
6690 |
);
|
6691 |
|
6692 |
sucuriscan_posthack_reinstall_plugins($process_form);
|
6693 |
+
$all_plugins = SucuriScanAPI::get_plugins();
|
6694 |
$counter = 0;
|
6695 |
|
6696 |
foreach( $all_plugins as $plugin_path => $plugin_data ){
|
6700 |
$plugin_status = $plugin_data['IsPluginActive'] ? 'active' : 'not active';
|
6701 |
$plugin_status_class = $plugin_data['IsPluginActive'] ? 'success' : 'default';
|
6702 |
|
6703 |
+
$template_variables['ResetPlugin.PluginList'] .= SucuriScanTemplate::get_snippet('posthack-resetplugins', array(
|
6704 |
'ResetPlugin.CssClass' => $css_class,
|
6705 |
'ResetPlugin.Disabled' => $input_disabled,
|
6706 |
+
'ResetPlugin.PluginPath' => SucuriScan::escape($plugin_path),
|
6707 |
+
'ResetPlugin.Plugin' => SucuriScan::excerpt($plugin_data['Name'], 35),
|
6708 |
'ResetPlugin.Version' => $plugin_data['Version'],
|
6709 |
'ResetPlugin.Type' => $plugin_data['PluginType'],
|
6710 |
'ResetPlugin.TypeClass' => $plugin_type_class,
|
6715 |
$counter += 1;
|
6716 |
}
|
6717 |
|
6718 |
+
return SucuriScanTemplate::get_section('posthack-resetplugins', $template_variables);
|
6719 |
}
|
6720 |
|
6721 |
/**
|
6732 |
include_once( ABSPATH . 'wp-admin/includes/class-wp-upgrader.php' );
|
6733 |
include_once( ABSPATH . 'wp-admin/includes/plugin-install.php' ); // For plugins_api.
|
6734 |
|
6735 |
+
if( $plugin_list = SucuriScanRequest::post('plugin_path', '_array') ){
|
|
|
|
|
|
|
6736 |
// Create an instance of the FileInfo interface.
|
6737 |
$sucuri_fileinfo = new SucuriScanFileInfo();
|
6738 |
$sucuri_fileinfo->ignore_files = FALSE;
|
6739 |
$sucuri_fileinfo->ignore_directories = FALSE;
|
6740 |
|
6741 |
// Get (possible) cached information from the installed plugins.
|
6742 |
+
$all_plugins = SucuriScanAPI::get_plugins();
|
6743 |
|
6744 |
// Loop through all the installed plugins.
|
6745 |
foreach( $_POST['plugin_path'] as $plugin_path ){
|
6748 |
|
6749 |
// Check if the plugin can be downloaded from the free market.
|
6750 |
if( $plugin_data['IsFreePlugin'] === TRUE ){
|
6751 |
+
$plugin_info = SucuriScanAPI::get_remote_plugin_data($plugin_data['RepositoryName']);
|
6752 |
|
6753 |
if( $plugin_info ){
|
6754 |
// First, remove all files/sub-folders from the plugin's directory.
|
6760 |
$upgrader = new Plugin_Upgrader($upgrader_skin);
|
6761 |
$upgrader->install($plugin_info->download_link);
|
6762 |
} else {
|
6763 |
+
SucuriScanInterface::error( 'Could not establish a stable connection with the WordPress plugins market.' );
|
6764 |
}
|
6765 |
}
|
6766 |
}
|
6767 |
}
|
6768 |
} else {
|
6769 |
+
SucuriScanInterface::error( 'You did not select a free plugin to reinstall.' );
|
6770 |
}
|
6771 |
}
|
6772 |
}
|
6779 |
* @return string Last-logings for the administrator accounts.
|
6780 |
*/
|
6781 |
function sucuriscan_lastlogins_page(){
|
6782 |
+
SucuriScanInterface::check_permissions();
|
|
|
|
|
6783 |
|
6784 |
// Page pseudo-variables initialization.
|
6785 |
$template_variables = array(
|
6790 |
'FailedLogins' => sucuriscan_failed_logins_panel(),
|
6791 |
);
|
6792 |
|
6793 |
+
echo SucuriScanTemplate::get_template('lastlogins', $template_variables);
|
6794 |
}
|
6795 |
|
6796 |
/**
|
6814 |
$admin->lastlogins = $last_logins['entries'];
|
6815 |
|
6816 |
$user_snippet = array(
|
6817 |
+
'AdminUsers.Username' => SucuriScan::escape($admin->user_login),
|
6818 |
+
'AdminUsers.Email' => SucuriScan::escape($admin->user_email),
|
6819 |
'AdminUsers.LastLogins' => '',
|
6820 |
'AdminUsers.RegisteredAt' => 'Undefined',
|
6821 |
'AdminUsers.UserURL' => admin_url('user-edit.php?user_id='.$admin->ID),
|
6831 |
|
6832 |
foreach( $admin->lastlogins as $lastlogin ){
|
6833 |
$css_class = ( $counter % 2 == 0 ) ? '' : 'alternate';
|
6834 |
+
$user_snippet['AdminUsers.LastLogins'] .= SucuriScanTemplate::get_snippet('lastlogins-admins-lastlogin', array(
|
6835 |
+
'AdminUsers.RemoteAddr' => SucuriScan::escape($lastlogin->user_remoteaddr),
|
6836 |
+
'AdminUsers.Datetime' => SucuriScan::escape($lastlogin->user_lastlogin),
|
6837 |
'AdminUsers.CssClass' => $css_class,
|
6838 |
));
|
6839 |
$counter += 1;
|
6840 |
}
|
6841 |
}
|
6842 |
|
6843 |
+
$template_variables['AdminUsers.List'] .= SucuriScanTemplate::get_snippet('lastlogins-admins', $user_snippet);
|
6844 |
}
|
6845 |
|
6846 |
+
return SucuriScanTemplate::get_section('lastlogins-admins', $template_variables);
|
6847 |
}
|
6848 |
|
6849 |
/**
|
6855 |
*/
|
6856 |
function sucuriscan_lastlogins_all(){
|
6857 |
$max_per_page = SUCURISCAN_LASTLOGINS_USERSLIMIT;
|
6858 |
+
$page_number = SucuriScanTemplate::get_page_number();
|
6859 |
$offset = ($max_per_page * $page_number) - $max_per_page;
|
6860 |
|
6861 |
$template_variables = array(
|
6868 |
);
|
6869 |
|
6870 |
if( !sucuriscan_lastlogins_datastore_is_writable() ){
|
6871 |
+
SucuriScanInterface::error( 'Last-logins datastore file is not writable: <code>'.sucuriscan_lastlogins_datastore_filepath().'</code>' );
|
6872 |
}
|
6873 |
|
6874 |
$counter = 0;
|
6877 |
|
6878 |
if( $last_logins['total'] > $max_per_page ){
|
6879 |
$template_variables['UserList.PaginationVisibility'] = 'visible';
|
6880 |
+
}
|
6881 |
+
|
6882 |
+
if( $last_logins['total'] > 0 ){
|
6883 |
$template_variables['UserList.NoItemsVisibility'] = 'hidden';
|
6884 |
}
|
6885 |
|
6894 |
'UserList.Displayname' => '',
|
6895 |
'UserList.Email' => '',
|
6896 |
'UserList.Registered' => '',
|
6897 |
+
'UserList.RemoteAddr' => SucuriScan::escape($user->user_remoteaddr),
|
6898 |
+
'UserList.Hostname' => SucuriScan::escape($user->user_hostname),
|
6899 |
+
'UserList.Datetime' => SucuriScan::escape($user->user_lastlogin),
|
6900 |
+
'UserList.TimeAgo' => SucuriScan::time_ago($user->user_lastlogin),
|
6901 |
'UserList.UserURL' => admin_url('user-edit.php?user_id='.$user->user_id),
|
6902 |
'UserList.CssClass' => $css_class,
|
6903 |
);
|
6904 |
|
6905 |
if( $user->user_exists ){
|
6906 |
+
$user_dataset['UserList.Username'] = SucuriScan::escape($user->user_login);
|
6907 |
+
$user_dataset['UserList.Displayname'] = SucuriScan::escape($user->display_name);
|
6908 |
+
$user_dataset['UserList.Email'] = SucuriScan::escape($user->user_email);
|
6909 |
+
$user_dataset['UserList.Registered'] = SucuriScan::escape($user->user_registered);
|
6910 |
}
|
6911 |
|
6912 |
+
$template_variables['UserList'] .= SucuriScanTemplate::get_snippet('lastlogins-all', $user_dataset);
|
6913 |
}
|
6914 |
|
6915 |
// Generate the pagination for the list.
|
6916 |
+
$template_variables['UserList.Pagination'] = SucuriScanTemplate::get_pagination(
|
6917 |
'%%SUCURI.URL.Lastlogins%%',
|
6918 |
$last_logins['total'],
|
6919 |
$max_per_page
|
6920 |
);
|
6921 |
|
6922 |
+
return SucuriScanTemplate::get_section('lastlogins-all', $template_variables);
|
6923 |
}
|
6924 |
|
6925 |
/**
|
6928 |
* @return string Absolute filepath where the user's last login information is stored.
|
6929 |
*/
|
6930 |
function sucuriscan_lastlogins_datastore_filepath(){
|
6931 |
+
return SucuriScan::datastore_folder_path( 'sucuri-lastlogins.php' );
|
6932 |
}
|
6933 |
|
6934 |
/**
|
6957 |
*/
|
6958 |
function sucuriscan_lastlogins_datastore_is_writable(){
|
6959 |
$datastore_filepath = sucuriscan_lastlogins_datastore_exists();
|
6960 |
+
|
6961 |
if($datastore_filepath){
|
6962 |
if( !is_writable($datastore_filepath) ){
|
6963 |
@chmod($datastore_filepath, 0644);
|
6964 |
}
|
6965 |
+
|
6966 |
+
if( is_writable($datastore_filepath) ){
|
6967 |
+
return $datastore_filepath;
|
6968 |
+
}
|
6969 |
}
|
6970 |
+
|
6971 |
return FALSE;
|
6972 |
}
|
6973 |
|
6979 |
*/
|
6980 |
function sucuriscan_lastlogins_datastore_is_readable(){
|
6981 |
$datastore_filepath = sucuriscan_lastlogins_datastore_exists();
|
6982 |
+
|
6983 |
if( $datastore_filepath && is_readable($datastore_filepath) ){
|
6984 |
return $datastore_filepath;
|
6985 |
}
|
6986 |
+
|
6987 |
return FALSE;
|
6988 |
}
|
6989 |
|
6999 |
|
7000 |
if($datastore_filepath){
|
7001 |
$current_user = get_user_by('login', $user_login);
|
7002 |
+
$remote_addr = SucuriScan::get_remote_addr();
|
7003 |
|
7004 |
$login_info = array(
|
7005 |
'user_id' => $current_user->ID,
|
7035 |
|
7036 |
if( $datastore_filepath ){
|
7037 |
$parsed_lines = 0;
|
7038 |
+
$data_lines = SucuriScanFileInfo::file_lines($datastore_filepath);
|
7039 |
|
7040 |
if( $data_lines ){
|
7041 |
/**
|
7064 |
for( $i=$offset; $i<$total_lines; $i++ ){
|
7065 |
$line = $reversed_lines[$i] ? trim($reversed_lines[$i]) : '';
|
7066 |
|
7067 |
+
if( preg_match('/^a:[0-9]+:.+/', $line) ){
|
7068 |
$last_login = @unserialize($line);
|
7069 |
|
7070 |
// Only administrators can see all login stats.
|
7094 |
$parsed_lines += 1;
|
7095 |
}
|
7096 |
|
7097 |
+
if( preg_match('/^[0-9]+$/', $limit) && $limit>0 ){
|
7098 |
if( $parsed_lines >= $limit ){ break; }
|
7099 |
}
|
7100 |
}
|
7124 |
return $login_url;
|
7125 |
}
|
7126 |
|
7127 |
+
if( SucuriScanOption::get_option(':lastlogin_redirection') == 'enabled' ){
|
|
|
7128 |
add_filter('login_redirect', 'sucuriscan_login_redirect', 10, 3);
|
7129 |
}
|
7130 |
}
|
7136 |
* @return void
|
7137 |
*/
|
7138 |
function sucuriscan_get_user_lastlogin(){
|
7139 |
+
if(
|
7140 |
+
current_user_can('manage_options')
|
7141 |
+
&& SucuriScanRequest::get(':lastlogin', '1')
|
7142 |
+
){
|
7143 |
$current_user = wp_get_current_user();
|
7144 |
|
7145 |
// Select the penultimate entry, not the last one.
|
7148 |
if( isset($last_logins['entries'][1]) ){
|
7149 |
$row = $last_logins['entries'][1];
|
7150 |
|
7151 |
+
$message_tpl = 'Last time you logged in was at <code>%s</code> from <code>%s</code> - <code>%s</code>';
|
7152 |
$lastlogin_message = sprintf( $message_tpl, date('d/M/Y H:i'), $row->user_remoteaddr, $row->user_hostname );
|
7153 |
+
$lastlogin_message .= chr(32).'(<a href="'.SucuriScanTemplate::get_url('lastlogins').'">view all logs</a>)';
|
7154 |
+
SucuriScanInterface::info( $lastlogin_message );
|
7155 |
}
|
7156 |
}
|
7157 |
}
|
7172 |
);
|
7173 |
|
7174 |
$logged_in_users = sucuriscan_get_online_users(TRUE);
|
7175 |
+
|
7176 |
if( is_array($logged_in_users) && !empty($logged_in_users) ){
|
7177 |
$template_variables['LoggedInUsers.Total'] = count($logged_in_users);
|
7178 |
$counter = 0;
|
7182 |
$logged_in_user['last_activity_datetime'] = date('d/M/Y H:i', $logged_in_user['last_activity']);
|
7183 |
$logged_in_user['user_registered_datetime'] = date('d/M/Y H:i', strtotime($logged_in_user['user_registered']));
|
7184 |
|
7185 |
+
$template_variables['LoggedInUsers.List'] .= SucuriScanTemplate::get_snippet('lastlogins-loggedin', array(
|
7186 |
+
'LoggedInUsers.Id' => SucuriScan::escape($logged_in_user['user_id']),
|
7187 |
'LoggedInUsers.UserURL' => admin_url('user-edit.php?user_id='.$logged_in_user['user_id']),
|
7188 |
+
'LoggedInUsers.UserLogin' => SucuriScan::escape($logged_in_user['user_login']),
|
7189 |
+
'LoggedInUsers.UserEmail' => SucuriScan::escape($logged_in_user['user_email']),
|
7190 |
+
'LoggedInUsers.LastActivity' => SucuriScan::escape($logged_in_user['last_activity_datetime']),
|
7191 |
+
'LoggedInUsers.Registered' => SucuriScan::escape($logged_in_user['user_registered_datetime']),
|
7192 |
+
'LoggedInUsers.RemoveAddr' => SucuriScan::escape($logged_in_user['remote_addr']),
|
7193 |
'LoggedInUsers.CssClass' => ( $counter % 2 == 0 ) ? '' : 'alternate'
|
7194 |
));
|
7195 |
}
|
7196 |
}
|
7197 |
|
7198 |
+
return SucuriScanTemplate::get_section('lastlogins-loggedin', $template_variables);
|
7199 |
}
|
7200 |
|
7201 |
/**
|
7207 |
function sucuriscan_get_online_users( $add_current_user=FALSE ){
|
7208 |
$users = array();
|
7209 |
|
7210 |
+
if( SucuriScan::is_multisite() ){
|
7211 |
$users = get_site_transient('online_users');
|
7212 |
} else {
|
7213 |
$users = get_transient('online_users');
|
7238 |
function sucuriscan_save_online_users( $logged_in_users=array() ){
|
7239 |
$expiration = 30 * 60;
|
7240 |
|
7241 |
+
if( SucuriScan::is_multisite() ){
|
7242 |
return set_site_transient('online_users', $logged_in_users, $expiration);
|
7243 |
} else {
|
7244 |
return set_transient('online_users', $logged_in_users, $expiration);
|
7253 |
* @return void
|
7254 |
*/
|
7255 |
function sucuriscan_unset_online_user_on_logout(){
|
7256 |
+
$remote_addr = SucuriScan::get_remote_addr();
|
7257 |
$current_user = wp_get_current_user();
|
7258 |
$user_id = $current_user->ID;
|
7259 |
|
7303 |
// Get logged in user information.
|
7304 |
$current_user = ($user instanceof WP_User) ? $user : wp_get_current_user();
|
7305 |
$current_user_id = $current_user->ID;
|
7306 |
+
$remote_addr = SucuriScan::get_remote_addr();
|
7307 |
$current_time = current_time('timestamp');
|
7308 |
$logged_in_users = sucuriscan_get_online_users();
|
7309 |
|
7314 |
'user_email' => $current_user->user_email,
|
7315 |
'user_registered' => $current_user->user_registered,
|
7316 |
'last_activity' => $current_time,
|
7317 |
+
'remote_addr' => $remote_addr,
|
7318 |
);
|
7319 |
|
7320 |
if( !is_array($logged_in_users) || empty($logged_in_users) ){
|
7372 |
'FailedLogins.WarningVisibility' => 'visible',
|
7373 |
);
|
7374 |
|
7375 |
+
$max_failed_logins = SucuriScanOption::get_option(':maximum_failed_logins');
|
7376 |
+
$notify_bruteforce_attack = SucuriScanOption::get_option(':notify_bruteforce_attack');
|
7377 |
$failed_logins = sucuriscan_get_failed_logins();
|
7378 |
|
7379 |
if( $failed_logins ){
|
7382 |
foreach( $failed_logins['entries'] as $login_data ){
|
7383 |
$css_class = ( $counter % 2 == 0 ) ? '' : 'alternate';
|
7384 |
|
7385 |
+
$template_variables['FailedLogins.List'] .= SucuriScanTemplate::get_snippet('lastlogins-failedlogins', array(
|
7386 |
'FailedLogins.CssClass' => $css_class,
|
7387 |
'FailedLogins.Num' => ($counter + 1),
|
7388 |
+
'FailedLogins.Username' => SucuriScan::escape($login_data['user_login']),
|
7389 |
+
'FailedLogins.RemoteAddr' => SucuriScan::escape($login_data['remote_addr']),
|
7390 |
'FailedLogins.Datetime' => date('d/M/Y H:i', $login_data['attempt_time']),
|
7391 |
+
'FailedLogins.UserAgent' => SucuriScan::escape($login_data['user_agent']),
|
7392 |
));
|
7393 |
|
7394 |
$counter += 1;
|
7405 |
$template_variables['FailedLogins.WarningVisibility'] = 'hidden';
|
7406 |
}
|
7407 |
|
7408 |
+
return SucuriScanTemplate::get_section('lastlogins-failedlogins', $template_variables);
|
7409 |
}
|
7410 |
|
7411 |
/**
|
7420 |
* @return string The full (relative) path where the file is located.
|
7421 |
*/
|
7422 |
function sucuriscan_failed_logins_datastore_path( $reset=FALSE ){
|
7423 |
+
$datastore_path = SucuriScan::datastore_folder_path('sucuri-failedlogins.php');
|
7424 |
$default_content = sucuriscan_failed_logins_default_content();
|
7425 |
|
7426 |
// Create the file if it does not exists.
|
7466 |
$default_content_n = substr_count($default_content, "\n");
|
7467 |
|
7468 |
if( $datastore_path ){
|
7469 |
+
$lines = SucuriScanFileInfo::file_lines($datastore_path);
|
7470 |
|
7471 |
if( $lines ){
|
7472 |
$failed_logins = array(
|
7480 |
// Read and parse all the entries found in the datastore file.
|
7481 |
foreach( $lines as $i => $line ){
|
7482 |
if( $i >= $default_content_n ){
|
7483 |
+
$login_data = @json_decode( trim($line), TRUE );
|
7484 |
$login_data['attempt_date'] = date('r', $login_data['attempt_time']);
|
7485 |
|
7486 |
if( !$login_data['user_agent'] ){
|
7523 |
$login_data = json_encode(array(
|
7524 |
'user_login' => $user_login,
|
7525 |
'attempt_time' => time(),
|
7526 |
+
'remote_addr' => SucuriScan::get_remote_addr(),
|
7527 |
+
'user_agent' => SucuriScan::get_user_agent(),
|
7528 |
));
|
7529 |
|
7530 |
$logged = @file_put_contents( $datastore_path, $login_data . "\n", FILE_APPEND );
|
7546 |
*/
|
7547 |
function sucuriscan_report_failed_logins( $failed_logins=array() ){
|
7548 |
if( $failed_logins && $failed_logins['count'] > 0 ){
|
7549 |
+
$prettify_mails = SucuriScanMail::prettify_mails();
|
7550 |
$mail_content = '';
|
7551 |
|
7552 |
if( $prettify_mails ){
|
7582 |
}
|
7583 |
}
|
7584 |
|
7585 |
+
if( $prettify_mails ){
|
7586 |
+
$table_html .= '</tbody>';
|
7587 |
+
$table_html .= '</table>';
|
7588 |
+
$mail_content = $table_html;
|
7589 |
+
}
|
7590 |
+
|
7591 |
+
if( SucuriScanEvent::notify_event( 'bruteforce_attack', $mail_content ) ){
|
7592 |
+
sucuriscan_reset_failed_logins();
|
7593 |
+
|
7594 |
+
return TRUE;
|
7595 |
+
}
|
7596 |
+
}
|
7597 |
+
|
7598 |
+
return FALSE;
|
7599 |
+
}
|
7600 |
+
|
7601 |
+
/**
|
7602 |
+
* Remove all the entries in the datastore file where the failed logins are
|
7603 |
+
* being kept. The execution of this function will not delete the file (which is
|
7604 |
+
* likely the best move) but rather will clean its content and append the
|
7605 |
+
* default code defined by another function above.
|
7606 |
+
*
|
7607 |
+
* @return boolean Whether the datastore file was resetted or not.
|
7608 |
+
*/
|
7609 |
+
function sucuriscan_reset_failed_logins(){
|
7610 |
+
return (bool) sucuriscan_failed_logins_datastore_path(TRUE);
|
7611 |
+
}
|
7612 |
+
|
7613 |
+
/**
|
7614 |
+
* Print a HTML code with the settings of the plugin.
|
7615 |
+
*
|
7616 |
+
* @return void
|
7617 |
+
*/
|
7618 |
+
function sucuriscan_settings_page(){
|
7619 |
+
SucuriScanInterface::check_permissions();
|
7620 |
+
|
7621 |
+
$template_variables = array(
|
7622 |
+
'PageTitle' => 'Settings',
|
7623 |
+
'Settings.General' => sucuriscan_settings_general(),
|
7624 |
+
'Settings.Notifications' => sucuriscan_settings_notifications(),
|
7625 |
+
'Settings.IgnoreRules' => sucuriscan_settings_ignore_rules(),
|
7626 |
+
);
|
7627 |
+
|
7628 |
+
echo SucuriScanTemplate::get_template('settings', $template_variables);
|
7629 |
+
}
|
7630 |
+
|
7631 |
+
/**
|
7632 |
+
* Process the requests sent by the form submissions originated in the settings
|
7633 |
+
* page, all forms must have a nonce field that will be checked against the one
|
7634 |
+
* generated in the template render function.
|
7635 |
+
*
|
7636 |
+
* @param boolean $page_nonce True if the nonce is valid, False otherwise.
|
7637 |
+
* @return void
|
7638 |
+
*/
|
7639 |
+
function sucuriscan_settings_form_submissions( $page_nonce=NULL ){
|
7640 |
+
global $sucuriscan_schedule_allowed,
|
7641 |
+
$sucuriscan_interface_allowed,
|
7642 |
+
$sucuriscan_notify_options,
|
7643 |
+
$sucuriscan_emails_per_hour,
|
7644 |
+
$sucuriscan_maximum_failed_logins,
|
7645 |
+
$sucuriscan_verify_ssl_cert;
|
7646 |
+
|
7647 |
+
// Use this conditional to avoid double checking.
|
7648 |
+
if( is_null($page_nonce) ){
|
7649 |
+
$page_nonce = SucuriScanInterface::check_nonce();
|
7650 |
+
}
|
7651 |
+
|
7652 |
+
if( $page_nonce ){
|
7653 |
+
|
7654 |
+
// Recover API key through the email registered previously.
|
7655 |
+
if( SucuriScanRequest::post(':recover_key') !== FALSE ){
|
7656 |
+
SucuriScanAPI::recover_key();
|
7657 |
+
}
|
7658 |
+
|
7659 |
+
// Save API key after it was recovered by the administrator.
|
7660 |
+
if( $api_key = SucuriScanRequest::post(':manual_api_key') ){
|
7661 |
+
SucuriScanAPI::set_plugin_key( $api_key, TRUE );
|
7662 |
+
SucuriScanEvent::schedule_task();
|
7663 |
+
}
|
7664 |
+
|
7665 |
+
// Remove API key from the local storage.
|
7666 |
+
if( SucuriScanRequest::post(':remove_api_key') !== FALSE ){
|
7667 |
+
SucuriScanAPI::set_plugin_key('');
|
7668 |
+
wp_clear_scheduled_hook('sucuriscan_scheduled_scan');
|
7669 |
+
SucuriScanEvent::notify_event( 'plugin_change', 'Sucuri API key removed' );
|
7670 |
+
}
|
7671 |
+
|
7672 |
+
// Enable or disable the filesystem scanner.
|
7673 |
+
if( $fs_scanner = SucuriScanRequest::post(':fs_scanner', '(en|dis)able') ){
|
7674 |
+
$action_d = $fs_scanner . 'd';
|
7675 |
+
SucuriScanOption::update_option(':fs_scanner', $action_d);
|
7676 |
+
SucuriScanEvent::notify_event( 'plugin_change', 'Filesystem scanner was: ' . $action_d );
|
7677 |
+
SucuriScanInterface::info( 'Filesystem scanner was <code>' . $action_d . '</code>' );
|
7678 |
+
}
|
7679 |
+
|
7680 |
+
// Enable or disable the filesystem scanner for modified files.
|
7681 |
+
if( $scan_modfiles = SucuriScanRequest::post(':scan_modfiles', '(en|dis)able') ){
|
7682 |
+
$action_d = $scan_modfiles . 'd';
|
7683 |
+
SucuriScanOption::update_option(':scan_modfiles', $action_d);
|
7684 |
+
SucuriScanEvent::notify_event( 'plugin_change', 'Filesystem scanner for modified files was: ' . $action_d );
|
7685 |
+
SucuriScanInterface::info( 'Filesystem scanner for modified files was <code>' . $action_d . '</code>' );
|
7686 |
+
}
|
7687 |
+
|
7688 |
+
// Enable or disable the filesystem scanner for file integrity.
|
7689 |
+
if( $scan_checksums = SucuriScanRequest::post(':scan_checksums', '(en|dis)able') ){
|
7690 |
+
$action_d = $scan_checksums . 'd';
|
7691 |
+
SucuriScanOption::update_option(':scan_checksums', $action_d);
|
7692 |
+
SucuriScanEvent::notify_event( 'plugin_change', 'Filesystem scanner for file integrity was: ' . $action_d );
|
7693 |
+
SucuriScanInterface::info( 'Filesystem scanner for file integrity was <code>' . $action_d . '</code>' );
|
7694 |
+
}
|
7695 |
+
|
7696 |
+
// Modify the schedule of the filesystem scanner.
|
7697 |
+
if( $frequency = SucuriScanRequest::post(':scan_frequency') ){
|
7698 |
+
$allowed_frequency = array_keys($sucuriscan_schedule_allowed);
|
7699 |
+
|
7700 |
+
if( in_array($frequency, $allowed_frequency) ){
|
7701 |
+
SucuriScanOption::update_option(':scan_frequency', $frequency);
|
7702 |
+
wp_clear_scheduled_hook('sucuriscan_scheduled_scan');
|
7703 |
+
|
7704 |
+
if( $frequency != '_oneoff' ){
|
7705 |
+
wp_schedule_event( time()+10, $frequency, 'sucuriscan_scheduled_scan' );
|
7706 |
+
}
|
7707 |
+
|
7708 |
+
SucuriScanEvent::notify_event( 'plugin_change', 'Filesystem scanning frequency changed to: ' . $frequency );
|
7709 |
+
SucuriScanInterface::info( 'Filesystem scan scheduled to run <code>'.$frequency.'</code>' );
|
7710 |
+
}
|
7711 |
+
}
|
7712 |
+
|
7713 |
+
// Set the method (aka. interface) that will be used to scan the site.
|
7714 |
+
if( $interface = SucuriScanRequest::post(':scan_interface') ){
|
7715 |
+
$allowed_values = array_keys($sucuriscan_interface_allowed);
|
7716 |
+
|
7717 |
+
if( in_array($interface, $allowed_values) ){
|
7718 |
+
SucuriScanOption::update_option(':scan_interface', $interface);
|
7719 |
+
SucuriScanEvent::notify_event( 'plugin_change', 'Filesystem scanning interface changed to: ' . $interface );
|
7720 |
+
SucuriScanInterface::info( 'Filesystem scan interface set to <code>'.$interface.'</code>' );
|
7721 |
+
}
|
7722 |
+
}
|
7723 |
+
|
7724 |
+
// Update the value for the maximum emails per hour.
|
7725 |
+
if( $per_hour = SucuriScanRequest::post(':emails_per_hour') ){
|
7726 |
+
if( array_key_exists($per_hour, $sucuriscan_emails_per_hour) ){
|
7727 |
+
$per_hour_label = $sucuriscan_emails_per_hour[$per_hour];
|
7728 |
+
SucuriScanOption::update_option( ':emails_per_hour', $per_hour );
|
7729 |
+
SucuriScanEvent::notify_event( 'plugin_change', 'Maximum email notifications per hour changed' );
|
7730 |
+
SucuriScanInterface::info( 'E-mail notifications: <code>' . $per_hour_label . '</code>' );
|
7731 |
+
} else {
|
7732 |
+
SucuriScanInterface::error( 'Invalid value for the maximum emails per hour.' );
|
7733 |
+
}
|
7734 |
+
}
|
7735 |
+
|
7736 |
+
// Update the email where the event notifications will be sent.
|
7737 |
+
if( $new_email = SucuriScanRequest::post(':notify_to') ){
|
7738 |
+
if( SucuriScan::is_valid_email($new_email) ){
|
7739 |
+
SucuriScanOption::update_option( ':notify_to', $new_email );
|
7740 |
+
SucuriScanEvent::notify_event( 'plugin_change', 'Email address to get the event notifications was changed' );
|
7741 |
+
SucuriScanInterface::info( 'All the event notifications will be sent to the email specified.' );
|
7742 |
+
} else {
|
7743 |
+
SucuriScanInterface::error( 'Email format not supported.' );
|
7744 |
+
}
|
7745 |
+
}
|
7746 |
+
|
7747 |
+
// Update the maximum failed logins per hour before consider it a brute-force attack.
|
7748 |
+
if( $failed_logins = SucuriScanRequest::post(':maximum_failed_logins') ){
|
7749 |
+
if( array_key_exists($failed_logins, $sucuriscan_maximum_failed_logins) ){
|
7750 |
+
SucuriScanOption::update_option( ':maximum_failed_logins', $failed_logins );
|
7751 |
+
$message = 'You will receive an email with a report containing information of the failed
|
7752 |
+
logins occurred during the last hour if its quantity is bigger than the value you just
|
7753 |
+
selected, which is <code>' . $failed_logins . '</code>. The information collected per
|
7754 |
+
hour will be resetted if the quantity of failed logins is lower.';
|
7755 |
+
SucuriScanEvent::notify_event( 'plugin_change', $message );
|
7756 |
+
SucuriScanInterface::info($message);
|
7757 |
+
} else {
|
7758 |
+
SucuriScanInterface::error( 'Invalid value for the maximum failed logins per hour before consider it a brute-force attack.' );
|
7759 |
+
}
|
7760 |
+
}
|
7761 |
+
|
7762 |
+
// Update the configuration for the SSL certificate verification.
|
7763 |
+
if( $verify_ssl_cert = SucuriScanRequest::post(':verify_ssl_cert') ){
|
7764 |
+
if( array_key_exists($verify_ssl_cert, $sucuriscan_verify_ssl_cert) ){
|
7765 |
+
SucuriScanOption::update_option( ':verify_ssl_cert', $verify_ssl_cert );
|
7766 |
+
$message = 'SSL certificates will not be verified when executing a HTTP request '
|
7767 |
+
. 'while communicating with the Sucuri API service, nor the official '
|
7768 |
+
. 'WordPress API.';
|
7769 |
+
SucuriScanEvent::notify_event( 'plugin_change', $message );
|
7770 |
+
SucuriScanInterface::info( $message );
|
7771 |
+
} else {
|
7772 |
+
SucuriScanInterface::error( 'Invalid value for the SSL certificate verification.' );
|
7773 |
+
}
|
7774 |
+
}
|
7775 |
+
|
7776 |
+
// Update the notification settings.
|
7777 |
+
if( SucuriScanRequest::post(':save_notification_settings') !== FALSE ){
|
7778 |
+
$options_updated_counter = 0;
|
7779 |
+
|
7780 |
+
foreach( $sucuriscan_notify_options as $alert_type => $alert_label ){
|
7781 |
+
if( $option_value = SucuriScanRequest::post($alert_type, '(1|0)') ){
|
7782 |
+
$option_value = ( $option_value == '1' ) ? 'enabled' : 'disabled';
|
7783 |
+
SucuriScanOption::update_option( $alert_type, $option_value );
|
7784 |
+
$options_updated_counter += 1;
|
7785 |
+
}
|
7786 |
+
}
|
7787 |
+
|
7788 |
+
if( $options_updated_counter > 0 ){
|
7789 |
+
SucuriScanEvent::notify_event( 'plugin_change', 'Email notification settings changed' );
|
7790 |
+
SucuriScanInterface::info( 'Notification settings updated.' );
|
7791 |
+
}
|
7792 |
+
}
|
7793 |
+
|
7794 |
+
// Reset all the plugin's options.
|
7795 |
+
if( SucuriScanRequest::post(':reset_options') !== FALSE ){
|
7796 |
+
// Notify the event before the API key is removed.
|
7797 |
+
$event_msg = 'All plugin\'s options were resetted.';
|
7798 |
+
SucuriScanEvent::report_event( 1, 'core', $event_msg );
|
7799 |
+
SucuriScanEvent::notify_event( 'plugin_change', $event_msg );
|
7800 |
+
|
7801 |
+
// Remove all plugin's options from the database.
|
7802 |
+
$options = SucuriScanOption::get_options_from_db('all_plugin_options');
|
7803 |
+
|
7804 |
+
foreach( $options as $option ){
|
7805 |
+
SucuriScanOption::delete_option( $option->option_name );
|
7806 |
+
}
|
7807 |
+
|
7808 |
+
// Remove the scheduled tasks.
|
7809 |
+
wp_clear_scheduled_hook('sucuriscan_scheduled_scan');
|
7810 |
+
|
7811 |
+
SucuriScanInterface::info( 'All plugin options were resetted successfully' );
|
7812 |
+
}
|
7813 |
+
|
7814 |
+
// Ignore a new event for email notifications.
|
7815 |
+
if( $action = SucuriScanRequest::post(':ignorerule_action', '(add|remove)') ){
|
7816 |
+
$ignore_rule = SucuriScanRequest::post(':ignorerule');
|
7817 |
+
|
7818 |
+
if( $action == 'add' ){
|
7819 |
+
if( SucuriScanOption::add_ignored_event($ignore_rule) ){
|
7820 |
+
SucuriScanInterface::info( 'Post-type ignored successfully.' );
|
7821 |
+
} else {
|
7822 |
+
SucuriScanInterface::error( 'The post-type is invalid or it may be already ignored.' );
|
7823 |
+
}
|
7824 |
+
}
|
7825 |
+
|
7826 |
+
elseif( $action == 'remove' ) {
|
7827 |
+
SucuriScanOption::remove_ignored_event($ignore_rule);
|
7828 |
+
SucuriScanInterface::info( 'Post-type removed from the list successfully.' );
|
7829 |
+
}
|
7830 |
+
}
|
7831 |
+
|
7832 |
+
}
|
7833 |
+
}
|
7834 |
+
|
7835 |
+
/**
|
7836 |
+
* Read and parse the content of the general settings template.
|
7837 |
+
*
|
7838 |
+
* @return string Parsed HTML code for the general settings panel.
|
7839 |
+
*/
|
7840 |
+
function sucuriscan_settings_general(){
|
7841 |
+
|
7842 |
+
global $sucuriscan_schedule_allowed,
|
7843 |
+
$sucuriscan_interface_allowed,
|
7844 |
+
$sucuriscan_emails_per_hour,
|
7845 |
+
$sucuriscan_maximum_failed_logins,
|
7846 |
+
$sucuriscan_verify_ssl_cert;
|
7847 |
+
|
7848 |
+
// Check the nonce here to populate the value through other functions.
|
7849 |
+
$page_nonce = SucuriScanInterface::check_nonce();
|
7850 |
+
|
7851 |
+
// Process all form submissions.
|
7852 |
+
sucuriscan_settings_form_submissions($page_nonce);
|
7853 |
+
|
7854 |
+
// Register the site, get its API key, and store it locally for future usage.
|
7855 |
+
$api_registered_modal = '';
|
7856 |
+
|
7857 |
+
// Whether the form to manually add the API key should be shown or not.
|
7858 |
+
$display_manual_key_form = (bool) ( SucuriScanRequest::post(':recover_key') !== FALSE );
|
7859 |
+
|
7860 |
+
if( $page_nonce && SucuriScanRequest::post(':plugin_api_key') !== FALSE ){
|
7861 |
+
$registered = SucuriScanAPI::register_site();
|
7862 |
+
|
7863 |
+
if( $registered ){
|
7864 |
+
$api_registered_modal = SucuriScanTemplate::get_modal('settings-apiregistered', array(
|
7865 |
+
'Title' => 'Site registered successfully',
|
7866 |
+
'CssClass' => 'sucuriscan-apikey-registered',
|
7867 |
+
));
|
7868 |
+
} else {
|
7869 |
+
$display_manual_key_form = TRUE;
|
7870 |
+
}
|
7871 |
+
}
|
7872 |
+
|
7873 |
+
// Get initial variables to decide some things bellow.
|
7874 |
+
$api_key = SucuriScanAPI::get_plugin_key();
|
7875 |
+
$fs_scanner = SucuriScanOption::get_option(':fs_scanner');
|
7876 |
+
$scan_freq = SucuriScanOption::get_option(':scan_frequency');
|
7877 |
+
$scan_interface = SucuriScanOption::get_option(':scan_interface');
|
7878 |
+
$scan_modfiles = SucuriScanOption::get_option(':scan_modfiles');
|
7879 |
+
$scan_checksums = SucuriScanOption::get_option(':scan_checksums');
|
7880 |
+
$emails_per_hour = SucuriScanOption::get_option(':emails_per_hour');
|
7881 |
+
$maximum_failed_logins = SucuriScanOption::get_option(':maximum_failed_logins');
|
7882 |
+
$verify_ssl_cert = SucuriScanOption::get_option(':verify_ssl_cert');
|
7883 |
+
$runtime_scan_human = SucuriScanOption::get_filesystem_runtime(TRUE);
|
7884 |
+
|
7885 |
+
// Generate the HTML code for the option list in the form select fields.
|
7886 |
+
$scan_freq_options = SucuriScanTemplate::get_select_options( $sucuriscan_schedule_allowed, $scan_freq );
|
7887 |
+
$scan_interface_options = SucuriScanTemplate::get_select_options( $sucuriscan_interface_allowed, $scan_interface );
|
7888 |
+
$emails_per_hour_options = SucuriScanTemplate::get_select_options( $sucuriscan_emails_per_hour, $emails_per_hour );
|
7889 |
+
$maximum_failed_logins_options = SucuriScanTemplate::get_select_options( $sucuriscan_maximum_failed_logins, $maximum_failed_logins );
|
7890 |
+
$verify_ssl_cert_options = SucuriScanTemplate::get_select_options( $sucuriscan_verify_ssl_cert, $verify_ssl_cert );
|
7891 |
+
|
7892 |
+
$template_variables = array(
|
7893 |
+
'APIKey' => $api_key,
|
7894 |
+
'APIKey.RecoverVisibility' => SucuriScanTemplate::visibility( !$api_key && !$display_manual_key_form ),
|
7895 |
+
'APIKey.ManualKeyFormVisibility' => SucuriScanTemplate::visibility($display_manual_key_form),
|
7896 |
+
'APIKey.RemoveVisibility' => SucuriScanTemplate::visibility($api_key),
|
7897 |
+
/* Filesystem scanner */
|
7898 |
+
'FsScannerStatus' => 'Enabled',
|
7899 |
+
'FsScannerSwitchText' => 'Disable',
|
7900 |
+
'FsScannerSwitchValue' => 'disable',
|
7901 |
+
'FsScannerSwitchCssClass' => 'button-danger',
|
7902 |
+
/* Scan modified files. */
|
7903 |
+
'ScanModfilesStatus' => 'Enabled',
|
7904 |
+
'ScanModfilesSwitchText' => 'Disable',
|
7905 |
+
'ScanModfilesSwitchValue' => 'disable',
|
7906 |
+
'ScanModfilesSwitchCssClass' => 'button-danger',
|
7907 |
+
/* Scan files checksum. */
|
7908 |
+
'ScanChecksumsStatus' => 'Enabled',
|
7909 |
+
'ScanChecksumsSwitchText' => 'Disable',
|
7910 |
+
'ScanChecksumsSwitchValue' => 'disable',
|
7911 |
+
'ScanChecksumsSwitchCssClass' => 'button-danger',
|
7912 |
+
/* Filsystem scanning frequency. */
|
7913 |
+
'ScanningFrequency' => 'Undefined',
|
7914 |
+
'ScanningFrequencyOptions' => $scan_freq_options,
|
7915 |
+
'ScanningInterface' => ( $scan_interface ? $sucuriscan_interface_allowed[$scan_interface] : 'Undefined' ),
|
7916 |
+
'ScanningInterfaceOptions' => $scan_interface_options,
|
7917 |
+
'ScanningInterfaceVisibility' => SucuriScanTemplate::visibility( !SucuriScanFileInfo::is_spl_available() ),
|
7918 |
+
/* Filesystem scanning runtime. */
|
7919 |
+
'ScanningRuntimeHuman' => $runtime_scan_human,
|
7920 |
+
'ModalWhenAPIRegistered' => $api_registered_modal,
|
7921 |
+
'NotifyTo' => SucuriScanOption::get_option(':notify_to'),
|
7922 |
+
'EmailsPerHour' => 'Undefined',
|
7923 |
+
'EmailsPerHourOptions' => $emails_per_hour_options,
|
7924 |
+
'MaximumFailedLogins' => 'Undefined',
|
7925 |
+
'MaximumFailedLoginsOptions' => $maximum_failed_logins_options,
|
7926 |
+
'VerifySSLCert' => 'Undefined',
|
7927 |
+
'VerifySSLCertOptions' => $verify_ssl_cert_options,
|
7928 |
+
'ModalWhenAPIRegistered' => $api_registered_modal,
|
7929 |
+
);
|
7930 |
+
|
7931 |
+
if( $fs_scanner == 'disabled' ){
|
7932 |
+
$template_variables['FsScannerStatus'] = 'Disabled';
|
7933 |
+
$template_variables['FsScannerSwitchText'] = 'Enable';
|
7934 |
+
$template_variables['FsScannerSwitchValue'] = 'enable';
|
7935 |
+
$template_variables['FsScannerSwitchCssClass'] = 'button-success';
|
7936 |
+
}
|
7937 |
+
|
7938 |
+
if( $scan_modfiles == 'disabled' ){
|
7939 |
+
$template_variables['ScanModfilesStatus'] = 'Disabled';
|
7940 |
+
$template_variables['ScanModfilesSwitchText'] = 'Enable';
|
7941 |
+
$template_variables['ScanModfilesSwitchValue'] = 'enable';
|
7942 |
+
$template_variables['ScanModfilesSwitchCssClass'] = 'button-success';
|
7943 |
+
}
|
7944 |
+
|
7945 |
+
if( $scan_checksums == 'disabled' ){
|
7946 |
+
$template_variables['ScanChecksumsStatus'] = 'Disabled';
|
7947 |
+
$template_variables['ScanChecksumsSwitchText'] = 'Enable';
|
7948 |
+
$template_variables['ScanChecksumsSwitchValue'] = 'enable';
|
7949 |
+
$template_variables['ScanChecksumsSwitchCssClass'] = 'button-success';
|
7950 |
+
}
|
7951 |
+
|
7952 |
+
if( array_key_exists($scan_freq, $sucuriscan_schedule_allowed) ){
|
7953 |
+
$template_variables['ScanningFrequency'] = $sucuriscan_schedule_allowed[$scan_freq];
|
7954 |
+
}
|
7955 |
+
|
7956 |
+
if( array_key_exists($emails_per_hour, $sucuriscan_emails_per_hour) ){
|
7957 |
+
$template_variables['EmailsPerHour'] = $sucuriscan_emails_per_hour[$emails_per_hour];
|
7958 |
+
}
|
7959 |
+
|
7960 |
+
if( array_key_exists($maximum_failed_logins, $sucuriscan_maximum_failed_logins) ){
|
7961 |
+
$template_variables['MaximumFailedLogins'] = $sucuriscan_maximum_failed_logins[$maximum_failed_logins];
|
7962 |
+
}
|
7963 |
+
|
7964 |
+
if( array_key_exists($verify_ssl_cert, $sucuriscan_verify_ssl_cert) ){
|
7965 |
+
$template_variables['VerifySSLCert'] = $sucuriscan_verify_ssl_cert[$verify_ssl_cert];
|
7966 |
+
}
|
7967 |
+
|
7968 |
+
return SucuriScanTemplate::get_section('settings-general', $template_variables);
|
7969 |
+
}
|
7970 |
+
|
7971 |
+
/**
|
7972 |
+
* Read and parse the content of the notification settings template.
|
7973 |
+
*
|
7974 |
+
* @return string Parsed HTML code for the notification settings panel.
|
7975 |
+
*/
|
7976 |
+
function sucuriscan_settings_notifications(){
|
7977 |
+
global $sucuriscan_notify_options;
|
7978 |
+
|
7979 |
+
$template_variables = array(
|
7980 |
+
'NotificationOptions' => '',
|
7981 |
+
);
|
7982 |
+
|
7983 |
+
$counter = 0;
|
7984 |
|
7985 |
+
foreach( $sucuriscan_notify_options as $alert_type => $alert_label ){
|
7986 |
+
$alert_value = SucuriScanOption::get_option($alert_type);
|
7987 |
+
$checked = ( $alert_value == 'enabled' ? 'checked="checked"' : '' );
|
7988 |
+
$css_class = ( $counter % 2 == 0 ) ? 'alternate' : '';
|
7989 |
|
7990 |
+
$template_variables['NotificationOptions'] .= SucuriScanTemplate::get_snippet('settings-notifications', array(
|
7991 |
+
'Notification.CssClass' => $css_class,
|
7992 |
+
'Notification.Name' => $alert_type,
|
7993 |
+
'Notification.Checked' => $checked,
|
7994 |
+
'Notification.Label' => $alert_label,
|
7995 |
+
));
|
7996 |
+
$counter += 1;
|
7997 |
}
|
7998 |
|
7999 |
+
return SucuriScanTemplate::get_section('settings-notifications', $template_variables);
|
8000 |
}
|
8001 |
|
8002 |
/**
|
8003 |
+
* Read and parse the content of the ignored-rules settings template.
|
|
|
|
|
|
|
8004 |
*
|
8005 |
+
* @return string Parsed HTML code for the ignored-rules settings panel.
|
8006 |
*/
|
8007 |
+
function sucuriscan_settings_ignore_rules(){
|
8008 |
+
$notify_new_site_content = SucuriScanOption::get_option(':notify_post_publication');
|
8009 |
+
|
8010 |
+
$template_variables = array(
|
8011 |
+
'IgnoreRules.MessageVisibility' => 'visible',
|
8012 |
+
'IgnoreRules.TableVisibility' => 'hidden',
|
8013 |
+
'IgnoreRules.PostTypes' => '',
|
8014 |
+
);
|
8015 |
+
|
8016 |
+
if( $notify_new_site_content == 'enabled' ){
|
8017 |
+
$post_types = get_post_types();
|
8018 |
+
$ignored_events = SucuriScanOption::get_ignored_events();
|
8019 |
+
|
8020 |
+
$template_variables['IgnoreRules.MessageVisibility'] = 'hidden';
|
8021 |
+
$template_variables['IgnoreRules.TableVisibility'] = 'visible';
|
8022 |
+
$counter = 0;
|
8023 |
+
|
8024 |
+
foreach( $post_types as $post_type => $post_type_object ){
|
8025 |
+
$counter += 1;
|
8026 |
+
$css_class = ( $counter % 2 == 0 ) ? 'alternate' : '';
|
8027 |
+
$post_type_title = ucwords( str_replace('_', chr(32), $post_type) );
|
8028 |
+
|
8029 |
+
if( array_key_exists($post_type, $ignored_events) ){
|
8030 |
+
$is_ignored_text = 'YES';
|
8031 |
+
$was_ignored_at = @date('d/M/Y - H:i:s', $ignored_events[$post_type]);
|
8032 |
+
$is_ignored_class = 'danger';
|
8033 |
+
$button_action = 'remove';
|
8034 |
+
$button_class = 'button-primary';
|
8035 |
+
$button_text = 'Allow';
|
8036 |
+
} else {
|
8037 |
+
$is_ignored_text = 'NO';
|
8038 |
+
$was_ignored_at = 'Not ignored';
|
8039 |
+
$is_ignored_class = 'success';
|
8040 |
+
$button_action = 'add';
|
8041 |
+
$button_class = 'button-primary button-danger';
|
8042 |
+
$button_text = 'Ignore';
|
8043 |
+
}
|
8044 |
+
|
8045 |
+
$template_variables['IgnoreRules.PostTypes'] .= SucuriScanTemplate::get_snippet('settings-ignorerules', array(
|
8046 |
+
'IgnoreRules.CssClass' => $css_class,
|
8047 |
+
'IgnoreRules.Num' => $counter,
|
8048 |
+
'IgnoreRules.PostTypeTitle' => $post_type_title,
|
8049 |
+
'IgnoreRules.IsIgnored' => $is_ignored_text,
|
8050 |
+
'IgnoreRules.WasIgnoredAt' => $was_ignored_at,
|
8051 |
+
'IgnoreRules.IsIgnoredClass' => $is_ignored_class,
|
8052 |
+
'IgnoreRules.PostType' => $post_type,
|
8053 |
+
'IgnoreRules.Action' => $button_action,
|
8054 |
+
'IgnoreRules.ButtonClass' => 'button ' . $button_class,
|
8055 |
+
'IgnoreRules.ButtonText' => $button_text,
|
8056 |
+
));
|
8057 |
+
}
|
8058 |
+
}
|
8059 |
+
|
8060 |
+
return SucuriScanTemplate::get_section('settings-ignorerules', $template_variables);
|
8061 |
}
|
8062 |
|
8063 |
/**
|
8070 |
* @return void
|
8071 |
*/
|
8072 |
function sucuriscan_infosys_page(){
|
8073 |
+
SucuriScanInterface::check_permissions();
|
8074 |
+
|
8075 |
+
// Process all form submissions.
|
8076 |
+
sucuriscan_infosys_form_submissions();
|
8077 |
|
8078 |
// Page pseudo-variables initialization.
|
8079 |
$template_variables = array(
|
8084 |
'WordpressConfig' => sucuriscan_infosys_wpconfig(),
|
8085 |
);
|
8086 |
|
8087 |
+
echo SucuriScanTemplate::get_template('infosys', $template_variables);
|
8088 |
}
|
8089 |
|
8090 |
/**
|
8094 |
* @return string The HTML code displaying the information about the HTAccess rules.
|
8095 |
*/
|
8096 |
function sucuriscan_infosys_htaccess(){
|
8097 |
+
$htaccess_path = SucuriScan::get_htaccess_path();
|
8098 |
|
8099 |
$template_variables = array(
|
8100 |
'HTAccess.Content' => '',
|
8129 |
$template_variables['HTAccess.MessageVisible'] = 'visible';
|
8130 |
}
|
8131 |
|
8132 |
+
return SucuriScanTemplate::get_section('infosys-htaccess', $template_variables);
|
8133 |
}
|
8134 |
|
8135 |
/**
|
8141 |
*/
|
8142 |
function sucuriscan_htaccess_is_standard($rules=FALSE){
|
8143 |
if( $rules===FALSE ){
|
8144 |
+
$htaccess_path = SucuriScan::get_htaccess_path();
|
8145 |
$rules = $htaccess_path ? file_get_contents($htaccess_path) : '';
|
8146 |
}
|
8147 |
|
8188 |
$template_variables = array(
|
8189 |
'WordpressConfig.Rules' => '',
|
8190 |
'WordpressConfig.Total' => 0,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8191 |
);
|
8192 |
|
8193 |
+
$ignore_wp_rules = array( 'DB_PASSWORD' );
|
8194 |
+
$wp_config_path = SucuriScan::get_wpconfig_path();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8195 |
|
8196 |
+
if( $wp_config_path ){
|
8197 |
+
$wp_config_rules = array();
|
8198 |
+
$wp_config_content = SucuriScanFileInfo::file_lines($wp_config_path);
|
8199 |
|
8200 |
+
// Parse the main configuration file and look for constants and global variables.
|
8201 |
+
foreach( (array) $wp_config_content as $line ){
|
8202 |
+
// Detect PHP constants even if the line if indented.
|
8203 |
+
if( preg_match('/define\(/', $line) ){
|
8204 |
+
$line = preg_replace('*define\((.+)\);*', '$1', $line);
|
8205 |
+
$line_parts = explode(',', $line, 2);
|
|
|
8206 |
}
|
|
|
|
|
|
|
|
|
|
|
8207 |
|
8208 |
+
// Detect global variables like the database table prefix.
|
8209 |
+
else if( preg_match('/^\$[a-zA-Z_]+/', $line) ){
|
8210 |
+
$line_parts = explode('=', $line, 2);
|
|
|
|
|
|
|
8211 |
}
|
|
|
8212 |
|
8213 |
+
// Ignore other lines.
|
8214 |
+
else{ continue; }
|
|
|
8215 |
|
8216 |
+
// Clean and append the rule to the wp_config_rules variable.
|
8217 |
+
if( isset($line_parts) && count($line_parts)==2 ){
|
8218 |
+
$key_name = '';
|
8219 |
+
$key_value = '';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8220 |
|
8221 |
+
// TODO: A foreach loop is not really necessary, find a better way.
|
8222 |
+
foreach( $line_parts as $i => $line_part ){
|
8223 |
+
$line_part = trim($line_part);
|
8224 |
+
$line_part = ltrim($line_part, '$');
|
8225 |
+
$line_part = rtrim($line_part, ';');
|
8226 |
|
8227 |
+
// Remove single/double quotes at the beginning and end of the string.
|
8228 |
+
$line_part = ltrim($line_part, "'");
|
8229 |
+
$line_part = rtrim($line_part, "'");
|
8230 |
+
$line_part = ltrim($line_part, '"');
|
8231 |
+
$line_part = rtrim($line_part, '"');
|
|
|
|
|
|
|
|
|
|
|
|
|
8232 |
|
8233 |
+
// Assign the clean strings to specific variables.
|
8234 |
+
if( $i==0 ){ $key_name = $line_part; }
|
8235 |
+
if( $i==1 ){
|
8236 |
+
if( defined($key_name) ){
|
8237 |
+
$key_value = constant($key_name);
|
8238 |
+
|
8239 |
+
if( is_bool($key_value) ){
|
8240 |
+
$key_value = ( $key_value === TRUE ) ? 'TRUE' : 'FALSE';
|
8241 |
+
}
|
8242 |
+
} else {
|
8243 |
+
$key_value = $line_part;
|
8244 |
+
}
|
8245 |
+
}
|
8246 |
+
}
|
8247 |
|
8248 |
+
// Remove the value of sensitive variables like the database password.
|
8249 |
+
if( in_array($key_name, $ignore_wp_rules) ){
|
8250 |
+
$key_value = 'hidden';
|
|
|
|
|
8251 |
}
|
|
|
8252 |
|
8253 |
+
// Append the value to the configuration rules.
|
8254 |
+
$wp_config_rules[$key_name] = $key_value;
|
|
|
8255 |
}
|
8256 |
}
|
8257 |
|
8258 |
+
// Pass the WordPress configuration rules to the template and show them.
|
8259 |
+
$counter = 0;
|
8260 |
+
foreach( $wp_config_rules as $var_name => $var_value ){
|
8261 |
+
$css_class = ( $counter % 2 == 0 ) ? '' : 'alternate';
|
8262 |
+
$label_css = 'sucuriscan-monospace';
|
|
|
|
|
|
|
|
|
8263 |
|
8264 |
+
if( empty($var_value) ){
|
8265 |
+
$var_value = 'empty';
|
8266 |
+
$label_css = 'sucuriscan-label-default';
|
8267 |
}
|
8268 |
|
8269 |
+
elseif( $var_value == 'hidden' ){
|
8270 |
+
$label_css = 'sucuriscan-label-info';
|
8271 |
+
}
|
8272 |
|
8273 |
+
$template_variables['WordpressConfig.Total'] += 1;
|
8274 |
+
$template_variables['WordpressConfig.Rules'] .= SucuriScanTemplate::get_snippet('infosys-wpconfig', array(
|
8275 |
+
'WordpressConfig.VariableName' => SucuriScan::escape($var_name),
|
8276 |
+
'WordpressConfig.VariableValue' => SucuriScan::escape($var_value),
|
8277 |
+
'WordpressConfig.VariableCssClass' => $label_css,
|
8278 |
+
'WordpressConfig.CssClass' => $css_class,
|
8279 |
+
));
|
8280 |
+
$counter += 1;
|
8281 |
}
|
8282 |
+
}
|
8283 |
|
8284 |
+
return SucuriScanTemplate::get_section('infosys-wpconfig', $template_variables);
|
8285 |
+
}
|
|
|
|
|
|
|
|
|
|
|
8286 |
|
8287 |
+
/**
|
8288 |
+
* Retrieve a list with the scheduled tasks configured for the site.
|
8289 |
+
*
|
8290 |
+
* @return array A list of pseudo-variables and values that will replace them in the HTML template.
|
8291 |
+
*/
|
8292 |
+
function sucuriscan_show_cronjobs(){
|
8293 |
+
$template_variables = array(
|
8294 |
+
'Cronjobs.List' => '',
|
8295 |
+
'Cronjobs.Total' => 0,
|
8296 |
+
);
|
8297 |
+
|
8298 |
+
$cronjobs = _get_cron_array();
|
8299 |
+
$schedules = wp_get_schedules();
|
8300 |
+
$date_format = _x('M j, Y - H:i', 'Publish box date format', 'cron-view' );
|
8301 |
+
$counter = 0;
|
8302 |
+
|
8303 |
+
foreach( $cronjobs as $timestamp => $cronhooks ){
|
8304 |
+
foreach( (array) $cronhooks as $hook => $events ){
|
8305 |
+
foreach( (array) $events as $key => $event ){
|
8306 |
+
$template_variables['Cronjobs.Total'] += 1;
|
8307 |
+
$template_variables['Cronjobs.List'] .= SucuriScanTemplate::get_snippet('infosys-cronjobs', array(
|
8308 |
+
'Cronjob.Hook' => $hook,
|
8309 |
+
'Cronjob.Schedule' => $event['schedule'],
|
8310 |
+
'Cronjob.NextTime' => date_i18n($date_format, $timestamp),
|
8311 |
+
'Cronjob.Arguments' => !empty($event['args']) ? implode(', ', $event['args']) : '<em>empty</em>',
|
8312 |
+
'Cronjob.CssClass' => ( $counter % 2 == 0 ) ? '' : 'alternate',
|
8313 |
+
));
|
8314 |
+
$counter += 1;
|
8315 |
}
|
8316 |
}
|
|
|
8317 |
}
|
8318 |
|
8319 |
+
return SucuriScanTemplate::get_section('infosys-cronjobs', $template_variables);
|
8320 |
}
|
8321 |
|
8322 |
/**
|
8323 |
+
* Process the requests sent by the form submissions originated in the infosys
|
8324 |
+
* page, all forms must have a nonce field that will be checked against the one
|
8325 |
+
* generated in the template render function.
|
8326 |
*
|
8327 |
+
* @param boolean $page_nonce True if the nonce is valid, False otherwise.
|
8328 |
+
* @return void
|
8329 |
*/
|
8330 |
+
function sucuriscan_infosys_form_submissions(){
|
8331 |
+
if( SucuriScanInterface::check_nonce() ){
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8332 |
|
8333 |
+
// Modify the scheduled tasks (run now, remove, re-schedule).
|
8334 |
+
$allowed_actions = '(runnow|hourly|twicedaily|daily|remove)';
|
8335 |
|
8336 |
+
if( $cronjob_action = SucuriScanRequest::post( ':cronjob_action', $allowed_actions ) ){
|
8337 |
+
$cronjobs = SucuriScanRequest::post(':cronjobs', '_array');
|
8338 |
|
8339 |
+
if( !empty($cronjobs) ){
|
8340 |
+
$total_tasks = count($cronjobs);
|
8341 |
|
8342 |
+
switch( $cronjob_action ){
|
8343 |
+
case 'runnow':
|
8344 |
+
SucuriScanInterface::info( $total_tasks . ' tasks were scheduled to run in the next ten seconds.' );
|
8345 |
+
foreach( $cronjobs as $task_name ){
|
8346 |
+
wp_schedule_single_event( time() + 600, $task_name );
|
8347 |
+
}
|
8348 |
+
break;
|
8349 |
+
case 'remove':
|
8350 |
+
SucuriScanInterface::info( $total_tasks . ' scheduled tasks were removed.' );
|
8351 |
+
foreach( $cronjobs as $task_name ){
|
8352 |
+
wp_clear_scheduled_hook($task_name);
|
8353 |
+
}
|
8354 |
+
break;
|
8355 |
+
default:
|
8356 |
+
SucuriScanInterface::info( $total_tasks . ' tasks were re-scheduled to run <code>' . $cronjob_action . '</code>.' );
|
8357 |
+
foreach( $cronjobs as $task_name ){
|
8358 |
+
wp_clear_scheduled_hook($task_name);
|
8359 |
+
$next_due = wp_next_scheduled($task_name);
|
8360 |
+
wp_schedule_event( $next_due, $cronjob_action, $task_name );
|
8361 |
+
}
|
8362 |
+
break;
|
8363 |
+
}
|
8364 |
+
} else {
|
8365 |
+
SucuriScanInterface::error( 'No scheduled tasks were selected from the list.' );
|
8366 |
+
}
|
8367 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8368 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8369 |
}
|
8370 |
+
}
|
8371 |
|
8372 |
+
/**
|
8373 |
+
* Gather information from the server, database engine, and PHP interpreter.
|
8374 |
+
*
|
8375 |
+
* @return array A list of pseudo-variables and values that will replace them in the HTML template.
|
8376 |
+
*/
|
8377 |
+
function sucuriscan_server_info(){
|
8378 |
+
global $wpdb;
|
|
|
|
|
|
|
|
|
8379 |
|
8380 |
$template_variables = array(
|
8381 |
+
'ServerInfo.Variables' => '',
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8382 |
);
|
8383 |
|
8384 |
+
$info_vars = array(
|
8385 |
+
'Plugin_version' => SUCURISCAN_VERSION,
|
8386 |
+
'Plugin_checksum' => SUCURISCAN_PLUGIN_CHECKSUM,
|
8387 |
+
'Last_filesystem_scan' => SucuriScanOption::get_filesystem_runtime(TRUE),
|
8388 |
+
'Using_CloudProxy' => 'No',
|
8389 |
+
'Operating_system' => sprintf('%s (%d Bit)', PHP_OS, PHP_INT_SIZE*8),
|
8390 |
+
'Server' => 'Unknown',
|
8391 |
+
'Developer_mode' => 'OFF',
|
8392 |
+
'Memory_usage' => 'N/A',
|
8393 |
+
'MySQL_version' => '0.0',
|
8394 |
+
'SQL_mode' => 'Not set',
|
8395 |
+
'PHP_version' => PHP_VERSION,
|
8396 |
+
);
|
8397 |
+
|
8398 |
+
if( SucuriScan::is_behind_cloudproxy() ){
|
8399 |
+
$info_vars['Using_CloudProxy'] = 'Yes';
|
8400 |
}
|
8401 |
|
8402 |
+
if( defined('WP_DEBUG') && WP_DEBUG ){
|
8403 |
+
$info_vars['Developer_mode'] = 'ON';
|
8404 |
}
|
8405 |
|
8406 |
+
if( function_exists('memory_get_usage') ){
|
8407 |
+
$info_vars['Memory_usage'] = round(memory_get_usage() / 1024 / 1024, 2).' MB';
|
8408 |
}
|
8409 |
|
8410 |
+
if( isset($_SERVER['SERVER_SOFTWARE']) ){
|
8411 |
+
$info_vars['Server'] = SucuriScan::escape($_SERVER['SERVER_SOFTWARE']);
|
8412 |
}
|
8413 |
|
8414 |
+
if( $wpdb ){
|
8415 |
+
$info_vars['MySQL_version'] = $wpdb->get_var('SELECT VERSION() AS version');
|
8416 |
|
8417 |
+
$mysql_info = $wpdb->get_results('SHOW VARIABLES LIKE "sql_mode"');
|
8418 |
+
if( is_array($mysql_info) && !empty($mysql_info[0]->Value) ){
|
8419 |
+
$info_vars['SQL_mode'] = $mysql_info[0]->Value;
|
8420 |
+
}
|
8421 |
+
}
|
|
|
|
|
8422 |
|
8423 |
+
$field_names = array(
|
8424 |
+
'safe_mode',
|
8425 |
+
'allow_url_fopen',
|
8426 |
+
'memory_limit',
|
8427 |
+
'upload_max_filesize',
|
8428 |
+
'post_max_size',
|
8429 |
+
'max_execution_time',
|
8430 |
+
'max_input_time',
|
8431 |
);
|
8432 |
|
8433 |
+
foreach( $field_names as $php_flag ){
|
8434 |
+
$php_flag_value = ini_get($php_flag);
|
8435 |
+
$php_flag_name = 'PHP_' . $php_flag;
|
8436 |
+
$info_vars[$php_flag_name] = $php_flag_value ? $php_flag_value : 'N/A';
|
8437 |
+
}
|
8438 |
+
|
8439 |
$counter = 0;
|
8440 |
|
8441 |
+
foreach( $info_vars as $var_name => $var_value ){
|
8442 |
+
$css_class = ( $counter %2 == 0 ) ? '' : 'alternate';
|
8443 |
+
$var_name = str_replace('_', chr(32), $var_name);
|
|
|
8444 |
|
8445 |
+
$template_variables['ServerInfo.Variables'] .= SucuriScanTemplate::get_snippet('infosys-serverinfo', array(
|
8446 |
+
'ServerInfo.CssClass' => $css_class,
|
8447 |
+
'ServerInfo.Title' => $var_name,
|
8448 |
+
'ServerInfo.Value' => $var_value,
|
|
|
8449 |
));
|
8450 |
$counter += 1;
|
8451 |
}
|
8452 |
|
8453 |
+
return SucuriScanTemplate::get_section('infosys-serverinfo', $template_variables);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8454 |
}
|
8455 |
|