Version Description
- Initial release with new auditing options.
Download this release
Release Info
Developer | dd@sucuri.net |
Plugin | Sucuri Security – Auditing, Malware Scanner and Security Hardening |
Version | 1.6.1 |
Comparing to | |
See all releases |
Code changes from version 1.6.0 to 1.6.1
- inc/css/sucuriscan-default-css.css +176 -49
- inc/js/sucuriscan-scripts.js +31 -2
- inc/tpl/about.html.tpl +0 -111
- inc/tpl/base.html.tpl +10 -6
- inc/tpl/infosys-cronjobs.snippet.tpl +1 -0
- inc/tpl/infosys-htaccess.html.tpl +3 -2
- inc/tpl/infosys-loggedin.html.tpl +2 -1
- inc/tpl/infosys-serverinfo.html.tpl +1 -1
- inc/tpl/infosys-wpconfig.html.tpl +2 -1
- inc/tpl/initial-page.html.tpl +0 -97
- inc/tpl/integrity-admins-lastlogin.snippet.tpl +0 -4
- inc/tpl/integrity-auditlogs.html.tpl +38 -0
- inc/tpl/integrity-auditlogs.snippet.tpl +9 -0
- inc/tpl/integrity-corefiles.html.tpl +42 -0
- inc/tpl/integrity-corefiles.snippet.tpl +9 -0
- inc/tpl/integrity-modifiedfiles.html.tpl +40 -0
- inc/tpl/integrity-modifiedfiles.snippet.tpl +6 -0
- inc/tpl/integrity-wpoutdate.html.tpl +14 -0
- inc/tpl/integrity.html.tpl +10 -0
- inc/tpl/lastlogins-admins-lastlogin.snippet.tpl +5 -0
- inc/tpl/{integrity-admins.html.tpl → lastlogins-admins.html.tpl} +3 -5
- inc/tpl/{integrity-admins.snippet.tpl → lastlogins-admins.snippet.tpl} +3 -2
- inc/tpl/lastlogins-all.html.tpl +23 -0
- inc/tpl/{lastlogins.snippet.tpl → lastlogins-all.snippet.tpl} +0 -0
- inc/tpl/lastlogins.html.tpl +19 -21
- inc/tpl/malwarescan.html.tpl +17 -0
- inc/tpl/modalwindow.html.tpl +26 -0
- inc/tpl/monitoring-logs.html.tpl +74 -0
- inc/tpl/monitoring-logs.snippet.tpl +64 -0
- inc/tpl/monitoring-settings.html.tpl +28 -0
- inc/tpl/monitoring-settings.snippet.tpl +5 -0
- inc/tpl/monitoring.html.tpl +58 -0
- inc/tpl/{notification.html.tpl → notification-pretty.html.tpl} +5 -5
- inc/tpl/{notification.txt.tpl → notification-simple.html.tpl} +1 -1
- inc/tpl/posthack-databasebackups.html.tpl +41 -0
- inc/tpl/posthack-databasebackups.snippet.tpl +10 -0
- inc/tpl/posthack-resetpassword.html.tpl +47 -0
- inc/tpl/posthack-updatesecretkeys.html.tpl +31 -0
- inc/tpl/posthack.html.tpl +22 -71
- inc/tpl/settings-apiregistered.html.tpl +16 -0
- inc/tpl/settings-notification.snippet.tpl +12 -0
- inc/tpl/settings.html.tpl +118 -0
- inc/tpl/setup_notice.html.tpl +23 -0
- readme.txt +6 -3
- sucuri.php +5974 -1554
inc/css/sucuriscan-default-css.css
CHANGED
@@ -3,89 +3,216 @@
|
|
3 |
* Copyright (C) 2010-2014 Sucuri Security - http://sucuri.net
|
4 |
* Released under the GPL - see LICENSE file for details.
|
5 |
*/
|
6 |
-
/*
|
7 |
.sucuriscan-wrap *, .sucuriscan-wrap *:before, .sucuriscan-wrap *:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}
|
8 |
.sucuriscan-clearfix:before, .sucuriscan-clearfix:after{display:table;content:' '}
|
9 |
.sucuriscan-clearfix:after{clear:both}
|
10 |
.sucuriscan-visible{}
|
11 |
.sucuriscan-hidden{display:none !important}
|
12 |
.sucuriscan-monospace{font-family:Monospace, Courier}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
13 |
.sucuriscan-wrap .sucuriscan-maincontent{margin:20px 0}
|
14 |
-
.sucuriscan-wrap .sucuriscan-leftside{width:
|
15 |
-
.sucuriscan-wrap .sucuriscan-sidebar{width:
|
|
|
|
|
|
|
16 |
.sucuriscan-header, .sucuriscan-footer{position:relative;min-width:255px;background:#333;margin:0;padding:10px;border-radius:4px}
|
17 |
.sucuriscan-footer .sucuriscan-help{color:#fff;float:right;text-align:right}
|
18 |
.sucuriscan-footer .sucuriscan-help p{line-height:38px;margin:0 10px 0 0;padding:0}
|
19 |
-
.sucuriscan-wrap .sucuriscan-
|
|
|
|
|
20 |
.sucuriscan-wrap .sucuriscan-header h2, .sucuriscan-wrap .sucuriscan-footer h2{color:#fff;line-height:38px;margin-left:10px;text-shadow:#000 0 1px 0}
|
21 |
.sucuriscan-leftside #poststuff .postbox:last-child{margin-bottom:0}
|
22 |
-
|
23 |
-
.
|
24 |
-
.sucuriscan-
|
25 |
-
.sucuriscan-
|
26 |
-
.sucuriscan-
|
27 |
-
.
|
28 |
-
.sucuriscan-
|
29 |
-
|
30 |
.sucuriscan-maincontent .sucuriscan-table{margin-top:12px}
|
31 |
-
.sucuriscan-maincontent .sucuriscan-table tr > th{
|
32 |
.sucuriscan-maincontent .sucuriscan-table tr:first-child th{border-top:0}
|
33 |
.sucuriscan-maincontent .sucuriscan-table td.check-column{padding:8px 10px}
|
34 |
-
.sucuriscan-table-
|
35 |
-
.sucuriscan-
|
36 |
-
.sucuriscan-
|
37 |
-
.sucuriscan-maincontent .sucuriscan-
|
38 |
-
.
|
39 |
-
.
|
40 |
-
.
|
41 |
-
.sucuriscan-
|
42 |
-
.sucuriscan-
|
|
|
|
|
|
|
|
|
|
|
43 |
.sucuriscan-maincontent .thead-with-button .input-text{line-height:26px}
|
|
|
44 |
.sucuriscan-maincontent .thead-topright-action{display:inline-block;float:right}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
45 |
.sucuriscan-tabs{}
|
46 |
.sucuriscan-tabs > ul{margin:0}
|
47 |
.sucuriscan-tabs > ul li, .sucuriscan-tabs > ul li > a{display:inline-block}
|
48 |
.sucuriscan-tabs > ul li{margin-bottom:0}
|
49 |
.sucuriscan-tabs > ul li > a{background:#e5e5e5;font-size:13px;font-weight:bold;color:#333;line-height:38px;text-decoration:none;padding:0 10px}
|
50 |
.sucuriscan-tabs > ul li > a.sucuriscan-tab-active{background:#fff;border:1px solid #e1e1e1;border-bottom:0}
|
|
|
|
|
51 |
.sucuriscan-maincontent .sucuriscan-tab-containers > div > table{margin-top:0}
|
52 |
.sucuriscan-maincontent .sucuriscan-tab-containers > div > #poststuff{margin-top:0}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
53 |
.sucuriscan-maincontent .sucuriscan-full-textarea{width:100%;height:400px;line-height:normal;resize:vertical;padding:10px}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
54 |
.sucuriscan-wpconfig-textarea{width:600px;height:525px;background:#f5f5f5;font-size:12px;line-height:1.4em;resize:none;margin:15px 0 0 0;padding:10px}
|
55 |
-
|
56 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
57 |
/* Old styles */
|
58 |
.sucuriscan-maincontent #poststuff{min-width:initial;padding-top:0}
|
59 |
.sucuriscan-maincontent .widefat tbody th.check-column{padding:6px 0 3px 0}
|
60 |
.sucuriscan-maincontent .hardening-box .primary-secondary{margin:0 0 0 10px}
|
61 |
.sucuriscan-maincontent a.lastlogins-showall{display:inline-block;float:right}
|
62 |
-
.sucuri-alert{position:relative}
|
63 |
-
.sucuri-alert>a.close{position:absolute;top:8px;right:10px;font-size:18px;text-decoration:none}
|
64 |
-
.sucuri-alert-updated, .sucuri-alert-error{background:#fff;margin:5px 0 15px;padding:1px 12px;border:1px solid #e5e5e5;border-left:4px solid #ccc}
|
65 |
-
.sucuri-alert-updated{border-left:4px solid #7ad03a}
|
66 |
-
.sucuri-alert-error{border-left:4px solid #dd3d36}
|
67 |
-
.sucuri-alert-updated p, .sucuri-alert-error p{margin:.5em 0;padding:2px}
|
68 |
.sucuri-inline-error{font-weight:bold;color:red}
|
69 |
-
.sucuri-list li{list-style:disc;margin:0 0 5px 15px}
|
70 |
.sucuriscan-maincontent .alternate{background:#f5f5f5}
|
71 |
.sucuriscan-maincontent hr{border:none;border-top:1px solid #999}
|
72 |
.sucuriscan-maincontent table td > table{background:#fff}
|
73 |
.sucuriscan-maincontent table td > table th{padding:4px 8px}
|
74 |
-
.sucuriscan-results .icon-ok, .sucuriscan-results .icon-warn, .sucuriscan-results .icon-error{position:relative;top:5px;width:22px;height:22px}
|
75 |
-
.sucuriscan-scanner-video{width:100%;background:#fff;border:1px solid #ddd}
|
76 |
-
.sucuriscan-column-left, .sucuriscan-column-right{width:49%;min-width:initial !important}
|
77 |
-
.sucuriscan-column-left{float:left}
|
78 |
-
.sucuriscan-column-right{float:right}
|
79 |
-
.sucuriscan-hstatus{position:relative;margin:0 -12px;padding:10px 12px;border:1px solid transparent}
|
80 |
-
.sucuriscan-hstatus-1{background-color:#dff0d8;color:#3c763d;border-color:#d6e9c6}
|
81 |
-
.sucuriscan-hstatus-0{background-color:#f2dede;color:#a94442;border-color:#ebccd1}
|
82 |
-
.sucuriscan-hstatus .button-primary, .sucuriscan-hstatus .button-secondary{position:absolute;top:5px;right:5px}
|
83 |
-
.sucuriscan-initial-page{}
|
84 |
-
.sucuriscan-initial-page a{text-decoration:none}
|
85 |
-
.sucuriscan-initial-page .sucuriscan-column-left{width:70%}
|
86 |
-
.sucuriscan-initial-page .sucuriscan-column-right{width:29%;text-align:right}
|
87 |
-
.sucuriscan-initial-page #poststuff .inside, .sucuriscan-initial-page #poststuff .inside p{font-size:16px;margin:0;padding:0}
|
88 |
-
.sucuriscan-initial-page #poststuff .inside{padding:20px}
|
89 |
-
.sucuriscan-initial-page #poststuff .button.button-hero{width:202px;text-align:center;padding:0}
|
90 |
-
.sucuriscan-initial-page .sucuriscan-disclaimer{padding:20px;padding-top:0}
|
91 |
-
.sucuriscan-initial-page .sucuriscan-disclaimer p{font-size:10px;margin:0}
|
3 |
* Copyright (C) 2010-2014 Sucuri Security - http://sucuri.net
|
4 |
* Released under the GPL - see LICENSE file for details.
|
5 |
*/
|
6 |
+
/* Generic Styles */
|
7 |
.sucuriscan-wrap *, .sucuriscan-wrap *:before, .sucuriscan-wrap *:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}
|
8 |
.sucuriscan-clearfix:before, .sucuriscan-clearfix:after{display:table;content:' '}
|
9 |
.sucuriscan-clearfix:after{clear:both}
|
10 |
.sucuriscan-visible{}
|
11 |
.sucuriscan-hidden{display:none !important}
|
12 |
.sucuriscan-monospace{font-family:Monospace, Courier}
|
13 |
+
.sucuriscan-ellipsis{overflow:hidden;display:inline-block;white-space:nowrap;text-overflow:ellipsis}
|
14 |
+
.sucuriscan-wraptext{word-break:break-all}
|
15 |
+
.sucuriscan-pull-left{float:left}
|
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}
|
23 |
+
.wp-core-ui .button-danger.active, .wp-core-ui .button-danger.active:focus, .wp-core-ui .button-danger.active:hover, .wp-core-ui .button-danger:active{background:#a61b1b;border-color:#840000}
|
24 |
+
.wp-core-ui .button-danger-disabled, .wp-core-ui .button-danger.disabled, .wp-core-ui .button-danger:disabled, .wp-core-ui .button-danger[disabled]{color:#e79494 !important;background:#ba2929 !important;border-color:#7f1b1b !important}
|
25 |
+
/* Modal Window */
|
26 |
+
.sucuriscan-overlay{position:fixed;top:0;left:0;bottom:0;right:0;z-index:800;background:rgba(0, 0, 0, 0.5)}
|
27 |
+
.sucuriscan-modal{position:fixed;top:100px;left:50%;z-index:900}
|
28 |
+
.sucuriscan-modal-outside{position:relative;left:-50%;border:1px solid #ddd}
|
29 |
+
.sucuriscan-modal-inside{background:#fff;padding:20px}
|
30 |
+
.sucuriscan-modal-header{padding:10px 20px;border-bottom:1px solid #ddd}
|
31 |
+
.sucuriscan-modal-header .sucuriscan-modal-title{min-height:18px;margin:0}
|
32 |
+
.sucuriscan-modal-close{display:inline-block;position:absolute;top:0;right:0;font-size:16px;font-weight:bold;text-decoration:none;line-height:39px;padding:0 15px;border-left:1px solid #ddd}
|
33 |
+
.sucuriscan-modal-inside p:first-child{margin-top:0}
|
34 |
+
.sucuriscan-modal-inside p:last-child{margin-bottom:0}
|
35 |
+
/* Interface Wrapper */
|
36 |
+
.sucuriscan-wrap{margin-top:20px}
|
37 |
.sucuriscan-wrap .sucuriscan-maincontent{margin:20px 0}
|
38 |
+
.sucuriscan-wrap .sucuriscan-leftside{width:73.5%;float:left}
|
39 |
+
.sucuriscan-wrap .sucuriscan-sidebar{width:25%;float:right}
|
40 |
+
.sucuriscan-wrap #warnings_hook{line-height:initial;padding:0}
|
41 |
+
.sucuriscan-wrap .sucuriscan-navbar{padding-top:20px;padding-left:6px}
|
42 |
+
.sucuriscan-wrap .sucuriscan-navbar .nav-tab{margin-right:0}
|
43 |
.sucuriscan-header, .sucuriscan-footer{position:relative;min-width:255px;background:#333;margin:0;padding:10px;border-radius:4px}
|
44 |
.sucuriscan-footer .sucuriscan-help{color:#fff;float:right;text-align:right}
|
45 |
.sucuriscan-footer .sucuriscan-help p{line-height:38px;margin:0 10px 0 0;padding:0}
|
46 |
+
.sucuriscan-wrap .sucuriscan-logo, .sucuriscan-wrap .sucuriscan-header h2, .sucuriscan-wrap .sucuriscan-footer h2{float:left;margin:0;padding:0}
|
47 |
+
.sucuriscan-wrap .sucuriscan-logo{display:inline-block}
|
48 |
+
.sucuriscan-wrap .sucuriscan-logo img{display:block}
|
49 |
.sucuriscan-wrap .sucuriscan-header h2, .sucuriscan-wrap .sucuriscan-footer h2{color:#fff;line-height:38px;margin-left:10px;text-shadow:#000 0 1px 0}
|
50 |
.sucuriscan-leftside #poststuff .postbox:last-child{margin-bottom:0}
|
51 |
+
/* Page Setup Notice */
|
52 |
+
.wrap div.sucuriscan-setup-notice{background:#bbe8f5;margin:0 0 20px 0;padding:0;border:1px solid #bbb;border-radius:3px;-webkit-box-shadow:none;box-shadow:none}
|
53 |
+
.wrap div.sucuriscan-setup-notice .sucuriscan-setup-image, .wrap div.sucuriscan-setup-notice .sucuriscan-setup-image img{border-radius:3px 0 0 3px}
|
54 |
+
.wrap div.sucuriscan-setup-notice .sucuriscan-setup-image{background:#333;margin:-1px 0 -1px -1px;padding:7px 10px;border-right:1px solid transparent}
|
55 |
+
.wrap div.sucuriscan-setup-notice .sucuriscan-setup-form{padding:4px;padding-left:0}
|
56 |
+
.wrap div.sucuriscan-setup-notice p{font-size:14px;line-height:20px;margin:0 0 0 10px;padding:7px 0}
|
57 |
+
.wrap div.sucuriscan-setup-notice, .wrap div.sucuriscan-setup-notice .sucuriscan-setup-image{border-color:#4393ac}
|
58 |
+
/* Table Styles */
|
59 |
.sucuriscan-maincontent .sucuriscan-table{margin-top:12px}
|
60 |
+
.sucuriscan-maincontent .sucuriscan-table tr > th{border-top:1px solid #e5e5e5;border-bottom:1px solid #e5e5e5}
|
61 |
.sucuriscan-maincontent .sucuriscan-table tr:first-child th{border-top:0}
|
62 |
.sucuriscan-maincontent .sucuriscan-table td.check-column{padding:8px 10px}
|
63 |
+
.sucuriscan-table-double-title tr:first-child th{border-bottom:0}
|
64 |
+
.sucuriscan-table-triple-title tr:first-child th, .sucuriscan-table-triple-title tr:first-child + tr th{border-bottom:0}
|
65 |
+
.sucuriscan-table-quad-title tr:first-child th, .sucuriscan-table-quad-title tr:first-child + tr th, .sucuriscan-table-quad-title tr:first-child + tr + tr th{border-bottom:0}
|
66 |
+
.sucuriscan-maincontent .sucuriscan-lastmodified td{font-family:Monospace, Courier, serif;font-weight:bold}
|
67 |
+
.widefat td.td-with-button{text-align:right;padding:3px 10px}
|
68 |
+
.widefat td.td-with-button button{min-width:90px}
|
69 |
+
.widefat td.td-with-button select{height:initial;line-height:initial;vertical-align:top;margin:0;padding:2px 0 3px 0}
|
70 |
+
.sucuriscan-list-as-table{background:#fff;border:1px solid #e5e5e5}
|
71 |
+
.sucuriscan-list-as-table li{line-height:30px;margin:0;padding:0 10px}
|
72 |
+
.sucuriscan-list-as-table li:nth-child(odd){background:#f5f5f5}
|
73 |
+
.sucuriscan-list-as-table-scrollable{height:300px;overflow:hidden;overflow-y:scroll}
|
74 |
+
/* Table Top-Right Buttons */
|
75 |
+
.sucuriscan-maincontent .thead-with-button{padding:5px 5px 5px 10px}
|
76 |
+
.sucuriscan-maincontent .thead-with-button > span{display:inline-block;line-height:28px}
|
77 |
.sucuriscan-maincontent .thead-with-button .input-text{line-height:26px}
|
78 |
+
.sucuriscan-maincontent .thead-with-button select{margin:0;padding:0}
|
79 |
.sucuriscan-maincontent .thead-topright-action{display:inline-block;float:right}
|
80 |
+
/* Sidebar Styles */
|
81 |
+
.sucuriscan-sidebar .sucuriscan-ad{border:1px solid #ccc;margin:0 0 20px 0;padding:20px;border-radius:4px}
|
82 |
+
.sucuriscan-sidebar .sucuriscan-ad h2{font-size:18px;line-height:normal;padding:0}
|
83 |
+
.sucuriscan-sidebar .sucuriscan-ad p:last-child{margin-bottom:0}
|
84 |
+
.sucuriscan-sidebar .sucuriscan-ad:nth-child(odd){background-color:#bbe8f5;border-color:#4393ac}
|
85 |
+
.sucuriscan-sidebar .sucuriscan-ad:nth-child(even){background-color:#ececec;border-color:#999}
|
86 |
+
.sucuriscan-scanner-video{width:100%;background:#fff;border:1px solid #ddd}
|
87 |
+
/* WordPress Alerts */
|
88 |
+
div.sucuriscan-alert{position:relative;margin:0 0 20px 0}
|
89 |
+
div.sucuriscan-alert > a.close{position:absolute;top:10px;right:10px;font-size:18px;font-weight:bold;text-decoration:none}
|
90 |
+
/* Tabulation Panels */
|
91 |
.sucuriscan-tabs{}
|
92 |
.sucuriscan-tabs > ul{margin:0}
|
93 |
.sucuriscan-tabs > ul li, .sucuriscan-tabs > ul li > a{display:inline-block}
|
94 |
.sucuriscan-tabs > ul li{margin-bottom:0}
|
95 |
.sucuriscan-tabs > ul li > a{background:#e5e5e5;font-size:13px;font-weight:bold;color:#333;line-height:38px;text-decoration:none;padding:0 10px}
|
96 |
.sucuriscan-tabs > ul li > a.sucuriscan-tab-active{background:#fff;border:1px solid #e1e1e1;border-bottom:0}
|
97 |
+
.sucuriscan-tabs > ul li.sucuriscan-red-tab a{background:#ff8a83;color:#fff}
|
98 |
+
.sucuriscan-tabs > ul li.sucuriscan-red-tab a.sucuriscan-tab-active{background:#dd3d36;border-color:#dd3d36}
|
99 |
.sucuriscan-maincontent .sucuriscan-tab-containers > div > table{margin-top:0}
|
100 |
.sucuriscan-maincontent .sucuriscan-tab-containers > div > #poststuff{margin-top:0}
|
101 |
+
/* Get API Form */
|
102 |
+
.sucuriscan-getapi-div{background:#fff;margin:0 0 20px 0;border:1px solid #e5e5e5;border-radius:3px}
|
103 |
+
.sucuriscan-getapi-div p{margin:0;padding:10px}
|
104 |
+
.sucuriscan-getapi-form{}
|
105 |
+
.sucuriscan-getapi-form button.button-primary{width:100%;height:initial;line-height:30px;margin:0 0 -1px 0;padding:0;border-radius:0 0 3px 3px}
|
106 |
+
/* Scanner Page */
|
107 |
+
.sucuriscan-malwarescan-message{margin-bottom:20px !important}
|
108 |
+
.sucuriscan-loading{background:#fff;text-align:center;padding:30px;padding-bottom:15px;border:1px solid #ddd;border-radius:4px}
|
109 |
+
.sucuriscan-loading p, .sucuriscan-loading h3{margin:0;padding:0}
|
110 |
+
.sucuriscan-loading .title{font-size:26px;margin-bottom:10px}
|
111 |
+
.sucuriscan-loading .description{font-size:18px}
|
112 |
+
.sucuriscan-sitelogo{width:190px;height:100px;background:url('http://sitecheck.sucuri.net/images/sucuri-sprite.png') no-repeat;margin:0 auto}
|
113 |
+
/* Scanner Results */
|
114 |
+
.sucuriscan-maincontent .sucuriscan-border{border:0;border-left:4px solid #ddd}
|
115 |
+
.sucuriscan-maincontent .sucuriscan-border > h3, .sucuriscan-maincontent .sucuriscan-border > .inside{border-top:1px solid #e5e5e5;border-right:1px solid #e5e5e5}
|
116 |
+
.sucuriscan-maincontent .sucuriscan-border > h3{border-bottom:0}
|
117 |
+
.sucuriscan-maincontent .sucuriscan-border > .inside{margin-top:0 !important;border-bottom:1px solid #ddd}
|
118 |
+
.sucuriscan-maincontent .sucuriscan-border-good{border-left-color:#7ad03a}
|
119 |
+
.sucuriscan-maincontent .sucuriscan-border-bad{border-left-color:#dd3d36}
|
120 |
+
.sucuriscan-maincontent .sucuriscan-border-info{border-left-color:#2ea2cc}
|
121 |
+
.sucuriscan-maincontent .sucuriscan-cleanup-btn{display:block;text-align:center;margin:20px 0 0 0}
|
122 |
+
.sucuriscan-scanner-results .sucuriscan-scanner-details tr:nth-child(even),
|
123 |
+
.sucuriscan-scanner-results .sucuriscan-scanner-links tr:nth-child(even){background:#f5f5f5}
|
124 |
+
.sucuriscan-scanner-results td.sucuriscan-border-bad{border-left-width:4px;border-left-style:solid}
|
125 |
+
/* Integrity Styles */
|
126 |
+
.sucuriscan-status-type{width:20px;background:#ddd;text-align:center;text-transform:uppercase;margin-right:10px;padding:0 3px;border:1px solid transparent;border-radius:3px}
|
127 |
+
.sucuriscan-status-added{background:#dff0d8;color:#3c763d;border-color:#d6e9c6}
|
128 |
+
.sucuriscan-status-modified{background:#fcf8e3;color:#8a6d3b;border-color:#faebcc}
|
129 |
+
.sucuriscan-status-removed, td.sucuriscan-corefiles-warning > div{background:#f2dede;color:#a94442;border-color:#ebccd1}
|
130 |
+
.sucuriscan-maincontent .sucuriscan-corefiles,
|
131 |
+
.sucuriscan-maincontent .sucuriscan-integrity-message,
|
132 |
+
.sucuriscan-maincontent .sucuriscan-wordpress-outdated,
|
133 |
+
.sucuriscan-maincontent .sucuriscan-auditlogs{margin-top:0;margin-bottom:20px}
|
134 |
+
.sucuriscan-maincontent .sucuriscan-corefiles td{padding:4px 10px}
|
135 |
+
.sucuriscan-corefiles-abbrs .sucuriscan-status-type{display:inline-block;width:initial;font-size:12px;text-transform:capitalize;float:left;margin-top:4px;margin-right:5px}
|
136 |
+
.sucuriscan-maincontent td.sucuriscan-corefiles-warning, .sucuriscan-maincontent td.sucuriscan-corefiles-warning p{margin:0;padding:0}
|
137 |
+
.sucuriscan-maincontent td.sucuriscan-corefiles-warning div{padding:10px;border-width:1px;border-style:solid}
|
138 |
+
.sucuriscan-maincontent td.sucuriscan-corefiles-warning code{font-size:12px;padding:0 5px}
|
139 |
+
.sucuriscan-maincontent .sucuriscan-integrity-message{position:relative}
|
140 |
+
.sucuriscan-maincontent .sucuriscan-integrity-message .sucuriscan-integrity-mark{position:absolute;top:1px;right:1px;background:#7ad03a;font-weight:bold;color:#fff;line-height:35px;padding:0 10px;border-left:1px solid #ddd}
|
141 |
+
/* Monitoring Styles */
|
142 |
+
.sucuriscan-monitoring-settings{margin-bottom:20px}
|
143 |
+
.sucuriscan-monitoring-settings td.td-with-button{text-align:left}
|
144 |
+
.sucuriscan-monitoring-settings .sucuriscan-list-as-table{margin:0}
|
145 |
+
.sucuriscan-monitoring-apikey-form .input-text{width:85%}
|
146 |
+
.sucuriscan-monitoring-clear-cache-form{}
|
147 |
+
.sucuriscan-monitoring-logs{}
|
148 |
+
.sucuriscan-monitoring-logs .thead-with-button .button{width:65px}
|
149 |
+
.sucuriscan-monitoring-logs .thead-with-button .input-text, .sucuriscan-monitoring-logs .thead-with-button select{width:250px}
|
150 |
+
.sucuriscan-monitoring-logs .sucuriscan-monitoring-search-form{}
|
151 |
+
.sucuriscan-monitoring-logs .sucuriscan-monitoring-denial-types-form{}
|
152 |
+
.sucuriscan-monitoring-logs .sucuriscan-monitoring-date-form{}
|
153 |
+
.sucuriscan-monitoring-logs .sucuriscan-monitoring-date-form select{width:70px}
|
154 |
+
.sucuriscan-monitoring-logs .sucuriscan-monitoring-date-form select + select{width:112px}
|
155 |
+
.sucuriscan-monitoring-logs .sucuriscan-monitoring-date-form select + select + select{width:60px}
|
156 |
+
.sucuriscan-monitoring-logs .sucuriscan-target-date{font-size:12px;color:#999;margin-right:5px}
|
157 |
+
/* Monitoring AccessLog Styles */
|
158 |
+
.sucuriscan-request-summary{margin:-15px;margin-top:-3px}
|
159 |
+
.sucuriscan-request-summary ul{margin:0}
|
160 |
+
.sucuriscan-request-summary label, .sucuriscan-request-summary span{display:inline-block;font-size:14px}
|
161 |
+
.sucuriscan-request-summary label{width:200px;font-weight:bold}
|
162 |
+
.sucuriscan-request-summary span{max-width:395px;font-family:monospace;vertical-align:top;word-break:break-all}
|
163 |
+
/* Hardening Status */
|
164 |
+
.sucuriscan-hstatus{position:relative;margin:0 -12px;padding:10px 12px;border:1px solid transparent}
|
165 |
+
.sucuriscan-hstatus-1{background-color:#dff0d8;color:#3c763d;border-color:#d6e9c6}
|
166 |
+
.sucuriscan-hstatus-0{background-color:#f2dede;color:#a94442;border-color:#ebccd1}
|
167 |
+
.sucuriscan-hstatus .button-primary, .sucuriscan-hstatus .button-secondary{position:absolute;top:5px;right:5px}
|
168 |
+
/* About Page */
|
169 |
+
.sucuriscan-about ul{margin-left:20px}
|
170 |
+
.sucuriscan-about ul li{list-style:initial}
|
171 |
+
.sucuriscan-about li label{font-weight:bold;vertical-align:initial}
|
172 |
+
/* API Registered Modal */
|
173 |
+
.sucuriscan-apikey-registered{}
|
174 |
+
.sucuriscan-apikey-registered .sucuriscan-pull-right{width:400px;margin-left:20px}
|
175 |
+
.sucuriscan-apikey-registered .sucuriscan-sitelogo{background-position:0 -17px;height:83px}
|
176 |
+
/* Resetter Styles */
|
177 |
+
.sucuriscan_wpconfig_keys_updated textarea{width:100%;height:250px;background:#f5f5f5;font-family:monospace;font-size:12px;resize:vertical;margin:20px 0 0 0}
|
178 |
+
.sucuriscan-maincontent .sucuriscan-last-logins{margin-top:0}
|
179 |
+
.sucuriscan-maincontent .sucuriscan-last-logins .sucuriscan-ellipsis{width:150px;line-height:inherit}
|
180 |
+
.sucuriscan-maincontent .sucuriscan-modifiedfiles .sucuriscan-ellipsis{width:100px}
|
181 |
.sucuriscan-maincontent .sucuriscan-full-textarea{width:100%;height:400px;line-height:normal;resize:vertical;padding:10px}
|
182 |
+
.sucuriscan-maincontent .sucuriscan-auditlogs{margin-bottom:0}
|
183 |
+
.sucuriscan-maincontent .sucuriscan-auditlogs td small{font-style:italic}
|
184 |
+
.sucuriscan-maincontent .sucuriscan-auditlogs .sucuriscan-maxper-page{text-align:right}
|
185 |
+
.sucuriscan-maincontent .sucuriscan-settings{margin-top:0}
|
186 |
+
.sucuriscan-maincontent .sucuriscan-settings form{display:inline-block}
|
187 |
+
.sucuriscan-maincontent .sucuriscan-settings select, .sucuriscan-maincontent .sucuriscan-settings .input-text{min-width:245px}
|
188 |
+
.sucuriscan-maincontent .sucuriscan-settings-notifications{margin-top:20px}
|
189 |
.sucuriscan-wpconfig-textarea{width:600px;height:525px;background:#f5f5f5;font-size:12px;line-height:1.4em;resize:none;margin:15px 0 0 0;padding:10px}
|
190 |
+
/* Responsive Styles */
|
191 |
+
@media (max-width: 620px) {
|
192 |
+
.sucuriscan-tabs > ul li, .sucuriscan-tabs > ul li > a{display:block}
|
193 |
+
.sucuriscan-getapi-form button.button-primary{line-height:40px}
|
194 |
+
}
|
195 |
+
@media (max-width: 768px) {
|
196 |
+
.sucuriscan-wrap .sucuriscan-leftside,
|
197 |
+
.sucuriscan-wrap .sucuriscan-sidebar,
|
198 |
+
.sucuriscan-wrap .sucuriscan-footer .sucuriscan-logo,
|
199 |
+
.sucuriscan-wrap .sucuriscan-footer .sucuriscan-help{float:none}
|
200 |
+
.sucuriscan-wrap .sucuriscan-leftside, .sucuriscan-wrap .sucuriscan-sidebar{width:100%}
|
201 |
+
.sucuriscan-wrap .sucuriscan-sidebar{margin-top:20px}
|
202 |
+
.sucuriscan-wrap .sucuriscan-footer .sucuriscan-logo{display:table;margin:0 auto}
|
203 |
+
}
|
204 |
+
@media (max-width: 920px) {
|
205 |
+
.sucuriscan-wrap .sucuriscan-navbar{padding-left:0;padding-right:0}
|
206 |
+
.sucuriscan-wrap .sucuriscan-navbar .nav-tab{display:block}
|
207 |
+
.sucuriscan-wrap .sucuriscan-navbar .nav-tab:last-child{border-bottom:1px solid #ccc}
|
208 |
+
}
|
209 |
/* Old styles */
|
210 |
.sucuriscan-maincontent #poststuff{min-width:initial;padding-top:0}
|
211 |
.sucuriscan-maincontent .widefat tbody th.check-column{padding:6px 0 3px 0}
|
212 |
.sucuriscan-maincontent .hardening-box .primary-secondary{margin:0 0 0 10px}
|
213 |
.sucuriscan-maincontent a.lastlogins-showall{display:inline-block;float:right}
|
|
|
|
|
|
|
|
|
|
|
|
|
214 |
.sucuri-inline-error{font-weight:bold;color:red}
|
|
|
215 |
.sucuriscan-maincontent .alternate{background:#f5f5f5}
|
216 |
.sucuriscan-maincontent hr{border:none;border-top:1px solid #999}
|
217 |
.sucuriscan-maincontent table td > table{background:#fff}
|
218 |
.sucuriscan-maincontent table td > table th{padding:4px 8px}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
inc/js/sucuriscan-scripts.js
CHANGED
@@ -5,7 +5,7 @@
|
|
5 |
*/
|
6 |
|
7 |
function sucuriscan_alert_close(id){
|
8 |
-
var element = document.getElementById('
|
9 |
element.parentNode.removeChild(element);
|
10 |
}
|
11 |
|
@@ -13,6 +13,7 @@ jQuery(document).ready(function($){
|
|
13 |
if( $('.sucuriscan-tabs').length ){
|
14 |
var hidden_class = 'sucuriscan-hidden';
|
15 |
var active_class = 'sucuriscan-tab-active';
|
|
|
16 |
|
17 |
$('.sucuriscan-tabs > ul a').on('click', function(e){
|
18 |
e.preventDefault();
|
@@ -30,6 +31,34 @@ jQuery(document).ready(function($){
|
|
30 |
});
|
31 |
|
32 |
$('.sucuriscan-tab-containers > div').addClass(hidden_class);
|
33 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
34 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
35 |
});
|
5 |
*/
|
6 |
|
7 |
function sucuriscan_alert_close(id){
|
8 |
+
var element = document.getElementById('sucuriscan-alert-'+id);
|
9 |
element.parentNode.removeChild(element);
|
10 |
}
|
11 |
|
13 |
if( $('.sucuriscan-tabs').length ){
|
14 |
var hidden_class = 'sucuriscan-hidden';
|
15 |
var active_class = 'sucuriscan-tab-active';
|
16 |
+
var anchor = location.href.split('#')[1];
|
17 |
|
18 |
$('.sucuriscan-tabs > ul a').on('click', function(e){
|
19 |
e.preventDefault();
|
31 |
});
|
32 |
|
33 |
$('.sucuriscan-tab-containers > div').addClass(hidden_class);
|
34 |
+
|
35 |
+
if( anchor != undefined ){
|
36 |
+
$('.sucuriscan-tabs > ul li a').each(function(i, el){
|
37 |
+
if( $(el).data('tabname') == anchor ){
|
38 |
+
$(el).trigger('click');
|
39 |
+
}
|
40 |
+
});
|
41 |
+
} else {
|
42 |
+
$('.sucuriscan-tabs > ul li:first-child a').trigger('click');
|
43 |
+
}
|
44 |
}
|
45 |
+
|
46 |
+
$('#sucuriscan-corefiles-show').on('click', function(e){
|
47 |
+
e.preventDefault();
|
48 |
+
|
49 |
+
var this_button = $(this);
|
50 |
+
var action = this_button.data('action');
|
51 |
+
|
52 |
+
if( action == 'show' ){
|
53 |
+
$('.sucuriscan-corefiles tbody > tr').removeClass('sucuriscan-hidden');
|
54 |
+
this_button.html('Hide files').data('action', 'hide');
|
55 |
+
} else {
|
56 |
+
$('.sucuriscan-corefiles tbody > tr').addClass('sucuriscan-hidden');
|
57 |
+
this_button.html('Show files').data('action', 'show');
|
58 |
+
}
|
59 |
+
});
|
60 |
+
|
61 |
+
$('#sucuriscan_last_days').on('change', function(){
|
62 |
+
$(this).closest('form').submit();
|
63 |
+
});
|
64 |
});
|
inc/tpl/about.html.tpl
DELETED
@@ -1,111 +0,0 @@
|
|
1 |
-
|
2 |
-
<div id="poststuff">
|
3 |
-
<div class="postbox">
|
4 |
-
<h3>About</h3>
|
5 |
-
<div class="inside">
|
6 |
-
<p>
|
7 |
-
Our WordPress Security Plugin will monitor your site from the inside, creating
|
8 |
-
a complete audit trail, alerting you of possible security issues (file changes,
|
9 |
-
password guessing attacks, etc) and blocking the attackers. This is the perfect
|
10 |
-
complement for our external security scans.
|
11 |
-
</p>
|
12 |
-
</div>
|
13 |
-
</div>
|
14 |
-
|
15 |
-
|
16 |
-
<div class="postbox">
|
17 |
-
<h3>How does it work?</h3>
|
18 |
-
<div class="inside">
|
19 |
-
<ul>
|
20 |
-
<li>Web Application Firewall. Block attacks before they reach your site.</li>
|
21 |
-
<li>Integrity Monitoring. Receive notifications if any of your files are modified.</li>
|
22 |
-
<li>Audit Logs. Keep track of everything that happens inside WordPress, including new users, posts, login failures and successful logins.</li>
|
23 |
-
<li>Activity Reporting</li>
|
24 |
-
<li>1-Click Hardening. Easy-to-use hardening options for your site.</li>
|
25 |
-
</ul>
|
26 |
-
</div>
|
27 |
-
</div>
|
28 |
-
|
29 |
-
|
30 |
-
<div class="postbox">
|
31 |
-
<h3>Web Application Firewall (WAF)</h3>
|
32 |
-
<div class="inside">
|
33 |
-
<p>
|
34 |
-
The WAF is a unique feature that is designed to intelligently protect your sites
|
35 |
-
from brute-force attacks like dictionary attacks and other similar unauthorized
|
36 |
-
access attempts. When a bad IP is identified it is blacklisted in your admin
|
37 |
-
dashboard. If it was an unintentional block, you have the ability to white-list
|
38 |
-
access to any IP.
|
39 |
-
</p>
|
40 |
-
<p>
|
41 |
-
The WAF is not tied to your application, it communicates with our servers and
|
42 |
-
allows us to see malicious attacks across the network. When one client gets attacked
|
43 |
-
by one bad IP in Croatia, we are able to push preventive measures to every plugin
|
44 |
-
to protect against that IP.
|
45 |
-
</p>
|
46 |
-
</div>
|
47 |
-
</div>
|
48 |
-
|
49 |
-
|
50 |
-
<div class="postbox">
|
51 |
-
<h3>Integrity Monitoring</h3>
|
52 |
-
<div class="inside">
|
53 |
-
<p>
|
54 |
-
This feature compares your core install against a clean version of core. In other
|
55 |
-
words, if it is not a 1-to-1 match with core you will be notified of a problem.
|
56 |
-
Future add-ons include:
|
57 |
-
</p>
|
58 |
-
<ul>
|
59 |
-
<li>Theme Integrity Checks</li>
|
60 |
-
<li>Plugin Integrity Checks</li>
|
61 |
-
<li>Third-party Integrity Checks</li>
|
62 |
-
</ul>
|
63 |
-
</div>
|
64 |
-
</div>
|
65 |
-
|
66 |
-
|
67 |
-
<div class="postbox">
|
68 |
-
<h3>Audit Trails</h3>
|
69 |
-
<div class="inside">
|
70 |
-
<p>
|
71 |
-
This feature is great for proactive webmasters who want to monitor their website
|
72 |
-
to ensure no unauthorized access or changes are made without prior approval.
|
73 |
-
Monitor your site for changes. This feature monitors for a large number of actions,
|
74 |
-
including:
|
75 |
-
</p>
|
76 |
-
<ul>
|
77 |
-
<li>Login attempts</li>
|
78 |
-
<li>New Posts</li>
|
79 |
-
<li>Failed Logins</li>
|
80 |
-
<li>New Plugins</li>
|
81 |
-
<li>File Changes</li>
|
82 |
-
<li>New Users</li>
|
83 |
-
<li>New Attachments</li>
|
84 |
-
<li>Delete Actions (users and posts)</li>
|
85 |
-
<li>Revisions</li>
|
86 |
-
</ul>
|
87 |
-
</div>
|
88 |
-
</div>
|
89 |
-
|
90 |
-
|
91 |
-
<div class="postbox">
|
92 |
-
<h3>1-Click Hardening</h3>
|
93 |
-
<div class="inside">
|
94 |
-
<p>
|
95 |
-
In our experience a high-percentage of the infections we see every day come from
|
96 |
-
poor management on the end-user’s part. This feature uses common hardening
|
97 |
-
measures that can be taken at any time and helps reduce infection risk. This
|
98 |
-
feature performs the following:
|
99 |
-
</p>
|
100 |
-
<ul>
|
101 |
-
<li>Checks software core version</li>
|
102 |
-
<li>Hides your version (security through obscurity)</li>
|
103 |
-
<li>Upload directory protected</li>
|
104 |
-
<li>Secret keys and salts created</li>
|
105 |
-
<li>Configuration file hardening/location verification</li>
|
106 |
-
<li>Hardening of readme file</li>
|
107 |
-
<li>PHP verification</li>
|
108 |
-
</ul>
|
109 |
-
</div>
|
110 |
-
</div>
|
111 |
-
</div><!-- End poststuff -->
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
inc/tpl/base.html.tpl
CHANGED
@@ -4,12 +4,16 @@
|
|
4 |
<h2 id="warnings_hook"></h2>
|
5 |
|
6 |
<div class="sucuriscan-header sucuriscan-clearfix">
|
7 |
-
<a href="http://sucuri.net/signup" target="_blank" title="Sucuri Security">
|
8 |
<img src="%%SUCURI.SucuriURL%%/inc/images/logo.png" alt="Sucuri Security" />
|
9 |
</a>
|
10 |
-
<h2>
|
11 |
</div>
|
12 |
|
|
|
|
|
|
|
|
|
13 |
<div class="sucuriscan-maincontent sucuriscan-clearfix">
|
14 |
|
15 |
<div class="sucuriscan-leftside sucuriscan-%%SUCURI.PageStyleClass%%">
|
@@ -23,12 +27,12 @@
|
|
23 |
<div class="sucuriscan-ad">
|
24 |
<h2>Is your website infected with malware? Blacklisted by Google?</h2>
|
25 |
<p>Don't know where to start? Get cleared today by <a href="http://sucuri.net/signup">Sucuri Security</a>!</p>
|
26 |
-
<p><a
|
27 |
</div>
|
28 |
|
29 |
<div class="sucuriscan-ad">
|
30 |
<h2>Preventive website security in the cloud!</h2>
|
31 |
-
<ul class="
|
32 |
<li>Web Application Firewall (WAF) Protection</li>
|
33 |
<li>Virtual Website Patching</li>
|
34 |
<li>Cloud Intrusion Prevention System (IPS)</li>
|
@@ -41,14 +45,14 @@
|
|
41 |
</p>
|
42 |
</div>
|
43 |
|
44 |
-
<iframe src="https://www.youtube-nocookie.com/embed/
|
45 |
|
46 |
</div>
|
47 |
|
48 |
</div>
|
49 |
|
50 |
<div class="sucuriscan-footer sucuriscan-clearfix">
|
51 |
-
<a href="http://sucuri.net/signup" target="_blank" title="Sucuri Security">
|
52 |
<img src="%%SUCURI.SucuriURL%%/inc/images/logo.png" alt="Sucuri Security" />
|
53 |
</a>
|
54 |
<div class="sucuriscan-help">
|
4 |
<h2 id="warnings_hook"></h2>
|
5 |
|
6 |
<div class="sucuriscan-header sucuriscan-clearfix">
|
7 |
+
<a href="http://sucuri.net/signup" target="_blank" title="Sucuri Security" class="sucuriscan-logo">
|
8 |
<img src="%%SUCURI.SucuriURL%%/inc/images/logo.png" alt="Sucuri Security" />
|
9 |
</a>
|
10 |
+
<h2>Sucuri Security %%SUCURI.PageTitle%%</h2>
|
11 |
</div>
|
12 |
|
13 |
+
<h2 class="nav-tab-wrapper sucuriscan-navbar">
|
14 |
+
%%SUCURI.Navbar%%
|
15 |
+
</h2>
|
16 |
+
|
17 |
<div class="sucuriscan-maincontent sucuriscan-clearfix">
|
18 |
|
19 |
<div class="sucuriscan-leftside sucuriscan-%%SUCURI.PageStyleClass%%">
|
27 |
<div class="sucuriscan-ad">
|
28 |
<h2>Is your website infected with malware? Blacklisted by Google?</h2>
|
29 |
<p>Don't know where to start? Get cleared today by <a href="http://sucuri.net/signup">Sucuri Security</a>!</p>
|
30 |
+
<p><a href="http://sucuri.net/tour" target="_blank" class="button-primary">Read more</a></p>
|
31 |
</div>
|
32 |
|
33 |
<div class="sucuriscan-ad">
|
34 |
<h2>Preventive website security in the cloud!</h2>
|
35 |
+
<ul class="sucuriscan-list">
|
36 |
<li>Web Application Firewall (WAF) Protection</li>
|
37 |
<li>Virtual Website Patching</li>
|
38 |
<li>Cloud Intrusion Prevention System (IPS)</li>
|
45 |
</p>
|
46 |
</div>
|
47 |
|
48 |
+
<iframe src="https://www.youtube-nocookie.com/embed/EVa9FY3nKuQ" height="250" class="sucuriscan-scanner-video" allowfullscreen></iframe>
|
49 |
|
50 |
</div>
|
51 |
|
52 |
</div>
|
53 |
|
54 |
<div class="sucuriscan-footer sucuriscan-clearfix">
|
55 |
+
<a href="http://sucuri.net/signup" target="_blank" title="Sucuri Security" class="sucuriscan-logo">
|
56 |
<img src="%%SUCURI.SucuriURL%%/inc/images/logo.png" alt="Sucuri Security" />
|
57 |
</a>
|
58 |
<div class="sucuriscan-help">
|
inc/tpl/infosys-cronjobs.snippet.tpl
CHANGED
@@ -1,3 +1,4 @@
|
|
|
|
1 |
<tr class="%%SUCURI.Cronjob.CssClass%%">
|
2 |
<td>%%SUCURI.Cronjob.Task%%</td>
|
3 |
<td>%%SUCURI.Cronjob.Schedule%%</td>
|
1 |
+
|
2 |
<tr class="%%SUCURI.Cronjob.CssClass%%">
|
3 |
<td>%%SUCURI.Cronjob.Task%%</td>
|
4 |
<td>%%SUCURI.Cronjob.Schedule%%</td>
|
inc/tpl/infosys-htaccess.html.tpl
CHANGED
@@ -1,7 +1,8 @@
|
|
1 |
|
2 |
-
<div id="poststuff" class="
|
3 |
<div class="postbox">
|
4 |
<h3>HTAccess Integrity</h3>
|
|
|
5 |
<div class="inside">
|
6 |
<p>
|
7 |
The <code>.htaccess</code> is a distributed configuration file, and is how Apache handles
|
@@ -10,7 +11,7 @@
|
|
10 |
modifies this file to be able to handle pretty permalinks.
|
11 |
</p>
|
12 |
|
13 |
-
<div class="
|
14 |
<p>%%SUCURI.HTAccess.Message%%</p>
|
15 |
</div>
|
16 |
|
1 |
|
2 |
+
<div id="poststuff" class="sucuriscan-infosys-htaccess">
|
3 |
<div class="postbox">
|
4 |
<h3>HTAccess Integrity</h3>
|
5 |
+
|
6 |
<div class="inside">
|
7 |
<p>
|
8 |
The <code>.htaccess</code> is a distributed configuration file, and is how Apache handles
|
11 |
modifies this file to be able to handle pretty permalinks.
|
12 |
</p>
|
13 |
|
14 |
+
<div class="sucuriscan-alert-%%SUCURI.HTAccess.MessageType%% %%SUCURI.HTAccess.MessageVisible%%">
|
15 |
<p>%%SUCURI.HTAccess.Message%%</p>
|
16 |
</div>
|
17 |
|
inc/tpl/infosys-loggedin.html.tpl
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
|
2 |
-
<table class="wp-list-table widefat
|
3 |
<thead>
|
4 |
<tr>
|
5 |
<th colspan="6">Logged in Users (%%SUCURI.LoggedInUsers.Total%% users)</th>
|
@@ -13,6 +13,7 @@
|
|
13 |
<th> </th>
|
14 |
</tr>
|
15 |
</thead>
|
|
|
16 |
<tbody>
|
17 |
%%SUCURI.LoggedInUsers.List%%
|
18 |
</tbody>
|
1 |
|
2 |
+
<table class="wp-list-table widefat sucuriscan-loggedin-users">
|
3 |
<thead>
|
4 |
<tr>
|
5 |
<th colspan="6">Logged in Users (%%SUCURI.LoggedInUsers.Total%% users)</th>
|
13 |
<th> </th>
|
14 |
</tr>
|
15 |
</thead>
|
16 |
+
|
17 |
<tbody>
|
18 |
%%SUCURI.LoggedInUsers.List%%
|
19 |
</tbody>
|
inc/tpl/infosys-serverinfo.html.tpl
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
|
2 |
-
<table class="wp-list-table widefat
|
3 |
<tbody>
|
4 |
<tr class="alternate">
|
5 |
<td>Sucuri Plugin version</td>
|
1 |
|
2 |
+
<table class="wp-list-table widefat sucuriscan-server-info">
|
3 |
<tbody>
|
4 |
<tr class="alternate">
|
5 |
<td>Sucuri Plugin version</td>
|
inc/tpl/infosys-wpconfig.html.tpl
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
|
2 |
-
<table class="wp-list-table widefat
|
3 |
<thead>
|
4 |
<th colspan="7" class="thead-with-button">
|
5 |
<span>WP-Config Variables</span>
|
@@ -12,6 +12,7 @@
|
|
12 |
<th>Value</th>
|
13 |
</tr>
|
14 |
</thead>
|
|
|
15 |
<tbody>
|
16 |
%%SUCURI.WordpressConfig.Rules%%
|
17 |
</tbody>
|
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>
|
12 |
<th>Value</th>
|
13 |
</tr>
|
14 |
</thead>
|
15 |
+
|
16 |
<tbody>
|
17 |
%%SUCURI.WordpressConfig.Rules%%
|
18 |
</tbody>
|
inc/tpl/initial-page.html.tpl
DELETED
@@ -1,97 +0,0 @@
|
|
1 |
-
|
2 |
-
<div id="poststuff">
|
3 |
-
|
4 |
-
<div class="postbox">
|
5 |
-
<h3>Sucuri SiteCheck</h3>
|
6 |
-
<div class="inside sucuriscan-clearfix">
|
7 |
-
<div class="sucuriscan-column-left">
|
8 |
-
<p>
|
9 |
-
<a href="http://sitecheck.sucuri.net/" target="_blank">Sucuri SiteCheck</a>
|
10 |
-
scanner will check your website for known malware, blacklisting status, website
|
11 |
-
errors, and out-of-date software.
|
12 |
-
</p>
|
13 |
-
</div>
|
14 |
-
<div class="sucuriscan-column-right">
|
15 |
-
<form method="post">
|
16 |
-
<input type="hidden" name="wpsucuri-doscan" value="wpsucuri-doscan" />
|
17 |
-
<input type="submit" name="wpsucuri_doscanrun" value="Scan this site now" class="button button-primary button-hero" />
|
18 |
-
</form>
|
19 |
-
</div>
|
20 |
-
</div>
|
21 |
-
<div class="sucuriscan-disclaimer">
|
22 |
-
<p>
|
23 |
-
<strong>Disclaimer</strong>: Sucuri SiteCheck is a free and remote scanner.
|
24 |
-
Although we do our best to provide the best results, 100% accuracy is not
|
25 |
-
realistic, and not guaranteed.
|
26 |
-
</p>
|
27 |
-
</div>
|
28 |
-
</div>
|
29 |
-
|
30 |
-
|
31 |
-
<div class="postbox">
|
32 |
-
<h3>1-Click Hardening</h3>
|
33 |
-
<div class="inside sucuriscan-clearfix">
|
34 |
-
<div class="sucuriscan-column-left">
|
35 |
-
<p>
|
36 |
-
In our experience a high-percentage of the infections we see every day come from
|
37 |
-
poor management on the end-user's part. This feature uses common hardening
|
38 |
-
measures that can be taken at any time and helps reduce infection risk.
|
39 |
-
</p>
|
40 |
-
</div>
|
41 |
-
<div class="sucuriscan-column-right">
|
42 |
-
<a href="%%SUCURI.URL.Hardening%%" class="button button-primary button-hero">Harden this site now</a>
|
43 |
-
</div>
|
44 |
-
</div>
|
45 |
-
</div>
|
46 |
-
|
47 |
-
|
48 |
-
<div class="postbox">
|
49 |
-
<h3>WordPress Integrity</h3>
|
50 |
-
<div class="inside sucuriscan-clearfix">
|
51 |
-
<div class="sucuriscan-column-left">
|
52 |
-
<p>
|
53 |
-
This feature compares your core install against a clean version of core. In
|
54 |
-
other words, if it is not a 1-to-1 match with core you will be notified of a
|
55 |
-
problem.
|
56 |
-
</p>
|
57 |
-
</div>
|
58 |
-
<div class="sucuriscan-column-right">
|
59 |
-
<a href="%%SUCURI.URL.CoreIntegrity%%" class="button button-primary button-hero">Check site integrity now</a>
|
60 |
-
</div>
|
61 |
-
</div>
|
62 |
-
</div>
|
63 |
-
|
64 |
-
|
65 |
-
<div class="postbox">
|
66 |
-
<h3>Post-Hack</h3>
|
67 |
-
<div class="inside sucuriscan-clearfix">
|
68 |
-
<div class="sucuriscan-column-left">
|
69 |
-
<p>
|
70 |
-
After being hacked or infected with malware, we recommend that you update your
|
71 |
-
wp-config keys, and also reset all your user passwords. Do it with ease using
|
72 |
-
Sucuri Post-Hack.
|
73 |
-
</p>
|
74 |
-
</div>
|
75 |
-
<div class="sucuriscan-column-right">
|
76 |
-
<a href="%%SUCURI.URL.PostHack%%" class="button button-primary button-hero">Run Post-Hack resets</a>
|
77 |
-
</div>
|
78 |
-
</div>
|
79 |
-
</div>
|
80 |
-
|
81 |
-
|
82 |
-
<div class="postbox">
|
83 |
-
<h3>Last Logins</h3>
|
84 |
-
<div class="inside sucuriscan-clearfix">
|
85 |
-
<div class="sucuriscan-column-left">
|
86 |
-
<p>
|
87 |
-
It's always good to know who is logging into your site. This feature allows you
|
88 |
-
to view logins, where they came from, and when they logged in.
|
89 |
-
</p>
|
90 |
-
</div>
|
91 |
-
<div class="sucuriscan-column-right">
|
92 |
-
<a href="%%SUCURI.URL.LastLogins%%" class="button button-primary button-hero">View Last Logins</a>
|
93 |
-
</div>
|
94 |
-
</div>
|
95 |
-
</div>
|
96 |
-
|
97 |
-
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
inc/tpl/integrity-admins-lastlogin.snippet.tpl
DELETED
@@ -1,4 +0,0 @@
|
|
1 |
-
<tr>
|
2 |
-
<td>%%SUCURI.AdminUsers.RemoteAddr%%</td>
|
3 |
-
<td>%%SUCURI.AdminUsers.Datetime%%</td>
|
4 |
-
</tr>
|
|
|
|
|
|
|
|
inc/tpl/integrity-auditlogs.html.tpl
ADDED
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
<table class="wp-list-table widefat sucuriscan-table sucuriscan-table-double-title sucuriscan-auditlogs">
|
3 |
+
<thead>
|
4 |
+
<tr>
|
5 |
+
<th colspan="2" class="thead-with-button">
|
6 |
+
<span>Audit Logs (%%SUCURI.AuditLogs.Count%% logs)</span>
|
7 |
+
<form action="%%SUCURI.URL.Home%%" method="post" class="thead-topright-action">
|
8 |
+
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
|
9 |
+
<button type="submit" name="sucuriscan_force_scan" class="button-primary">Force Scan</button>
|
10 |
+
</form>
|
11 |
+
</th>
|
12 |
+
</tr>
|
13 |
+
<tr>
|
14 |
+
<th width="150">Date & Time</th>
|
15 |
+
<th>Event & Message</th>
|
16 |
+
</tr>
|
17 |
+
</thead>
|
18 |
+
|
19 |
+
<tbody>
|
20 |
+
%%SUCURI.AuditLogs.List%%
|
21 |
+
|
22 |
+
<tr class="sucuriscan-%%SUCURI.AuditLogs.MaxItemsVisibility%%">
|
23 |
+
<td colspan="2">
|
24 |
+
<div class="sucuriscan-maxper-page">
|
25 |
+
Showing <b>%%SUCURI.AuditLogs.MaxPerPage%%</b> out of <b>%%SUCURI.AuditLogs.Count%%</b>
|
26 |
+
-
|
27 |
+
<a href="%%SUCURI.URL.Core_integrity%%&show_all=1">Show all</a>
|
28 |
+
</div>
|
29 |
+
</td>
|
30 |
+
</tr>
|
31 |
+
|
32 |
+
<tr class="sucuriscan-%%SUCURI.AuditLogs.NoItemsVisibility%%">
|
33 |
+
<td colspan="2">
|
34 |
+
<em>No logs so far.</em>
|
35 |
+
</td>
|
36 |
+
</tr>
|
37 |
+
</tbody>
|
38 |
+
</table>
|
inc/tpl/integrity-auditlogs.snippet.tpl
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
<tr class="%%SUCURI.AuditLog.CssClass%%">
|
3 |
+
<td>%%SUCURI.AuditLog.DateTime%%</td>
|
4 |
+
<td>
|
5 |
+
<span class="sucuriscan-monospace">%%SUCURI.AuditLog.Message%%</span>
|
6 |
+
|
7 |
+
%%SUCURI.AuditLog.Extra%%
|
8 |
+
</td>
|
9 |
+
</tr>
|
inc/tpl/integrity-corefiles.html.tpl
ADDED
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
<div class="postbox sucuriscan-border sucuriscan-border-good sucuriscan-integrity-message sucuriscan-%%SUCURI.CoreFiles.GoodVisibility%%">
|
3 |
+
<span class="sucuriscan-integrity-mark">OK</span>
|
4 |
+
<h3>WordPress core integrity</h3>
|
5 |
+
|
6 |
+
<div class="inside">
|
7 |
+
<p>Your WordPress core files are clean and were not modified.</p>
|
8 |
+
</div>
|
9 |
+
</div>
|
10 |
+
|
11 |
+
<table class="wp-list-table widefat sucuriscan-table sucuriscan-corefiles sucuriscan-%%SUCURI.CoreFiles.BadVisibility%%">
|
12 |
+
<thead>
|
13 |
+
<tr>
|
14 |
+
<th class="sucuriscan-clearfix thead-with-button">
|
15 |
+
<span>WordPress core integrity (%%SUCURI.CoreFiles.ListCount%% files)</span>
|
16 |
+
<div class="sucuriscan-pull-right sucuriscan-corefiles-abbrs">
|
17 |
+
<span class="sucuriscan-status-type sucuriscan-status-added">Added</span>
|
18 |
+
<span class="sucuriscan-status-type sucuriscan-status-modified">Modified</span>
|
19 |
+
<span class="sucuriscan-status-type sucuriscan-status-removed">Removed</span>
|
20 |
+
<button id="sucuriscan-corefiles-show" class="button button-primary thead-topright-action" data-action="show">Show files</button>
|
21 |
+
</div>
|
22 |
+
</th>
|
23 |
+
</tr>
|
24 |
+
|
25 |
+
<tr>
|
26 |
+
<td class="sucuriscan-corefiles-warning">
|
27 |
+
<div>
|
28 |
+
<p>
|
29 |
+
We detected changes in the integrity of your WordPress core files. There are files that
|
30 |
+
were added, modified, and/or removed in the core directories <code>/<root></code>,
|
31 |
+
<code>/wp-admin</code> and/or <code>/wp-includes</code>.
|
32 |
+
</p>
|
33 |
+
</div>
|
34 |
+
</td>
|
35 |
+
</tr>
|
36 |
+
</thead>
|
37 |
+
|
38 |
+
<tbody>
|
39 |
+
|
40 |
+
%%SUCURI.CoreFiles.List%%
|
41 |
+
</tbody>
|
42 |
+
</table>
|
inc/tpl/integrity-corefiles.snippet.tpl
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
<tr class="%%SUCURI.CoreFiles.CssClass%% sucuriscan-hidden">
|
3 |
+
<td>
|
4 |
+
<div class="sucuriscan-clearfix">
|
5 |
+
<div class="sucuriscan-pull-left sucuriscan-status-type sucuriscan-status-%%SUCURI.CoreFiles.StatusType%%">%%SUCURI.CoreFiles.StatusAbbr%%</div>
|
6 |
+
<div class="sucuriscan-pull-left sucuriscan-monospace">%%SUCURI.CoreFiles.FilePath%%</div>
|
7 |
+
</div>
|
8 |
+
</td>
|
9 |
+
</tr>
|
inc/tpl/integrity-modifiedfiles.html.tpl
ADDED
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
<table class="wp-list-table widefat sucuriscan-table sucuriscan-table-double-title sucuriscan-modifiedfiles">
|
3 |
+
<thead>
|
4 |
+
<tr>
|
5 |
+
<th colspan="3" class="thead-with-button">
|
6 |
+
<span>Modified files <em>(inside the content directory)</em></span>
|
7 |
+
|
8 |
+
<form action="%%SUCURI.CurrentURL%%#modified-files" method="post" class="thead-topright-action">
|
9 |
+
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
|
10 |
+
<label>
|
11 |
+
Modified in the last
|
12 |
+
<select name="sucuriscan_last_days" id="sucuriscan_last_days">
|
13 |
+
%%SUCURI.ModifiedFiles.SelectOptions%%
|
14 |
+
</select>
|
15 |
+
days
|
16 |
+
</label>
|
17 |
+
|
18 |
+
<!-- This field was added to give backward compatibility with the SiteCheck form. -->
|
19 |
+
<input type="hidden" name="sucuriscan_malware_scan" value="1" />
|
20 |
+
</form>
|
21 |
+
</th>
|
22 |
+
</tr>
|
23 |
+
|
24 |
+
<tr>
|
25 |
+
<th width="540">Filepath</th>
|
26 |
+
<th>CheckSum</th>
|
27 |
+
<th width="160">Modification</th>
|
28 |
+
</tr>
|
29 |
+
</thead>
|
30 |
+
|
31 |
+
<tbody>
|
32 |
+
%%SUCURI.ModifiedFiles.List%%
|
33 |
+
|
34 |
+
<tr class="sucuriscan-%%SUCURI.ModifiedFiles.NoFilesVisibility%%">
|
35 |
+
<td colspan="3">
|
36 |
+
<em>No files modified in the last %%SUCURI.ModifiedFiles.Days%% days</em>
|
37 |
+
</td>
|
38 |
+
</tr>
|
39 |
+
</tbody>
|
40 |
+
</table>
|
inc/tpl/integrity-modifiedfiles.snippet.tpl
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
<tr class="sucuriscan-wraptext %%SUCURI.ModifiedFiles.CssClass%%">
|
3 |
+
<td><span class="sucuriscan-monospace">%%SUCURI.ModifiedFiles.FilePath%%</span></td>
|
4 |
+
<td><span class="sucuriscan-monospace sucuriscan-ellipsis" title="%%SUCURI.ModifiedFiles.CheckSum%%">%%SUCURI.ModifiedFiles.CheckSum%%</span></td>
|
5 |
+
<td>%%SUCURI.ModifiedFiles.DateTime%%</td>
|
6 |
+
</tr>
|
inc/tpl/integrity-wpoutdate.html.tpl
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
<div class="postbox sucuriscan-wordpress-outdated sucuriscan-border sucuriscan-border-bad sucuriscan-%%SUCURI.WordPress.UpdateVisibility%%">
|
3 |
+
<h3>WordPress version outdated</h3>
|
4 |
+
|
5 |
+
<div class="inside">
|
6 |
+
<p>
|
7 |
+
The current version of your site was detected as
|
8 |
+
<code>%%SUCURI.WordPress.Version%%</code> which is different to the official
|
9 |
+
latest version. The integrity check can not run using this version number
|
10 |
+
<a href="%%SUCURI.WordPress.UpgradeURL%%" target="_blank">update now</a> to
|
11 |
+
be able to run the integrity check.
|
12 |
+
</p>
|
13 |
+
</div>
|
14 |
+
</div>
|
inc/tpl/integrity.html.tpl
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
<div id="poststuff">
|
3 |
+
|
4 |
+
%%SUCURI.WordpressVersion%%
|
5 |
+
|
6 |
+
%%SUCURI.CoreFiles%%
|
7 |
+
|
8 |
+
%%SUCURI.AuditLogs%%
|
9 |
+
|
10 |
+
</div>
|
inc/tpl/lastlogins-admins-lastlogin.snippet.tpl
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
<tr class="%%SUCURI.AdminUsers.CssClass%%">
|
3 |
+
<td><span class="sucuriscan-monospace">%%SUCURI.AdminUsers.RemoteAddr%%</span></td>
|
4 |
+
<td><span class="sucuriscan-monospace">%%SUCURI.AdminUsers.Datetime%%</span></td>
|
5 |
+
</tr>
|
inc/tpl/{integrity-admins.html.tpl → lastlogins-admins.html.tpl}
RENAMED
@@ -1,8 +1,6 @@
|
|
1 |
-
|
|
|
2 |
<thead>
|
3 |
-
<tr>
|
4 |
-
<th colspan="4">Administrator Users</th>
|
5 |
-
</tr>
|
6 |
<tr>
|
7 |
<th class="manage-column">Username</th>
|
8 |
<th class="manage-column">Email</th>
|
@@ -12,6 +10,6 @@
|
|
12 |
</thead>
|
13 |
|
14 |
<tbody>
|
15 |
-
%%SUCURI.AdminUsers.
|
16 |
</tbody>
|
17 |
</table>
|
1 |
+
|
2 |
+
<table class="wp-list-table widefat sucuriscan-table sucuriscan-table-double-title sucuriscan-adminusers">
|
3 |
<thead>
|
|
|
|
|
|
|
4 |
<tr>
|
5 |
<th class="manage-column">Username</th>
|
6 |
<th class="manage-column">Email</th>
|
10 |
</thead>
|
11 |
|
12 |
<tbody>
|
13 |
+
%%SUCURI.AdminUsers.List%%
|
14 |
</tbody>
|
15 |
</table>
|
inc/tpl/{integrity-admins.snippet.tpl → lastlogins-admins.snippet.tpl}
RENAMED
@@ -1,12 +1,13 @@
|
|
|
|
1 |
<tr>
|
2 |
<td>%%SUCURI.AdminUsers.Username%%</td>
|
3 |
<td><a href="mailto:%%SUCURI.AdminUsers.Email%%">%%SUCURI.AdminUsers.Email%%</a></td>
|
4 |
<td class="adminusers-lastlogin">
|
5 |
-
<div class="
|
6 |
<i>There isn't information available for this account.</i>
|
7 |
</div>
|
8 |
|
9 |
-
<table class="widefat
|
10 |
<thead>
|
11 |
<tr>
|
12 |
<th>IP Address</th>
|
1 |
+
|
2 |
<tr>
|
3 |
<td>%%SUCURI.AdminUsers.Username%%</td>
|
4 |
<td><a href="mailto:%%SUCURI.AdminUsers.Email%%">%%SUCURI.AdminUsers.Email%%</a></td>
|
5 |
<td class="adminusers-lastlogin">
|
6 |
+
<div class="sucuriscan-%%SUCURI.AdminUsers.NoLastLogins%%">
|
7 |
<i>There isn't information available for this account.</i>
|
8 |
</div>
|
9 |
|
10 |
+
<table class="widefat sucuriscan-%%SUCURI.AdminUsers.NoLastLoginsTable%%">
|
11 |
<thead>
|
12 |
<tr>
|
13 |
<th>IP Address</th>
|
inc/tpl/lastlogins-all.html.tpl
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
<table class="wp-list-table widefat sucuriscan-table sucuriscan-table-double-title sucuriscan-last-logins">
|
3 |
+
<thead>
|
4 |
+
<tr>
|
5 |
+
<th colspan="6" class="thead-with-button">
|
6 |
+
<span>User logins (latest %%SUCURI.UserListLimit%%, newest to oldest)</span>
|
7 |
+
<a href="%%SUCURI.CurrentURL%%&limit=0" class="button button-primary lastlogins-showall thead-topright-action sucuriscan-%%SUCURI.UserList.ShowAll%%">Show all results</a>
|
8 |
+
</th>
|
9 |
+
</tr>
|
10 |
+
<tr>
|
11 |
+
<th class="manage-column">No.</th>
|
12 |
+
<th class="manage-column">User</th>
|
13 |
+
<th class="manage-column">IP Address</th>
|
14 |
+
<th class="manage-column">Hostname</th>
|
15 |
+
<th class="manage-column">Date/Time</th>
|
16 |
+
<th class="manage-column"> </th>
|
17 |
+
</tr>
|
18 |
+
</thead>
|
19 |
+
|
20 |
+
<tbody>
|
21 |
+
%%SUCURI.UserList%%
|
22 |
+
</tbody>
|
23 |
+
</table>
|
inc/tpl/{lastlogins.snippet.tpl → lastlogins-all.snippet.tpl}
RENAMED
File without changes
|
inc/tpl/lastlogins.html.tpl
CHANGED
@@ -1,23 +1,21 @@
|
|
1 |
|
2 |
-
<
|
3 |
-
<
|
4 |
-
<
|
5 |
-
<
|
6 |
-
|
7 |
-
|
8 |
-
</
|
9 |
-
</
|
10 |
-
|
11 |
-
<th class="manage-column">No.</th>
|
12 |
-
<th class="manage-column">User</th>
|
13 |
-
<th class="manage-column">IP Address</th>
|
14 |
-
<th class="manage-column">Hostname</th>
|
15 |
-
<th class="manage-column">Date/Time</th>
|
16 |
-
<th class="manage-column"> </th>
|
17 |
-
</tr>
|
18 |
-
</thead>
|
19 |
|
20 |
-
<
|
21 |
-
|
22 |
-
|
23 |
-
</
|
|
|
|
|
|
|
|
|
|
|
|
1 |
|
2 |
+
<div class="sucuriscan-tabs">
|
3 |
+
<ul>
|
4 |
+
<li>
|
5 |
+
<a href="#" data-tabname="lastlogins-allusers">All Users</a>
|
6 |
+
</li>
|
7 |
+
<li>
|
8 |
+
<a href="#" data-tabname="lastlogins-admins">Admin Users</a>
|
9 |
+
</li>
|
10 |
+
</ul>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
11 |
|
12 |
+
<div class="sucuriscan-tab-containers">
|
13 |
+
<div id="sucuriscan-lastlogins-allusers">
|
14 |
+
%%SUCURI.LastLogins.AllUsers%%
|
15 |
+
</div>
|
16 |
+
|
17 |
+
<div id="sucuriscan-lastlogins-admins">
|
18 |
+
%%SUCURI.LastLogins.Admins%%
|
19 |
+
</div>
|
20 |
+
</div>
|
21 |
+
</div>
|
inc/tpl/malwarescan.html.tpl
ADDED
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
<div class="sucuriscan-loading">
|
3 |
+
<h3 class="title">Website Security Scans by Sucuri Sitecheck</h3>
|
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 |
+
<p><img src="http://sitecheck.sucuri.net/images/loading.gif" alt="Loading..." /></p>
|
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 |
+
<script type="text/javascript">setTimeout(function(){ document.forms.sucuriscan_sitecheck_form.submit() }, 3000)</script>
|
17 |
+
</div>
|
inc/tpl/modalwindow.html.tpl
ADDED
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
<div class="sucuriscan-overlay"></div>
|
3 |
+
|
4 |
+
<div class="sucuriscan-modal">
|
5 |
+
<div class="sucuriscan-modal-outside %%SUCURI.CssClass%%">
|
6 |
+
|
7 |
+
<div class="sucuriscan-modal-header">
|
8 |
+
<a href="#" class="sucuriscan-modal-close">×</a>
|
9 |
+
<h3 class="sucuriscan-modal-title">%%SUCURI.Title%%</h3>
|
10 |
+
</div>
|
11 |
+
|
12 |
+
<div class="sucuriscan-modal-inside">
|
13 |
+
%%SUCURI.Content%%
|
14 |
+
</div>
|
15 |
+
|
16 |
+
</div>
|
17 |
+
</div>
|
18 |
+
|
19 |
+
<script type="text/javascript">
|
20 |
+
jQuery(function($){
|
21 |
+
$('.sucuriscan-overlay, .sucuriscan-modal-close').on('click', function(e){
|
22 |
+
e.preventDefault();
|
23 |
+
$('.sucuriscan-overlay, .sucuriscan-modal').remove();
|
24 |
+
});
|
25 |
+
});
|
26 |
+
</script>
|
inc/tpl/monitoring-logs.html.tpl
ADDED
@@ -0,0 +1,74 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
<table class="wp-list-table widefat sucuriscan-table sucuriscan-table-quad-title sucuriscan-monitoring-logs">
|
3 |
+
<thead>
|
4 |
+
<tr>
|
5 |
+
<th colspan="4" class="thead-with-button">
|
6 |
+
<span>Search among the logs:</span>
|
7 |
+
<div class="thead-topright-action">
|
8 |
+
<form action="%%SUCURI.URL.Monitoring%%#monitoring-logs" method="post" class="sucuriscan-monitoring-search-form">
|
9 |
+
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
|
10 |
+
<input type="text" name="sucuriscan_monitoring_log_filter" class="input-text" />
|
11 |
+
<input type="submit" value="Search" class="button button-primary" />
|
12 |
+
</form>
|
13 |
+
</div>
|
14 |
+
</th>
|
15 |
+
</tr>
|
16 |
+
|
17 |
+
<tr>
|
18 |
+
<th colspan="4" class="thead-with-button">
|
19 |
+
<span>Filter by the denial type:</span>
|
20 |
+
<div class="thead-topright-action">
|
21 |
+
<form action="%%SUCURI.URL.Monitoring%%#monitoring-logs" method="post" class="sucuriscan-monitoring-denial-types-form">
|
22 |
+
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
|
23 |
+
<select name="sucuriscan_monitoring_denial_type">%%SUCURI.AuditLogs.DenialTypeOptions%%</select>
|
24 |
+
<input type="submit" value="Filter" class="button button-primary" />
|
25 |
+
</form>
|
26 |
+
</div>
|
27 |
+
</th>
|
28 |
+
</tr>
|
29 |
+
|
30 |
+
<tr>
|
31 |
+
<th colspan="4" class="thead-with-button">
|
32 |
+
<span>Filter by date:</span>
|
33 |
+
<div class="thead-topright-action">
|
34 |
+
<form action="%%SUCURI.URL.Monitoring%%#monitoring-logs" method="post" class="sucuriscan-monitoring-date-form">
|
35 |
+
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
|
36 |
+
<input type="hidden" name="sucuriscan_monitoring_date" value="1" />
|
37 |
+
<em class="sucuriscan-target-date">(%%SUCURI.AuditLogs.TargetDate%%)</em>
|
38 |
+
<select name="sucuriscan_year">%%SUCURI.AuditLogs.DateYears%%</select>
|
39 |
+
<select name="sucuriscan_month">%%SUCURI.AuditLogs.DateMonths%%</select>
|
40 |
+
<select name="sucuriscan_day">%%SUCURI.AuditLogs.DateDays%%</select>
|
41 |
+
<input type="submit" value="Filter" class="button button-primary" />
|
42 |
+
</form>
|
43 |
+
</div>
|
44 |
+
</th>
|
45 |
+
</tr>
|
46 |
+
|
47 |
+
<tr>
|
48 |
+
<th>Denial Type</th>
|
49 |
+
<th>Time</th>
|
50 |
+
<th>Remote Address</th>
|
51 |
+
<th>Request Path</th>
|
52 |
+
</tr>
|
53 |
+
</thead>
|
54 |
+
|
55 |
+
<tbody>
|
56 |
+
%%SUCURI.AuditLogs.List%%
|
57 |
+
|
58 |
+
<tr class="sucuriscan-%%SUCURI.AuditLogs.NoItemsVisibility%%">
|
59 |
+
<td colspan="4">
|
60 |
+
<em>Audit trails is empty.</em>
|
61 |
+
</td>
|
62 |
+
</tr>
|
63 |
+
</tbody>
|
64 |
+
|
65 |
+
<tfoot>
|
66 |
+
<tr class="sucuriscan-%%SUCURI.AuditLogs.PaginationVisibility%%">
|
67 |
+
<td colspan="4">
|
68 |
+
<div class='pagination' style="float:right;">
|
69 |
+
%%SUCURI.AuditLogs.AuditPagination%%
|
70 |
+
</div>
|
71 |
+
</td>
|
72 |
+
</tr>
|
73 |
+
</tfoot>
|
74 |
+
</table>
|
inc/tpl/monitoring-logs.snippet.tpl
ADDED
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
<tr class="%%SUCURI.AuditLog.CssClass%%">
|
3 |
+
<td>%%SUCURI.AuditLog.SucuriBlockReason%%</td>
|
4 |
+
<td>
|
5 |
+
<span class="sucuriscan-monospace" title="%%SUCURI.AuditLog.RequestDate%% %%SUCURI.AuditLog.RequestTime%% %%SUCURI.AuditLog.RequestTimezone%%">
|
6 |
+
%%SUCURI.AuditLog.RequestTime%% %%SUCURI.AuditLog.RequestTimezone%%
|
7 |
+
</span>
|
8 |
+
</td>
|
9 |
+
<td><span class="sucuriscan-monospace">%%SUCURI.AuditLog.RemoteAddr%%</span></td>
|
10 |
+
<td>
|
11 |
+
<div class="sucuriscan-wraptext">
|
12 |
+
<a href="#TB_inline?width=600&height=300&inlineId=sucuriscan-reqsummary-%%SUCURI.AuditLog.Id%%" title="Access Log Summary" class="thickbox">
|
13 |
+
<span class="sucuriscan-monospace">%%SUCURI.AuditLog.ResourcePath%%</span>
|
14 |
+
</a>
|
15 |
+
</div>
|
16 |
+
|
17 |
+
<div id="sucuriscan-reqsummary-%%SUCURI.AuditLog.Id%%" style="display:none">
|
18 |
+
<div class="sucuriscan-request-summary">
|
19 |
+
<ul class="sucuriscan-list-as-table">
|
20 |
+
<li>
|
21 |
+
<label>Blocked Reason:</label>
|
22 |
+
<span>%%SUCURI.AuditLog.SucuriBlockReason%%</span>
|
23 |
+
</li>
|
24 |
+
<li>
|
25 |
+
<label>Remote Address:</label>
|
26 |
+
<span>%%SUCURI.AuditLog.RemoteAddr%%</span>
|
27 |
+
</li>
|
28 |
+
<li>
|
29 |
+
<label>Date/Time (Timezone)</label>
|
30 |
+
<span>%%SUCURI.AuditLog.RequestDate%% %%SUCURI.AuditLog.RequestTime%% (%%SUCURI.AuditLog.RequestTimezone%%)</span>
|
31 |
+
</li>
|
32 |
+
<li>
|
33 |
+
<label>Resource Path:</label>
|
34 |
+
<span>%%SUCURI.AuditLog.ResourcePath%%</span>
|
35 |
+
</li>
|
36 |
+
<li>
|
37 |
+
<label>Request Method:</label>
|
38 |
+
<span>%%SUCURI.AuditLog.RequestMethod%%</span>
|
39 |
+
</li>
|
40 |
+
<li>
|
41 |
+
<label>HTTP Protocol:</label>
|
42 |
+
<span>%%SUCURI.AuditLog.HttpProtocol%%</span>
|
43 |
+
</li>
|
44 |
+
<li>
|
45 |
+
<label>HTTP Status:</label>
|
46 |
+
<span>%%SUCURI.AuditLog.HttpStatus%% %%SUCURI.AuditLog.HttpStatusTitle%%</span>
|
47 |
+
</li>
|
48 |
+
<li>
|
49 |
+
<label>HTTP Bytes Sent:</label>
|
50 |
+
<span>%%SUCURI.AuditLog.HttpBytesSent%%</span>
|
51 |
+
</li>
|
52 |
+
<li>
|
53 |
+
<label>HTTP Referer:</label>
|
54 |
+
<span>%%SUCURI.AuditLog.HttpReferer%%</span>
|
55 |
+
</li>
|
56 |
+
<li>
|
57 |
+
<label>HTTP User Agent:</label>
|
58 |
+
<span>%%SUCURI.AuditLog.HttpUserAgent%%</span>
|
59 |
+
</li>
|
60 |
+
</ul>
|
61 |
+
</div>
|
62 |
+
</div>
|
63 |
+
</td>
|
64 |
+
</tr>
|
inc/tpl/monitoring-settings.html.tpl
ADDED
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
<table class="wp-list-table widefat sucuriscan-table sucuriscan-monitoring-settings">
|
3 |
+
<tbody>
|
4 |
+
<tr>
|
5 |
+
<td width="200"><label>CloudProxy API key</label></td>
|
6 |
+
<td class="td-with-button">
|
7 |
+
<form method="post" class="sucuriscan-monitoring-apikey-form">
|
8 |
+
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
|
9 |
+
<input type="text" name="sucuriscan_cloudproxy_apikey" value="%%SUCURI.Monitoring.APIKey%%" class="input-text" />
|
10 |
+
<input type="submit" value="Save" class="button button-primary" />
|
11 |
+
</form>
|
12 |
+
</td>
|
13 |
+
</tr>
|
14 |
+
|
15 |
+
%%SUCURI.Monitoring.SettingOptions%%
|
16 |
+
|
17 |
+
<tr class="alternate sucuriscan-%%SUCURI.Monitoring.SettingsVisibility%%">
|
18 |
+
<td><label>Clear cache</label></td>
|
19 |
+
<td class="td-with-button">
|
20 |
+
<form method="post" class="sucuriscan-monitoring-clear-cache-form">
|
21 |
+
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
|
22 |
+
<input type="hidden" name="sucuriscan_clear_cache" value="1" />
|
23 |
+
<input type="submit" value="Clear Cache" class="button button-primary" />
|
24 |
+
</form>
|
25 |
+
</td>
|
26 |
+
</tr>
|
27 |
+
</tbody>
|
28 |
+
</table>
|
inc/tpl/monitoring-settings.snippet.tpl
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
<tr class="%%SUCURI.Monitoring.OptionCssClass%%">
|
3 |
+
<td><label>%%SUCURI.Monitoring.OptionName%%</label></td>
|
4 |
+
<td><span class="sucuriscan-monospace">%%SUCURI.Monitoring.OptionValue%%</span></td>
|
5 |
+
</tr>
|
inc/tpl/monitoring.html.tpl
ADDED
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
<div id="poststuff">
|
3 |
+
|
4 |
+
<div class="postbox sucuriscan-monitoring-instructions sucuriscan-%%SUCURI.Monitoring.InstructionsVisibility%%">
|
5 |
+
<h3>Instructions to enable CloudProxy WAF</h3>
|
6 |
+
|
7 |
+
<div class="inside">
|
8 |
+
<p>
|
9 |
+
A powerful <b>WAF</b> <em>(Web Application Firewall)</em> and <b>Intrusion Prevention</b>
|
10 |
+
system for any WordPress user. If you do not have an account, you can sign up for one here:
|
11 |
+
<a href="http://cloudproxy.sucuri.net/" target="_blank">Sucuri CloudProxy</a>
|
12 |
+
</p>
|
13 |
+
|
14 |
+
<ol>
|
15 |
+
<li>
|
16 |
+
Sign up for a Sucuri CloudProxy account here:
|
17 |
+
<a href="https://login.sucuri.net/signup2/create?CloudProxy" target="_blank">Sign up</a>
|
18 |
+
</li>
|
19 |
+
<li>
|
20 |
+
Change your DNS to point your site to one of our servers. This link explains
|
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 |
+
Once enabled, our firewall will act as a shield, protecting your site from attacks
|
30 |
+
and preventing malware infections and reinfections. It will block SQL injection attempts,
|
31 |
+
brute force attacks, XSS, RFI, backdoors and many other threats against your site.
|
32 |
+
</p>
|
33 |
+
</div>
|
34 |
+
</div>
|
35 |
+
|
36 |
+
|
37 |
+
<div class="sucuriscan-tabs">
|
38 |
+
<ul>
|
39 |
+
<li>
|
40 |
+
<a href="#" data-tabname="monitoring-settings">Firewall (WAF) Settings</a>
|
41 |
+
</li>
|
42 |
+
<li>
|
43 |
+
<a href="#" data-tabname="monitoring-logs">Firewall (WAF) Logs</a>
|
44 |
+
</li>
|
45 |
+
</ul>
|
46 |
+
|
47 |
+
<div class="sucuriscan-tab-containers">
|
48 |
+
<div id="sucuriscan-monitoring-settings">
|
49 |
+
%%SUCURI.Monitoring.Settings%%
|
50 |
+
</div>
|
51 |
+
|
52 |
+
<div id="sucuriscan-monitoring-logs">
|
53 |
+
%%SUCURI.Monitoring.Logs%%
|
54 |
+
</div>
|
55 |
+
</div>
|
56 |
+
</div>
|
57 |
+
|
58 |
+
</div>
|
inc/tpl/{notification.html.tpl → notification-pretty.html.tpl}
RENAMED
@@ -4,7 +4,7 @@
|
|
4 |
<title>%%SUCURI.TemplateTitle%%</title>
|
5 |
</head>
|
6 |
<body>
|
7 |
-
<table class="
|
8 |
<thead sytle="border-bottom:1px solid #ccc">
|
9 |
<tr style="background-color:#4b4b4b;background-image:-moz-linear-gradient(top, #555555, #3b3b3b);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#555555), to(#3b3b3b));background-image:-webkit-linear-gradient(top, #555555, #3b3b3b);background-image:-o-linear-gradient(top, #555555, #3b3b3b);background-image:linear-gradient(to bottom, #555555, #3b3b3b);background-repeat:repeat-x">
|
10 |
<td sytle="font-size:20px;font-weight:normal;color:#ffffff;padding:10px;border-right:1px solid #2f2f2f;border-left:1px solid #6f6f6f;-webkit-box-shadow:inset 0 1px 0 #888888;-moz-box-shadow:inset 0 1px 0 #888888;box-shadow:inset 0 1px 0 #888888;text-shadow:1px 1px 2px rgba(0, 0, 0, 0.5)">
|
@@ -20,13 +20,13 @@
|
|
20 |
<td style="padding:20px 20px 10px 20px;border:1px solid #ccc;border-top:none">
|
21 |
<h4 style="margin:0">Information:</h4>
|
22 |
<p style="margin:0 0 10px 0">
|
23 |
-
|
24 |
-
|
25 |
</p>
|
26 |
<h4 style="text-transform:uppercase;margin:0">Website Information:</h4>
|
27 |
<p style="margin:0 0 10px 0">
|
28 |
-
Site: <a href="%%SUCURI.Website%%">%%SUCURI.Website%%</a><br
|
29 |
-
IP Address: %%SUCURI.RemoteAddress%%<br
|
30 |
</p>
|
31 |
<h4 style="text-transform:uppercase;margin:0">Notification Message:</h4>
|
32 |
<p style="margin:0 0 10px 0">%%SUCURI.Message%%</p>
|
4 |
<title>%%SUCURI.TemplateTitle%%</title>
|
5 |
</head>
|
6 |
<body>
|
7 |
+
<table class="sucuriscan-template" style="width:90%;background:#fff;font-family:Arial,Helvetica,sans-serif;border-spacing:0">
|
8 |
<thead sytle="border-bottom:1px solid #ccc">
|
9 |
<tr style="background-color:#4b4b4b;background-image:-moz-linear-gradient(top, #555555, #3b3b3b);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#555555), to(#3b3b3b));background-image:-webkit-linear-gradient(top, #555555, #3b3b3b);background-image:-o-linear-gradient(top, #555555, #3b3b3b);background-image:linear-gradient(to bottom, #555555, #3b3b3b);background-repeat:repeat-x">
|
10 |
<td sytle="font-size:20px;font-weight:normal;color:#ffffff;padding:10px;border-right:1px solid #2f2f2f;border-left:1px solid #6f6f6f;-webkit-box-shadow:inset 0 1px 0 #888888;-moz-box-shadow:inset 0 1px 0 #888888;box-shadow:inset 0 1px 0 #888888;text-shadow:1px 1px 2px rgba(0, 0, 0, 0.5)">
|
20 |
<td style="padding:20px 20px 10px 20px;border:1px solid #ccc;border-top:none">
|
21 |
<h4 style="margin:0">Information:</h4>
|
22 |
<p style="margin:0 0 10px 0">
|
23 |
+
Alert Time: %%SUCURI.Time%%<br>
|
24 |
+
%%SUCURI.User%%
|
25 |
</p>
|
26 |
<h4 style="text-transform:uppercase;margin:0">Website Information:</h4>
|
27 |
<p style="margin:0 0 10px 0">
|
28 |
+
Site: <a href="%%SUCURI.Website%%">%%SUCURI.Website%%</a><br>
|
29 |
+
IP Address: %%SUCURI.RemoteAddress%%<br>
|
30 |
</p>
|
31 |
<h4 style="text-transform:uppercase;margin:0">Notification Message:</h4>
|
32 |
<p style="margin:0 0 10px 0">%%SUCURI.Message%%</p>
|
inc/tpl/{notification.txt.tpl → notification-simple.html.tpl}
RENAMED
@@ -1,8 +1,8 @@
|
|
1 |
Subject: %%SUCURI.Subject%%
|
2 |
|
3 |
Login Info:
|
4 |
-
Username: %%SUCURI.User%%
|
5 |
Time: %%SUCURI.Time%%
|
|
|
6 |
|
7 |
Website Info:
|
8 |
Site: %%SUCURI.Website%%
|
1 |
Subject: %%SUCURI.Subject%%
|
2 |
|
3 |
Login Info:
|
|
|
4 |
Time: %%SUCURI.Time%%
|
5 |
+
%%SUCURI.User%%
|
6 |
|
7 |
Website Info:
|
8 |
Site: %%SUCURI.Website%%
|
inc/tpl/posthack-databasebackups.html.tpl
ADDED
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
<form action="%%SUCURI.URL.Posthack%%#database-backups" method="post">
|
3 |
+
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
|
4 |
+
<input type="hidden" name="sucuriscan_database_backup" value="1" />
|
5 |
+
<input type="hidden" name="sucuriscan_process_form" value="1" />
|
6 |
+
|
7 |
+
<table class="wp-list-table widefat">
|
8 |
+
<thead>
|
9 |
+
<tr>
|
10 |
+
<th colspan="5" class="thead-with-button">
|
11 |
+
<span>Database Backups</span>
|
12 |
+
<div class="generate-dbbackup-form thead-topright-action">
|
13 |
+
<input type="submit" name="generate_dbbackup" value="Generate DB Backup" class="button button-primary" />
|
14 |
+
</div>
|
15 |
+
</th>
|
16 |
+
</tr>
|
17 |
+
<tr>
|
18 |
+
<th class="manage-column column-cb check-column">
|
19 |
+
<label class="screen-reader-text" for="cb-select-all-1">Select All</label>
|
20 |
+
<input id="cb-select-all-1" type="checkbox">
|
21 |
+
</th>
|
22 |
+
<th class="manage-column">Filename</th>
|
23 |
+
<th class="manage-column">Type</th>
|
24 |
+
<th class="manage-column">Size</th>
|
25 |
+
<th class="manage-column">Date/Time</th>
|
26 |
+
</tr>
|
27 |
+
</thead>
|
28 |
+
|
29 |
+
<tbody>
|
30 |
+
%%SUCURI.BackupList%%
|
31 |
+
</tbody>
|
32 |
+
|
33 |
+
<tfoot>
|
34 |
+
<tr>
|
35 |
+
<td colspan="5">
|
36 |
+
<input type="submit" name="remove_dbbackup" value="Remove selected files" class="button button-primary" />
|
37 |
+
</td>
|
38 |
+
</tr>
|
39 |
+
</tfoot>
|
40 |
+
</table>
|
41 |
+
</form>
|
inc/tpl/posthack-databasebackups.snippet.tpl
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
<tr class="%%SUCURI.BackupList.CssClass%%">
|
3 |
+
<th class="check-column">
|
4 |
+
<input type="checkbox" name="dbbackup_filenames[]" value="%%SUCURI.BackupList.Filename%%" />
|
5 |
+
</th>
|
6 |
+
<td><a href="%%SUCURI.BackupList.FileURL%%" target="_blank">%%SUCURI.BackupList.Filename%%</a></td>
|
7 |
+
<td>%%SUCURI.BackupList.Filetype%%</td>
|
8 |
+
<td>%%SUCURI.BackupList.Filesize%%</td>
|
9 |
+
<td>%%SUCURI.BackupList.Filetime%%</td>
|
10 |
+
</tr>
|
inc/tpl/posthack-resetpassword.html.tpl
ADDED
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
<div id="poststuff" class="sucuriscan-reset-users-password">
|
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_reset_password" value="1" />
|
8 |
+
|
9 |
+
<p>
|
10 |
+
Use this button to reset the current password for some specific users or for all
|
11 |
+
of them. We will send an email to each of those users adivising the password change
|
12 |
+
that includes the new password automatically generated by WordPress. After the
|
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>
|
19 |
+
<th class="manage-column column-cb check-column">
|
20 |
+
<label class="screen-reader-text" for="cb-select-all-1">Select All</label>
|
21 |
+
<input id="cb-select-all-1" type="checkbox">
|
22 |
+
</th>
|
23 |
+
<th class="manage-column">User</th>
|
24 |
+
<th class="manage-column">Email address</th>
|
25 |
+
<th class="manage-column">Registered</th>
|
26 |
+
<th class="manage-column">Roles</th>
|
27 |
+
</tr>
|
28 |
+
</thead>
|
29 |
+
|
30 |
+
<tbody>
|
31 |
+
%%SUCURI.ResetPassword.UserList%%
|
32 |
+
</tbody>
|
33 |
+
</table>
|
34 |
+
|
35 |
+
<p>
|
36 |
+
<label>
|
37 |
+
<input type="hidden" name="sucuriscan_process_form" value="0" />
|
38 |
+
<input type="checkbox" name="sucuriscan_process_form" value="1" />
|
39 |
+
<span>I understand that this operation can not be reverted.</span>
|
40 |
+
</label>
|
41 |
+
</p>
|
42 |
+
|
43 |
+
<input type="submit" value="Reset User Password" class="button button-primary" />
|
44 |
+
</form>
|
45 |
+
</div>
|
46 |
+
</div>
|
47 |
+
</div>
|
inc/tpl/posthack-updatesecretkeys.html.tpl
ADDED
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
<div id="poststuff" class="sucuriscan-update-secret-keys">
|
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" />
|
18 |
+
<input type="checkbox" name="sucuriscan_process_form" value="1" />
|
19 |
+
<span>I understand that this operation can not be reverted.</span>
|
20 |
+
</label>
|
21 |
+
</p>
|
22 |
+
|
23 |
+
<input type="submit" value="Update WP-Config Keys" class="button button-primary" />
|
24 |
+
</form>
|
25 |
+
|
26 |
+
<div class="sucuriscan_wpconfig_keys_updated sucuriscan-%%SUCURI.WPConfigUpdate.Visibility%%">
|
27 |
+
<textarea>%%SUCURI.WPConfigUpdate.NewConfig%%</textarea>
|
28 |
+
</div>
|
29 |
+
</div>
|
30 |
+
</div>
|
31 |
+
</div>
|
inc/tpl/posthack.html.tpl
CHANGED
@@ -1,78 +1,29 @@
|
|
1 |
|
2 |
-
<div id="poststuff">
|
3 |
-
<div class="postbox">
|
4 |
-
<h3>Update WP-Config Keys</h3>
|
5 |
-
<div class="inside">
|
6 |
-
<form method="post">
|
7 |
-
<input type="hidden" name="sucuri_posthack_nonce" value="%%SUCURI.PosthackNonce%%" />
|
8 |
-
<input type="hidden" name="sucuri_posthack_action" value="update_wpconfig" />
|
9 |
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
<div style="%%SUCURI.WPConfigUpdate.Display%%" class="sucuriscan_wpconfig_keys_updated">
|
28 |
-
<textarea>%%SUCURI.WPConfigUpdate.NewConfig%%</textarea>
|
29 |
-
</div>
|
30 |
</div>
|
31 |
-
</div>
|
32 |
-
|
33 |
-
<div class="postbox">
|
34 |
-
<h3>Reset user password</h3>
|
35 |
-
<div class="inside">
|
36 |
-
<form method="post">
|
37 |
-
<input type="hidden" name="sucuri_posthack_nonce" value="%%SUCURI.PosthackNonce%%" />
|
38 |
-
<input type="hidden" name="sucuri_posthack_action" value="reset_password" />
|
39 |
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
that includes the new password automatically generated by WordPress. After the
|
44 |
-
password reset your current session will be closed and you'll need to login again.
|
45 |
-
</p>
|
46 |
-
|
47 |
-
<table class="wp-list-table widefat sucuriscan-table">
|
48 |
-
<thead>
|
49 |
-
<tr>
|
50 |
-
<th class="manage-column column-cb check-column">
|
51 |
-
<label class="screen-reader-text" for="cb-select-all-1">Select All</label>
|
52 |
-
<input id="cb-select-all-1" type="checkbox">
|
53 |
-
</th>
|
54 |
-
<th class="manage-column">User</th>
|
55 |
-
<th class="manage-column">Email address</th>
|
56 |
-
<th class="manage-column">Registered</th>
|
57 |
-
<th class="manage-column">Roles</th>
|
58 |
-
</tr>
|
59 |
-
</thead>
|
60 |
-
|
61 |
-
<tbody>
|
62 |
-
%%SUCURI.ResetPassword.UserList%%
|
63 |
-
</tbody>
|
64 |
-
</table>
|
65 |
-
|
66 |
-
<p>
|
67 |
-
<label>
|
68 |
-
<input type="hidden" name="sucuri_reset_password" value="0" />
|
69 |
-
<input type="checkbox" name="sucuri_reset_password" value="1" />
|
70 |
-
<span>I understand that this operation can not be reverted.</span>
|
71 |
-
</label>
|
72 |
-
</p>
|
73 |
|
74 |
-
|
75 |
-
|
76 |
</div>
|
77 |
</div>
|
78 |
-
</div
|
1 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
|
3 |
+
<div class="sucuriscan-tabs">
|
4 |
+
<ul>
|
5 |
+
<li>
|
6 |
+
<a href="#" data-tabname="update-secret-keys">Update WordPress Keys</a>
|
7 |
+
</li>
|
8 |
+
<li>
|
9 |
+
<a href="#" data-tabname="reset-users-password">Reset User's Password</a>
|
10 |
+
</li>
|
11 |
+
<li>
|
12 |
+
<a href="#" data-tabname="database-backups">Database Backups</a>
|
13 |
+
</li>
|
14 |
+
</ul>
|
15 |
+
|
16 |
+
<div class="sucuriscan-tab-containers">
|
17 |
+
<div id="sucuriscan-update-secret-keys">
|
18 |
+
%%SUCURI.UpdateSecretKeys%%
|
|
|
|
|
|
|
|
|
19 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
20 |
|
21 |
+
<div id="sucuriscan-reset-users-password">
|
22 |
+
%%SUCURI.ResetPassword%%
|
23 |
+
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
24 |
|
25 |
+
<div id="sucuriscan-database-backups">
|
26 |
+
%%SUCURI.DatabaseBackups%%
|
27 |
</div>
|
28 |
</div>
|
29 |
+
</div>
|
inc/tpl/settings-apiregistered.html.tpl
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
<div class="sucuriscan-clearfix">
|
3 |
+
<div class="sucuriscan-pull-left sucuriscan-sitelogo"> </div>
|
4 |
+
|
5 |
+
<div class="sucuriscan-pull-right">
|
6 |
+
<p>
|
7 |
+
Thanks so much for enabling your <strong>Sucuri Security</strong> plugin. This
|
8 |
+
product is designed to supplement existing security products. It's not a silver
|
9 |
+
bullet for your security needs, but it'll give you greater security awareness
|
10 |
+
and better posture, all with the intent of reducing risk.
|
11 |
+
</p>
|
12 |
+
|
13 |
+
<a href="%%SUCURI.URL.Home%%" class="button button-primary">Go to your Dashboard</a>
|
14 |
+
</div>
|
15 |
+
</div>
|
16 |
+
|
inc/tpl/settings-notification.snippet.tpl
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
<tr class="%%SUCURI.Notification.CssClass%%">
|
3 |
+
<td colspan="3">
|
4 |
+
<div>
|
5 |
+
<label>
|
6 |
+
<input type="hidden" name="%%SUCURI.Notification.Name%%" value="0" />
|
7 |
+
<input type="checkbox" name="%%SUCURI.Notification.Name%%" value="1" %%SUCURI.Notification.Checked%% />
|
8 |
+
<span>%%SUCURI.Notification.Label%%</span>
|
9 |
+
</label>
|
10 |
+
</div>
|
11 |
+
</td>
|
12 |
+
</tr>
|
inc/tpl/settings.html.tpl
ADDED
@@ -0,0 +1,118 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
%%SUCURI.ModalWhenAPIRegistered%%
|
3 |
+
|
4 |
+
<table class="wp-list-table widefat sucuriscan-table sucuriscan-settings">
|
5 |
+
<thead>
|
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>
|
13 |
+
</th>
|
14 |
+
</tr>
|
15 |
+
</thead>
|
16 |
+
|
17 |
+
<tbody>
|
18 |
+
|
19 |
+
<tr>
|
20 |
+
<td colspan="3">
|
21 |
+
<p>
|
22 |
+
Most of the tools in this plugin can be used without a specific configuration,
|
23 |
+
but the core features <strong>require an API key</strong> to communicate with
|
24 |
+
the Sucuri services. The key is generated using your administrator e-mail and
|
25 |
+
the domain of this site, this will allow you to have access to our free
|
26 |
+
monitoring tool forever even if you remove the API key and generate it again.
|
27 |
+
</p>
|
28 |
+
</td>
|
29 |
+
</tr>
|
30 |
+
|
31 |
+
<tr class="alternate">
|
32 |
+
<td>API Key</td>
|
33 |
+
<td>
|
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="sucuriscan_recover_api_key" class="button-primary">Recover</button>
|
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>
|
52 |
+
</td>
|
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>Scanning frequency</td>
|
68 |
+
<td><span class="sucuriscan-monospace">%%SUCURI.ScanningFrequency%%</span></td>
|
69 |
+
<td class="td-with-button">
|
70 |
+
<form method="post">
|
71 |
+
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
|
72 |
+
<select name="sucuriscan_scan_frequency">
|
73 |
+
%%SUCURI.ScanningFrequencyOptions%%
|
74 |
+
</select>
|
75 |
+
<button type="submit" class="button-primary">Change</button>
|
76 |
+
</form>
|
77 |
+
</td>
|
78 |
+
</tr>
|
79 |
+
|
80 |
+
<tr class="sucuriscan-%%SUCURI.ScanningInterfaceVisibility%%">
|
81 |
+
<td>Scanning interface</td>
|
82 |
+
<td><span class="sucuriscan-monospace">%%SUCURI.ScanningInterface%%</span></td>
|
83 |
+
<td class="td-with-button">
|
84 |
+
<form method="post">
|
85 |
+
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
|
86 |
+
<select name="sucuriscan_scan_interface">
|
87 |
+
%%SUCURI.ScanningInterfaceOptions%%
|
88 |
+
</select>
|
89 |
+
<button type="submit" class="button-primary">Change</button>
|
90 |
+
</form>
|
91 |
+
</td>
|
92 |
+
</tr>
|
93 |
+
|
94 |
+
</tbody>
|
95 |
+
</table>
|
96 |
+
|
97 |
+
|
98 |
+
<form method="post">
|
99 |
+
<table class="wp-list-table widefat sucuriscan-table sucuriscan-settings-notifications">
|
100 |
+
<thead>
|
101 |
+
<tr>
|
102 |
+
<th colspan="3" class="thead-with-button">
|
103 |
+
<span>Email Alerts Settings</span>
|
104 |
+
<div class="thead-topright-action">
|
105 |
+
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
|
106 |
+
<button type="submit" name="sucuriscan_save_notification_settings" class="button-primary">Save</button>
|
107 |
+
</div>
|
108 |
+
</th>
|
109 |
+
</tr>
|
110 |
+
</thead>
|
111 |
+
|
112 |
+
<tbody>
|
113 |
+
|
114 |
+
%%SUCURI.NotificationOptions%%
|
115 |
+
|
116 |
+
</tbody>
|
117 |
+
</table>
|
118 |
+
</form>
|
inc/tpl/setup_notice.html.tpl
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
<div class="updated sucuriscan-setup-notice sucuriscan-clearfix">
|
3 |
+
<a href="http://sucuri.net/" target="_blank" class="sucuriscan-pull-left sucuriscan-setup-image">
|
4 |
+
<img src="%%SUCURI.SucuriURL%%/inc/images/logo.png" alt="Sucuri Scanner" />
|
5 |
+
</a>
|
6 |
+
|
7 |
+
<div class="sucuriscan-pull-left">
|
8 |
+
<p>
|
9 |
+
Plugin not fully activated yet. Please generate the free API<br>
|
10 |
+
to enable audit logging, integrity checking and email alerts.
|
11 |
+
</p>
|
12 |
+
</div>
|
13 |
+
|
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_wordpress_apikey" 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>
|
21 |
+
</form>
|
22 |
+
</div>
|
23 |
+
</div>
|
readme.txt
CHANGED
@@ -1,12 +1,12 @@
|
|
1 |
-
=== Sucuri Security -
|
2 |
Contributors: dd@sucuri.net
|
3 |
Donate Link: http://sitecheck.sucuri.net
|
4 |
Tags: malware, security, firewall, scan, spam, virus, sucuri, protection
|
5 |
Requires at least:3.2
|
6 |
-
Stable tag:1.6.
|
7 |
Tested up to: 3.9.1
|
8 |
|
9 |
-
The Sucuri Security - SiteCheck Malware Scanner 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 also includes post-hack security ions to help you reset passwords and secret keys in case it has been already hacked, or infected with malware.
|
10 |
|
11 |
== Description ==
|
12 |
|
@@ -66,6 +66,9 @@ the compromise on your site).
|
|
66 |
|
67 |
== Changelog ==
|
68 |
|
|
|
|
|
|
|
69 |
= 1.6.0 =
|
70 |
* A new dashboard to welcome users to the new features of the plugin.
|
71 |
* Overall design of the interface of all the pages were modified.
|
1 |
+
=== Sucuri Security - Auditing, Malware Scanner and Hardening ===
|
2 |
Contributors: dd@sucuri.net
|
3 |
Donate Link: http://sitecheck.sucuri.net
|
4 |
Tags: malware, security, firewall, scan, spam, virus, sucuri, protection
|
5 |
Requires at least:3.2
|
6 |
+
Stable tag:1.6.1
|
7 |
Tested up to: 3.9.1
|
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 also includes post-hack security ions to help you reset passwords and secret keys in case it has been already hacked, or infected with malware.
|
10 |
|
11 |
== Description ==
|
12 |
|
66 |
|
67 |
== Changelog ==
|
68 |
|
69 |
+
= 1.6.1 =
|
70 |
+
* Initial release with new auditing options.
|
71 |
+
|
72 |
= 1.6.0 =
|
73 |
* A new dashboard to welcome users to the new features of the plugin.
|
74 |
* Overall design of the interface of all the pages were modified.
|
sucuri.php
CHANGED
@@ -1,13 +1,10 @@
|
|
1 |
<?php
|
2 |
/*
|
3 |
-
Plugin Name: Sucuri Security -
|
4 |
-
Plugin URI: http://
|
5 |
-
Description: The <a href="http://sucuri.net">Sucuri Security</a>
|
6 |
-
|
7 |
-
You can also scan your site at <a href="http://sitecheck.sucuri.net">SiteCheck.Sucuri.net</a>.
|
8 |
-
|
9 |
Author: Sucuri, INC
|
10 |
-
Version: 1.6.
|
11 |
Author URI: http://sucuri.net
|
12 |
*/
|
13 |
|
@@ -39,7 +36,7 @@ define('SUCURISCAN','sucuriscan');
|
|
39 |
/**
|
40 |
* Current version of the plugin's code.
|
41 |
*/
|
42 |
-
define('SUCURISCAN_VERSION','1.6.
|
43 |
|
44 |
/**
|
45 |
* The local URL where the plugin's files and assets are served.
|
@@ -67,1244 +64,5550 @@ define('SUCURISCAN_PLUGIN_PATH', WP_PLUGIN_DIR.'/'.SUCURISCAN_PLUGIN_FOLDER);
|
|
67 |
define('SUCURISCAN_PLUGIN_FILEPATH', SUCURISCAN_PLUGIN_PATH.'/'.SUCURISCAN_PLUGIN_FILE);
|
68 |
|
69 |
/**
|
70 |
-
*
|
71 |
*/
|
72 |
-
define('
|
73 |
-
|
74 |
-
if( !function_exists('sucuriscan_create_uploaddir') ){
|
75 |
-
/**
|
76 |
-
* Create a folder in the WordPress upload directory where the plugin will
|
77 |
-
* store all the temporal or dynamic information.
|
78 |
-
*
|
79 |
-
* @return void
|
80 |
-
*/
|
81 |
-
function sucuriscan_create_uploaddir(){
|
82 |
-
$plugin_upload_folder = sucuriscan_dir_filepath();
|
83 |
-
if( !file_exists($plugin_upload_folder) ){
|
84 |
-
if( @mkdir($plugin_upload_folder) ){
|
85 |
-
sucuriscan_lastlogins_datastore_exists();
|
86 |
-
}else{
|
87 |
-
sucuriscan_admin_notice('error', "<strong>Error.</strong> Sucuri data folder doesn't
|
88 |
-
exists and couldn't be created. You'll need to create this folder manually and
|
89 |
-
give it write permissions:<br><code>{$plugin_upload_folder}</code>");
|
90 |
-
}
|
91 |
-
}
|
92 |
-
}
|
93 |
-
|
94 |
-
add_action('admin_init', 'sucuriscan_create_uploaddir');
|
95 |
-
}
|
96 |
|
97 |
/**
|
98 |
-
*
|
99 |
-
* @return void
|
100 |
*/
|
101 |
-
|
102 |
-
wp_register_style( 'sucuriscan', SUCURI_URL . '/inc/css/sucuriscan-default-css.css' );
|
103 |
-
wp_register_script( 'sucuriscan', SUCURI_URL . '/inc/js/sucuriscan-scripts.js' );
|
104 |
-
|
105 |
-
wp_enqueue_style( 'sucuriscan' );
|
106 |
-
wp_enqueue_script( 'sucuriscan' );
|
107 |
-
}
|
108 |
-
add_action( 'admin_enqueue_scripts', 'sucuriscan_admin_script_style_registration', 1 );
|
109 |
|
110 |
/**
|
111 |
-
*
|
112 |
-
* site. This is a multisite capable function.
|
113 |
-
*
|
114 |
-
* @param string $path The relative path that needs to be completed to get the absolute path.
|
115 |
-
* @return string The full filesystem path including the directory specified.
|
116 |
*/
|
117 |
-
|
118 |
-
{
|
119 |
-
$wp_dir_array = wp_upload_dir();
|
120 |
-
$wp_dir_array['basedir'] = untrailingslashit($wp_dir_array['basedir']);
|
121 |
-
return($wp_dir_array['basedir']."/sucuri/$path");
|
122 |
-
}
|
123 |
|
124 |
/**
|
125 |
-
*
|
126 |
-
*
|
127 |
-
* @return void
|
128 |
*/
|
129 |
-
|
130 |
-
{
|
131 |
-
add_menu_page('Sucuri Free', 'Sucuri Free', 'manage_options',
|
132 |
-
'sucuriscan', 'sucuri_scan_page', SUCURI_URL.'/inc/images/menu-icon.png');
|
133 |
-
add_submenu_page('sucuriscan', 'Sucuri Scanner', 'Sucuri Scanner', 'manage_options',
|
134 |
-
'sucuriscan', 'sucuri_scan_page');
|
135 |
-
|
136 |
-
add_submenu_page('sucuriscan', '1-Click Hardening', '1-Click Hardening', 'manage_options',
|
137 |
-
'sucuriscan_hardening', 'sucuriscan_hardening_page');
|
138 |
-
|
139 |
-
add_submenu_page('sucuriscan', 'WordPress Integrity', 'WordPress Integrity', 'manage_options',
|
140 |
-
'sucuriscan_core_integrity', 'sucuriscan_core_integrity_page');
|
141 |
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
'sucuriscan_lastlogins', 'sucuriscan_lastlogins_page');
|
147 |
-
|
148 |
-
add_submenu_page('sucuriscan', 'Site Info', 'Site Info', 'manage_options',
|
149 |
-
'sucuriscan_infosys', 'sucuriscan_infosys_page');
|
150 |
-
|
151 |
-
add_submenu_page('sucuriscan', 'About', 'About', 'manage_options',
|
152 |
-
'sucuriscan_about', 'sucuriscan_about_page');
|
153 |
-
}
|
154 |
-
|
155 |
-
add_action('admin_menu', 'sucuriscan_menu');
|
156 |
-
remove_action('wp_head', 'wp_generator');
|
157 |
|
158 |
/**
|
159 |
-
*
|
160 |
-
*
|
161 |
-
* @param string $sucuri_title Title of the page that will be loaded.
|
162 |
-
* @return void
|
163 |
*/
|
164 |
-
|
165 |
-
{
|
166 |
-
if(!current_user_can('manage_options'))
|
167 |
-
{
|
168 |
-
wp_die(__('You do not have sufficient permissions to access this page: Sucuri Header') );
|
169 |
-
}
|
170 |
-
?>
|
171 |
-
<h2><?php echo htmlspecialchars($sucuri_title); ?></h2>
|
172 |
-
<br class="clear"/>
|
173 |
-
<?php
|
174 |
-
}
|
175 |
|
176 |
/**
|
177 |
-
*
|
178 |
-
*
|
179 |
-
* @param string $to The email address of the recipient that will receive the message.
|
180 |
-
* @param string $subject The reason of the message that will be sent.
|
181 |
-
* @param string $message Body of the message that will be sent.
|
182 |
-
* @param array $data_set Optional parameter to add more information to the notification.
|
183 |
-
* @param boolean $debug TRUE if you want to test the function printing the email before sending it.
|
184 |
-
* @return void
|
185 |
*/
|
186 |
-
|
187 |
-
{
|
188 |
-
$headers = array();
|
189 |
-
$subject = ucwords(strtolower($subject));
|
190 |
-
$wp_domain = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : get_option('siteurl');
|
191 |
-
if( get_option('sucuri_wp_prettify_mails')!='disabled' ){
|
192 |
-
$headers = array( 'Content-type: text/html' );
|
193 |
-
$data_set['PrettifyType'] = 'html';
|
194 |
-
}
|
195 |
-
$message = sucuriscan_prettify_mail($subject, $message, $data_set);
|
196 |
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
}
|
202 |
-
}
|
203 |
|
204 |
/**
|
205 |
-
*
|
206 |
-
*
|
207 |
-
* @param string $type The type of alert, it can be either Updated or Error.
|
208 |
-
* @param string $message The message that will be printed in the alert.
|
209 |
-
* @return void
|
210 |
*/
|
211 |
-
|
212 |
-
{
|
213 |
-
$alert_id = rand(100, 999);
|
214 |
-
if( !empty($message) ): ?>
|
215 |
-
<div id="sucuri-alert-<?php echo $alert_id; ?>" class="<?php echo $type; ?> sucuri-alert sucuri-alert-<?php echo $type; ?>">
|
216 |
-
<a href="javascript:void(0)" class="close" onclick="sucuriscan_alert_close('<?php echo $alert_id; ?>')">×</a>
|
217 |
-
<p><?php _e($message); ?></p>
|
218 |
-
</div>
|
219 |
-
<?php endif;
|
220 |
-
}
|
221 |
|
222 |
/**
|
223 |
-
*
|
224 |
*
|
225 |
-
*
|
226 |
-
*
|
227 |
-
*
|
228 |
-
* @return string The message formatted in a HTML template.
|
229 |
*/
|
230 |
-
|
231 |
-
{
|
232 |
-
$current_user = wp_get_current_user();
|
233 |
-
|
234 |
-
$prettify_type = isset($data_set['PrettifyType']) ? $data_set['PrettifyType'] : 'txt';
|
235 |
-
$real_ip = isset($_SERVER['SUCURI_RIP']) ? $_SERVER['SUCURI_RIP'] : $_SERVER['REMOTE_ADDR'];
|
236 |
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
'RemoteAddress'=>$real_ip,
|
242 |
-
'Message'=>$message,
|
243 |
-
'User'=>$current_user->display_name,
|
244 |
-
'Time'=>current_time('mysql')
|
245 |
-
);
|
246 |
-
foreach($data_set as $var_key=>$var_value){
|
247 |
-
$mail_variables[$var_key] = $var_value;
|
248 |
}
|
249 |
|
250 |
-
|
251 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
252 |
|
253 |
-
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
* @param string $template Filename of the template that will be used to generate the page.
|
259 |
-
* @param array $params A hash containing the pseudo-variable name as the key and the value that will replace it.
|
260 |
-
* @param boolean $type Either page, section or snippet indicating the type of template that will be retrieved.
|
261 |
-
* @return string The formatted HTML page after replace all the pseudo-variables.
|
262 |
-
*/
|
263 |
-
function sucuriscan_get_template($template='', $params=array(), $type='page'){
|
264 |
-
switch( $type ){
|
265 |
-
case 'page': /* no_break */
|
266 |
-
case 'section':
|
267 |
-
$template_path_pattern = '%s/%s/inc/tpl/%s.html.tpl';
|
268 |
-
break;
|
269 |
-
case 'snippet':
|
270 |
-
$template_path_pattern = '%s/%s/inc/tpl/%s.snippet.tpl';
|
271 |
-
break;
|
272 |
}
|
273 |
|
274 |
-
|
275 |
-
|
276 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
277 |
|
278 |
-
|
279 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
280 |
|
281 |
-
|
282 |
-
|
283 |
-
$params['SucuriURL'] = SUCURI_URL;
|
284 |
-
$params['PageNonce'] = wp_create_nonce('sucuri_page_nonce');
|
285 |
|
286 |
-
|
287 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
288 |
}
|
289 |
-
}
|
290 |
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
'
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
303 |
|
304 |
-
|
305 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
306 |
}
|
307 |
|
308 |
-
return
|
309 |
}
|
310 |
-
}
|
311 |
|
312 |
-
/**
|
313 |
-
* Generate a HTML code using a template and replacing all the pseudo-variables
|
314 |
-
* by the dynamic variables provided by the developer through one of the parameters
|
315 |
-
* of the function.
|
316 |
-
*
|
317 |
-
* @param string $template Filename of the template that will be used to generate the page.
|
318 |
-
* @param array $params A hash containing the pseudo-variable name as the key and the value that will replace it.
|
319 |
-
* @return string The formatted HTML page after replace all the pseudo-variables.
|
320 |
-
*/
|
321 |
-
function sucuriscan_get_section($template='', $params=array()){
|
322 |
-
return sucuriscan_get_template( $template, $params, 'section' );
|
323 |
}
|
324 |
|
325 |
/**
|
326 |
-
*
|
327 |
-
* by the dynamic variables provided by the developer through one of the parameters
|
328 |
-
* of the function.
|
329 |
*
|
330 |
-
*
|
331 |
-
*
|
332 |
-
*
|
|
|
333 |
*/
|
334 |
-
|
335 |
-
return sucuriscan_get_template( $template, $params, 'snippet' );
|
336 |
-
}
|
337 |
|
338 |
-
/**
|
339 |
-
|
340 |
-
|
341 |
-
|
342 |
-
|
343 |
-
|
344 |
-
|
345 |
-
|
346 |
-
|
347 |
-
|
348 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
349 |
}
|
350 |
|
351 |
-
|
352 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
353 |
|
354 |
-
|
355 |
-
|
356 |
-
|
357 |
-
|
358 |
-
|
359 |
-
|
360 |
-
|
361 |
-
|
362 |
-
|
363 |
-
|
364 |
-
|
365 |
-
|
366 |
-
|
367 |
-
$
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
368 |
}
|
369 |
-
return $new_keys;
|
370 |
}
|
|
|
|
|
371 |
}
|
372 |
-
return FALSE;
|
373 |
-
}
|
374 |
|
375 |
-
/**
|
376 |
-
|
377 |
-
|
378 |
-
|
379 |
-
|
380 |
-
|
381 |
-
|
382 |
-
|
383 |
-
|
384 |
-
function
|
385 |
-
{
|
386 |
-
|
387 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
388 |
|
389 |
-
|
390 |
-
|
391 |
-
|
392 |
-
$old_keys = array();
|
393 |
-
$old_keys_string = $new_keys_string = '';
|
394 |
|
395 |
-
|
396 |
-
|
|
|
397 |
|
398 |
-
|
399 |
-
|
400 |
-
|
401 |
-
|
402 |
-
$old_keys[$key_name] = $match[3];
|
403 |
-
$wp_config_line = "define('{$key_name}',{$white_spaces}'{$new_keys[$key_name]}');";
|
404 |
|
405 |
-
|
406 |
-
|
407 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
408 |
}
|
409 |
|
410 |
-
$
|
|
|
|
|
|
|
411 |
}
|
412 |
|
413 |
-
$
|
414 |
-
|
415 |
-
|
416 |
-
|
417 |
-
|
418 |
-
|
419 |
-
|
420 |
-
|
421 |
-
|
422 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
423 |
}
|
424 |
-
|
|
|
425 |
}
|
426 |
-
return FALSE;
|
427 |
-
}
|
428 |
|
429 |
-
/**
|
430 |
-
|
431 |
-
|
432 |
-
|
433 |
-
|
434 |
-
|
435 |
-
|
436 |
-
|
437 |
-
|
438 |
-
|
|
|
439 |
|
440 |
-
|
441 |
-
$
|
442 |
-
|
443 |
|
444 |
-
|
445 |
-
|
446 |
-
this is the new password automatically generated by the system, please update ASAP.<br>
|
447 |
-
<div style='display:inline-block;background:#ddd;font-family:monaco,monospace,courier;
|
448 |
-
font-size:30px;margin:0;padding:15px;border:1px solid #999'>{$new_password}</div>";
|
449 |
-
sucuriscan_send_mail($user->user_email, 'Changed password', $message, $data_set);
|
450 |
|
451 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
452 |
|
453 |
-
|
|
|
454 |
}
|
455 |
-
return FALSE;
|
456 |
-
}
|
457 |
|
458 |
-
/**
|
459 |
-
|
460 |
-
|
461 |
-
|
462 |
-
|
463 |
-
|
464 |
-
|
465 |
-
$
|
466 |
-
|
467 |
-
'
|
468 |
-
'HTTP_X_FORWARDED_FOR',
|
469 |
-
'HTTP_X_FORWARDED',
|
470 |
-
'HTTP_FORWARDED_FOR',
|
471 |
-
'HTTP_FORWARDED',
|
472 |
-
'REMOTE_ADDR',
|
473 |
-
'SUCURI_RIP',
|
474 |
-
);
|
475 |
-
foreach($alternatives as $alternative){
|
476 |
-
if( !isset($_SERVER[$alternative]) ){ continue; }
|
477 |
|
478 |
-
|
479 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
480 |
}
|
481 |
|
482 |
-
|
483 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
484 |
|
485 |
-
|
486 |
-
|
487 |
-
|
488 |
-
|
489 |
-
|
490 |
-
|
491 |
-
|
492 |
-
|
493 |
-
|
494 |
-
|
|
|
495 |
|
496 |
-
if(
|
497 |
-
isset($_SERVER['SUCURIREAL_REMOTE_ADDR'])
|
498 |
-
|| preg_match('/^cloudproxy([0-9]+)\.sucuri\.net$/', $host_by_addr)
|
499 |
-
){
|
500 |
return TRUE;
|
501 |
}
|
502 |
|
503 |
-
|
504 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
505 |
|
506 |
-
|
507 |
-
|
508 |
-
|
509 |
-
* @return boolean Either TRUE or FALSE in case WordPress is being used as a multi-site instance.
|
510 |
-
*/
|
511 |
-
function sucuriscan_is_multisite(){
|
512 |
-
if( function_exists('is_multisite') && is_multisite() ){ return TRUE; }
|
513 |
-
return FALSE;
|
514 |
-
}
|
515 |
|
516 |
-
|
517 |
-
|
518 |
-
*
|
519 |
-
* @return string Absolute path of the WordPress configuration file.
|
520 |
-
*/
|
521 |
-
function sucuriscan_get_wpconfig_path(){
|
522 |
-
$wp_config_path = ABSPATH.'wp-config.php';
|
523 |
|
524 |
-
|
525 |
-
|
526 |
-
|
|
|
|
|
|
|
527 |
}
|
528 |
-
return $wp_config_path;
|
529 |
-
}
|
530 |
|
531 |
-
/**
|
532 |
-
|
533 |
-
|
534 |
-
|
535 |
-
|
536 |
-
|
537 |
-
$
|
538 |
-
|
539 |
-
|
540 |
-
dirname(dirname(ABSPATH))
|
541 |
-
);
|
542 |
|
543 |
-
|
544 |
-
|
545 |
-
|
546 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
547 |
}
|
|
|
|
|
548 |
}
|
549 |
|
550 |
-
return FALSE;
|
551 |
}
|
552 |
|
553 |
/**
|
554 |
-
*
|
555 |
*
|
556 |
-
*
|
557 |
-
*
|
|
|
558 |
*/
|
559 |
-
|
560 |
-
if( !is_numeric($timestamp) ){
|
561 |
-
$timestamp = strtotime($timestamp);
|
562 |
-
}
|
563 |
|
564 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
565 |
|
566 |
-
|
|
|
567 |
|
568 |
-
|
569 |
-
|
570 |
-
|
571 |
-
$diff < 2629744 => array('week', 604800),
|
572 |
-
$diff < 604800 => array('day', 86400),
|
573 |
-
$diff < 86400 => array('hour', 3600),
|
574 |
-
$diff < 3600 => array('minute', 60),
|
575 |
-
$diff < 60 => array('second', 1)
|
576 |
-
);
|
577 |
|
578 |
-
|
579 |
-
|
580 |
-
}
|
581 |
|
582 |
-
/**
|
583 |
-
|
584 |
-
|
585 |
-
|
586 |
-
|
587 |
-
|
588 |
-
|
589 |
-
|
590 |
-
if( !current_user_can('manage_options') ){
|
591 |
-
wp_die(__('You do not have sufficient permissions to access this page: Sucuri Malware Scanner') );
|
592 |
}
|
593 |
|
594 |
-
|
595 |
-
|
596 |
-
|
|
|
|
|
|
|
|
|
597 |
}
|
598 |
|
599 |
-
|
600 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
601 |
|
602 |
-
|
603 |
-
|
604 |
-
*
|
605 |
-
* @return void
|
606 |
-
*/
|
607 |
-
function sucuriscan_print_scan(){
|
608 |
-
$website_scanned = home_url();
|
609 |
-
$remote_url = 'http://sitecheck.sucuri.net/scanner/?serialized&clear&fromwp&scan='.$website_scanned;
|
610 |
-
$scan_results = wp_remote_get($remote_url, array('timeout' => 180));
|
611 |
-
ob_start();
|
612 |
-
?>
|
613 |
|
|
|
|
|
614 |
|
615 |
-
|
|
|
616 |
|
617 |
-
|
618 |
-
|
619 |
-
<h3>Error retrieving the scan report</h3>
|
620 |
-
<div class="inside">
|
621 |
-
<pre><?php print_r($scan_results); ?></pre>
|
622 |
-
</div>
|
623 |
-
</div>
|
624 |
-
</div>
|
625 |
|
626 |
-
|
|
|
|
|
|
|
|
|
|
|
627 |
|
628 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
629 |
|
630 |
-
|
|
|
631 |
|
632 |
-
|
633 |
-
|
634 |
|
635 |
-
|
636 |
-
|
637 |
-
|
638 |
|
639 |
-
|
640 |
-
|
641 |
-
$wordpress_updated = FALSE;
|
642 |
-
$updates = function_exists('get_core_updates') ? get_core_updates() : array();
|
643 |
|
644 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
645 |
$wordpress_updated = TRUE;
|
646 |
}
|
647 |
|
648 |
-
|
649 |
-
|
650 |
-
|
651 |
-
|
652 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
653 |
|
654 |
-
|
655 |
-
|
656 |
-
<li>
|
657 |
-
<a href="#" data-tabname="sitecheck-results">SiteCheck Results</a>
|
658 |
-
</li>
|
659 |
-
<li>
|
660 |
-
<a href="#" data-tabname="website-details">Website Details</a>
|
661 |
-
</li>
|
662 |
-
<li>
|
663 |
-
<a href="#" data-tabname="blacklist-status">Blacklist Status</a>
|
664 |
-
</li>
|
665 |
-
</ul>
|
666 |
|
667 |
-
|
|
|
|
|
|
|
668 |
|
669 |
-
<
|
670 |
-
|
671 |
-
|
672 |
-
|
673 |
-
|
674 |
-
|
675 |
-
|
676 |
-
|
677 |
-
|
678 |
-
|
679 |
|
680 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
681 |
|
682 |
-
|
683 |
-
|
684 |
-
|
685 |
-
|
686 |
-
|
687 |
-
|
688 |
-
|
689 |
-
|
690 |
-
|
691 |
-
|
692 |
-
|
693 |
-
|
694 |
-
|
695 |
-
$mwdetails = explode("\n", htmlspecialchars($malres[1]));
|
696 |
-
echo htmlspecialchars($malres[0])."\n<br />". substr($mwdetails[0], 1)."<br />\n";
|
697 |
-
}
|
698 |
-
}
|
699 |
-
?>
|
700 |
-
<?php endif; ?>
|
701 |
|
702 |
-
|
703 |
-
|
704 |
-
|
705 |
-
|
706 |
-
|
707 |
-
<hr />
|
708 |
-
<i>
|
709 |
-
If our free scanner did not detect any issue, you may have a more complicated and hidden
|
710 |
-
problem. You can try our <a href="admin.php?page=sucuriscan_core_integrity">WordPress integrity
|
711 |
-
checks</a> or sign up with Sucuri <a target="_blank" href="http://sucuri.net/signup">here</a>
|
712 |
-
for a complete and in depth scan+cleanup (not included in the free checks).
|
713 |
-
</i>
|
714 |
-
</p>
|
715 |
|
716 |
-
|
717 |
-
|
718 |
-
|
719 |
-
|
|
|
|
|
|
|
720 |
|
721 |
-
|
722 |
-
|
723 |
-
|
724 |
-
|
725 |
-
|
726 |
-
|
727 |
-
|
728 |
-
|
729 |
-
|
730 |
-
</a>
|
731 |
-
<?php endif; ?>
|
732 |
-
</th>
|
733 |
-
</tr>
|
734 |
-
</thead>
|
735 |
|
736 |
-
|
737 |
-
|
738 |
-
|
739 |
-
$possible_keys = array(
|
740 |
-
'DOMAIN' => 'Domain Scanned',
|
741 |
-
'IP' => 'Site IP Address',
|
742 |
-
'HOSTING' => 'Hosting Company',
|
743 |
-
'CMS' => 'CMS Found',
|
744 |
-
);
|
745 |
-
$possible_url_keys = array(
|
746 |
-
'JSLOCAL' => 'List of scripts included',
|
747 |
-
'JSEXTERNAL' => 'List of external scripts included',
|
748 |
-
'URL' => 'List of links found',
|
749 |
-
);
|
750 |
-
?>
|
751 |
|
752 |
-
|
753 |
-
|
754 |
-
<?php $result_value = implode(', ', $res['SCAN'][$result_key]); ?>
|
755 |
-
<tr>
|
756 |
-
<td><?php _e($result_title) ?></td>
|
757 |
-
<td><span class="sucuriscan-monospace"><?php _e($result_value) ?></span></td>
|
758 |
-
</tr>
|
759 |
-
<?php endif; ?>
|
760 |
-
<?php endforeach; ?>
|
761 |
|
762 |
-
|
763 |
-
|
764 |
-
|
765 |
-
|
766 |
-
<tr>
|
767 |
-
<td>PHP Version</td>
|
768 |
-
<td><span class="sucuriscan-monospace"><?php _e(phpversion()) ?></span></td>
|
769 |
-
</tr>
|
770 |
|
771 |
-
|
772 |
-
|
773 |
-
|
774 |
-
|
775 |
-
|
776 |
-
|
777 |
-
|
778 |
-
|
779 |
-
|
780 |
-
|
781 |
-
<span class="sucuriscan-monospace"><?php _e($details) ?></span>
|
782 |
-
</td>
|
783 |
-
</tr>
|
784 |
-
<?php endforeach; ?>
|
785 |
-
<?php endif; ?>
|
786 |
-
<?php endforeach; ?>
|
787 |
|
788 |
-
|
789 |
-
|
790 |
-
|
791 |
-
|
792 |
-
|
793 |
-
|
794 |
-
|
795 |
-
|
|
|
|
|
|
|
|
|
796 |
|
797 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
798 |
|
799 |
-
|
800 |
-
|
801 |
-
|
802 |
-
|
803 |
-
|
804 |
-
__($result_url_title),
|
805 |
-
count($res['LINKS'][$result_url_key])
|
806 |
-
) ?>
|
807 |
-
</th>
|
808 |
-
</tr>
|
809 |
|
810 |
-
|
811 |
-
|
812 |
-
|
813 |
-
|
814 |
-
|
815 |
-
|
816 |
-
|
817 |
-
<?php endif; ?>
|
818 |
|
819 |
-
|
820 |
-
|
821 |
-
|
822 |
-
</
|
|
|
|
|
|
|
|
|
|
|
823 |
|
824 |
-
|
825 |
-
|
826 |
-
|
827 |
-
<h3>
|
828 |
-
<?php if( $blacklist_warns_exists ): ?>
|
829 |
-
Site blacklisted
|
830 |
-
<?php else: ?>
|
831 |
-
Site blacklist-free
|
832 |
-
<?php endif; ?>
|
833 |
-
</h3>
|
834 |
|
835 |
-
|
836 |
-
|
837 |
-
|
838 |
-
|
839 |
-
|
840 |
-
|
841 |
-
if( isset($res['BLACKLIST'][$type]) ){
|
842 |
-
foreach($res['BLACKLIST'][$type] as $blres){
|
843 |
-
$report_site = htmlspecialchars($blres[0]);
|
844 |
-
$report_url = htmlspecialchars($blres[1]);
|
845 |
-
echo "<b>{$group_title}: </b>{$report_site} <a href='{$report_url}' target='_blank'>{$report_url}</a><br />";
|
846 |
-
}
|
847 |
-
}
|
848 |
-
}
|
849 |
-
?>
|
850 |
-
</div>
|
851 |
-
</div>
|
852 |
-
</div>
|
853 |
-
</div>
|
854 |
-
</div>
|
855 |
-
</div>
|
856 |
|
857 |
-
|
858 |
-
|
859 |
-
|
860 |
-
|
861 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
862 |
|
863 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
864 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
865 |
|
866 |
-
|
867 |
-
|
868 |
-
|
869 |
-
|
870 |
-
'
|
871 |
-
'
|
872 |
-
'
|
873 |
-
|
874 |
-
|
875 |
}
|
876 |
|
877 |
/**
|
878 |
-
*
|
879 |
-
*
|
880 |
-
* It checks whether the WordPress core files are the original ones, and the state
|
881 |
-
* of the themes and plugins reporting the availability of updates. It also checks
|
882 |
-
* the user accounts under the administrator group.
|
883 |
*
|
884 |
* @return void
|
885 |
*/
|
886 |
-
function
|
|
|
|
|
|
|
887 |
|
888 |
-
if(
|
889 |
-
|
|
|
890 |
}
|
891 |
|
892 |
-
|
893 |
-
|
894 |
-
|
895 |
-
|
896 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
897 |
|
898 |
-
|
899 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
900 |
|
901 |
-
|
902 |
-
|
903 |
-
|
904 |
-
|
905 |
-
|
906 |
-
'
|
907 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
908 |
);
|
909 |
|
910 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
911 |
|
912 |
-
|
913 |
-
'
|
914 |
-
'
|
915 |
-
|
916 |
-
|
|
|
|
|
|
|
917 |
|
918 |
-
|
919 |
-
|
920 |
-
|
921 |
-
|
922 |
-
|
923 |
-
|
924 |
-
</div>
|
925 |
|
926 |
-
|
927 |
-
|
928 |
-
|
929 |
-
|
930 |
-
'
|
931 |
-
'
|
932 |
-
|
933 |
-
|
934 |
-
|
935 |
}
|
936 |
|
937 |
/**
|
938 |
-
*
|
939 |
-
*
|
|
|
940 |
*
|
941 |
-
* @param string $function_name Name of the function that will be executed on form submission.
|
942 |
-
* @param string $stitle Title of the HTML panel.
|
943 |
-
* @param string $description Explanation of the action that will be performed once the form is submitted.
|
944 |
* @return void
|
945 |
*/
|
946 |
-
function
|
947 |
-
|
948 |
-
|
949 |
-
|
950 |
-
<div class="inside">
|
951 |
-
<form method="post">
|
952 |
-
<input type="hidden" name="<?php _e($function_name) ?>nonce" value="<?php echo wp_create_nonce($function_name.'nonce'); ?>" />
|
953 |
-
<input type="hidden" name="<?php _e($function_name) ?>" value="1" />
|
954 |
-
<p><?php _e($description) ?></p>
|
955 |
-
<input class="button-primary" type="submit" name="<?php _e($function_name) ?>" value="Check" />
|
956 |
-
</form>
|
957 |
|
958 |
-
|
959 |
-
|
960 |
-
|
961 |
-
|
962 |
-
|
|
|
|
|
963 |
}
|
964 |
-
|
965 |
-
|
966 |
-
|
967 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
968 |
|
969 |
/**
|
970 |
-
*
|
|
|
971 |
*
|
972 |
* @return void
|
973 |
*/
|
974 |
-
function
|
975 |
-
|
976 |
-
|
977 |
-
|
978 |
-
|
979 |
-
|
980 |
-
|
981 |
-
|
982 |
-
|
983 |
-
|
984 |
-
|
985 |
-
|
986 |
-
|
987 |
-
|
988 |
-
|
989 |
-
|
990 |
-
|
991 |
-
|
992 |
-
|
993 |
-
|
994 |
-
|
995 |
-
|
996 |
-
|
997 |
-
|
998 |
-
&& isset($_POST['sucuriwp_content_check'])
|
999 |
-
): ?>
|
1000 |
-
<table class="wp-list-table widefat sucuriscan-table sucuriscan-table-doubletitle sucuriscan-lastmodified">
|
1001 |
-
<thead>
|
1002 |
-
<tr>
|
1003 |
-
<th colspan="2">wp_content latest modified files</th>
|
1004 |
-
</tr>
|
1005 |
-
<tr>
|
1006 |
-
<th class="manage-column">Filepath</th>
|
1007 |
-
<th class="manage-column">Modification date/time</th>
|
1008 |
-
</tr>
|
1009 |
-
</thead>
|
1010 |
-
<tbody>
|
1011 |
-
<?php
|
1012 |
-
$wp_content_hashes = read_dir_r(ABSPATH.'wp-content', true);
|
1013 |
-
$days = htmlspecialchars(trim((int)$_POST['sucuriwp_content_check_back']));
|
1014 |
-
$back_days = current_time( 'timestamp' ) - ( $days * 86400);
|
1015 |
-
$counter = 0;
|
1016 |
-
|
1017 |
-
foreach ( $wp_content_hashes as $key => $value) {
|
1018 |
-
if ($value['time'] >= $back_days ){
|
1019 |
-
$css_class = ( $counter % 2 == 0 ) ? '' : 'alternate';
|
1020 |
-
$date = date('d-m-Y H:i:s', $value['time']);
|
1021 |
-
printf('<tr class="%s"><td>%s</td><td>%s</td></tr>', $css_class, $key, $date);
|
1022 |
-
$counter += 1;
|
1023 |
-
}
|
1024 |
-
}
|
1025 |
-
?>
|
1026 |
-
</tbody>
|
1027 |
-
</table>
|
1028 |
-
<?php endif; ?>
|
1029 |
-
</div>
|
1030 |
-
</div>
|
1031 |
-
<?php }
|
1032 |
|
1033 |
/**
|
1034 |
-
*
|
1035 |
-
* folder specified. This is a recursive function.
|
1036 |
*
|
1037 |
-
* @
|
1038 |
-
* @param boolean $recursiv Either TRUE or FALSE if the scan should be performed recursively.
|
1039 |
-
* @return array List of arrays containing the md5sum and last modification time of the files found.
|
1040 |
*/
|
1041 |
-
function
|
1042 |
-
$
|
1043 |
-
$skipname .= ",_sucuribackup,wp-config.php";
|
1044 |
|
1045 |
-
|
1046 |
-
|
1047 |
-
|
1048 |
-
|
1049 |
-
while(($entry = readdir($dir_handler)) !== false) {
|
1050 |
-
if ($entry != "." && $entry != "..") {
|
1051 |
-
$dir = preg_replace("/^(.*)(\/)+$/", "$1", $dir);
|
1052 |
-
$item = sprintf( '%s/%s', $dir, $entry );
|
1053 |
|
1054 |
-
|
1055 |
-
|
1056 |
|
1057 |
-
|
1058 |
-
|
1059 |
-
|
1060 |
-
}
|
|
|
1061 |
}
|
1062 |
|
1063 |
-
$
|
1064 |
-
|
1065 |
-
$
|
1066 |
-
|
1067 |
-
|
1068 |
-
|
1069 |
-
|
1070 |
}
|
|
|
1071 |
|
1072 |
-
|
1073 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1074 |
}
|
1075 |
}
|
1076 |
}
|
1077 |
|
1078 |
-
|
1079 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1080 |
}
|
1081 |
|
1082 |
/**
|
1083 |
-
*
|
1084 |
-
*
|
1085 |
-
*
|
1086 |
*
|
1087 |
* @return void
|
1088 |
*/
|
1089 |
-
function
|
1090 |
-
|
1091 |
-
global $wp_version;
|
1092 |
|
1093 |
-
$
|
1094 |
|
1095 |
-
|
1096 |
-
|
1097 |
-
|
1098 |
-
|
1099 |
-
|
1100 |
-
|
1101 |
-
{
|
1102 |
-
$
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1103 |
}
|
1104 |
-
$wp_version = htmlspecialchars($wp_version);
|
1105 |
|
1106 |
-
|
1107 |
-
|
1108 |
-
|
1109 |
-
|
1110 |
-
|
1111 |
-
|
1112 |
-
|
1113 |
-
|
1114 |
-
|
1115 |
-
|
1116 |
-
|
1117 |
-
|
1118 |
-
|
1119 |
-
|
1120 |
-
|
1121 |
-
|
1122 |
-
|
1123 |
-
|
1124 |
-
|
|
|
|
|
|
|
|
|
1125 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1126 |
}
|
1127 |
|
1128 |
/**
|
1129 |
-
*
|
|
|
|
|
1130 |
*
|
1131 |
-
* @param array $list List of WordPress core files modified.
|
1132 |
* @return void
|
1133 |
*/
|
1134 |
-
function
|
1135 |
-
if(
|
1136 |
-
|
1137 |
-
|
1138 |
-
|
1139 |
-
|
1140 |
-
|
1141 |
-
|
1142 |
-
|
1143 |
-
|
1144 |
-
|
1145 |
-
|
1146 |
-
|
1147 |
-
|
1148 |
-
|
1149 |
-
</tbody>
|
1150 |
-
</table>
|
1151 |
-
<?php endif; ?>
|
1152 |
-
<?php }
|
1153 |
|
1154 |
/**
|
1155 |
-
*
|
|
|
1156 |
*
|
1157 |
-
* @
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1158 |
*
|
1159 |
* @return void
|
1160 |
*/
|
1161 |
-
function
|
1162 |
|
1163 |
-
|
|
|
|
|
1164 |
|
1165 |
-
// Page pseudo-variables initialization.
|
1166 |
$template_variables = array(
|
1167 |
-
'
|
|
|
|
|
|
|
|
|
|
|
1168 |
);
|
1169 |
|
1170 |
-
|
1171 |
-
|
|
|
1172 |
|
1173 |
-
|
1174 |
-
$
|
1175 |
|
1176 |
-
$
|
1177 |
-
'
|
1178 |
-
|
1179 |
-
'AdminUsers.LastLogins'=>'',
|
1180 |
-
'AdminUsers.UserURL'=>admin_url('user-edit.php?user_id='.$admin->ID)
|
1181 |
-
);
|
1182 |
|
1183 |
-
|
1184 |
-
$
|
1185 |
-
$user_snippet['AdminUsers.NoLastLoginsTable'] = 'visible';
|
1186 |
|
1187 |
-
|
1188 |
-
|
1189 |
-
|
1190 |
-
|
1191 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1192 |
}
|
1193 |
-
|
1194 |
-
$
|
1195 |
-
$
|
1196 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1197 |
|
1198 |
-
|
|
|
1199 |
}
|
1200 |
|
1201 |
-
|
1202 |
}
|
1203 |
|
1204 |
/**
|
1205 |
-
*
|
|
|
|
|
1206 |
*
|
1207 |
* @return void
|
1208 |
*/
|
1209 |
-
function
|
|
|
1210 |
|
1211 |
-
|
1212 |
-
|
1213 |
-
|
1214 |
-
|
1215 |
-
|
|
|
1216 |
|
1217 |
-
|
1218 |
-
|
1219 |
-
do_action('wp_update_plugins');
|
1220 |
-
wp_update_plugins();
|
1221 |
-
$update_plugins = get_site_transient('update_plugins');
|
1222 |
-
$plugins_need_update = (bool) !empty($update_plugins->response);
|
1223 |
-
?>
|
1224 |
|
1225 |
-
|
1226 |
-
|
1227 |
-
|
1228 |
-
|
1229 |
-
|
1230 |
-
|
1231 |
-
|
1232 |
-
|
1233 |
-
|
1234 |
-
|
1235 |
-
|
1236 |
-
|
1237 |
-
|
1238 |
-
|
1239 |
-
|
1240 |
-
|
1241 |
-
|
1242 |
-
|
1243 |
-
|
1244 |
-
|
1245 |
-
<td><a href="<?php _e($plugin_info->package) ?>" target="_blank">Download</a></td>
|
1246 |
-
</tr>
|
1247 |
-
<?php endforeach; ?>
|
1248 |
-
<?php else: ?>
|
1249 |
-
<tr>
|
1250 |
-
<td colspan="4">All plugins are up-to-date.</td>
|
1251 |
-
</tr>
|
1252 |
-
<?php endif; ?>
|
1253 |
|
1254 |
-
|
1255 |
-
|
1256 |
-
|
1257 |
-
|
1258 |
-
|
1259 |
-
|
1260 |
-
|
|
|
1261 |
|
1262 |
-
<tr>
|
1263 |
-
<th>Theme</th>
|
1264 |
-
<th>Installed Version</th>
|
1265 |
-
<th>New Version</th>
|
1266 |
-
<th> </th>
|
1267 |
-
</tr>
|
1268 |
-
|
1269 |
-
<?php if( $themes_need_update ): ?>
|
1270 |
-
<?php
|
1271 |
-
$counter = 0;
|
1272 |
-
foreach( $update_themes as $stylesheet => $theme ):
|
1273 |
$css_class = ( $counter % 2 == 0 ) ? '' : 'alternate';
|
|
|
|
|
|
|
|
|
|
|
|
|
1274 |
$counter += 1;
|
1275 |
-
|
1276 |
-
|
1277 |
-
<tr class="<?php _e($css_class) ?>">
|
1278 |
-
<td><?php _e($theme->display('Name')) ?></td>
|
1279 |
-
<td><?php _e($theme->display('Version')) ?></td>
|
1280 |
-
<td><?php _e($theme->update['new_version']) ?></td>
|
1281 |
-
<td><a href="<?php _e($theme->update['package']) ?>" target="_blank">Download</a></td>
|
1282 |
-
</tr>
|
1283 |
-
<?php endforeach; ?>
|
1284 |
-
<?php else: ?>
|
1285 |
-
<tr>
|
1286 |
-
<td colspan="4">All themes are up-to-date.</td>
|
1287 |
-
</tr>
|
1288 |
-
<?php endif; ?>
|
1289 |
-
</tbody>
|
1290 |
-
</table>
|
1291 |
|
1292 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1293 |
|
1294 |
/**
|
1295 |
* Retrieve a list with the checksums of the files in a specific version of WordPress.
|
1296 |
*
|
|
|
|
|
1297 |
* @param integer $version Valid version number of the WordPress project.
|
1298 |
* @return object Associative object with the relative filepath and the checksums of the project files.
|
1299 |
*/
|
1300 |
-
function sucuriscan_get_official_checksums($version=0){
|
1301 |
$api_url = sprintf('http://api.wordpress.org/core/checksums/1.0/?version=%s&locale=en_US', $version);
|
1302 |
-
|
1303 |
$request = wp_remote_get($api_url);
|
|
|
1304 |
if( !is_wp_error($request) || wp_remote_retrieve_response_code($request) === 200 ){
|
1305 |
$json_data = json_decode($request['body']);
|
|
|
1306 |
if( $json_data->checksums !== FALSE ){
|
1307 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1308 |
}
|
1309 |
}
|
1310 |
|
@@ -1317,47 +5620,59 @@ function sucuriscan_get_official_checksums($version=0){
|
|
1317 |
* these keys:
|
1318 |
*
|
1319 |
* <ul>
|
1320 |
-
* <li>
|
1321 |
-
* <li>
|
1322 |
* <li>removed: Official files which are not present in the local project,</li>
|
1323 |
* <li>added: Files present in the local project but not in the official WordPress packages.</li>
|
1324 |
* </ul>
|
1325 |
*
|
1326 |
* @param integer $version Valid version number of the WordPress project.
|
1327 |
-
* @return array Associative array with these keys:
|
1328 |
*/
|
1329 |
-
function sucuriscan_check_wp_integrity($version=0){
|
1330 |
$latest_hashes = sucuriscan_get_official_checksums($version);
|
1331 |
|
1332 |
if( !$latest_hashes ){ return FALSE; }
|
1333 |
|
1334 |
-
$output = array(
|
|
|
|
|
|
|
|
|
|
|
1335 |
|
1336 |
// Get current filesystem tree.
|
1337 |
-
$wp_top_hashes =
|
1338 |
-
$wp_admin_hashes =
|
1339 |
-
$wp_includes_hashes =
|
1340 |
$wp_core_hashes = array_merge( $wp_top_hashes, $wp_admin_hashes, $wp_includes_hashes );
|
1341 |
|
1342 |
-
// Compare remote and local
|
1343 |
-
foreach( $latest_hashes as $filepath
|
|
|
|
|
1344 |
$full_filepath = sprintf('%s/%s', ABSPATH, $filepath);
|
|
|
1345 |
if( file_exists($full_filepath) ){
|
1346 |
$local_checksum = @md5_file($full_filepath);
|
|
|
1347 |
if( $local_checksum && $local_checksum == $remote_checksum ){
|
1348 |
-
$output['
|
1349 |
-
}else{
|
1350 |
-
$output['
|
1351 |
}
|
1352 |
-
}else{
|
1353 |
$output['removed'][] = $filepath;
|
1354 |
}
|
1355 |
}
|
1356 |
|
1357 |
// Search added files (files not common in a normal wordpress installation).
|
1358 |
-
foreach( $wp_core_hashes
|
1359 |
$filepath = preg_replace('/^\.\/(.*)/', '$1', $filepath);
|
1360 |
-
|
|
|
|
|
|
|
1361 |
$output['added'][] = $filepath;
|
1362 |
}
|
1363 |
}
|
@@ -1366,621 +5681,462 @@ function sucuriscan_check_wp_integrity($version=0){
|
|
1366 |
}
|
1367 |
|
1368 |
/**
|
1369 |
-
*
|
1370 |
-
*
|
1371 |
-
* It loads all the functions defined in /lib/hardening.php and shows the forms
|
1372 |
-
* that the administrator can use to harden multiple parts of the site.
|
1373 |
*
|
1374 |
-
* @
|
|
|
1375 |
*/
|
1376 |
-
function
|
1377 |
-
|
1378 |
-
|
1379 |
-
|
1380 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1381 |
|
1382 |
-
if(
|
1383 |
-
|
1384 |
-
|
1385 |
-
|
|
|
|
|
1386 |
}
|
1387 |
|
1388 |
-
|
1389 |
-
?>
|
1390 |
-
|
1391 |
-
<div id="poststuff">
|
1392 |
-
<form method="post">
|
1393 |
-
<input type="hidden" name="sucuriscan_hardening_nonce" value="<?php echo wp_create_nonce('sucuriscan_hardening_nonce'); ?>" />
|
1394 |
-
<input type="hidden" name="wpsucuri-doharden" value="wpsucuri-doharden" />
|
1395 |
-
|
1396 |
-
<?php
|
1397 |
-
sucuriscan_harden_version();
|
1398 |
-
sucuriscan_cloudproxy_enabled();
|
1399 |
-
sucuri_harden_removegenerator();
|
1400 |
-
sucuriscan_harden_upload();
|
1401 |
-
sucuriscan_harden_wpcontent();
|
1402 |
-
sucuriscan_harden_wpincludes();
|
1403 |
-
sucuriscan_harden_phpversion();
|
1404 |
-
?>
|
1405 |
-
</form>
|
1406 |
-
</div>
|
1407 |
-
|
1408 |
-
<?php
|
1409 |
-
$_html = ob_get_contents();
|
1410 |
-
ob_end_clean();
|
1411 |
-
echo sucuriscan_get_template('base', array(
|
1412 |
-
'PageTitle' => '(1-Click Hardening)',
|
1413 |
-
'PageContent' => $_html,
|
1414 |
-
'PageStyleClass' => 'hardening'
|
1415 |
-
));
|
1416 |
-
return;
|
1417 |
-
}
|
1418 |
-
|
1419 |
-
/**
|
1420 |
-
* Print the HTML code to show the title of a hardening option box.
|
1421 |
-
*
|
1422 |
-
* @param string $msg The title of the hardening option.
|
1423 |
-
* @return void
|
1424 |
-
*/
|
1425 |
-
function sucuriscan_wrapper_open($msg){
|
1426 |
-
?>
|
1427 |
-
<div class="postbox">
|
1428 |
-
<h3><?php echo $msg; ?></h3>
|
1429 |
-
<div class="inside">
|
1430 |
-
<?php
|
1431 |
}
|
1432 |
|
1433 |
/**
|
1434 |
-
*
|
1435 |
*
|
1436 |
* @return void
|
1437 |
*/
|
1438 |
-
function
|
1439 |
-
|
1440 |
-
|
1441 |
-
|
1442 |
-
|
1443 |
-
|
|
|
|
|
1444 |
|
1445 |
-
|
1446 |
-
|
1447 |
-
*
|
1448 |
-
* @param string $message The text string that will be shown inside the error box.
|
1449 |
-
* @return void
|
1450 |
-
*/
|
1451 |
-
function sucuriscan_harden_error($message){
|
1452 |
-
return('<div id="message" class="error"><p>'.$message.'</p></div>');
|
1453 |
-
}
|
1454 |
|
1455 |
-
|
1456 |
-
|
1457 |
-
|
1458 |
-
|
1459 |
-
|
1460 |
-
|
1461 |
-
function sucuriscan_harden_ok($message){
|
1462 |
-
return( '<div id="message" class="updated"><p>'.$message.'</p></div>');
|
1463 |
-
}
|
1464 |
|
1465 |
-
|
1466 |
-
|
1467 |
-
|
1468 |
-
|
1469 |
-
|
1470 |
-
|
1471 |
-
|
1472 |
-
* @param string $messageok Message that will be shown if the hardening was executed.
|
1473 |
-
* @param string $messagewarn Message that will be shown if the hardening is not executed.
|
1474 |
-
* @param string $desc Optional description of the hardening.
|
1475 |
-
* @param string $updatemsg Optional explanation of the hardening after the submission of the form.
|
1476 |
-
* @return void
|
1477 |
-
*/
|
1478 |
-
function sucuriscan_harden_status($status=0, $type='', $messageok='', $messagewarn='', $desc = NULL, $updatemsg = NULL){
|
1479 |
-
if($desc != NULL)
|
1480 |
-
{
|
1481 |
-
echo "<p>$desc</p>";
|
1482 |
}
|
1483 |
|
1484 |
-
|
1485 |
-
|
1486 |
-
|
1487 |
-
|
1488 |
-
|
1489 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1490 |
}
|
1491 |
}
|
1492 |
|
1493 |
-
|
1494 |
-
|
1495 |
-
if($updatemsg != NULL){
|
1496 |
-
printf( '<p>%s</p>', $updatemsg );
|
1497 |
}
|
|
|
|
|
1498 |
}
|
1499 |
|
1500 |
/**
|
1501 |
-
*
|
1502 |
-
* version available officially.
|
1503 |
*
|
1504 |
* @return void
|
1505 |
*/
|
1506 |
-
function
|
1507 |
-
|
1508 |
-
|
1509 |
-
$updates = get_core_updates();
|
1510 |
-
if(
|
1511 |
-
!is_array($updates)
|
1512 |
-
|| empty($updates)
|
1513 |
-
|| $updates[0]->response == 'latest'
|
1514 |
-
){
|
1515 |
-
$cp = 1;
|
1516 |
-
} else {
|
1517 |
-
$cp = 0;
|
1518 |
}
|
1519 |
|
1520 |
-
|
1521 |
-
{
|
1522 |
-
$cp = 0;
|
1523 |
-
}
|
1524 |
|
1525 |
-
|
1526 |
-
$
|
1527 |
-
|
1528 |
-
|
1529 |
-
|
1530 |
-
|
1531 |
-
$messageok = sprintf('Your WordPress installation (%s) is current.', $wp_version);
|
1532 |
-
$messagewarn = sprintf(
|
1533 |
-
'Your current version (%s) is not current.<br>
|
1534 |
-
<a href="update-core.php" class="button-primary">Update now!</a>',
|
1535 |
-
$wp_version
|
1536 |
);
|
1537 |
|
1538 |
-
|
1539 |
-
sucuriscan_harden_status( $cp, NULL, $messageok, $messagewarn, $initial_msg );
|
1540 |
-
sucuriscan_wrapper_close();
|
1541 |
}
|
1542 |
|
1543 |
/**
|
1544 |
-
*
|
1545 |
-
* HTML code printed by WordPress to show the current version number of the
|
1546 |
-
* installation.
|
1547 |
*
|
1548 |
-
* @return
|
1549 |
*/
|
1550 |
-
function
|
1551 |
-
|
1552 |
-
|
1553 |
-
|
1554 |
-
|
1555 |
-
|
1556 |
-
|
1557 |
-
|
1558 |
-
"It checks if your WordPress version is being hidden".
|
1559 |
-
" from being displayed in the generator tag ".
|
1560 |
-
"(enabled by default with this plugin).");
|
1561 |
|
1562 |
-
|
1563 |
}
|
1564 |
|
1565 |
/**
|
1566 |
-
*
|
1567 |
-
*
|
1568 |
-
* A htaccess file is placed in the upload folder denying the access to any php
|
1569 |
-
* file that could be uploaded through a vulnerability in a Plugin, Theme or
|
1570 |
-
* WordPress itself.
|
1571 |
*
|
1572 |
-
* @
|
|
|
1573 |
*/
|
1574 |
-
function
|
1575 |
-
$
|
1576 |
-
|
1577 |
-
|
1578 |
-
|
1579 |
-
if(!is_readable($htaccess_upload))
|
1580 |
-
{
|
1581 |
-
$cp = 0;
|
1582 |
-
}
|
1583 |
-
else
|
1584 |
-
{
|
1585 |
-
$cp = 0;
|
1586 |
-
$fcontent = file($htaccess_upload);
|
1587 |
-
foreach($fcontent as $fline)
|
1588 |
-
{
|
1589 |
-
if(strpos($fline, "deny from all") !== FALSE)
|
1590 |
-
{
|
1591 |
-
$cp = 1;
|
1592 |
-
break;
|
1593 |
-
}
|
1594 |
-
}
|
1595 |
-
}
|
1596 |
-
|
1597 |
-
if( isset($_POST['wpsucuri-doharden']) ){
|
1598 |
-
if( isset($_POST['sucuriscan_harden_upload']) && $cp == 0 )
|
1599 |
-
{
|
1600 |
-
if(@file_put_contents($htaccess_upload,
|
1601 |
-
"\n<Files *.php>\ndeny from all\n</Files>")===FALSE)
|
1602 |
-
{
|
1603 |
-
$upmsg = sucuriscan_harden_error("ERROR: Unable to create <code>.htaccess</code> file, folder destination is not writable.");
|
1604 |
-
}
|
1605 |
-
else
|
1606 |
-
{
|
1607 |
-
$upmsg = sucuriscan_harden_ok("COMPLETE: Upload directory successfully hardened");
|
1608 |
-
$cp = 1;
|
1609 |
-
}
|
1610 |
-
}
|
1611 |
-
|
1612 |
-
elseif( isset($_POST['sucuriscan_harden_upload_unharden']) ){
|
1613 |
-
$htaccess_upload_writable = ( file_exists($htaccess_upload) && is_writable($htaccess_upload) ) ? TRUE : FALSE;
|
1614 |
-
$htaccess_content = $htaccess_upload_writable ? file_get_contents($htaccess_upload) : '';
|
1615 |
|
1616 |
-
|
1617 |
-
|
1618 |
-
|
1619 |
-
|
1620 |
-
|
1621 |
-
|
1622 |
-
|
1623 |
-
|
1624 |
-
|
1625 |
-
|
1626 |
-
|
1627 |
-
|
|
|
|
|
|
|
|
|
|
|
1628 |
}
|
|
|
|
|
1629 |
}
|
1630 |
}
|
1631 |
|
1632 |
-
|
1633 |
-
sucuriscan_harden_status($cp, "sucuriscan_harden_upload",
|
1634 |
-
"Upload directory properly hardened",
|
1635 |
-
"Upload directory not hardened",
|
1636 |
-
"It checks if your upload directory allows PHP ".
|
1637 |
-
"execution or if it is browsable.", $upmsg);
|
1638 |
-
sucuriscan_wrapper_close();
|
1639 |
}
|
1640 |
|
1641 |
/**
|
1642 |
-
*
|
1643 |
-
*
|
1644 |
-
* A htaccess file is placed in the content folder denying the access to any php
|
1645 |
-
* file that could be uploaded through a vulnerability in a Plugin, Theme or
|
1646 |
-
* WordPress itself.
|
1647 |
*
|
1648 |
-
* @
|
|
|
1649 |
*/
|
1650 |
-
function
|
1651 |
-
$
|
1652 |
-
|
1653 |
-
|
1654 |
|
1655 |
-
if
|
1656 |
-
|
1657 |
-
$cp = 0;
|
1658 |
-
}
|
1659 |
-
else
|
1660 |
-
{
|
1661 |
-
$cp = 0;
|
1662 |
-
$fcontent = file($htaccess_upload);
|
1663 |
-
foreach($fcontent as $fline)
|
1664 |
-
{
|
1665 |
-
if(strpos($fline, "deny from all") !== FALSE)
|
1666 |
-
{
|
1667 |
-
$cp = 1;
|
1668 |
-
break;
|
1669 |
-
}
|
1670 |
-
}
|
1671 |
-
}
|
1672 |
|
1673 |
-
|
1674 |
-
|
1675 |
-
{
|
1676 |
-
if(@file_put_contents($htaccess_upload,
|
1677 |
-
"\n<Files *.php>\ndeny from all\n</Files>")===FALSE)
|
1678 |
-
{
|
1679 |
-
$upmsg = sucuriscan_harden_error("ERROR: Unable to create <code>.htaccess</code> file, folder destination is not writable.");
|
1680 |
-
}
|
1681 |
-
else
|
1682 |
-
{
|
1683 |
-
$upmsg = sucuriscan_harden_ok("COMPLETE: wp-content directory successfully hardened");
|
1684 |
-
$cp = 1;
|
1685 |
-
}
|
1686 |
-
}
|
1687 |
|
1688 |
-
|
1689 |
-
|
1690 |
-
$htaccess_content = $htaccess_upload_writable ? file_get_contents($htaccess_upload) : '';
|
1691 |
|
1692 |
-
|
1693 |
-
|
1694 |
-
|
1695 |
-
|
1696 |
-
|
1697 |
-
|
1698 |
-
|
1699 |
-
|
1700 |
-
|
1701 |
-
|
1702 |
-
|
1703 |
-
|
1704 |
-
|
|
|
|
|
|
|
|
|
1705 |
}
|
1706 |
}
|
1707 |
|
1708 |
-
|
1709 |
-
sucuriscan_harden_status(
|
1710 |
-
$cp,
|
1711 |
-
'sucuriscan_harden_wpcontent',
|
1712 |
-
'WP-content directory properly hardened',
|
1713 |
-
'WP-content directory not hardened',
|
1714 |
-
'This option blocks direct PHP access to any file inside wp-content. If you experience any
|
1715 |
-
issue after this with a theme or plugin in your site, like for example images not displaying,
|
1716 |
-
remove the <code>.htaccess</code> file located at the <code>/wp-content/</code> directory.',
|
1717 |
-
$upmsg);
|
1718 |
-
sucuriscan_wrapper_close();
|
1719 |
}
|
1720 |
|
1721 |
/**
|
1722 |
-
*
|
1723 |
-
*
|
1724 |
-
* A htaccess file is placed in the includes folder denying the access to any php
|
1725 |
-
* file that could be uploaded through a vulnerability in a Plugin, Theme or
|
1726 |
-
* WordPress itself, there are some exceptions for some specific files that must
|
1727 |
-
* be available publicly.
|
1728 |
*
|
|
|
1729 |
* @return void
|
1730 |
*/
|
1731 |
-
function
|
1732 |
-
$
|
1733 |
-
|
1734 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1735 |
|
1736 |
-
|
1737 |
-
|
1738 |
-
$cp = 0;
|
1739 |
-
}
|
1740 |
-
else
|
1741 |
-
{
|
1742 |
-
$cp = 0;
|
1743 |
-
$fcontent = file($htaccess_upload);
|
1744 |
-
foreach($fcontent as $fline)
|
1745 |
-
{
|
1746 |
-
if(strpos($fline, "deny from all") !== FALSE)
|
1747 |
-
{
|
1748 |
-
$cp = 1;
|
1749 |
-
break;
|
1750 |
}
|
1751 |
-
}
|
1752 |
-
}
|
1753 |
|
1754 |
-
|
1755 |
-
|
1756 |
-
{
|
1757 |
-
if(@file_put_contents($htaccess_upload,
|
1758 |
-
"\n<Files *.php>\ndeny from all\n</Files>\n<Files wp-tinymce.php>\nallow from all\n</Files>\n")===FALSE)
|
1759 |
-
{
|
1760 |
-
$upmsg = sucuriscan_harden_error("ERROR: Unable to create <code>.htaccess</code> file, folder destination is not writable.");
|
1761 |
-
}
|
1762 |
-
else
|
1763 |
-
{
|
1764 |
-
$upmsg = sucuriscan_harden_ok("COMPLETE: wp-includes directory successfully hardened.");
|
1765 |
-
$cp = 1;
|
1766 |
}
|
|
|
|
|
1767 |
}
|
|
|
|
|
1768 |
|
1769 |
-
|
1770 |
-
|
1771 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1772 |
|
1773 |
-
|
1774 |
-
|
1775 |
-
|
1776 |
-
|
1777 |
-
|
1778 |
-
|
1779 |
-
|
1780 |
-
|
1781 |
-
|
1782 |
-
|
1783 |
-
|
1784 |
-
|
1785 |
-
|
1786 |
-
|
1787 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1788 |
}
|
1789 |
}
|
1790 |
|
1791 |
-
|
1792 |
-
sucuriscan_harden_status($cp, "sucuriscan_harden_wpincludes",
|
1793 |
-
"wp-includes directory properly hardened",
|
1794 |
-
"wp-includes directory not hardened",
|
1795 |
-
"This option blocks direct PHP access to any file inside wp-includes. ", $upmsg);
|
1796 |
-
sucuriscan_wrapper_close();
|
1797 |
}
|
1798 |
|
1799 |
/**
|
1800 |
-
*
|
1801 |
-
* is considered that old versions of the PHP interpreter are insecure.
|
1802 |
*
|
|
|
1803 |
* @return void
|
1804 |
*/
|
1805 |
-
function
|
1806 |
-
$
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1807 |
|
1808 |
-
if(strncmp($phpv, "5.", 2) < 0)
|
1809 |
-
{
|
1810 |
-
$cp = 0;
|
1811 |
}
|
1812 |
-
|
1813 |
-
|
1814 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1815 |
}
|
1816 |
|
1817 |
-
|
1818 |
-
sucuriscan_harden_status($cp, NULL,
|
1819 |
-
"Using an updated version of PHP (v $phpv)",
|
1820 |
-
"The version of PHP you are using ($phpv) is not current, not recommended, and/or not supported",
|
1821 |
-
"This checks if you have the latest version of PHP installed.", NULL);
|
1822 |
-
sucuriscan_wrapper_close();
|
1823 |
}
|
1824 |
|
1825 |
/**
|
1826 |
-
*
|
1827 |
*
|
1828 |
-
*
|
|
|
|
|
1829 |
*/
|
1830 |
-
function
|
1831 |
-
|
1832 |
-
|
1833 |
-
if( $enabled!==TRUE ){
|
1834 |
-
$btn_string = '<a href="http://cloudproxy.sucuri.net/" target="_blank" class="button button-primary">Harden</a>';
|
1835 |
}
|
1836 |
|
1837 |
-
|
1838 |
-
|
1839 |
-
|
1840 |
-
'
|
1841 |
-
|
1842 |
-
'
|
1843 |
-
|
1844 |
-
|
1845 |
-
NULL
|
1846 |
);
|
1847 |
-
|
|
|
1848 |
}
|
1849 |
|
1850 |
/**
|
1851 |
-
*
|
|
|
|
|
1852 |
*
|
1853 |
* @return void
|
1854 |
*/
|
1855 |
-
function
|
1856 |
-
|
1857 |
-
if( !current_user_can('manage_options') ){
|
1858 |
-
wp_die(__('You do not have sufficient permissions to access this page: Sucuri Post-Hack') );
|
1859 |
-
}
|
1860 |
-
|
1861 |
// Page pseudo-variables initialization.
|
1862 |
$template_variables = array(
|
1863 |
-
'
|
1864 |
-
'PosthackNonce' => wp_create_nonce('sucuri_posthack_nonce'),
|
1865 |
-
'WPConfigUpdate.Display' => 'display:none',
|
1866 |
-
'WPConfigUpdate.NewConfig' => '',
|
1867 |
-
'ResetPassword.UserList' => ''
|
1868 |
);
|
1869 |
|
1870 |
-
|
1871 |
-
|
1872 |
-
if( !wp_verify_nonce($_POST['sucuri_posthack_nonce'], 'sucuri_posthack_nonce') ){
|
1873 |
-
wp_die(__('WordPress Nonce verification failed, try again going back and checking the form.') );
|
1874 |
-
}
|
1875 |
|
1876 |
-
|
1877 |
-
|
1878 |
-
$update_wpconfig = ( isset($_POST['sucuri_update_wpconfig']) && $_POST['sucuri_update_wpconfig']==1 ) ? TRUE : FALSE;
|
1879 |
|
1880 |
-
|
1881 |
-
|
1882 |
-
|
|
|
|
|
|
|
|
|
|
|
1883 |
|
1884 |
-
|
1885 |
-
|
1886 |
-
|
1887 |
-
|
1888 |
-
|
1889 |
-
|
1890 |
-
|
1891 |
-
|
1892 |
-
|
1893 |
-
|
1894 |
-
|
1895 |
-
|
1896 |
-
|
1897 |
-
|
1898 |
-
}
|
1899 |
-
}else{
|
1900 |
-
sucuriscan_admin_notice('error', '<strong>Error.</strong> You need to confirm that you understand the risk of this operation');
|
1901 |
-
}
|
1902 |
-
break;
|
1903 |
-
case 'reset_password':
|
1904 |
-
$reset_password = ( isset($_POST['sucuri_reset_password']) && $_POST['sucuri_reset_password']==1 ) ? TRUE : FALSE;
|
1905 |
-
|
1906 |
-
if( $reset_password ){
|
1907 |
-
$user_identifiers = isset($_POST['user_ids']) ? $_POST['user_ids'] : array();
|
1908 |
-
$pwd_changed = $pwd_not_changed = array();
|
1909 |
-
|
1910 |
-
if( is_array($user_identifiers) && !empty($user_identifiers) ){
|
1911 |
-
arsort($user_identifiers);
|
1912 |
-
foreach($user_identifiers as $user_id){
|
1913 |
-
if( sucuriscan_new_password($user_id) ){
|
1914 |
-
$pwd_changed[] = $user_id;
|
1915 |
-
}else{
|
1916 |
-
$pwd_not_changed[] = $user_id;
|
1917 |
-
}
|
1918 |
-
}
|
1919 |
-
if( !empty($pwd_changed) ){
|
1920 |
-
sucuriscan_admin_notice('updated', '<strong>OK.</strong> Password changed successfully for users: '.implode(', ',$pwd_changed));
|
1921 |
-
}
|
1922 |
-
if( !empty($pwd_not_changed) ){
|
1923 |
-
sucuriscan_admin_notice('error', '<strong>Error.</strong> Password change failed for users: '.implode(', ',$pwd_not_changed));
|
1924 |
-
}
|
1925 |
-
}else{
|
1926 |
-
sucuriscan_admin_notice('error', '<strong>Error.</strong> You did not select any user account to be reseted');
|
1927 |
-
}
|
1928 |
-
}else{
|
1929 |
-
sucuriscan_admin_notice('error', '<strong>Error.</strong> You need to confirm that you understand the risk of this operation');
|
1930 |
-
}
|
1931 |
-
break;
|
1932 |
-
default:
|
1933 |
-
wp_die(__('Sucuri WP Plugin, invalid form action, go back and try again.'));
|
1934 |
-
break;
|
1935 |
}
|
1936 |
-
}
|
1937 |
|
1938 |
-
|
1939 |
-
$counter = 0;
|
1940 |
-
$user_list = get_users();
|
1941 |
-
foreach($user_list as $user){
|
1942 |
-
$counter += 1;
|
1943 |
-
$user->user_registered_timestamp = strtotime($user->user_registered);
|
1944 |
-
$user->user_registered_formatted = date('D, M/Y H:i', $user->user_registered_timestamp);
|
1945 |
-
$user_snippet = sucuriscan_get_snippet('resetpassword', array(
|
1946 |
-
'ResetPassword.UserId' => $user->ID,
|
1947 |
-
'ResetPassword.Username' => $user->user_login,
|
1948 |
-
'ResetPassword.Displayname' => $user->display_name,
|
1949 |
-
'ResetPassword.Email' => $user->user_email,
|
1950 |
-
'ResetPassword.Registered' => $user->user_registered_formatted,
|
1951 |
-
'ResetPassword.Roles' => implode(', ', $user->roles),
|
1952 |
-
'ResetPassword.CssClass' => ( $counter%2 == 0 ) ? '' : 'alternate'
|
1953 |
-
));
|
1954 |
-
$template_variables['ResetPassword.UserList'] .= $user_snippet;
|
1955 |
}
|
1956 |
|
1957 |
-
|
1958 |
}
|
1959 |
|
1960 |
/**
|
1961 |
-
*
|
1962 |
*
|
1963 |
* This page will contains information of all the logins of the registered users.
|
1964 |
*
|
1965 |
-
* @return
|
1966 |
*/
|
1967 |
-
function
|
1968 |
-
if( !current_user_can('manage_options') ){
|
1969 |
-
wp_die(__('You do not have sufficient permissions to access this page: Sucuri Last-Logins') );
|
1970 |
-
}
|
1971 |
-
|
1972 |
-
// Page pseudo-variables initialization.
|
1973 |
$template_variables = array(
|
1974 |
-
'PageTitle' => 'Last Logins',
|
1975 |
-
'LastLoginsNonce' => wp_create_nonce('sucuriscan_lastlogins_nonce'),
|
1976 |
'UserList' => '',
|
1977 |
'UserListLimit' => SUCURISCAN_LASTLOGINS_USERSLIMIT,
|
1978 |
);
|
1979 |
|
1980 |
if( !sucuriscan_lastlogins_datastore_is_writable() ){
|
1981 |
-
|
1982 |
-
file is not writable, gives permissions to write in this location:<br>'.
|
1983 |
-
'<code>'.sucuriscan_lastlogins_datastore_filepath().'</code>');
|
1984 |
}
|
1985 |
|
1986 |
$limit = isset($_GET['limit']) ? intval($_GET['limit']) : SUCURISCAN_LASTLOGINS_USERSLIMIT;
|
@@ -1988,26 +6144,37 @@ function sucuriscan_lastlogins_page(){
|
|
1988 |
|
1989 |
$counter = 0;
|
1990 |
$user_list = sucuriscan_get_logins($limit);
|
1991 |
-
|
|
|
1992 |
$counter += 1;
|
1993 |
-
$
|
|
|
|
|
1994 |
'UserList.Number' => $counter,
|
1995 |
-
'UserList.UserId' =>
|
1996 |
-
'UserList.Username' =>
|
1997 |
-
'UserList.Displayname' =>
|
1998 |
-
'UserList.Email' =>
|
1999 |
-
'UserList.Registered' =>
|
2000 |
'UserList.RemoteAddr' => $user->user_remoteaddr,
|
2001 |
'UserList.Hostname' => $user->user_hostname,
|
2002 |
'UserList.Datetime' => $user->user_lastlogin,
|
2003 |
'UserList.TimeAgo' => sucuriscan_time_ago($user->user_lastlogin),
|
2004 |
-
'UserList.UserURL' => admin_url('user-edit.php?user_id='.$user->
|
2005 |
-
'UserList.CssClass' =>
|
2006 |
-
)
|
2007 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2008 |
}
|
2009 |
|
2010 |
-
|
2011 |
}
|
2012 |
|
2013 |
/**
|
@@ -2108,15 +6275,17 @@ if( !function_exists('sucuri_set_lastlogin') ){
|
|
2108 |
* @param integer $user_id Optional user identifier to filter the results.
|
2109 |
* @return array The list of all the user logins through the time until now.
|
2110 |
*/
|
2111 |
-
function sucuriscan_get_logins($limit=10, $user_id=0){
|
2112 |
$lastlogins = array();
|
2113 |
$datastore_filepath = sucuriscan_lastlogins_datastore_is_readable();
|
2114 |
|
2115 |
-
if($datastore_filepath){
|
2116 |
$parsed_lines = 0;
|
2117 |
$lastlogins_lines = array_reverse(file($datastore_filepath));
|
2118 |
-
|
|
|
2119 |
$line = str_replace("\n", '', $line);
|
|
|
2120 |
if( preg_match('/^a:/', $line) ){
|
2121 |
$user_lastlogin = unserialize($line);
|
2122 |
|
@@ -2132,11 +6301,18 @@ function sucuriscan_get_logins($limit=10, $user_id=0){
|
|
2132 |
}
|
2133 |
|
2134 |
/* Get the WP_User object and add extra information from the last-login data */
|
|
|
2135 |
$user_account = get_userdata($user_lastlogin['user_id']);
|
2136 |
-
|
2137 |
-
|
|
|
|
|
|
|
|
|
|
|
2138 |
}
|
2139 |
-
|
|
|
2140 |
$parsed_lines += 1;
|
2141 |
}
|
2142 |
|
@@ -2159,14 +6335,20 @@ if( !function_exists('sucuri_login_redirect') ){
|
|
2159 |
* @param boolean $user WordPress user object with the information of the account involved in the operation.
|
2160 |
* @return string URL where the browser must be redirected to.
|
2161 |
*/
|
2162 |
-
function sucuriscan_login_redirect($redirect_to='', $request=NULL, $user=FALSE){
|
2163 |
$login_url = !empty($redirect_to) ? $redirect_to : admin_url();
|
|
|
2164 |
if( $user instanceof WP_User && $user->ID ){
|
2165 |
-
$login_url = add_query_arg( '
|
2166 |
}
|
|
|
2167 |
return $login_url;
|
2168 |
}
|
2169 |
-
|
|
|
|
|
|
|
|
|
2170 |
}
|
2171 |
|
2172 |
if( !function_exists('sucuri_get_user_lastlogin') ){
|
@@ -2176,7 +6358,7 @@ if( !function_exists('sucuri_get_user_lastlogin') ){
|
|
2176 |
* @return void
|
2177 |
*/
|
2178 |
function sucuriscan_get_user_lastlogin(){
|
2179 |
-
if( isset($_GET['
|
2180 |
$current_user = wp_get_current_user();
|
2181 |
|
2182 |
// Select the penultimate entry, not the last one.
|
@@ -2187,7 +6369,7 @@ if( !function_exists('sucuri_get_user_lastlogin') ){
|
|
2187 |
$message_tpl = 'The last time you logged in was: %s, from %s - %s';
|
2188 |
$lastlogin_message = sprintf( $message_tpl, date('Y/M/d'), $row->user_remoteaddr, $row->user_hostname );
|
2189 |
$lastlogin_message .= chr(32).'(<a href="'.site_url('wp-admin/admin.php?page='.SUCURISCAN.'_lastlogins').'">View Last-Logins</a>)';
|
2190 |
-
|
2191 |
}
|
2192 |
}
|
2193 |
}
|
@@ -2628,10 +6810,9 @@ function sucuriscan_show_cronjobs(){
|
|
2628 |
}
|
2629 |
|
2630 |
/**
|
2631 |
-
* Gather information from the server, database engine and PHP interpreter.
|
2632 |
*
|
2633 |
-
* @
|
2634 |
-
* @return array A list of pseudo-variables and values that will replace them in the HTML template.
|
2635 |
*/
|
2636 |
function sucuriscan_server_info(){
|
2637 |
global $wpdb;
|
@@ -2641,21 +6822,19 @@ function sucuriscan_server_info(){
|
|
2641 |
$mysql_version = $wpdb->get_var('SELECT VERSION() AS version');
|
2642 |
$mysql_info = $wpdb->get_results('SHOW VARIABLES LIKE "sql_mode"');
|
2643 |
$sql_mode = ( is_array($mysql_info) && !empty($mysql_info[0]->Value) ) ? $mysql_info[0]->Value : 'Not set';
|
2644 |
-
$
|
2645 |
-
$
|
2646 |
|
2647 |
$template_variables = array(
|
2648 |
-
'
|
2649 |
-
'
|
2650 |
-
'
|
2651 |
-
'
|
2652 |
-
'
|
2653 |
-
'
|
2654 |
-
'
|
2655 |
-
'
|
2656 |
-
'
|
2657 |
-
'SQLMode'=>$sql_mode,
|
2658 |
-
'PHPVersion'=>PHP_VERSION,
|
2659 |
);
|
2660 |
|
2661 |
$field_names = array(
|
@@ -2681,21 +6860,262 @@ function sucuriscan_server_info(){
|
|
2681 |
|
2682 |
|
2683 |
/**
|
2684 |
-
*
|
2685 |
-
*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2686 |
*
|
2687 |
* @return void
|
2688 |
*/
|
2689 |
-
function
|
2690 |
|
2691 |
-
|
2692 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2693 |
}
|
2694 |
|
2695 |
$template_variables = array(
|
2696 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2697 |
);
|
2698 |
|
2699 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2700 |
}
|
2701 |
|
1 |
<?php
|
2 |
/*
|
3 |
+
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.1
|
8 |
Author URI: http://sucuri.net
|
9 |
*/
|
10 |
|
36 |
/**
|
37 |
* Current version of the plugin's code.
|
38 |
*/
|
39 |
+
define('SUCURISCAN_VERSION','1.6.1');
|
40 |
|
41 |
/**
|
42 |
* The local URL where the plugin's files and assets are served.
|
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 |
*/
|
69 |
+
define('SUCURISCAN_PLUGIN_CHECKSUM', @md5_file(SUCURISCAN_PLUGIN_FILEPATH));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
70 |
|
71 |
/**
|
72 |
+
* Remote URL where the public Sucuri API service is running.
|
|
|
73 |
*/
|
74 |
+
define('SUCURISCAN_API', 'https://wordpress.sucuri.net/api/');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
75 |
|
76 |
/**
|
77 |
+
* Latest version of the public Sucuri API.
|
|
|
|
|
|
|
|
|
78 |
*/
|
79 |
+
define('SUCURISCAN_API_VERSION', 'v1');
|
|
|
|
|
|
|
|
|
|
|
80 |
|
81 |
/**
|
82 |
+
* Remote URL where the CloudProxy API service is running.
|
|
|
|
|
83 |
*/
|
84 |
+
define('SUCURISCAN_CLOUDPROXY_API', 'https://waf.sucuri.net/api');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
85 |
|
86 |
+
/**
|
87 |
+
* Latest version of the CloudProxy API.
|
88 |
+
*/
|
89 |
+
define('SUCURISCAN_CLOUDPROXY_API_VERSION', 'v2');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
90 |
|
91 |
/**
|
92 |
+
* The maximum quantity of entries that will be displayed in the last login page.
|
|
|
|
|
|
|
93 |
*/
|
94 |
+
define('SUCURISCAN_LASTLOGINS_USERSLIMIT', 50);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
95 |
|
96 |
/**
|
97 |
+
* The maximum quantity of entries that will be displayed in the audit logs page.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
98 |
*/
|
99 |
+
define('SUCURISCAN_AUDITLOGS_PER_PAGE', 50);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
100 |
|
101 |
+
/**
|
102 |
+
* The minimum quantity of seconds to wait before each filesystem scan.
|
103 |
+
*/
|
104 |
+
define('SUCURISCAN_MINIMUM_RUNTIME', 10800);
|
|
|
|
|
105 |
|
106 |
/**
|
107 |
+
* The life time of the cache for the results of the SiteCheck scans.
|
|
|
|
|
|
|
|
|
108 |
*/
|
109 |
+
define('SUCURISCAN_SITECHECK_LIFETIME', 1200);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
110 |
|
111 |
/**
|
112 |
+
* Miscellaneous library.
|
113 |
*
|
114 |
+
* Multiple and generic functions that will be used through out the code of
|
115 |
+
* other libraries extending from this and functions defined in other files, be
|
116 |
+
* aware of the hierarchy and check the other libraries for duplicated methods.
|
|
|
117 |
*/
|
118 |
+
class SucuriScan {
|
|
|
|
|
|
|
|
|
|
|
119 |
|
120 |
+
/**
|
121 |
+
* Class constructor.
|
122 |
+
*/
|
123 |
+
public function __construct(){
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
124 |
}
|
125 |
|
126 |
+
/**
|
127 |
+
* Generates a lowercase random string with an specific length.
|
128 |
+
*
|
129 |
+
* @param integer $length Length of the string that will be generated.
|
130 |
+
* @return string The random string generated.
|
131 |
+
*/
|
132 |
+
public static function random_char( $length=4 ){
|
133 |
+
$string = '';
|
134 |
+
$chars = range('a','z');
|
135 |
|
136 |
+
for( $i=0; $i<$length; $i++ ){
|
137 |
+
$string .= $chars[ rand(0, count($chars)-1) ];
|
138 |
+
}
|
139 |
+
|
140 |
+
return $string;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
141 |
}
|
142 |
|
143 |
+
/**
|
144 |
+
* Translate a given number in bytes to a human readable file size using the
|
145 |
+
* a approximate value in Kylo, Mega, Giga, etc.
|
146 |
+
*
|
147 |
+
* @link http://www.php.net/manual/en/function.filesize.php#106569
|
148 |
+
* @param integer $bytes An integer representing a file size in bytes.
|
149 |
+
* @param integer $decimals How many decimals should be returned after the translation.
|
150 |
+
* @return string Human readable representation of the given number in Kylo, Mega, Giga, etc.
|
151 |
+
*/
|
152 |
+
public static function human_filesize( $bytes=0, $decimals=2 ){
|
153 |
+
$sz = 'BKMGTP';
|
154 |
+
$factor = floor((strlen($bytes) - 1) / 3);
|
155 |
+
return sprintf("%.{$decimals}f", $bytes / pow(1024, $factor)) . @$sz[$factor];
|
156 |
+
}
|
157 |
|
158 |
+
/**
|
159 |
+
* Returns the system filepath to the relevant user uploads directory for this
|
160 |
+
* site. This is a multisite capable function.
|
161 |
+
*
|
162 |
+
* @param string $path The relative path that needs to be completed to get the absolute path.
|
163 |
+
* @return string The full filesystem path including the directory specified.
|
164 |
+
*/
|
165 |
+
public static function datastore_folder_path( $path='' ){
|
166 |
+
$wp_dir_array = wp_upload_dir();
|
167 |
+
$wp_dir_array['basedir'] = untrailingslashit($wp_dir_array['basedir']);
|
168 |
+
$wp_filepath = $wp_dir_array['basedir'] . '/sucuri/' . $path;
|
169 |
|
170 |
+
return $wp_filepath;
|
171 |
+
}
|
|
|
|
|
172 |
|
173 |
+
/**
|
174 |
+
* Check the nonce comming from any of the settings pages.
|
175 |
+
*
|
176 |
+
* @return boolean TRUE if the nonce is valid, FALSE otherwise.
|
177 |
+
*/
|
178 |
+
public static function sucuriscan_check_options_wpnonce(){
|
179 |
+
// Create the option_page value if permalink submission.
|
180 |
+
if(
|
181 |
+
!isset($_POST['option_page'])
|
182 |
+
&& isset($_POST['permalink_structure'])
|
183 |
+
){
|
184 |
+
$_POST['option_page'] = 'permalink';
|
185 |
}
|
|
|
186 |
|
187 |
+
// Check if the option_page has an allowed value.
|
188 |
+
if( isset($_POST['option_page']) ){
|
189 |
+
$nonce='_wpnonce';
|
190 |
+
$action = '';
|
191 |
+
|
192 |
+
switch( $_POST['option_page'] ){
|
193 |
+
case 'general': /* no_break */
|
194 |
+
case 'writing': /* no_break */
|
195 |
+
case 'reading': /* no_break */
|
196 |
+
case 'discussion': /* no_break */
|
197 |
+
case 'media': /* no_break */
|
198 |
+
case 'options': /* no_break */
|
199 |
+
$action = $_POST['option_page'] . '-options';
|
200 |
+
break;
|
201 |
+
case 'permalink':
|
202 |
+
$action = 'update-permalink';
|
203 |
+
break;
|
204 |
+
}
|
205 |
|
206 |
+
// Check the nonce validity.
|
207 |
+
if(
|
208 |
+
!empty($action)
|
209 |
+
&& isset($_REQUEST[$nonce])
|
210 |
+
&& wp_verify_nonce($_REQUEST[$nonce], $action)
|
211 |
+
){
|
212 |
+
return TRUE;
|
213 |
+
}
|
214 |
}
|
215 |
|
216 |
+
return FALSE;
|
217 |
}
|
|
|
218 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
219 |
}
|
220 |
|
221 |
/**
|
222 |
+
* Class to process files and folders.
|
|
|
|
|
223 |
*
|
224 |
+
* Here are implemented the functions needed to open, scan, read, create files
|
225 |
+
* and folders using the built-in PHP class SplFileInfo. The SplFileInfo class
|
226 |
+
* offers a high-level object oriented interface to information for an individual
|
227 |
+
* file.
|
228 |
*/
|
229 |
+
class SucuriScanFileInfo extends SucuriScan {
|
|
|
|
|
230 |
|
231 |
+
/**
|
232 |
+
* Whether the list of files that can be ignored from the filesystem scan will
|
233 |
+
* be used to return the directory tree, this should be disabled when scanning a
|
234 |
+
* directory without the need to filter the items in the list.
|
235 |
+
*
|
236 |
+
* @var boolean
|
237 |
+
*/
|
238 |
+
public $ignore_files = TRUE;
|
239 |
+
|
240 |
+
/**
|
241 |
+
* Whether the list of folders that can be ignored from the filesystem scan will
|
242 |
+
* be used to return the directory tree, this should be disabled when scanning a
|
243 |
+
* path without the need to filter the items in the list.
|
244 |
+
*
|
245 |
+
* @var boolean
|
246 |
+
*/
|
247 |
+
public $ignore_directories = TRUE;
|
248 |
+
|
249 |
+
/**
|
250 |
+
* Whether the filesystem scanner should run recursively or not.
|
251 |
+
*
|
252 |
+
* @var boolean
|
253 |
+
*/
|
254 |
+
public $run_recursively = TRUE;
|
255 |
+
|
256 |
+
/**
|
257 |
+
* Class constructor.
|
258 |
+
*/
|
259 |
+
public function __construct(){
|
260 |
}
|
261 |
|
262 |
+
/**
|
263 |
+
* Retrieve a long text string with signatures of all the files contained
|
264 |
+
* in the main and subdirectories of the folder specified, also the filesize
|
265 |
+
* and md5sum of that file. Some folders and files will be ignored depending
|
266 |
+
* on some rules defined by the developer.
|
267 |
+
*
|
268 |
+
* @param string $directory Parent directory where the filesystem scan will start.
|
269 |
+
* @param string $scan_with Set the tool used to scan the filesystem, SplFileInfo by default.
|
270 |
+
* @param boolean $as_array Whether the result of the operation will be returned as an array or string.
|
271 |
+
* @return array List of files in the main and subdirectories of the folder specified.
|
272 |
+
*/
|
273 |
+
public function get_directory_tree_md5( $directory='', $scan_with='spl', $as_array=FALSE ){
|
274 |
+
$project_signatures = '';
|
275 |
+
$abs_path = rtrim( ABSPATH, '/' );
|
276 |
+
$files = $this->get_directory_tree($directory, $scan_with);
|
277 |
+
sort($files);
|
278 |
+
|
279 |
+
if( $as_array ){
|
280 |
+
$project_signatures = array();
|
281 |
+
}
|
282 |
|
283 |
+
foreach( $files as $filepath){
|
284 |
+
$file_checksum = @md5_file($filepath);
|
285 |
+
$filesize = @filesize($filepath);
|
286 |
+
|
287 |
+
if( $as_array ){
|
288 |
+
$basename = str_replace( $abs_path . '/', '', $filepath );
|
289 |
+
$project_signatures[$basename] = array(
|
290 |
+
'filepath' => $filepath,
|
291 |
+
'checksum' => $file_checksum,
|
292 |
+
'filesize' => $filesize,
|
293 |
+
'filetime' => filectime($filepath),
|
294 |
+
);
|
295 |
+
} else {
|
296 |
+
$filepath = str_replace( $abs_path, $abs_path . '/', $filepath );
|
297 |
+
$project_signatures .= sprintf(
|
298 |
+
"%s%s%s%s\n",
|
299 |
+
$file_checksum,
|
300 |
+
$filesize,
|
301 |
+
chr(32),
|
302 |
+
$filepath
|
303 |
+
);
|
304 |
}
|
|
|
305 |
}
|
306 |
+
|
307 |
+
return $project_signatures;
|
308 |
}
|
|
|
|
|
309 |
|
310 |
+
/**
|
311 |
+
* Retrieve a list with all the files contained in the main and subdirectories
|
312 |
+
* of the folder specified. Some folders and files will be ignored depending
|
313 |
+
* on some rules defined by the developer.
|
314 |
+
*
|
315 |
+
* @param string $directory Parent directory where the filesystem scan will start.
|
316 |
+
* @param string $scan_with Set the tool used to scan the filesystem, SplFileInfo by default.
|
317 |
+
* @return array List of files in the main and subdirectories of the folder specified.
|
318 |
+
*/
|
319 |
+
public function get_directory_tree($directory='', $scan_with='spl'){
|
320 |
+
if( file_exists($directory) && is_dir($directory) ){
|
321 |
+
$tree = array();
|
322 |
+
|
323 |
+
switch( $scan_with ){
|
324 |
+
case 'spl':
|
325 |
+
if( $this->is_spl_available() ){
|
326 |
+
$tree = $this->get_directory_tree_with_spl($directory);
|
327 |
+
} else {
|
328 |
+
$tree = $this->get_directory_tree($directory, 'opendir');
|
329 |
+
}
|
330 |
+
break;
|
331 |
|
332 |
+
case 'glob':
|
333 |
+
$tree = $this->get_directory_tree_with_glob($directory);
|
334 |
+
break;
|
|
|
|
|
335 |
|
336 |
+
case 'opendir':
|
337 |
+
$tree = $this->get_directory_tree_with_opendir($directory);
|
338 |
+
break;
|
339 |
|
340 |
+
default:
|
341 |
+
$tree = $this->get_directory_tree($directory, 'spl');
|
342 |
+
break;
|
343 |
+
}
|
|
|
|
|
344 |
|
345 |
+
return $tree;
|
346 |
+
}
|
347 |
+
|
348 |
+
return FALSE;
|
349 |
+
}
|
350 |
+
|
351 |
+
/**
|
352 |
+
* Check whether the built-in class SplFileObject is available in the system
|
353 |
+
* or not, it is required to have PHP >= 5.1.0. The SplFileObject class offers
|
354 |
+
* an object oriented interface for a file.
|
355 |
+
*
|
356 |
+
* @link http://www.php.net/manual/en/class.splfileobject.php
|
357 |
+
*
|
358 |
+
* @return boolean Whether the PHP class "SplFileObject" is available or not.
|
359 |
+
*/
|
360 |
+
public static function is_spl_available(){
|
361 |
+
return (bool) class_exists('SplFileObject');
|
362 |
+
}
|
363 |
+
|
364 |
+
/**
|
365 |
+
* Retrieve a list with all the files contained in the main and subdirectories
|
366 |
+
* of the folder specified. Some folders and files will be ignored depending
|
367 |
+
* on some rules defined by the developer.
|
368 |
+
*
|
369 |
+
* @link http://www.php.net/manual/en/class.recursivedirectoryiterator.php
|
370 |
+
* @see RecursiveDirectoryIterator extends FilesystemIterator
|
371 |
+
* @see FilesystemIterator extends DirectoryIterator
|
372 |
+
* @see DirectoryIterator extends SplFileInfo
|
373 |
+
* @see SplFileInfo
|
374 |
+
*
|
375 |
+
* @param string $directory Parent directory where the filesystem scan will start.
|
376 |
+
* @return array List of files in the main and subdirectories of the folder specified.
|
377 |
+
*/
|
378 |
+
private function get_directory_tree_with_spl($directory=''){
|
379 |
+
$files = array();
|
380 |
+
$filepath = realpath($directory);
|
381 |
+
|
382 |
+
if( !class_exists('FilesystemIterator') ){
|
383 |
+
return $this->get_directory_tree($directory, 'opendir');
|
384 |
+
}
|
385 |
+
|
386 |
+
if( $this->run_recursively ){
|
387 |
+
$flags = FilesystemIterator::KEY_AS_PATHNAME
|
388 |
+
| FilesystemIterator::CURRENT_AS_FILEINFO
|
389 |
+
| FilesystemIterator::SKIP_DOTS
|
390 |
+
| FilesystemIterator::UNIX_PATHS;
|
391 |
+
$objects = new RecursiveIteratorIterator(
|
392 |
+
new RecursiveDirectoryIterator($filepath, $flags),
|
393 |
+
RecursiveIteratorIterator::SELF_FIRST
|
394 |
+
);
|
395 |
+
} else {
|
396 |
+
$objects = new DirectoryIterator($filepath);
|
397 |
+
}
|
398 |
+
|
399 |
+
foreach( $objects as $filepath => $fileinfo ){
|
400 |
+
if( $this->run_recursively ){
|
401 |
+
$directory = dirname($filepath);
|
402 |
+
$filename = $fileinfo->getFilename();
|
403 |
+
} else {
|
404 |
+
if( $fileinfo->isDot() || $fileinfo->isDir() ){ continue; }
|
405 |
+
|
406 |
+
$directory = $fileinfo->getPath();
|
407 |
+
$filename = $fileinfo->getFilename();
|
408 |
+
$filepath = $directory . '/' . $filename;
|
409 |
}
|
410 |
|
411 |
+
if( $this->ignore_folderpath($directory, $filename) ){ continue; }
|
412 |
+
if( $this->ignore_filepath($filename) ){ continue; }
|
413 |
+
|
414 |
+
$files[] = $filepath;
|
415 |
}
|
416 |
|
417 |
+
return $files;
|
418 |
+
}
|
419 |
+
|
420 |
+
/**
|
421 |
+
* Retrieve a list with all the files contained in the main and subdirectories
|
422 |
+
* of the folder specified. Some folders and files will be ignored depending
|
423 |
+
* on some rules defined by the developer.
|
424 |
+
*
|
425 |
+
* @param string $directory Parent directory where the filesystem scan will start.
|
426 |
+
* @return array List of files in the main and subdirectories of the folder specified.
|
427 |
+
*/
|
428 |
+
private function get_directory_tree_with_glob($directory=''){
|
429 |
+
$files = array();
|
430 |
+
|
431 |
+
$directory_pattern = sprintf( '%s/*', rtrim($directory,'/') );
|
432 |
+
$files_found = glob($directory_pattern);
|
433 |
+
|
434 |
+
if( is_array($files_found) ){
|
435 |
+
foreach( $files_found as $filepath ){
|
436 |
+
$filepath = realpath($filepath);
|
437 |
+
$directory = dirname($filepath);
|
438 |
+
$filename = array_pop(explode('/', $filepath));
|
439 |
+
|
440 |
+
if( is_dir($filepath) ){
|
441 |
+
if( $this->ignore_folderpath($directory, $filename) ){ continue; }
|
442 |
+
|
443 |
+
if( $this->run_recursively ){
|
444 |
+
$sub_files = $this->get_directory_tree_with_opendir($filepath);
|
445 |
+
$files = array_merge($files, $sub_files);
|
446 |
+
}
|
447 |
+
} else {
|
448 |
+
if( $this->ignore_filepath($filename) ){ continue; }
|
449 |
+
$files[] = $filepath;
|
450 |
+
}
|
451 |
+
}
|
452 |
}
|
453 |
+
|
454 |
+
return $files;
|
455 |
}
|
|
|
|
|
456 |
|
457 |
+
/**
|
458 |
+
* Retrieve a list with all the files contained in the main and subdirectories
|
459 |
+
* of the folder specified. Some folders and files will be ignored depending
|
460 |
+
* on some rules defined by the developer.
|
461 |
+
*
|
462 |
+
* @param string $directory Parent directory where the filesystem scan will start.
|
463 |
+
* @return array List of files in the main and subdirectories of the folder specified.
|
464 |
+
*/
|
465 |
+
private function get_directory_tree_with_opendir($directory=''){
|
466 |
+
$dh = @opendir($directory);
|
467 |
+
if( !$dh ){ return FALSE; }
|
468 |
|
469 |
+
$files = array();
|
470 |
+
while( ($filename = readdir($dh)) !== FALSE ){
|
471 |
+
$filepath = realpath($directory.'/'.$filename);
|
472 |
|
473 |
+
if( is_dir($filepath) ){
|
474 |
+
if( $this->ignore_folderpath($directory, $filename) ){ continue; }
|
|
|
|
|
|
|
|
|
475 |
|
476 |
+
if( $this->run_recursively ){
|
477 |
+
$sub_files = $this->get_directory_tree_with_opendir($filepath);
|
478 |
+
$files = array_merge($files, $sub_files);
|
479 |
+
}
|
480 |
+
} else {
|
481 |
+
if( $this->ignore_filepath($filename) ){ continue; }
|
482 |
+
$files[] = $filepath;
|
483 |
+
}
|
484 |
+
}
|
485 |
|
486 |
+
closedir($dh);
|
487 |
+
return $files;
|
488 |
}
|
|
|
|
|
489 |
|
490 |
+
/**
|
491 |
+
* Skip some specific directories and filepaths from the filesystem scan.
|
492 |
+
*
|
493 |
+
* @param string $directory Directory where the scanner is located at the moment.
|
494 |
+
* @param string $filename Name of the folder or file being scanned at the moment.
|
495 |
+
* @return boolean Either TRUE or FALSE representing that the scan should ignore this folder or not.
|
496 |
+
*/
|
497 |
+
private function ignore_folderpath( $directory='', $filename='' ){
|
498 |
+
// Ignoring current and parent folders.
|
499 |
+
if( $filename == '.' || $filename == '..' ){ return TRUE; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
500 |
|
501 |
+
if( $this->ignore_directories ){
|
502 |
+
$filepath = realpath( $directory . '/' . $filename );
|
503 |
+
$pattern = '/\/wp-content\/(uploads|cache|backup|w3tc)/';
|
504 |
+
|
505 |
+
if( preg_match($pattern, $filepath) ){
|
506 |
+
return TRUE;
|
507 |
+
}
|
508 |
+
}
|
509 |
+
|
510 |
+
return FALSE;
|
511 |
}
|
512 |
|
513 |
+
/**
|
514 |
+
* Skip some specific files from the filesystem scan.
|
515 |
+
*
|
516 |
+
* @param string $filename Name of the folder or file being scanned at the moment.
|
517 |
+
* @return boolean Either TRUE or FALSE representing that the scan should ignore this filename or not.
|
518 |
+
*/
|
519 |
+
private function ignore_filepath( $filename='' ){
|
520 |
+
if( !$this->ignore_files ){ return FALSE; }
|
521 |
|
522 |
+
// Ignoring backup files from our clean ups.
|
523 |
+
if( strpos($filename, '_sucuribackup.') !== FALSE ){ return TRUE; }
|
524 |
+
|
525 |
+
// Any file maching one of these rules WILL NOT be ignored.
|
526 |
+
if(
|
527 |
+
( strpos($filename, '.php') !== FALSE) ||
|
528 |
+
( strpos($filename, '.htm') !== FALSE) ||
|
529 |
+
( strpos($filename, '.js') !== FALSE) ||
|
530 |
+
( strcmp($filename, '.htaccess') == 0 ) ||
|
531 |
+
( strcmp($filename, 'php.ini') == 0 )
|
532 |
+
){ return FALSE; }
|
533 |
|
|
|
|
|
|
|
|
|
534 |
return TRUE;
|
535 |
}
|
536 |
|
537 |
+
/**
|
538 |
+
* Retrieve a list of unique directory paths.
|
539 |
+
*
|
540 |
+
* @param array $dir_tree A list of files under a directory.
|
541 |
+
* @return array A list of unique directory paths.
|
542 |
+
*/
|
543 |
+
public function get_diretories_only( $dir_tree=array() ){
|
544 |
+
$dirs = array();
|
545 |
|
546 |
+
if( is_string($dir_tree) ){
|
547 |
+
$dir_tree = $this->get_directory_tree($dir_tree);
|
548 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
549 |
|
550 |
+
foreach( $dir_tree as $filepath ){
|
551 |
+
$dir_path = dirname($filepath);
|
|
|
|
|
|
|
|
|
|
|
552 |
|
553 |
+
if( !in_array($dir_path, $dirs) ){
|
554 |
+
$dirs[] = $dir_path;
|
555 |
+
}
|
556 |
+
}
|
557 |
+
|
558 |
+
return $dirs;
|
559 |
}
|
|
|
|
|
560 |
|
561 |
+
/**
|
562 |
+
* Remove a directory recursively.
|
563 |
+
*
|
564 |
+
* @param string $directory Path of the existing directory that will be removed.
|
565 |
+
* @return boolean TRUE if all the files and folder inside the directory were removed.
|
566 |
+
*/
|
567 |
+
public function remove_directory_tree( $directory='' ){
|
568 |
+
$all_removed = TRUE;
|
569 |
+
$dir_tree = $this->get_directory_tree($directory);
|
|
|
|
|
570 |
|
571 |
+
if( $dir_tree ){
|
572 |
+
$dirs_only = array();
|
573 |
+
|
574 |
+
foreach( $dir_tree as $filepath ){
|
575 |
+
if( is_file($filepath) ){
|
576 |
+
$removed = @unlink($filepath);
|
577 |
+
|
578 |
+
if( !$removed ){
|
579 |
+
$all_removed = FALSE;
|
580 |
+
}
|
581 |
+
}
|
582 |
+
|
583 |
+
elseif( is_dir($filepath) ){
|
584 |
+
$dirs_only[] = $filepath;
|
585 |
+
}
|
586 |
+
}
|
587 |
+
|
588 |
+
if( !function_exists('sucuriscan_strlen_diff') ){
|
589 |
+
/**
|
590 |
+
* Evaluates the difference between the length of two strings.
|
591 |
+
*
|
592 |
+
* @param string $a First string of characters that will be measured.
|
593 |
+
* @param string $b Second string of characters that will be measured.
|
594 |
+
* @return integer The difference in length between the two strings.
|
595 |
+
*/
|
596 |
+
function sucuriscan_strlen_diff( $a='', $b='' ){
|
597 |
+
return strlen($b) - strlen($a);
|
598 |
+
}
|
599 |
+
}
|
600 |
+
|
601 |
+
usort($dirs_only, 'sucuriscan_strlen_diff');
|
602 |
+
|
603 |
+
foreach( $dirs_only as $dir_path ){
|
604 |
+
@rmdir($dir_path);
|
605 |
+
}
|
606 |
}
|
607 |
+
|
608 |
+
return $all_removed;
|
609 |
}
|
610 |
|
|
|
611 |
}
|
612 |
|
613 |
/**
|
614 |
+
* Class responsible for the processing of all the tasks associated to the database.
|
615 |
*
|
616 |
+
* Here are implemented the functions needed to rename tables, generate random names,
|
617 |
+
* change the Wordpress table prefix and modify the name of all the options linked to
|
618 |
+
* the previous database prefix.
|
619 |
*/
|
620 |
+
class SucuriScanDatabase extends SucuriScan {
|
|
|
|
|
|
|
621 |
|
622 |
+
/**
|
623 |
+
* List all database tables in a clean array of strings.
|
624 |
+
*
|
625 |
+
* @return array Array of strings.
|
626 |
+
*/
|
627 |
+
public function get_dbtables(){
|
628 |
+
global $wpdb;
|
629 |
|
630 |
+
$table_names = array();
|
631 |
+
$tables = $wpdb->get_results('SHOW TABLES', ARRAY_N);
|
632 |
|
633 |
+
foreach($tables as $table){
|
634 |
+
$table_names[] = $table[0];
|
635 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
636 |
|
637 |
+
return $table_names;
|
638 |
+
}
|
|
|
639 |
|
640 |
+
/**
|
641 |
+
* Set a new database table prefix to improve the security.
|
642 |
+
*
|
643 |
+
* @return void
|
644 |
+
*/
|
645 |
+
public function new_table_prefix(){
|
646 |
+
$new_table_prefix = $this->random_char( rand(4,7) ).'_';
|
647 |
+
$this->set_table_prefix($new_table_prefix);
|
|
|
|
|
648 |
}
|
649 |
|
650 |
+
/**
|
651 |
+
* Reset the database table prefix with the default value 'wp_'.
|
652 |
+
*
|
653 |
+
* @return void
|
654 |
+
*/
|
655 |
+
public function reset_table_prefix(){
|
656 |
+
$this->set_table_prefix('wp_');
|
657 |
}
|
658 |
|
659 |
+
/**
|
660 |
+
* Set a new table prefix and changes table names, options, configuration files, etc.
|
661 |
+
*
|
662 |
+
* @param string $new_table_prefix The new table prefix.
|
663 |
+
* @return void
|
664 |
+
*/
|
665 |
+
private function set_table_prefix( $new_table_prefix='wp_' ){
|
666 |
+
$resp_parts = array();
|
667 |
|
668 |
+
// Set the new table prefix in the configuration file.
|
669 |
+
$resp_parts[] = $this->new_table_prefix_wpconfig($new_table_prefix);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
670 |
|
671 |
+
// Update options table with the new table prefix.
|
672 |
+
$resp_parts[] = $this->new_table_prefix_optionstable($new_table_prefix);
|
673 |
|
674 |
+
// Update usermeta table with the new table prefix.
|
675 |
+
$resp_parts[] = $this->new_table_prefix_usermetatable($new_table_prefix);
|
676 |
|
677 |
+
// Rename table names with the new table prefix.
|
678 |
+
$resp_parts[] = $this->new_table_prefix_tablerename($new_table_prefix);
|
|
|
|
|
|
|
|
|
|
|
|
|
679 |
|
680 |
+
foreach( $resp_parts as $response ){
|
681 |
+
if( $response['process'] !== TRUE ){
|
682 |
+
sucuriscan_error( $response['message'] );
|
683 |
+
}
|
684 |
+
}
|
685 |
+
}
|
686 |
|
687 |
+
/**
|
688 |
+
* Using the new database table prefix, it modifies the main configuration file with that new value.
|
689 |
+
*
|
690 |
+
* @param string $new_table_prefix
|
691 |
+
* @return array An array with two default indexes containing the result of the operation and a message.
|
692 |
+
*/
|
693 |
+
private function new_table_prefix_wpconfig( $new_table_prefix='' ){
|
694 |
+
global $wpdb;
|
695 |
|
696 |
+
$response = array( 'process'=>FALSE, 'message'=>'' );
|
697 |
+
$wp_config_path = sucuriscan_get_wpconfig_path();
|
698 |
|
699 |
+
if( file_exists($wp_config_path) ){
|
700 |
+
@chmod($wp_config_path, 0777);
|
701 |
|
702 |
+
if( is_writable($wp_config_path) ){
|
703 |
+
$new_wpconfig = '';
|
704 |
+
$wpconfig_lines = @file($wp_config_path);
|
705 |
|
706 |
+
foreach( $wpconfig_lines as $line ){
|
707 |
+
$line = str_replace("\n", '', $line);
|
|
|
|
|
708 |
|
709 |
+
if( preg_match('/.*\$table_prefix([ ]+)?=.*/', $line, $match) ){
|
710 |
+
$line = str_replace($wpdb->prefix, $new_table_prefix, $match[0]);
|
711 |
+
}
|
712 |
+
|
713 |
+
$new_wpconfig .= "{$line}\n";
|
714 |
+
}
|
715 |
+
|
716 |
+
$handle = fopen($wp_config_path, 'w');
|
717 |
+
@fwrite($handle, $new_wpconfig);
|
718 |
+
@fclose($handle);
|
719 |
+
@chmod($wp_config_path, 0644);
|
720 |
+
|
721 |
+
$response['process'] = TRUE;
|
722 |
+
$response['message'] = 'Main configuration file modified.';
|
723 |
+
} else {
|
724 |
+
$response['message'] = 'Main configuration file is not writable, you will need to put the new
|
725 |
+
table prefix <code>'.$new_table_prefix.'</code> manually in <code>wp-config.php</code>.';
|
726 |
+
}
|
727 |
+
} else {
|
728 |
+
$response['message'] = 'Main configuration file was not located: <code>'.$wp_config_path.'</code>.';
|
729 |
+
}
|
730 |
+
|
731 |
+
return $response;
|
732 |
+
}
|
733 |
+
|
734 |
+
/**
|
735 |
+
* Returns a list of all the tables in the selected database containing the same prefix.
|
736 |
+
*
|
737 |
+
* @param string $prefix A text string used to filter the tables with a specific prefix.
|
738 |
+
* @return array A list of all the tables with the prefix specified.
|
739 |
+
*/
|
740 |
+
public function get_prefixed_tables( $prefix='' ){
|
741 |
+
global $wpdb;
|
742 |
+
|
743 |
+
$tables = array();
|
744 |
+
$prefix = empty($prefix) ? $wpdb->prefix : $prefix;
|
745 |
+
$db_tables = $this->get_dbtables();
|
746 |
+
|
747 |
+
foreach( $db_tables as $table_name ){
|
748 |
+
if( preg_match("/^{$prefix}/", $table_name) ){
|
749 |
+
$tables[] = $table_name;
|
750 |
+
}
|
751 |
+
}
|
752 |
+
|
753 |
+
return $tables;
|
754 |
+
}
|
755 |
+
|
756 |
+
/**
|
757 |
+
* Using the new database table prefix, it modifies the name of all tables with the new value.
|
758 |
+
*
|
759 |
+
* @param string $new_table_prefix
|
760 |
+
* @return array An array with two default indexes containing the result of the operation and a message.
|
761 |
+
*/
|
762 |
+
private function new_table_prefix_tablerename( $new_table_prefix='' ){
|
763 |
+
global $wpdb;
|
764 |
+
|
765 |
+
$response = array( 'process'=>FALSE, 'message'=>'' );
|
766 |
+
$db_tables = $this->get_prefixed_tables();
|
767 |
+
|
768 |
+
$renamed_count = 0;
|
769 |
+
$total_tables = count($db_tables);
|
770 |
+
$tables_not_renamed = array();
|
771 |
+
|
772 |
+
foreach( $db_tables as $table_name ){
|
773 |
+
$table_new_name = $new_table_prefix . str_replace($wpdb->prefix, '', $table_name);
|
774 |
+
$sql = 'RENAME TABLE `%s` TO `%s`';
|
775 |
+
|
776 |
+
/* Don't use WPDB->Prepare() */
|
777 |
+
if( $wpdb->query(sprintf($sql, $table_name, $table_new_name))===FALSE ){
|
778 |
+
$tables_not_renamed[] = $table_name;
|
779 |
+
} else {
|
780 |
+
$renamed_count += 1;
|
781 |
+
}
|
782 |
+
}
|
783 |
+
|
784 |
+
$response['message'] = 'Database tables renamed: '.$renamed_count.' out of '.$total_tables;
|
785 |
+
|
786 |
+
if( $renamed_count>0 && $renamed_count==$total_tables ){
|
787 |
+
$response['process'] = TRUE;
|
788 |
+
$error = $wpdb->set_prefix($new_table_prefix);
|
789 |
+
|
790 |
+
if( is_wp_error($error) ){
|
791 |
+
foreach( $error->errors as $error_index=>$error_data ){
|
792 |
+
if( is_array($error_data) ){
|
793 |
+
foreach( $error_data as $error_data_value ){
|
794 |
+
$response['message'] .= chr(32) . $error_data_value . '.';
|
795 |
+
}
|
796 |
+
}
|
797 |
+
}
|
798 |
+
}
|
799 |
+
} else {
|
800 |
+
$response['message'] .= '<br>These tables were not renamed, you will need to do it manually:';
|
801 |
+
$response['message'] .= chr(32) . implode( ',' . chr(32), $table_not_renamed );
|
802 |
+
}
|
803 |
+
|
804 |
+
return $response;
|
805 |
+
}
|
806 |
+
|
807 |
+
/**
|
808 |
+
* Using the new database table prefix, it modifies the name of all options with the new value.
|
809 |
+
*
|
810 |
+
* @param string $new_table_prefix
|
811 |
+
* @return array An array with two default indexes containing the result of the operation and a message.
|
812 |
+
*/
|
813 |
+
private function new_table_prefix_optionstable( $new_table_prefix='' ){
|
814 |
+
global $wpdb;
|
815 |
+
|
816 |
+
$response = array( 'process'=>TRUE, 'message'=>'' );
|
817 |
+
$results = $wpdb->get_results("SELECT option_id, option_name FROM {$wpdb->prefix}options WHERE option_name LIKE '{$wpdb->prefix}%'");
|
818 |
+
|
819 |
+
foreach( $results as $row ){
|
820 |
+
$row->new_option_name = $new_table_prefix.str_replace($wpdb->prefix, '', $row->option_name);
|
821 |
+
$sql = "UPDATE {$wpdb->prefix}options SET option_name=%s WHERE option_id=%s LIMIT 1";
|
822 |
+
|
823 |
+
if( $wpdb->query($wpdb->prepare($sql, $row->new_option_name, $row->option_id))===FALSE ){
|
824 |
+
$response['process'] = FALSE;
|
825 |
+
}
|
826 |
+
}
|
827 |
+
|
828 |
+
$response['message'] = $response['process']
|
829 |
+
? 'Database table options updated.'
|
830 |
+
: 'Some entries in the database table <strong>Options</strong> were not updated';
|
831 |
+
|
832 |
+
return $response;
|
833 |
+
}
|
834 |
+
|
835 |
+
/**
|
836 |
+
* Using the new database table prefix, it modifies the name of all usermeta keys with the new value.
|
837 |
+
*
|
838 |
+
* @param string $new_table_prefix
|
839 |
+
* @return array An array with two default indexes containing the result of the operation and a message.
|
840 |
+
*/
|
841 |
+
private function new_table_prefix_usermetatable( $new_table_prefix='' ){
|
842 |
+
global $wpdb;
|
843 |
+
|
844 |
+
$response = array( 'process'=>TRUE, 'message'=>'' );
|
845 |
+
$results = $wpdb->get_results("SELECT umeta_id, meta_key FROM {$wpdb->prefix}usermeta WHERE meta_key LIKE '{$wpdb->prefix}%'");
|
846 |
+
|
847 |
+
foreach( $results as $row ){
|
848 |
+
$row->new_meta_key = $new_table_prefix.str_replace($wpdb->prefix, '', $row->meta_key);
|
849 |
+
$sql = "UPDATE {$wpdb->prefix}usermeta SET meta_key=%s WHERE umeta_id=%s LIMIT 1";
|
850 |
+
|
851 |
+
if( $wpdb->query($wpdb->prepare($sql, $row->new_meta_key, $row->umeta_id))===FALSE ){
|
852 |
+
$response['process'] = FALSE;
|
853 |
+
}
|
854 |
+
}
|
855 |
+
|
856 |
+
$response['message'] = $response['process']
|
857 |
+
? 'Database table usermeta updated.'
|
858 |
+
: 'Some entries in the database table <strong>UserMeta</strong> were not updated';
|
859 |
+
|
860 |
+
return $response;
|
861 |
+
}
|
862 |
+
|
863 |
+
}
|
864 |
+
|
865 |
+
/**
|
866 |
+
* Class responsible for the processing of the generation of backups for the database.
|
867 |
+
*
|
868 |
+
* Here are implemented the functions needed to get the list of databases, information
|
869 |
+
* of single tables, generate the backup file (which can be a SQL or Zip file), a way
|
870 |
+
* to download and remove old backup files.
|
871 |
+
*/
|
872 |
+
class SucuriScanBackup extends SucuriScanDatabase {
|
873 |
+
|
874 |
+
/**
|
875 |
+
* Class constructor.
|
876 |
+
*/
|
877 |
+
public function __construct(){
|
878 |
+
ini_set('memory_limit', '-1');
|
879 |
+
}
|
880 |
+
|
881 |
+
/**
|
882 |
+
* Generate a SQL or Zip file with the current state of the database in use.
|
883 |
+
*
|
884 |
+
* @return string Returns the SQL or Zip full file path created.
|
885 |
+
*/
|
886 |
+
public function all_database(){
|
887 |
+
$sql_output = '';
|
888 |
+
$tables = $this->get_dbtables();
|
889 |
+
|
890 |
+
foreach($tables as $table_name){
|
891 |
+
$sql_output .= $this->single_table($table_name, TRUE);
|
892 |
+
$sql_output .= PHP_EOL.PHP_EOL;
|
893 |
+
}
|
894 |
+
|
895 |
+
$sql_output .= PHP_EOL.PHP_EOL;
|
896 |
+
|
897 |
+
return $this->generate_backup($sql_output);
|
898 |
+
}
|
899 |
+
|
900 |
+
/**
|
901 |
+
* Generate a SQL or Zip file containing all the content inside a single table in the current database.
|
902 |
+
*
|
903 |
+
* @param string $table_name Specify the table name to dump.
|
904 |
+
* @param boolean $batch_mode Specify whether if return the SQL generated or generate the SQL/Zip file.
|
905 |
+
* @return string Returns the SQL generated or the SQL/Zip full file path created.
|
906 |
+
*/
|
907 |
+
public function single_table( $table_name='', $batch_mode=FALSE ){
|
908 |
+
global $wpdb;
|
909 |
+
|
910 |
+
if( $wpdb->get_var("SHOW TABLES LIKE '{$table_name}'")==$table_name ){
|
911 |
+
$sql_output = '';
|
912 |
+
|
913 |
+
$results = $wpdb->get_results("SELECT * FROM `{$table_name}`", ARRAY_N);
|
914 |
+
$fields = $wpdb->get_col("DESCRIBE `{$table_name}`", 0);
|
915 |
+
$num_fields = count($fields);
|
916 |
+
|
917 |
+
$sql_output .= "DROP TABLE IF EXISTS `{$table_name}`;";
|
918 |
+
$table_definition = $wpdb->get_row("SHOW CREATE TABLE `{$table_name}`", ARRAY_N);
|
919 |
+
$sql_output .= PHP_EOL.PHP_EOL . $table_definition[1].';' . PHP_EOL.PHP_EOL;
|
920 |
+
|
921 |
+
foreach($results as $row){
|
922 |
+
$sql_output .= "INSERT INTO `{$table_name}` VALUES(";
|
923 |
+
|
924 |
+
for( $i=0; $i<$num_fields; $i++ ) {
|
925 |
+
$row[$i] = esc_sql($row[$i]);
|
926 |
+
$row[$i] = preg_replace('#'.PHP_EOL.'#', "\n", $row[$i]);
|
927 |
+
|
928 |
+
if( isset($row[$i]) ){
|
929 |
+
$sql_output .= "'{$row[$i]}'";
|
930 |
+
} else {
|
931 |
+
$sql_output .= "''";
|
932 |
+
}
|
933 |
+
|
934 |
+
if( $i < ($num_fields-1) ){
|
935 |
+
$sql_output .= ','.chr(32);
|
936 |
+
}
|
937 |
+
}
|
938 |
+
|
939 |
+
$sql_output .= ');'.PHP_EOL;
|
940 |
+
}
|
941 |
+
|
942 |
+
return $batch_mode===TRUE ? $sql_output : $this->generate_backup($sql_output);
|
943 |
+
}
|
944 |
+
|
945 |
+
return FALSE;
|
946 |
+
}
|
947 |
+
|
948 |
+
/**
|
949 |
+
* Create a SQL or Zip file with the passed content.
|
950 |
+
*
|
951 |
+
* @param string $content SQL generated.
|
952 |
+
* @return string|boolean Return FALSE or the SQL/Zip full file path created.
|
953 |
+
*/
|
954 |
+
private function generate_backup( $content='' ){
|
955 |
+
$plugin_upload_folder = $this->datastore_folder_path();
|
956 |
+
|
957 |
+
if( is_writable($plugin_upload_folder) ){
|
958 |
+
$filename = 'sucuri-dbbackup-'.current_time('timestamp').'.sql';
|
959 |
+
$filepath = rtrim($plugin_upload_folder,'/').'/'.$filename;
|
960 |
+
$handle = @fopen($filepath, 'w+');
|
961 |
+
@fwrite($handle, $content);
|
962 |
+
@fclose($handle);
|
963 |
+
|
964 |
+
if( class_exists('ZipArchive') ){
|
965 |
+
$package_path = $filepath.'.zip';
|
966 |
+
|
967 |
+
$zip = new ZipArchive();
|
968 |
+
$archive = $zip->open($package_path, ZipArchive::CREATE);
|
969 |
+
$zip->addFile($filepath, $filename);
|
970 |
+
$zip->close();
|
971 |
+
|
972 |
+
if( file_exists($package_path) && filesize($package_path)>0 ){
|
973 |
+
@unlink($filepath); /* Remove the old SQL file to keep the new Zip file */
|
974 |
+
$filename = $filename.'.zip';
|
975 |
+
$filepath = $package_path;
|
976 |
+
}
|
977 |
+
}
|
978 |
+
|
979 |
+
return ( file_exists($filepath) && filesize($filepath)>0 ) ? $filepath : FALSE;
|
980 |
+
} else {
|
981 |
+
sucuriscan_error('Upload folder is not writable, can not continue with the backup: <code>'.$plugin_upload_folder.'</code>');
|
982 |
+
}
|
983 |
+
|
984 |
+
return FALSE;
|
985 |
+
}
|
986 |
+
|
987 |
+
/**
|
988 |
+
* Get extra information of the filepath specified, including full filepath, filesize, timeatime, etc.
|
989 |
+
*
|
990 |
+
* @param string $filepath Relative path of the file.
|
991 |
+
* @return object Extra information of the file specified.
|
992 |
+
*/
|
993 |
+
private function get_backup_file_info( $filepath='' ){
|
994 |
+
$backup_file = FALSE;
|
995 |
+
$plugin_upload_folder = $this->datastore_folder_path();
|
996 |
+
|
997 |
+
if( file_exists($filepath) && is_file($filepath) && is_readable($filepath) ){
|
998 |
+
$filesize = filesize($filepath);
|
999 |
+
$filename_exploded = explode('.', $filepath);
|
1000 |
+
$backup_file = (object)array(
|
1001 |
+
'filepath' => $filepath,
|
1002 |
+
'filename' => basename($filepath),
|
1003 |
+
'filesize' => $filesize,
|
1004 |
+
'filehumansize' => $this->human_filesize($filesize),
|
1005 |
+
'filetime' => fileatime($filepath),
|
1006 |
+
'fileext' => array_pop($filename_exploded),
|
1007 |
+
'fileurl' => site_url( str_replace(ABSPATH, '', rtrim($plugin_upload_folder,'/').'/'.basename($filepath)) ),
|
1008 |
+
);
|
1009 |
+
}
|
1010 |
+
|
1011 |
+
return $backup_file;
|
1012 |
+
}
|
1013 |
+
|
1014 |
+
/**
|
1015 |
+
* List all database backup files generated with extra information.
|
1016 |
+
*
|
1017 |
+
* @return array Key-value list of backup files.
|
1018 |
+
*/
|
1019 |
+
public function get_backup_files(){
|
1020 |
+
$backup_files = array();
|
1021 |
+
$plugin_upload_folder = $this->datastore_folder_path();
|
1022 |
+
|
1023 |
+
$files = glob( rtrim($plugin_upload_folder,'/').'/sucuri-dbbackup*.{sql,zip}', GLOB_BRACE );
|
1024 |
+
if( is_array($files) && !empty($files) ){
|
1025 |
+
$files_ordered = array_reverse($files);
|
1026 |
+
|
1027 |
+
foreach( $files_ordered as $filepath ){
|
1028 |
+
$backup_file = $this->get_backup_file_info($filepath);
|
1029 |
+
|
1030 |
+
if( $backup_file ){
|
1031 |
+
$backup_files[] = $backup_file;
|
1032 |
+
}
|
1033 |
+
}
|
1034 |
+
}
|
1035 |
+
|
1036 |
+
return $backup_files;
|
1037 |
+
}
|
1038 |
+
|
1039 |
+
/**
|
1040 |
+
* Get extra information of the filename specified, including full filepath, filesize, timeatime, etc.
|
1041 |
+
*
|
1042 |
+
* @param string $filename Simple filename with extension.
|
1043 |
+
* @return object Extra information of the file specified.
|
1044 |
+
*/
|
1045 |
+
public function get_backup_file_from_filename( $filename='' ){
|
1046 |
+
$plugin_upload_folder = $this->datastore_folder_path();
|
1047 |
+
$filepath = rtrim($plugin_upload_folder,'/').'/'.$filename;
|
1048 |
+
|
1049 |
+
return $this->get_backup_file_info($filepath);
|
1050 |
+
}
|
1051 |
+
|
1052 |
+
/**
|
1053 |
+
* Remove a list of backup files selected by the user through the plugin interface.
|
1054 |
+
*
|
1055 |
+
* @param array $files List of filenames that will be deleted.
|
1056 |
+
* @return void
|
1057 |
+
*/
|
1058 |
+
public function remove_backup_file( $files=array() ){
|
1059 |
+
$files = is_array($files) ? $files : array($files);
|
1060 |
+
|
1061 |
+
if( !empty($files) ){
|
1062 |
+
$num_files_to_remove = count($files);
|
1063 |
+
$num_removed_files = 0;
|
1064 |
+
|
1065 |
+
foreach($files as $filename){
|
1066 |
+
$backup_file = $this->get_backup_file_from_filename($filename);
|
1067 |
+
|
1068 |
+
if($backup_file && @unlink($backup_file->filepath) ){
|
1069 |
+
$num_removed_files += 1;
|
1070 |
+
}
|
1071 |
+
}
|
1072 |
+
|
1073 |
+
$message = sprintf( 'Database backups removed: %d out of %d', $num_removed_files, $num_files_to_remove );
|
1074 |
+
|
1075 |
+
if( $num_removed_files == $num_files_to_remove ){
|
1076 |
+
sucuriscan_info( $message );
|
1077 |
+
} else {
|
1078 |
+
sucuriscan_error( $message );
|
1079 |
+
}
|
1080 |
+
} else {
|
1081 |
+
sucuriscan_error('You did not select any backup file to remove.');
|
1082 |
+
}
|
1083 |
+
}
|
1084 |
+
|
1085 |
+
}
|
1086 |
+
|
1087 |
+
/**
|
1088 |
+
* File-based cache library.
|
1089 |
+
*
|
1090 |
+
* WP_Object_Cache [1] is WordPress' class for caching data which may be
|
1091 |
+
* computationally expensive to regenerate, such as the result of complex
|
1092 |
+
* database queries. However the object cache is non-persistent. This means that
|
1093 |
+
* data stored in the cache resides in memory only and only for the duration of
|
1094 |
+
* the request. Cached data will not be stored persistently across page loads
|
1095 |
+
* unless of the installation of a 3party persistent caching plugin [2].
|
1096 |
+
*
|
1097 |
+
* [1] http://codex.wordpress.org/Class_Reference/WP_Object_Cache
|
1098 |
+
* [2] http://codex.wordpress.org/Class_Reference/WP_Object_Cache#Persistent_Caching
|
1099 |
+
*/
|
1100 |
+
class SucuriScanCache extends SucuriScan {
|
1101 |
+
|
1102 |
+
/**
|
1103 |
+
* The unique name (or identifier) of the file with the data.
|
1104 |
+
*
|
1105 |
+
* The file should be located in the same folder where the dynamic data
|
1106 |
+
* generated by the plugin is stored, and using the following format [1], it
|
1107 |
+
* most be a PHP file because it is expected to have an exit point in the first
|
1108 |
+
* line of the file causing it to stop the execution if a unauthorized user
|
1109 |
+
* tries to access it directly.
|
1110 |
+
*
|
1111 |
+
* [1] /public/data/sucuri-DATASTORE.php
|
1112 |
+
*
|
1113 |
+
* @var null|string
|
1114 |
+
*/
|
1115 |
+
private $datastore = NULL;
|
1116 |
+
|
1117 |
+
/**
|
1118 |
+
* The full path of the datastore file.
|
1119 |
+
*
|
1120 |
+
* @var string
|
1121 |
+
*/
|
1122 |
+
private $datastore_path = '';
|
1123 |
+
|
1124 |
+
/**
|
1125 |
+
* Whether the datastore file is usable or not.
|
1126 |
+
*
|
1127 |
+
* This variable will only be TRUE if the datastore file specified exists, is
|
1128 |
+
* writable and readable, in any other case it will always be FALSE.
|
1129 |
+
*
|
1130 |
+
* @var boolean
|
1131 |
+
*/
|
1132 |
+
private $usable_datastore = FALSE;
|
1133 |
+
|
1134 |
+
/**
|
1135 |
+
* Class constructor.
|
1136 |
+
*
|
1137 |
+
* @param string $datastore Unique name (or identifier) of the file with the data.
|
1138 |
+
* @return void
|
1139 |
+
*/
|
1140 |
+
public function __construct( $datastore='' ){
|
1141 |
+
$this->datastore = $datastore;
|
1142 |
+
$this->datastore_path = $this->datastore_file_path();
|
1143 |
+
$this->usable_datastore = (bool) $this->datastore_path;
|
1144 |
+
}
|
1145 |
+
|
1146 |
+
/**
|
1147 |
+
* Default attributes for every datastore file.
|
1148 |
+
*
|
1149 |
+
* @return string Default attributes for every datastore file.
|
1150 |
+
*/
|
1151 |
+
private function datastore_default_info(){
|
1152 |
+
$attrs = array(
|
1153 |
+
'datastore' => $this->datastore,
|
1154 |
+
'created_on' => time(),
|
1155 |
+
'updated_on' => time(),
|
1156 |
+
);
|
1157 |
+
|
1158 |
+
return $attrs;
|
1159 |
+
}
|
1160 |
+
|
1161 |
+
/**
|
1162 |
+
* Default content of every datastore file.
|
1163 |
+
*
|
1164 |
+
* @param array $finfo Rainbow table with the key names and decoded values.
|
1165 |
+
* @return string Default content of every datastore file.
|
1166 |
+
*/
|
1167 |
+
private function datastore_info( $finfo=array() ){
|
1168 |
+
$attrs = $this->datastore_default_info();
|
1169 |
+
$info_is_available = (bool) isset($finfo['info']);
|
1170 |
+
$info = "<?php\n";
|
1171 |
+
|
1172 |
+
foreach( $attrs as $attr_name => $attr_value ){
|
1173 |
+
if(
|
1174 |
+
$info_is_available
|
1175 |
+
&& $attr_name != 'updated_on'
|
1176 |
+
&& isset($finfo['info'][$attr_name])
|
1177 |
+
){
|
1178 |
+
$attr_value = $finfo['info'][$attr_name];
|
1179 |
+
}
|
1180 |
+
|
1181 |
+
$info .= sprintf( "// %s=%s;\n", $attr_name, $attr_value );
|
1182 |
+
}
|
1183 |
+
|
1184 |
+
$info .= "exit(0);\n";
|
1185 |
+
$info .= "?>\n";
|
1186 |
+
|
1187 |
+
return $info;
|
1188 |
+
}
|
1189 |
+
|
1190 |
+
/**
|
1191 |
+
* Check if the datastore file exists, if it's writable and readable by the same
|
1192 |
+
* user running the server, in case that it does not exists the function will
|
1193 |
+
* tries to create it by itself with the right permissions to use it.
|
1194 |
+
*
|
1195 |
+
* @return string The full path where the datastore file is located, FALSE otherwise.
|
1196 |
+
*/
|
1197 |
+
private function datastore_file_path(){
|
1198 |
+
if( !is_null($this->datastore) ){
|
1199 |
+
$folder_path = $this->datastore_folder_path();
|
1200 |
+
$file_path = $folder_path . 'sucuri-' . $this->datastore . '.php';
|
1201 |
+
|
1202 |
+
// Create the datastore file is it does not exists and the folder is writable.
|
1203 |
+
if(
|
1204 |
+
!file_exists($file_path)
|
1205 |
+
&& is_writable($folder_path)
|
1206 |
+
){
|
1207 |
+
@file_put_contents( $file_path, $this->datastore_info(), LOCK_EX );
|
1208 |
+
}
|
1209 |
+
|
1210 |
+
// Continue the operation after an attemp to create the datastore file.
|
1211 |
+
if(
|
1212 |
+
file_exists($file_path)
|
1213 |
+
&& is_writable($file_path)
|
1214 |
+
&& is_readable($file_path)
|
1215 |
+
){
|
1216 |
+
return $file_path;
|
1217 |
+
}
|
1218 |
+
}
|
1219 |
+
|
1220 |
+
return FALSE;
|
1221 |
+
}
|
1222 |
+
|
1223 |
+
/**
|
1224 |
+
* Check whether a key has a valid name or not.
|
1225 |
+
*
|
1226 |
+
* @param string $key Unique name to identify the data in the datastore file.
|
1227 |
+
* @return boolean TRUE if the format of the key name is valid, FALSE otherwise.
|
1228 |
+
*/
|
1229 |
+
private function valid_key_name( $key='' ){
|
1230 |
+
$key = trim($key);
|
1231 |
+
|
1232 |
+
if( !empty($key) ){
|
1233 |
+
return (bool) preg_match('/^([a-zA-Z_]+)$/', $key);
|
1234 |
+
}
|
1235 |
+
|
1236 |
+
return FALSE;
|
1237 |
+
}
|
1238 |
+
|
1239 |
+
/**
|
1240 |
+
* Update the content of the datastore file with the new entries.
|
1241 |
+
*
|
1242 |
+
* @param array $finfo Rainbow table with the key names and decoded values.
|
1243 |
+
* @return boolean TRUE if the operation finished successfully, FALSE otherwise.
|
1244 |
+
*/
|
1245 |
+
private function save_new_entries( $finfo=array() ){
|
1246 |
+
$data_string = $this->datastore_info($finfo);
|
1247 |
+
|
1248 |
+
if( !empty($finfo) ){
|
1249 |
+
foreach( $finfo['entries'] as $key => $data ){
|
1250 |
+
if( $this->valid_key_name($key) ){
|
1251 |
+
$data = json_encode($data);
|
1252 |
+
$data_string .= sprintf( "%s:%s\n", $key, $data );
|
1253 |
+
}
|
1254 |
+
}
|
1255 |
+
}
|
1256 |
+
|
1257 |
+
$saved = @file_put_contents( $this->datastore_path, $data_string, LOCK_EX );
|
1258 |
+
|
1259 |
+
return (bool) $saved;
|
1260 |
+
}
|
1261 |
+
|
1262 |
+
/**
|
1263 |
+
* Retrieve and parse the datastore file, and generate a rainbow table with the
|
1264 |
+
* key names and decoded data as the values of each entry. Duplicated key names
|
1265 |
+
* will be removed automatically while adding the keys to the array and their
|
1266 |
+
* values will correspond to the first occurrence found in the file.
|
1267 |
+
*
|
1268 |
+
* @param boolean $assoc When TRUE returned objects will be converted into associative arrays.
|
1269 |
+
* @return array Rainbow table with the key names and decoded values.
|
1270 |
+
*/
|
1271 |
+
private function get_datastore_content( $assoc=FALSE ){
|
1272 |
+
$data_object = array(
|
1273 |
+
'info' => array(),
|
1274 |
+
'entries' => array(),
|
1275 |
+
);
|
1276 |
+
|
1277 |
+
if( $this->usable_datastore ){
|
1278 |
+
$data_lines = @file($this->datastore_path);
|
1279 |
+
|
1280 |
+
if( !empty($data_lines) ){
|
1281 |
+
foreach( $data_lines as $line ){
|
1282 |
+
$line = trim($line);
|
1283 |
+
|
1284 |
+
if( preg_match('/^\/\/ ([a-z_]+)=(.*);$/', $line, $match) ){
|
1285 |
+
$data_object['info'][$match[1]] = $match[2];
|
1286 |
+
}
|
1287 |
+
|
1288 |
+
elseif( preg_match('/^([a-z_]+):(.+)/', $line, $match) ){
|
1289 |
+
if(
|
1290 |
+
$this->valid_key_name($match[1])
|
1291 |
+
&& !array_key_exists($match[1], $data_object)
|
1292 |
+
){
|
1293 |
+
$data_object['entries'][$match[1]] = json_decode( $match[2], $assoc );
|
1294 |
+
}
|
1295 |
+
}
|
1296 |
+
}
|
1297 |
+
}
|
1298 |
+
}
|
1299 |
+
|
1300 |
+
return $data_object;
|
1301 |
+
}
|
1302 |
+
|
1303 |
+
/**
|
1304 |
+
* Retrieve the headers of the datastore file.
|
1305 |
+
*
|
1306 |
+
* Each datastore file has a list of attributes at the beginning of the it with
|
1307 |
+
* information like the creation and last update time. If you are extending the
|
1308 |
+
* functionality of these headers please refer to the function that contains the
|
1309 |
+
* default attributes and their values [1].
|
1310 |
+
*
|
1311 |
+
* [1] SucuriScanCache::datastore_default_info()
|
1312 |
+
*
|
1313 |
+
* @return array Default content of every datastore file.
|
1314 |
+
*/
|
1315 |
+
public function get_datastore_info(){
|
1316 |
+
$finfo = $this->get_datastore_content();
|
1317 |
+
|
1318 |
+
if( !empty($finfo['info']) ){
|
1319 |
+
return $finfo['info'];
|
1320 |
+
}
|
1321 |
+
|
1322 |
+
return FALSE;
|
1323 |
+
}
|
1324 |
+
|
1325 |
+
/**
|
1326 |
+
* Get the total number of unique entries in the datastore file.
|
1327 |
+
*
|
1328 |
+
* @param array $finfo Rainbow table with the key names and decoded values.
|
1329 |
+
* @return integer Total number of unique entries found in the datastore file.
|
1330 |
+
*/
|
1331 |
+
public function get_count( $finfo=NULL ){
|
1332 |
+
if( !is_array($finfo) ){
|
1333 |
+
$finfo = $this->get_datastore_content();
|
1334 |
+
}
|
1335 |
+
|
1336 |
+
return count($finfo['entries']);
|
1337 |
+
}
|
1338 |
+
|
1339 |
+
/**
|
1340 |
+
* Check whether the last update time of the datastore file has surpassed the
|
1341 |
+
* lifetime specified for a key name. This function is the only one related with
|
1342 |
+
* the caching process, any others besides this are just methods used to handle
|
1343 |
+
* the data inside those files.
|
1344 |
+
*
|
1345 |
+
* @param integer $lifetime Life time of the key in the datastore file.
|
1346 |
+
* @param array $finfo Rainbow table with the key names and decoded values.
|
1347 |
+
* @return boolean TRUE if the life time of the data has expired, FALSE otherwise.
|
1348 |
+
*/
|
1349 |
+
public function data_has_expired( $lifetime=0, $finfo=NULL ){
|
1350 |
+
if( is_null($finfo) ){
|
1351 |
+
$finfo = $this->get_datastore_content();
|
1352 |
+
}
|
1353 |
+
|
1354 |
+
if( $lifetime > 0 && !empty($finfo['info']) ){
|
1355 |
+
$diff_time = time() - intval($finfo['info']['updated_on']);
|
1356 |
+
|
1357 |
+
if( $diff_time >= $lifetime ){
|
1358 |
+
return TRUE;
|
1359 |
+
}
|
1360 |
+
}
|
1361 |
+
|
1362 |
+
return FALSE;
|
1363 |
+
}
|
1364 |
+
|
1365 |
+
/**
|
1366 |
+
* Execute the action using the key name and data specified.
|
1367 |
+
*
|
1368 |
+
* @param string $key Unique name to identify the data in the datastore file.
|
1369 |
+
* @param string $data Mixed data stored in the datastore file following the unique key name.
|
1370 |
+
* @param string $action Either add, set, get, or delete.
|
1371 |
+
* @param integer $lifetime Life time of the key in the datastore file.
|
1372 |
+
* @param boolean $assoc When TRUE returned objects will be converted into associative arrays.
|
1373 |
+
* @return boolean TRUE if the operation finished successfully, FALSE otherwise.
|
1374 |
+
*/
|
1375 |
+
private function handle_key_data( $key='', $data=NULL, $action='', $lifetime=0, $assoc=FALSE ){
|
1376 |
+
if( preg_match('/^(add|set|get|delete)$/', $action) ){
|
1377 |
+
if( $this->valid_key_name($key) && $this->usable_datastore ){
|
1378 |
+
$finfo = $this->get_datastore_content($assoc);
|
1379 |
+
|
1380 |
+
switch( $action ){
|
1381 |
+
case 'add': /* no_break */
|
1382 |
+
case 'set':
|
1383 |
+
$finfo['entries'][$key] = $data;
|
1384 |
+
return $this->save_new_entries($finfo);
|
1385 |
+
break;
|
1386 |
+
case 'get':
|
1387 |
+
if(
|
1388 |
+
!$this->data_has_expired($lifetime, $finfo)
|
1389 |
+
&& array_key_exists($key, $finfo['entries'])
|
1390 |
+
){
|
1391 |
+
return $finfo['entries'][$key];
|
1392 |
+
}
|
1393 |
+
break;
|
1394 |
+
case 'delete':
|
1395 |
+
unset($finfo['entries'][$key]);
|
1396 |
+
return $this->save_new_entries($finfo);
|
1397 |
+
break;
|
1398 |
+
}
|
1399 |
+
}
|
1400 |
+
}
|
1401 |
+
|
1402 |
+
return FALSE;
|
1403 |
+
}
|
1404 |
+
|
1405 |
+
/**
|
1406 |
+
* JSON-encode the data and store it in the datastore file identifying it with
|
1407 |
+
* the key name, the data will be added to the file even if the key is
|
1408 |
+
* duplicated, but when getting the value of the same key later again it will
|
1409 |
+
* return only the value of the first occurrence found in the file.
|
1410 |
+
*
|
1411 |
+
* @param string $key Unique name to identify the data in the datastore file.
|
1412 |
+
* @param string $data Mixed data stored in the datastore file following the unique key name.
|
1413 |
+
* @return boolean TRUE if the data was stored successfully, FALSE otherwise.
|
1414 |
+
*/
|
1415 |
+
public function add( $key='', $data='' ){
|
1416 |
+
return $this->handle_key_data( $key, $data, 'add' );
|
1417 |
+
}
|
1418 |
+
|
1419 |
+
/**
|
1420 |
+
* Update the data of all the key names matching the one specified.
|
1421 |
+
*
|
1422 |
+
* @param string $key Unique name to identify the data in the datastore file.
|
1423 |
+
* @param string $data Mixed data stored in the datastore file following the unique key name.
|
1424 |
+
* @return boolean TRUE if the data was stored successfully, FALSE otherwise.
|
1425 |
+
*/
|
1426 |
+
public function set( $key='', $data='' ){
|
1427 |
+
return $this->handle_key_data( $key, $data, 'set' );
|
1428 |
+
}
|
1429 |
+
|
1430 |
+
/**
|
1431 |
+
* Retrieve the first occurrence of the key found in the datastore file.
|
1432 |
+
*
|
1433 |
+
* @param string $key Unique name to identify the data in the datastore file.
|
1434 |
+
* @param integer $lifetime Life time of the key in the datastore file.
|
1435 |
+
* @param boolean $assoc When TRUE returned objects will be converted into associative arrays.
|
1436 |
+
* @return string Mixed data stored in the datastore file following the unique key name.
|
1437 |
+
*/
|
1438 |
+
public function get( $key='', $lifetime=0, $assoc=FALSE ){
|
1439 |
+
$assoc = ( $assoc == 'array' ? TRUE : $assoc );
|
1440 |
+
|
1441 |
+
return $this->handle_key_data( $key, NULL, 'get', $lifetime, $assoc );
|
1442 |
+
}
|
1443 |
+
|
1444 |
+
/**
|
1445 |
+
* Delete any entry from the datastore file matching the key name specified.
|
1446 |
+
*
|
1447 |
+
* @param string $key Unique name to identify the data in the datastore file.
|
1448 |
+
* @return boolean TRUE if the entries were removed, FALSE otherwise.
|
1449 |
+
*/
|
1450 |
+
public function delete( $key='' ){
|
1451 |
+
return $this->handle_key_data( $key, NULL, 'delete' );
|
1452 |
+
}
|
1453 |
+
|
1454 |
+
/**
|
1455 |
+
* Remove all the entries from the datastore file.
|
1456 |
+
*
|
1457 |
+
* @return boolean Always TRUE unless the datastore file is not writable.
|
1458 |
+
*/
|
1459 |
+
public function flush(){
|
1460 |
+
$finfo = $this->get_datastore_content();
|
1461 |
+
|
1462 |
+
return $this->save_new_entries($finfo);
|
1463 |
+
}
|
1464 |
+
|
1465 |
+
}
|
1466 |
+
|
1467 |
+
/**
|
1468 |
+
* Check whether the current site is working as a multi-site instance.
|
1469 |
+
*
|
1470 |
+
* @return boolean Either TRUE or FALSE in case WordPress is being used as a multi-site instance.
|
1471 |
+
*/
|
1472 |
+
function sucuriscan_is_multisite(){
|
1473 |
+
if( function_exists('is_multisite') && is_multisite() ){ return TRUE; }
|
1474 |
+
return FALSE;
|
1475 |
+
}
|
1476 |
+
|
1477 |
+
/**
|
1478 |
+
* Check whether the IP address specified is a valid IPv4 format.
|
1479 |
+
*
|
1480 |
+
* @param string $remote_addr The host IP address.
|
1481 |
+
* @return boolean TRUE if the address specified is a valid IPv4 format, FALSE otherwise.
|
1482 |
+
*/
|
1483 |
+
function sucuriscan_is_valid_ipv4( $remote_addr='' ){
|
1484 |
+
if( preg_match('/^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/', $remote_addr, $match) ){
|
1485 |
+
for( $i=0; $i<4; $i++ ){
|
1486 |
+
if( $match[$i] > 255 ){ return FALSE; }
|
1487 |
+
}
|
1488 |
+
|
1489 |
+
return TRUE;
|
1490 |
+
}
|
1491 |
+
|
1492 |
+
return FALSE;
|
1493 |
+
}
|
1494 |
+
|
1495 |
+
if( !function_exists('sucuriscan_init') ){
|
1496 |
+
/**
|
1497 |
+
* Initialization code for the plugin.
|
1498 |
+
*
|
1499 |
+
* The initial variables and information needed by the plugin during the
|
1500 |
+
* execution of other functions will be generated. Things like the real IP
|
1501 |
+
* address of the client when it has been forwarded or it's behind an external
|
1502 |
+
* service like a Proxy.
|
1503 |
+
*
|
1504 |
+
* @return void
|
1505 |
+
*/
|
1506 |
+
function sucuriscan_init(){
|
1507 |
+
if(
|
1508 |
+
isset($_SERVER['HTTP_X_FORWARDED_FOR'])
|
1509 |
+
&& preg_match("/^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$/", $_SERVER['HTTP_X_FORWARDED_FOR'])
|
1510 |
+
&& sucuriscan_is_valid_ipv4($_SERVER['HTTP_X_FORWARDED_FOR'])
|
1511 |
+
){
|
1512 |
+
$_SERVER['SUCURIREAL_REMOTE_ADDR'] = $_SERVER['REMOTE_ADDR'];
|
1513 |
+
$_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_X_FORWARDED_FOR'];
|
1514 |
+
}
|
1515 |
+
}
|
1516 |
+
|
1517 |
+
add_action('init', 'sucuriscan_init', 1);
|
1518 |
+
}
|
1519 |
+
|
1520 |
+
if( !function_exists('sucuriscan_create_uploaddir') ){
|
1521 |
+
/**
|
1522 |
+
* Create a folder in the WordPress upload directory where the plugin will
|
1523 |
+
* store all the temporal or dynamic information.
|
1524 |
+
*
|
1525 |
+
* @return void
|
1526 |
+
*/
|
1527 |
+
function sucuriscan_create_uploaddir(){
|
1528 |
+
$plugin_upload_folder = sucuriscan_dir_filepath();
|
1529 |
+
|
1530 |
+
if( !file_exists($plugin_upload_folder) ){
|
1531 |
+
if( @mkdir($plugin_upload_folder) ){
|
1532 |
+
sucuriscan_lastlogins_datastore_exists();
|
1533 |
+
} else {
|
1534 |
+
sucuriscan_error(
|
1535 |
+
'Data folder does not exists and could not be created. You will need to
|
1536 |
+
create this folder manually and give it write permissions:<br><br><code>'
|
1537 |
+
. $plugin_upload_folder . '</code>'
|
1538 |
+
);
|
1539 |
+
}
|
1540 |
+
}
|
1541 |
+
}
|
1542 |
+
|
1543 |
+
add_action('admin_init', 'sucuriscan_create_uploaddir');
|
1544 |
+
}
|
1545 |
+
|
1546 |
+
if( !function_exists('sucuriscan_admin_script_style_registration') ){
|
1547 |
+
/**
|
1548 |
+
* Define which javascript and css files will be loaded in the header of the page.
|
1549 |
+
* @return void
|
1550 |
+
*/
|
1551 |
+
function sucuriscan_admin_script_style_registration(){
|
1552 |
+
$asset_version = '';
|
1553 |
+
|
1554 |
+
if( strlen(SUCURISCAN_PLUGIN_CHECKSUM) >= 7 ){
|
1555 |
+
$asset_version = substr(SUCURISCAN_PLUGIN_CHECKSUM, 0, 7);
|
1556 |
+
}
|
1557 |
+
|
1558 |
+
wp_register_style( 'sucuriscan', SUCURI_URL . '/inc/css/sucuriscan-default-css.css', array(), $asset_version );
|
1559 |
+
wp_register_script( 'sucuriscan', SUCURI_URL . '/inc/js/sucuriscan-scripts.js', array(), $asset_version );
|
1560 |
+
|
1561 |
+
wp_enqueue_style( 'sucuriscan' );
|
1562 |
+
wp_enqueue_script( 'sucuriscan' );
|
1563 |
+
}
|
1564 |
+
|
1565 |
+
add_action( 'admin_enqueue_scripts', 'sucuriscan_admin_script_style_registration', 1 );
|
1566 |
+
}
|
1567 |
+
|
1568 |
+
/**
|
1569 |
+
* Returns the system filepath to the relevant user uploads directory for this
|
1570 |
+
* site. This is a multisite capable function.
|
1571 |
+
*
|
1572 |
+
* @param string $path The relative path that needs to be completed to get the absolute path.
|
1573 |
+
* @return string The full filesystem path including the directory specified.
|
1574 |
+
*/
|
1575 |
+
function sucuriscan_dir_filepath($path = ''){
|
1576 |
+
return SucuriScan::datastore_folder_path($path);
|
1577 |
+
}
|
1578 |
+
|
1579 |
+
/**
|
1580 |
+
* List an associative array with the sub-pages of this plugin.
|
1581 |
+
*
|
1582 |
+
* @param boolean $for_navbar Either TRUE or FALSE indicanting that the first page will be named Dashboard.
|
1583 |
+
* @return array List of pages and sub-pages of this plugin.
|
1584 |
+
*/
|
1585 |
+
function sucuriscan_pages( $for_navbar=FALSE ){
|
1586 |
+
$pages = array(
|
1587 |
+
'sucuriscan' => 'Dashboard',
|
1588 |
+
'sucuriscan_scanner' => 'Malware Scan',
|
1589 |
+
'sucuriscan_monitoring' => 'Firewall (WAF)',
|
1590 |
+
'sucuriscan_hardening' => 'Hardening',
|
1591 |
+
'sucuriscan_posthack' => 'Post-Hack',
|
1592 |
+
'sucuriscan_lastlogins' => 'Last Logins',
|
1593 |
+
'sucuriscan_settings' => 'Settings',
|
1594 |
+
'sucuriscan_infosys' => 'Site Info',
|
1595 |
+
);
|
1596 |
+
|
1597 |
+
return $pages;
|
1598 |
+
}
|
1599 |
+
|
1600 |
+
/**
|
1601 |
+
* Generate the menu and submenus for the plugin in the admin interface.
|
1602 |
+
*
|
1603 |
+
* @return void
|
1604 |
+
*/
|
1605 |
+
function sucuriscan_menu(){
|
1606 |
+
// Add main menu link.
|
1607 |
+
add_menu_page(
|
1608 |
+
'Sucuri Security',
|
1609 |
+
'Sucuri Security',
|
1610 |
+
'manage_options',
|
1611 |
+
'sucuriscan',
|
1612 |
+
'sucuriscan_page',
|
1613 |
+
SUCURI_URL . '/inc/images/menu-icon.png'
|
1614 |
+
);
|
1615 |
+
|
1616 |
+
$sub_pages = sucuriscan_pages();
|
1617 |
+
|
1618 |
+
foreach( $sub_pages as $sub_page_func => $sub_page_title ){
|
1619 |
+
$page_func = $sub_page_func . '_page';
|
1620 |
+
|
1621 |
+
add_submenu_page(
|
1622 |
+
'sucuriscan',
|
1623 |
+
$sub_page_title,
|
1624 |
+
$sub_page_title,
|
1625 |
+
'manage_options',
|
1626 |
+
$sub_page_func,
|
1627 |
+
$page_func
|
1628 |
+
);
|
1629 |
+
}
|
1630 |
+
}
|
1631 |
+
|
1632 |
+
if( !function_exists('sucuriscan_handle_old_plugin') ){
|
1633 |
+
/**
|
1634 |
+
* Remove the old Sucuri plugins considering that with the new version (after
|
1635 |
+
* 1.6.0) all the functionality of the others will be merged here, this will
|
1636 |
+
* remove duplicated functionality, duplicated bugs and/or duplicated
|
1637 |
+
* maintenance reports allowing us to focus in one unique project.
|
1638 |
+
*
|
1639 |
+
* @return void
|
1640 |
+
*/
|
1641 |
+
function sucuriscan_handle_old_plugin(){
|
1642 |
+
$sucuri_fileinfo = new SucuriScanFileInfo();
|
1643 |
+
$sucuri_fileinfo->ignore_files = FALSE;
|
1644 |
+
$sucuri_fileinfo->ignore_directories = FALSE;
|
1645 |
+
|
1646 |
+
$plugins = array(
|
1647 |
+
'sucuri-wp-plugin/sucuri.php',
|
1648 |
+
'sucuri-cloudproxy-waf/cloudproxy.php',
|
1649 |
+
);
|
1650 |
+
|
1651 |
+
foreach( $plugins as $plugin ){
|
1652 |
+
$plugin_directory = dirname( WP_PLUGIN_DIR . '/' . $plugin );
|
1653 |
+
|
1654 |
+
if( file_exists($plugin_directory) ){
|
1655 |
+
if( is_plugin_active($plugin) ){
|
1656 |
+
deactivate_plugins($plugin);
|
1657 |
+
}
|
1658 |
+
|
1659 |
+
$plugin_removed = $sucuri_fileinfo->remove_directory_tree($plugin_directory);
|
1660 |
+
}
|
1661 |
+
}
|
1662 |
+
}
|
1663 |
+
|
1664 |
+
add_action('admin_init', 'sucuriscan_handle_old_plugin');
|
1665 |
+
}
|
1666 |
+
|
1667 |
+
/**
|
1668 |
+
* Initialize the execute of the main plugin's functions.
|
1669 |
+
*
|
1670 |
+
* This will load the menu options in the WordPress administrator panel, and
|
1671 |
+
* execute the bootstrap function of the plugin.
|
1672 |
+
*/
|
1673 |
+
add_action('admin_menu', 'sucuriscan_menu');
|
1674 |
+
add_action('sucuriscan_scheduled_scan', 'sucuriscan_filesystem_scan');
|
1675 |
+
remove_action('wp_head', 'wp_generator');
|
1676 |
+
|
1677 |
+
/**
|
1678 |
+
* Validate email address.
|
1679 |
+
*
|
1680 |
+
* This use the native PHP function filter_var which is available in PHP >=
|
1681 |
+
* 5.2.0 if it is not found in the interpreter this function will sue regular
|
1682 |
+
* expressions to check whether the email address passed is valid or not.
|
1683 |
+
*
|
1684 |
+
* @see http://www.php.net/manual/en/function.filter-var.php
|
1685 |
+
*
|
1686 |
+
* @param string $email The string that will be validated as an email address.
|
1687 |
+
* @return boolean TRUE if the email address passed to the function is valid, FALSE if not.
|
1688 |
+
*/
|
1689 |
+
function is_valid_email( $email='' ){
|
1690 |
+
if( function_exists('filter_var') ){
|
1691 |
+
return (bool) filter_var($email, FILTER_VALIDATE_EMAIL);
|
1692 |
+
} else {
|
1693 |
+
$pattern = '/^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6}$/ix';
|
1694 |
+
return (bool) preg_match($pattern, $email);
|
1695 |
+
}
|
1696 |
+
}
|
1697 |
+
|
1698 |
+
/**
|
1699 |
+
* Send a message to a specific email address.
|
1700 |
+
*
|
1701 |
+
* @param string $to The email address of the recipient that will receive the message.
|
1702 |
+
* @param string $subject The reason of the message that will be sent.
|
1703 |
+
* @param string $message Body of the message that will be sent.
|
1704 |
+
* @param array $data_set Optional parameter to add more information to the notification.
|
1705 |
+
* @param boolean $debug TRUE if you want to test the function printing the email before sending it.
|
1706 |
+
* @return void
|
1707 |
+
*/
|
1708 |
+
function sucuriscan_send_mail( $to='', $subject='', $message='', $data_set=array(), $debug=FALSE ){
|
1709 |
+
$headers = array();
|
1710 |
+
$subject = ucwords(strtolower($subject));
|
1711 |
+
$wp_domain = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : get_option('siteurl');
|
1712 |
+
|
1713 |
+
if( sucuriscan_get_option('sucuriscan_prettify_mails') == 'enabled' ){
|
1714 |
+
$headers = array( 'Content-type: text/html' );
|
1715 |
+
$data_set['PrettifyType'] = 'pretty';
|
1716 |
+
}
|
1717 |
+
|
1718 |
+
$message = sucuriscan_prettify_mail($subject, $message, $data_set);
|
1719 |
+
|
1720 |
+
if( $debug ){
|
1721 |
+
die($message);
|
1722 |
+
} else {
|
1723 |
+
wp_mail($to, "Sucuri WP Notification: {$wp_domain} - {$subject}" , $message, $headers);
|
1724 |
+
}
|
1725 |
+
}
|
1726 |
+
|
1727 |
+
/**
|
1728 |
+
* Generate a HTML version of the message that will be sent through an email.
|
1729 |
+
*
|
1730 |
+
* @param string $subject The reason of the message that will be sent.
|
1731 |
+
* @param string $message Body of the message that will be sent.
|
1732 |
+
* @param array $data_set Optional parameter to add more information to the notification.
|
1733 |
+
* @return string The message formatted in a HTML template.
|
1734 |
+
*/
|
1735 |
+
function sucuriscan_prettify_mail( $subject='', $message='', $data_set=array() ){
|
1736 |
+
$prettify_type = isset($data_set['PrettifyType']) ? $data_set['PrettifyType'] : 'simple';
|
1737 |
+
$template_name = 'notification-' . $prettify_type;
|
1738 |
+
$remote_addr = sucuriscan_get_remoteaddr();
|
1739 |
+
$user = wp_get_current_user();
|
1740 |
+
$display_name = '';
|
1741 |
+
|
1742 |
+
if(
|
1743 |
+
$user instanceof WP_User
|
1744 |
+
&& isset($user->user_login)
|
1745 |
+
&& !empty($user->user_login)
|
1746 |
+
){
|
1747 |
+
$display_name = sprintf( 'User: %s (%s)', $user->display_name, $user->user_login );
|
1748 |
+
}
|
1749 |
+
|
1750 |
+
$mail_variables = array(
|
1751 |
+
'TemplateTitle' => 'Sucuri WP Notification',
|
1752 |
+
'Subject' => $subject,
|
1753 |
+
'Website' => get_option('siteurl'),
|
1754 |
+
'RemoteAddress' => $remote_addr,
|
1755 |
+
'Message' => $message,
|
1756 |
+
'User' => $display_name,
|
1757 |
+
'Time' => current_time('mysql'),
|
1758 |
+
);
|
1759 |
+
|
1760 |
+
foreach($data_set as $var_key=>$var_value){
|
1761 |
+
$mail_variables[$var_key] = $var_value;
|
1762 |
+
}
|
1763 |
+
|
1764 |
+
return sucuriscan_get_section( $template_name, $mail_variables );
|
1765 |
+
}
|
1766 |
+
|
1767 |
+
/**
|
1768 |
+
* Prints a HTML alert in the WordPress admin interface.
|
1769 |
+
*
|
1770 |
+
* @param string $type The type of alert, it can be either Updated or Error.
|
1771 |
+
* @param string $message The message that will be printed in the alert.
|
1772 |
+
* @return void
|
1773 |
+
*/
|
1774 |
+
function sucuriscan_admin_notice($type='updated', $message=''){
|
1775 |
+
$alert_id = rand(100, 999);
|
1776 |
+
if( !empty($message) ): ?>
|
1777 |
+
<div id="sucuriscan-alert-<?php echo $alert_id; ?>" class="<?php echo $type; ?> sucuriscan-alert sucuriscan-alert-<?php echo $type; ?>">
|
1778 |
+
<a href="javascript:void(0)" class="close" onclick="sucuriscan_alert_close('<?php echo $alert_id; ?>')">×</a>
|
1779 |
+
<p><?php _e($message); ?></p>
|
1780 |
+
</div>
|
1781 |
+
<?php endif;
|
1782 |
+
}
|
1783 |
+
|
1784 |
+
/**
|
1785 |
+
* Prints a HTML alert of type ERROR in the WordPress admin interface.
|
1786 |
+
*
|
1787 |
+
* @param string $error_msg The message that will be printed in the alert.
|
1788 |
+
* @return void
|
1789 |
+
*/
|
1790 |
+
function sucuriscan_error( $error_msg='' ){
|
1791 |
+
sucuriscan_admin_notice( 'error', '<b>Sucuri:</b> ' . $error_msg );
|
1792 |
+
}
|
1793 |
+
|
1794 |
+
/**
|
1795 |
+
* Prints a HTML alert of type INFO in the WordPress admin interface.
|
1796 |
+
*
|
1797 |
+
* @param string $info_msg The message that will be printed in the alert.
|
1798 |
+
* @return void
|
1799 |
+
*/
|
1800 |
+
function sucuriscan_info( $info_msg='' ){
|
1801 |
+
sucuriscan_admin_notice( 'updated', '<b>Sucuri:</b> ' . $info_msg );
|
1802 |
+
}
|
1803 |
+
|
1804 |
+
/**
|
1805 |
+
* Verify the nonce of the previous page after a form submission. If the
|
1806 |
+
* validation fails the execution of the script will be stopped and a dead page
|
1807 |
+
* will be printed to the client using the official WordPress method.
|
1808 |
+
*
|
1809 |
+
* @return boolean Either TRUE or FALSE if the nonce is valid or not respectively.
|
1810 |
+
*/
|
1811 |
+
function sucuriscan_check_page_nonce(){
|
1812 |
+
if( !empty($_POST) ){
|
1813 |
+
$nonce_name = 'sucuriscan_page_nonce';
|
1814 |
+
|
1815 |
+
if( !isset($_POST[$nonce_name]) || !wp_verify_nonce($_POST[$nonce_name], $nonce_name) ){
|
1816 |
+
wp_die(__('WordPress Nonce verification failed, try again going back and checking the form.') );
|
1817 |
+
|
1818 |
+
return FALSE;
|
1819 |
+
}
|
1820 |
+
}
|
1821 |
+
|
1822 |
+
return TRUE;
|
1823 |
+
}
|
1824 |
+
|
1825 |
+
/**
|
1826 |
+
* Replace all pseudo-variables from a string of characters.
|
1827 |
+
*
|
1828 |
+
* @param string $content The content of a template file which contains pseudo-variables.
|
1829 |
+
* @param array $params List of pseudo-variables that will be replaced in the template.
|
1830 |
+
* @return string The content of the template with the pseudo-variables replated.
|
1831 |
+
*/
|
1832 |
+
function sucuriscan_replace_pseudovars( $content='', $params=array() ){
|
1833 |
+
if( is_array($params) ){
|
1834 |
+
foreach( $params as $tpl_key => $tpl_value ){
|
1835 |
+
$tpl_key = '%%SUCURI.' . $tpl_key . '%%';
|
1836 |
+
$content = str_replace( $tpl_key, $tpl_value, $content );
|
1837 |
+
}
|
1838 |
+
|
1839 |
+
return $content;
|
1840 |
+
}
|
1841 |
+
|
1842 |
+
return FALSE;
|
1843 |
+
}
|
1844 |
+
|
1845 |
+
/**
|
1846 |
+
* Complement the list of pseudo-variables that will be used in the base
|
1847 |
+
* template files, this will also generate the navigation bar and detect which
|
1848 |
+
* items in it are selected by the current page.
|
1849 |
+
*
|
1850 |
+
* @param array $params A hash containing the pseudo-variable name as the key and the value that will replace it.
|
1851 |
+
* @return array A complementary list of pseudo-variables for the template files.
|
1852 |
+
*/
|
1853 |
+
function sucuriscan_links_and_navbar( $params=array() ){
|
1854 |
+
$params = is_array($params) ? $params : array();
|
1855 |
+
$sub_pages = sucuriscan_pages(TRUE);
|
1856 |
+
|
1857 |
+
$params['Navbar'] = '';
|
1858 |
+
$params['CurrentPageFunc'] = isset($_GET['page']) ? $_GET['page'] : '';
|
1859 |
+
|
1860 |
+
foreach( $sub_pages as $sub_page_func => $sub_page_title ){
|
1861 |
+
$func_parts = explode( '_', $sub_page_func, 2 );
|
1862 |
+
|
1863 |
+
if( isset($func_parts[1]) ){
|
1864 |
+
$unique_name = $func_parts[1];
|
1865 |
+
$pseudo_var = 'URL.' . ucwords($unique_name);
|
1866 |
+
} else {
|
1867 |
+
$unique_name = '';
|
1868 |
+
$pseudo_var = 'URL.Home';
|
1869 |
+
}
|
1870 |
+
|
1871 |
+
$params[$pseudo_var] = sucuriscan_get_url($unique_name);
|
1872 |
+
|
1873 |
+
$navbar_item_css_class = 'nav-tab';
|
1874 |
+
|
1875 |
+
if( $params['CurrentPageFunc'] == $sub_page_func ){
|
1876 |
+
$navbar_item_css_class .= chr(32) . 'nav-tab-active';
|
1877 |
+
}
|
1878 |
+
|
1879 |
+
$params['Navbar'] .= sprintf(
|
1880 |
+
'<a class="%s" href="%s">%s</a>' . "\n",
|
1881 |
+
$navbar_item_css_class,
|
1882 |
+
$params[$pseudo_var],
|
1883 |
+
$sub_page_title
|
1884 |
+
);
|
1885 |
+
}
|
1886 |
+
|
1887 |
+
return $params;
|
1888 |
+
}
|
1889 |
+
|
1890 |
+
/**
|
1891 |
+
* Generate a HTML code using a template and replacing all the pseudo-variables
|
1892 |
+
* by the dynamic variables provided by the developer through one of the parameters
|
1893 |
+
* of the function.
|
1894 |
+
*
|
1895 |
+
* @param string $template Filename of the template that will be used to generate the page.
|
1896 |
+
* @param array $params A hash containing the pseudo-variable name as the key and the value that will replace it.
|
1897 |
+
* @param boolean $type Either page, section or snippet indicating the type of template that will be retrieved.
|
1898 |
+
* @return string The formatted HTML page after replace all the pseudo-variables.
|
1899 |
+
*/
|
1900 |
+
function sucuriscan_get_template( $template='', $params=array(), $type='page' ){
|
1901 |
+
switch( $type ){
|
1902 |
+
case 'page': /* no_break */
|
1903 |
+
case 'section':
|
1904 |
+
$template_path_pattern = '%s/%s/inc/tpl/%s.html.tpl';
|
1905 |
+
break;
|
1906 |
+
case 'snippet':
|
1907 |
+
$template_path_pattern = '%s/%s/inc/tpl/%s.snippet.tpl';
|
1908 |
+
break;
|
1909 |
+
}
|
1910 |
+
|
1911 |
+
$template_content = '';
|
1912 |
+
$template_path = sprintf( $template_path_pattern, WP_PLUGIN_DIR, SUCURISCAN_PLUGIN_FOLDER, $template );
|
1913 |
+
$params = is_array($params) ? $params : array();
|
1914 |
+
|
1915 |
+
if( file_exists($template_path) && is_readable($template_path) ){
|
1916 |
+
$template_content = file_get_contents($template_path);
|
1917 |
+
|
1918 |
+
$current_page = isset($_GET['page']) ? htmlentities($_GET['page']) : '';
|
1919 |
+
$params['CurrentURL'] = sprintf( '%s/wp-admin/admin.php?page=%s', site_url(), $current_page );
|
1920 |
+
$params['SucuriURL'] = SUCURI_URL;
|
1921 |
+
|
1922 |
+
// Replace the global pseudo-variables in the section/snippets templates.
|
1923 |
+
if(
|
1924 |
+
$template == 'base'
|
1925 |
+
&& isset($params['PageContent'])
|
1926 |
+
&& preg_match('/%%SUCURI\.(.+)%%/', $params['PageContent'])
|
1927 |
+
){
|
1928 |
+
$params['PageContent'] = sucuriscan_replace_pseudovars( $params['PageContent'], $params );
|
1929 |
+
}
|
1930 |
+
|
1931 |
+
$template_content = sucuriscan_replace_pseudovars( $template_content, $params );
|
1932 |
+
}
|
1933 |
+
|
1934 |
+
if( $template == 'base' || $type != 'page' ){
|
1935 |
+
return $template_content;
|
1936 |
+
}
|
1937 |
+
|
1938 |
+
return sucuriscan_get_base_template( $template_content, $params );
|
1939 |
+
}
|
1940 |
+
|
1941 |
+
/**
|
1942 |
+
* Gather and generate the information required globally by all the template files.
|
1943 |
+
*
|
1944 |
+
* @param array $params A hash containing the pseudo-variable name as the key and the value that will replace it.
|
1945 |
+
* @return array A complementary list of pseudo-variables for the template files.
|
1946 |
+
*/
|
1947 |
+
function sucuriscan_shared_params( $params=array() ){
|
1948 |
+
$params = is_array($params) ? $params : array();
|
1949 |
+
|
1950 |
+
// Base parameters, required to render all the pages.
|
1951 |
+
$params = sucuriscan_links_and_navbar($params);
|
1952 |
+
|
1953 |
+
// Global parameters, used through out all the pages.
|
1954 |
+
$params['PageTitle'] = isset($params['PageTitle']) ? '('.$params['PageTitle'].')' : '';
|
1955 |
+
$params['PageNonce'] = wp_create_nonce('sucuriscan_page_nonce');
|
1956 |
+
$params['PageStyleClass'] = isset($params['PageStyleClass']) ? $params['PageStyleClass'] : 'base';
|
1957 |
+
$params['CleanDomain'] = sucuriscan_get_domain();
|
1958 |
+
$params['AdminEmail'] = sucuriscan_get_site_email();
|
1959 |
+
|
1960 |
+
return $params;
|
1961 |
+
}
|
1962 |
+
|
1963 |
+
/**
|
1964 |
+
* Generate a HTML code using a template and replacing all the pseudo-variables
|
1965 |
+
* by the dynamic variables provided by the developer through one of the parameters
|
1966 |
+
* of the function.
|
1967 |
+
*
|
1968 |
+
* @param string $html The HTML content of a template file with its pseudo-variables parsed.
|
1969 |
+
* @param array $params A hash containing the pseudo-variable name as the key and the value that will replace it.
|
1970 |
+
* @return string The formatted HTML content of the base template.
|
1971 |
+
*/
|
1972 |
+
function sucuriscan_get_base_template( $html='', $params=array() ){
|
1973 |
+
$params = is_array($params) ? $params : array();
|
1974 |
+
|
1975 |
+
$params = sucuriscan_shared_params($params);
|
1976 |
+
$params['PageContent'] = $html;
|
1977 |
+
|
1978 |
+
return sucuriscan_get_template( 'base', $params );
|
1979 |
+
}
|
1980 |
+
|
1981 |
+
/**
|
1982 |
+
* Generate a HTML code using a template and replacing all the pseudo-variables
|
1983 |
+
* by the dynamic variables provided by the developer through one of the parameters
|
1984 |
+
* of the function.
|
1985 |
+
*
|
1986 |
+
* @param string $template Filename of the template that will be used to generate the page.
|
1987 |
+
* @param array $params A hash containing the pseudo-variable name as the key and the value that will replace it.
|
1988 |
+
* @return string The formatted HTML page after replace all the pseudo-variables.
|
1989 |
+
*/
|
1990 |
+
function sucuriscan_get_section($template='', $params=array()){
|
1991 |
+
$params = sucuriscan_shared_params($params);
|
1992 |
+
|
1993 |
+
return sucuriscan_get_template( $template, $params, 'section' );
|
1994 |
+
}
|
1995 |
+
|
1996 |
+
/**
|
1997 |
+
* Generate a HTML code using a template and replacing all the pseudo-variables
|
1998 |
+
* by the dynamic variables provided by the developer through one of the parameters
|
1999 |
+
* of the function.
|
2000 |
+
*
|
2001 |
+
* @param string $template Filename of the template that will be used to generate the page.
|
2002 |
+
* @param array $params A hash containing the pseudo-variable name as the key and the value that will replace it.
|
2003 |
+
* @return string The formatted HTML page after replace all the pseudo-variables.
|
2004 |
+
*/
|
2005 |
+
function sucuriscan_get_modal($template='', $params=array()){
|
2006 |
+
$required = array(
|
2007 |
+
'Title' => 'Lorem ipsum dolor sit amet',
|
2008 |
+
'CssClass' => '',
|
2009 |
+
'Content' => '<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do
|
2010 |
+
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
|
2011 |
+
veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
2012 |
+
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
2013 |
+
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
2014 |
+
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>',
|
2015 |
+
);
|
2016 |
+
|
2017 |
+
if( !empty($template) && $template != 'none' ){
|
2018 |
+
$params['Content'] = sucuriscan_get_section($template);
|
2019 |
+
}
|
2020 |
+
|
2021 |
+
foreach( $required as $param_name => $param_value ){
|
2022 |
+
if( !isset($params[$param_name]) ){
|
2023 |
+
$params[$param_name] = $param_value;
|
2024 |
+
}
|
2025 |
+
}
|
2026 |
+
|
2027 |
+
$params = sucuriscan_shared_params($params);
|
2028 |
+
|
2029 |
+
return sucuriscan_get_template( 'modalwindow', $params, 'section' );
|
2030 |
+
}
|
2031 |
+
|
2032 |
+
/**
|
2033 |
+
* Generate a HTML code using a template and replacing all the pseudo-variables
|
2034 |
+
* by the dynamic variables provided by the developer through one of the parameters
|
2035 |
+
* of the function.
|
2036 |
+
*
|
2037 |
+
* @param string $template Filename of the template that will be used to generate the page.
|
2038 |
+
* @param array $params A hash containing the pseudo-variable name as the key and the value that will replace it.
|
2039 |
+
* @return string The formatted HTML page after replace all the pseudo-variables.
|
2040 |
+
*/
|
2041 |
+
function sucuriscan_get_snippet($template='', $params=array()){
|
2042 |
+
return sucuriscan_get_template( $template, $params, 'snippet' );
|
2043 |
+
}
|
2044 |
+
|
2045 |
+
/**
|
2046 |
+
* Generate an URL pointing to the page indicated in the function and that must
|
2047 |
+
* be loaded through the administrator panel.
|
2048 |
+
*
|
2049 |
+
* @param string $page Short name of the page that will be generated.
|
2050 |
+
* @return string Full string containing the link of the page.
|
2051 |
+
*/
|
2052 |
+
function sucuriscan_get_url($page=''){
|
2053 |
+
$url_path = admin_url('admin.php?page=sucuriscan');
|
2054 |
+
|
2055 |
+
if( !empty($page) ){
|
2056 |
+
$url_path .= '_' . $page;
|
2057 |
+
}
|
2058 |
+
|
2059 |
+
return $url_path;
|
2060 |
+
}
|
2061 |
+
|
2062 |
+
/**
|
2063 |
+
* Retrieve a new set of keys for the WordPress configuration file using the
|
2064 |
+
* official API provided by WordPress itself.
|
2065 |
+
*
|
2066 |
+
* @return array A list of the new set of keys generated by WordPress API.
|
2067 |
+
*/
|
2068 |
+
function sucuriscan_get_new_config_keys(){
|
2069 |
+
$request = wp_remote_get('https://api.wordpress.org/secret-key/1.1/salt/');
|
2070 |
+
|
2071 |
+
if( !is_wp_error($request) || wp_remote_retrieve_response_code($request) === 200 ){
|
2072 |
+
if( preg_match_all("/define\('([A-Z_]+)',[ ]+'(.*)'\);/", $request['body'], $match) ){
|
2073 |
+
$new_keys = array();
|
2074 |
+
|
2075 |
+
foreach($match[1] as $i=>$value){
|
2076 |
+
$new_keys[$value] = $match[2][$i];
|
2077 |
+
}
|
2078 |
+
|
2079 |
+
return $new_keys;
|
2080 |
+
}
|
2081 |
+
}
|
2082 |
+
|
2083 |
+
return FALSE;
|
2084 |
+
}
|
2085 |
+
|
2086 |
+
/**
|
2087 |
+
* Modify the WordPress configuration file and change the keys that were defined
|
2088 |
+
* by a new random-generated list of keys retrieved from the official WordPress
|
2089 |
+
* API. The result of the operation will be either FALSE in case of error, or an
|
2090 |
+
* array containing multiple indexes explaining the modification, among them you
|
2091 |
+
* will find the old and new keys.
|
2092 |
+
*
|
2093 |
+
* @return false|array Either FALSE in case of error, or an array with the old and new keys.
|
2094 |
+
*/
|
2095 |
+
function sucuriscan_set_new_config_keys(){
|
2096 |
+
$new_wpconfig = '';
|
2097 |
+
$wp_config_path = ABSPATH.'wp-config.php';
|
2098 |
+
|
2099 |
+
if( file_exists($wp_config_path) ){
|
2100 |
+
$wp_config_lines = file($wp_config_path);
|
2101 |
+
$new_keys = sucuriscan_get_new_config_keys();
|
2102 |
+
$old_keys = array();
|
2103 |
+
$old_keys_string = $new_keys_string = '';
|
2104 |
+
|
2105 |
+
foreach($wp_config_lines as $wp_config_line){
|
2106 |
+
$wp_config_line = str_replace("\n", '', $wp_config_line);
|
2107 |
+
|
2108 |
+
if( preg_match("/define\('([A-Z_]+)',([ ]+)'(.*)'\);/", $wp_config_line, $match) ){
|
2109 |
+
$key_name = $match[1];
|
2110 |
+
if( array_key_exists($key_name, $new_keys) ){
|
2111 |
+
$white_spaces = $match[2];
|
2112 |
+
$old_keys[$key_name] = $match[3];
|
2113 |
+
$wp_config_line = "define('{$key_name}',{$white_spaces}'{$new_keys[$key_name]}');";
|
2114 |
+
|
2115 |
+
$old_keys_string .= "define('{$key_name}',{$white_spaces}'{$old_keys[$key_name]}');\n";
|
2116 |
+
$new_keys_string .= "{$wp_config_line}\n";
|
2117 |
+
}
|
2118 |
+
}
|
2119 |
+
|
2120 |
+
$new_wpconfig .= "{$wp_config_line}\n";
|
2121 |
+
}
|
2122 |
+
|
2123 |
+
$response = array(
|
2124 |
+
'updated' => is_writable($wp_config_path),
|
2125 |
+
'old_keys' => $old_keys,
|
2126 |
+
'old_keys_string' => $old_keys_string,
|
2127 |
+
'new_keys' => $new_keys,
|
2128 |
+
'new_keys_string' => $new_keys_string,
|
2129 |
+
'new_wpconfig' => $new_wpconfig,
|
2130 |
+
);
|
2131 |
+
|
2132 |
+
if( $response['updated'] ){
|
2133 |
+
file_put_contents($wp_config_path, $new_wpconfig, LOCK_EX);
|
2134 |
+
}
|
2135 |
+
return $response;
|
2136 |
+
}
|
2137 |
+
return FALSE;
|
2138 |
+
}
|
2139 |
+
|
2140 |
+
/**
|
2141 |
+
* Generate and set a new password for a specific user not in session.
|
2142 |
+
*
|
2143 |
+
* @param integer $user_id The user identifier that will be changed, this must be different than the user in session.
|
2144 |
+
* @return boolean Either TRUE or FALSE in case of success or error respectively.
|
2145 |
+
*/
|
2146 |
+
function sucuriscan_new_password($user_id=0){
|
2147 |
+
$user_id = intval($user_id);
|
2148 |
+
$current_user = wp_get_current_user();
|
2149 |
+
|
2150 |
+
if( $user_id>0 && $user_id!=$current_user->ID ){
|
2151 |
+
$user = get_userdata($user_id);
|
2152 |
+
$new_password = wp_generate_password(15, TRUE, FALSE);
|
2153 |
+
|
2154 |
+
$data_set = array( 'User'=>$user->display_name );
|
2155 |
+
$message = "The password for your user account in the website mentioned has been changed by an administrator,
|
2156 |
+
this is the new password automatically generated by the system, please update ASAP.<br>
|
2157 |
+
<div style='display:inline-block;background:#ddd;font-family:monaco,monospace,courier;
|
2158 |
+
font-size:30px;margin:0;padding:15px;border:1px solid #999'>{$new_password}</div>";
|
2159 |
+
sucuriscan_send_mail($user->user_email, 'Changed password', $message, $data_set);
|
2160 |
+
|
2161 |
+
wp_set_password($new_password, $user_id);
|
2162 |
+
|
2163 |
+
return TRUE;
|
2164 |
+
}
|
2165 |
+
return FALSE;
|
2166 |
+
}
|
2167 |
+
|
2168 |
+
/**
|
2169 |
+
* Retrieve the real ip address of the user in the current request.
|
2170 |
+
*
|
2171 |
+
* @return string The real ip address of the user in the current request.
|
2172 |
+
*/
|
2173 |
+
function sucuriscan_get_remoteaddr(){
|
2174 |
+
$alternatives = array(
|
2175 |
+
'HTTP_X_REAL_IP',
|
2176 |
+
'HTTP_CLIENT_IP',
|
2177 |
+
'HTTP_X_FORWARDED_FOR',
|
2178 |
+
'HTTP_X_FORWARDED',
|
2179 |
+
'HTTP_FORWARDED_FOR',
|
2180 |
+
'HTTP_FORWARDED',
|
2181 |
+
'REMOTE_ADDR',
|
2182 |
+
'SUCURI_RIP',
|
2183 |
+
);
|
2184 |
+
foreach($alternatives as $alternative){
|
2185 |
+
if( !isset($_SERVER[$alternative]) ){ continue; }
|
2186 |
+
|
2187 |
+
$remote_addr = preg_replace('/[^0-9a-z.,: ]/', '', $_SERVER[$alternative]);
|
2188 |
+
if($remote_addr) break;
|
2189 |
+
}
|
2190 |
+
|
2191 |
+
if( $remote_addr == '::1' ){
|
2192 |
+
$remote_addr = '127.0.0.1';
|
2193 |
+
}
|
2194 |
+
|
2195 |
+
return $remote_addr;
|
2196 |
+
}
|
2197 |
+
|
2198 |
+
/**
|
2199 |
+
* Check whether the site is behing the Sucuri CloudProxy network.
|
2200 |
+
*
|
2201 |
+
* @return boolean Either TRUE or FALSE if the site is behind CloudProxy.
|
2202 |
+
*/
|
2203 |
+
function sucuriscan_is_behind_cloudproxy(){
|
2204 |
+
$http_host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : 'localhost';
|
2205 |
+
if( preg_match('/^(.*):([0-9]+)/', $http_host, $match) ){ $http_host = $match[1]; }
|
2206 |
+
$host_by_name = gethostbyname($http_host);
|
2207 |
+
$host_by_addr = gethostbyaddr($host_by_name);
|
2208 |
+
|
2209 |
+
if(
|
2210 |
+
isset($_SERVER['SUCURIREAL_REMOTE_ADDR'])
|
2211 |
+
|| preg_match('/^cloudproxy([0-9]+)\.sucuri\.net$/', $host_by_addr)
|
2212 |
+
){
|
2213 |
+
return TRUE;
|
2214 |
+
}
|
2215 |
+
|
2216 |
+
return FALSE;
|
2217 |
+
}
|
2218 |
+
|
2219 |
+
/**
|
2220 |
+
* Find and retrieve the current version of Wordpress installed.
|
2221 |
+
*
|
2222 |
+
* @return string The version number of Wordpress installed.
|
2223 |
+
*/
|
2224 |
+
function sucuriscan_get_wpversion(){
|
2225 |
+
$version = get_option('version');
|
2226 |
+
if( $version ){ return $version; }
|
2227 |
+
|
2228 |
+
$wp_version_path = ABSPATH . WPINC . '/version.php';
|
2229 |
+
if( file_exists($wp_version_path) ){
|
2230 |
+
include($wp_version_path);
|
2231 |
+
if( isset($wp_version) ){ return $wp_version; }
|
2232 |
+
}
|
2233 |
+
|
2234 |
+
return md5_file(ABSPATH . WPINC . '/class-wp.php');
|
2235 |
+
}
|
2236 |
+
|
2237 |
+
/**
|
2238 |
+
* Find and retrieve the absolute path of the WordPress configuration file.
|
2239 |
+
*
|
2240 |
+
* @return string Absolute path of the WordPress configuration file.
|
2241 |
+
*/
|
2242 |
+
function sucuriscan_get_wpconfig_path(){
|
2243 |
+
$wp_config_path = ABSPATH.'wp-config.php';
|
2244 |
+
|
2245 |
+
// if wp-config.php doesn't exist/not readable check one directory up
|
2246 |
+
if( !is_readable($wp_config_path)){
|
2247 |
+
$wp_config_path = ABSPATH.'/../wp-config.php';
|
2248 |
+
}
|
2249 |
+
|
2250 |
+
return $wp_config_path;
|
2251 |
+
}
|
2252 |
+
|
2253 |
+
/**
|
2254 |
+
* Find and retrieve the absolute path of the main WordPress htaccess file.
|
2255 |
+
*
|
2256 |
+
* @return string Absolute path of the main WordPress htaccess file.
|
2257 |
+
*/
|
2258 |
+
function sucuriscan_get_htaccess_path(){
|
2259 |
+
$base_dirs = array(
|
2260 |
+
rtrim(ABSPATH, '/'),
|
2261 |
+
dirname(ABSPATH),
|
2262 |
+
dirname(dirname(ABSPATH))
|
2263 |
+
);
|
2264 |
+
|
2265 |
+
foreach($base_dirs as $base_dir){
|
2266 |
+
$htaccess_path = sprintf('%s/.htaccess', $base_dir);
|
2267 |
+
if( file_exists($htaccess_path) ){
|
2268 |
+
return $htaccess_path;
|
2269 |
+
}
|
2270 |
+
}
|
2271 |
+
|
2272 |
+
return FALSE;
|
2273 |
+
}
|
2274 |
+
|
2275 |
+
/**
|
2276 |
+
* Get the email address set by the administrator to receive the notifications
|
2277 |
+
* sent by the plugin, if the email is missing the WordPress email address is
|
2278 |
+
* chosen by default.
|
2279 |
+
*
|
2280 |
+
* @return string The administrator email address.
|
2281 |
+
*/
|
2282 |
+
function sucuriscan_get_site_email(){
|
2283 |
+
$email = get_option('admin_email');
|
2284 |
+
|
2285 |
+
if( is_valid_email($email) ){
|
2286 |
+
return $email;
|
2287 |
+
}
|
2288 |
+
|
2289 |
+
return FALSE;
|
2290 |
+
}
|
2291 |
+
|
2292 |
+
/**
|
2293 |
+
* Get the clean version of the current domain.
|
2294 |
+
*
|
2295 |
+
* @return string The domain of the current site.
|
2296 |
+
*/
|
2297 |
+
function sucuriscan_get_domain(){
|
2298 |
+
$http_host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : '';
|
2299 |
+
$domain_name = preg_replace( '/^www\./', '', $http_host );
|
2300 |
+
|
2301 |
+
return $domain_name;
|
2302 |
+
}
|
2303 |
+
|
2304 |
+
/**
|
2305 |
+
* Generate an user-agent for the HTTP requests.
|
2306 |
+
*
|
2307 |
+
* @return string An user-agent for the HTTP requests.
|
2308 |
+
*/
|
2309 |
+
function sucuriscan_user_agent(){
|
2310 |
+
global $wp_version;
|
2311 |
+
|
2312 |
+
$user_agent = 'WordPress/' . $wp_version . '; ' . sucuriscan_get_domain();
|
2313 |
+
|
2314 |
+
return $user_agent;
|
2315 |
+
}
|
2316 |
+
|
2317 |
+
/**
|
2318 |
+
* Return the time passed since the specified timestamp until now.
|
2319 |
+
*
|
2320 |
+
* @param integer $timestamp The Unix time number of the date/time before now.
|
2321 |
+
* @return string The time passed since the timestamp specified.
|
2322 |
+
*/
|
2323 |
+
function sucuriscan_time_ago($timestamp=0){
|
2324 |
+
if( !is_numeric($timestamp) ){
|
2325 |
+
$timestamp = strtotime($timestamp);
|
2326 |
+
}
|
2327 |
+
|
2328 |
+
$diff = time() - (int)$timestamp;
|
2329 |
+
|
2330 |
+
if( $diff == 0 ){ return 'just now'; }
|
2331 |
+
|
2332 |
+
$intervals = array(
|
2333 |
+
1 => array('year', 31556926),
|
2334 |
+
$diff < 31556926 => array('month', 2628000),
|
2335 |
+
$diff < 2629744 => array('week', 604800),
|
2336 |
+
$diff < 604800 => array('day', 86400),
|
2337 |
+
$diff < 86400 => array('hour', 3600),
|
2338 |
+
$diff < 3600 => array('minute', 60),
|
2339 |
+
$diff < 60 => array('second', 1)
|
2340 |
+
);
|
2341 |
+
|
2342 |
+
$value = floor($diff/$intervals[1][1]);
|
2343 |
+
return $value.chr(32).$intervals[1][0].($value > 1 ? 's' : '').' ago';
|
2344 |
+
}
|
2345 |
+
|
2346 |
+
/**
|
2347 |
+
* Convert an string of characters into a valid variable name.
|
2348 |
+
*
|
2349 |
+
* @see http://www.php.net/manual/en/language.variables.basics.php
|
2350 |
+
*
|
2351 |
+
* @param string $string A text containing alpha-numeric and special characters.
|
2352 |
+
* @return string A valid variable name.
|
2353 |
+
*/
|
2354 |
+
function sucuriscan_str_human2var($string=''){
|
2355 |
+
$pattern = '/[^a-zA-Z0-9_]/';
|
2356 |
+
$var_name = preg_replace($pattern, '_', strtolower($string));
|
2357 |
+
|
2358 |
+
return $var_name;
|
2359 |
+
}
|
2360 |
+
|
2361 |
+
/**
|
2362 |
+
* Retrieve specific options from the database.
|
2363 |
+
*
|
2364 |
+
* Considering the case in which this plugin is installed in a multisite instance
|
2365 |
+
* of Wordpress, the allowed values for the first parameter of this function will
|
2366 |
+
* be treated like this:
|
2367 |
+
*
|
2368 |
+
* <ul>
|
2369 |
+
* <li>all_sucuriscan_options: Will retrieve all the option values created by this plugin in the main site (aka. network),</li>
|
2370 |
+
* <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>
|
2371 |
+
* <li>sucuriscan_option: Will retrieve one specific option from the network site only if the option starts with the prefix <i>sucuri_<i>.</li>
|
2372 |
+
* </ul>
|
2373 |
+
*
|
2374 |
+
* @param string $filter_by Criteria to filter the results, valid values: all_sucuriscan_options, site_options, sucuri_option.
|
2375 |
+
* @param string $option_name Optional parameter with the name of the option that will be filtered.
|
2376 |
+
* @return array List of options retrieved from the query in the database.
|
2377 |
+
*/
|
2378 |
+
function sucuriscan_get_options_from_db( $filter_by='', $option_name='' ){
|
2379 |
+
global $wpdb;
|
2380 |
+
|
2381 |
+
$output = FALSE;
|
2382 |
+
switch($filter_by){
|
2383 |
+
case 'all_sucuriscan_options':
|
2384 |
+
$output = $wpdb->get_results("SELECT * FROM {$wpdb->options} WHERE option_name LIKE 'sucuriscan%' ORDER BY option_id ASC");
|
2385 |
+
break;
|
2386 |
+
case 'site_options':
|
2387 |
+
$output = $wpdb->get_results("SELECT * FROM {$wpdb->options} WHERE option_name NOT LIKE '%_transient_%' ORDER BY option_id ASC");
|
2388 |
+
break;
|
2389 |
+
case 'sucuriscan_option':
|
2390 |
+
$row = $wpdb->get_row( $wpdb->prepare("SELECT option_value FROM {$wpdb->base_prefix}options WHERE option_name = %s LIMIT 1", $option_name) );
|
2391 |
+
if( $row ){ $output = $row->option_value; }
|
2392 |
+
break;
|
2393 |
+
}
|
2394 |
+
|
2395 |
+
return $output;
|
2396 |
+
}
|
2397 |
+
|
2398 |
+
/**
|
2399 |
+
* Alias function for the method Common::SucuriScan_Get_Options()
|
2400 |
+
*
|
2401 |
+
* This function search the specified option in the database, not only the options
|
2402 |
+
* set by the plugin but all the options set for the site. If the value retrieved
|
2403 |
+
* is FALSE the method tries to search for a default value.
|
2404 |
+
*
|
2405 |
+
* @param string $option_name Optional parameter that you can use to filter the results to one option.
|
2406 |
+
* @return string The value (or default value) of the option specified.
|
2407 |
+
*/
|
2408 |
+
function sucuriscan_get_option( $option_name='' ){
|
2409 |
+
return sucuriscan_get_options($option_name);
|
2410 |
+
}
|
2411 |
+
|
2412 |
+
/**
|
2413 |
+
* Retrieve all the options created by this Plugin from the Wordpress database.
|
2414 |
+
*
|
2415 |
+
* The function acts as an alias of WP::get_option() and if the returned value
|
2416 |
+
* is FALSE it tries to search for a default value to complement the information.
|
2417 |
+
*
|
2418 |
+
* @param string $option_name Optional parameter that you can use to filter the results to one option.
|
2419 |
+
* @return array Either FALSE or an Array containing all the sucuri options in the database.
|
2420 |
+
*/
|
2421 |
+
function sucuriscan_get_options( $option_name='' ){
|
2422 |
+
if( !empty($option_name) ){
|
2423 |
+
return sucuriscan_get_single_option($option_name);
|
2424 |
+
}
|
2425 |
+
|
2426 |
+
$settings = array();
|
2427 |
+
$results = sucuriscan_get_options_from_db('all_sucuriscan_options');
|
2428 |
+
foreach( $results as $row ){
|
2429 |
+
$settings[$row->option_name] = $row->option_value;
|
2430 |
+
}
|
2431 |
+
|
2432 |
+
return sucuriscan_get_default_options($settings);
|
2433 |
+
}
|
2434 |
+
|
2435 |
+
/**
|
2436 |
+
* Retrieve a single option from the database.
|
2437 |
+
*
|
2438 |
+
* @param string $option_name Name of the option that will be retrieved.
|
2439 |
+
* @return string Value of the option stored in the database, FALSE if not found.
|
2440 |
+
*/
|
2441 |
+
function sucuriscan_get_single_option( $option_name='' ){
|
2442 |
+
$is_sucuri_option = preg_match('/^sucuriscan_/', $option_name) ? TRUE : FALSE;
|
2443 |
+
|
2444 |
+
if( sucuriscan_is_multisite() && $is_sucuri_option ){
|
2445 |
+
$option_value = sucuriscan_get_options_from_db('sucuriscan_option', $option_name);
|
2446 |
+
}else{
|
2447 |
+
$option_value = get_option($option_name);
|
2448 |
+
}
|
2449 |
+
|
2450 |
+
if( $option_value === FALSE && $is_sucuri_option ){
|
2451 |
+
$option_value = sucuriscan_get_default_options($option_name);
|
2452 |
+
}
|
2453 |
+
|
2454 |
+
return $option_value;
|
2455 |
+
}
|
2456 |
+
|
2457 |
+
/**
|
2458 |
+
* Retrieve the default values for some specific options.
|
2459 |
+
*
|
2460 |
+
* @param string|array $settings Either an array that will be complemented or a string with the name of the option.
|
2461 |
+
* @return string|array The default values for the specified options.
|
2462 |
+
*/
|
2463 |
+
function sucuriscan_get_default_options( $settings='' ){
|
2464 |
+
$default_options = array(
|
2465 |
+
'sucuriscan_api_key' => FALSE,
|
2466 |
+
'sucuriscan_account' => get_option('admin_email'),
|
2467 |
+
'sucuriscan_scan_frequency' => 'hourly',
|
2468 |
+
'sucuriscan_scan_interface' => 'spl',
|
2469 |
+
'sucuriscan_runtime' => 0,
|
2470 |
+
'sucuriscan_lastlogin_redirection' => 'enabled',
|
2471 |
+
'sucuriscan_prettify_mails' => 'enabled',
|
2472 |
+
'sucuriscan_notify_success_login' => 'enabled',
|
2473 |
+
'sucuriscan_notify_failed_login' => 'enabled',
|
2474 |
+
'sucuriscan_notify_post_publication' => 'enabled',
|
2475 |
+
'sucuriscan_notify_theme_editor' => 'enabled',
|
2476 |
+
);
|
2477 |
+
|
2478 |
+
if( is_array($settings) ){
|
2479 |
+
foreach( $default_options as $option_name => $option_value ){
|
2480 |
+
if( !isset($settings[$option_name]) ){
|
2481 |
+
$settings[$option_name] = $option_value;
|
2482 |
+
}
|
2483 |
+
}
|
2484 |
+
return $settings;
|
2485 |
+
}
|
2486 |
+
|
2487 |
+
if( is_string($settings) ){
|
2488 |
+
if( isset($default_options[$settings]) ){
|
2489 |
+
return $default_options[$settings];
|
2490 |
+
}
|
2491 |
+
}
|
2492 |
+
|
2493 |
+
return FALSE;
|
2494 |
+
}
|
2495 |
+
|
2496 |
+
/**
|
2497 |
+
* Retrieve all the options stored by Wordpress in the database. The options
|
2498 |
+
* containing the word "transient" are excluded from the results, this function
|
2499 |
+
* is compatible with multisite instances.
|
2500 |
+
*
|
2501 |
+
* @return array All the options stored by Wordpress in the database, except the transient options.
|
2502 |
+
*/
|
2503 |
+
function sucuriscan_get_wp_options(){
|
2504 |
+
$settings = array();
|
2505 |
+
|
2506 |
+
$results = sucuriscan_get_options_from_db('site_options');
|
2507 |
+
foreach( $results as $row ){
|
2508 |
+
$settings[$row->option_name] = $row->option_value;
|
2509 |
+
}
|
2510 |
+
|
2511 |
+
return $settings;
|
2512 |
+
}
|
2513 |
+
|
2514 |
+
/**
|
2515 |
+
* Check what Wordpress options were changed comparing the values in the database
|
2516 |
+
* with the values sent through a simple request using a GET or POST method.
|
2517 |
+
*
|
2518 |
+
* @param array $request The content of the global variable GET or POST considering SERVER[REQUEST_METHOD].
|
2519 |
+
* @return array A list of all the options that were changes through this request.
|
2520 |
+
*/
|
2521 |
+
function sucuriscan_what_options_were_changed( $request=array() ){
|
2522 |
+
$options_changed = array(
|
2523 |
+
'original' => array(),
|
2524 |
+
'changed' => array()
|
2525 |
+
);
|
2526 |
+
$wp_options = sucuriscan_get_wp_options();
|
2527 |
+
|
2528 |
+
foreach( $request as $req_name => $req_value ){
|
2529 |
+
if(
|
2530 |
+
array_key_exists($req_name, $wp_options)
|
2531 |
+
&& $wp_options[$req_name] != $req_value
|
2532 |
+
){
|
2533 |
+
$options_changed['original'][$req_name] = $wp_options[$req_name];
|
2534 |
+
$options_changed['changed'][$req_name] = $req_value;
|
2535 |
+
}
|
2536 |
+
}
|
2537 |
+
return $options_changed;
|
2538 |
+
}
|
2539 |
+
|
2540 |
+
if( !function_exists('sucuriscan_plugin_setup_notice') ){
|
2541 |
+
/**
|
2542 |
+
* Display a notice message with instructions to continue the setup of the
|
2543 |
+
* plugin, this includes the generation of the API key and other steps that need
|
2544 |
+
* to be done to fully activate this plugin.
|
2545 |
+
*
|
2546 |
+
* @return void
|
2547 |
+
*/
|
2548 |
+
function sucuriscan_plugin_setup_notice(){
|
2549 |
+
echo sucuriscan_get_section('setup_notice');
|
2550 |
+
}
|
2551 |
+
|
2552 |
+
if( !sucuriscan_wordpress_apikey() ){
|
2553 |
+
$sucuriscan_admin_notice_name = sucuriscan_is_multisite() ? 'network_admin_notices' : 'admin_notices';
|
2554 |
+
add_action( $sucuriscan_admin_notice_name, 'sucuriscan_plugin_setup_notice' );
|
2555 |
+
}
|
2556 |
+
}
|
2557 |
+
|
2558 |
+
/**
|
2559 |
+
* Display the page with a temporary message explaining the action that will be
|
2560 |
+
* performed once the hidden form is submitted to retrieve the scanning results
|
2561 |
+
* from the public SiteCheck API.
|
2562 |
+
*
|
2563 |
+
* @return void
|
2564 |
+
*/
|
2565 |
+
function sucuriscan_scanner_page(){
|
2566 |
+
if(
|
2567 |
+
sucuriscan_check_page_nonce()
|
2568 |
+
&& isset($_POST['sucuriscan_malware_scan'])
|
2569 |
+
){
|
2570 |
+
sucuriscan_sitecheck_info();
|
2571 |
+
} else {
|
2572 |
+
echo sucuriscan_get_template('malwarescan');
|
2573 |
+
}
|
2574 |
+
}
|
2575 |
+
|
2576 |
+
/**
|
2577 |
+
* Display the result of site scan made through SiteCheck.
|
2578 |
+
*
|
2579 |
+
* @return void
|
2580 |
+
*/
|
2581 |
+
function sucuriscan_sitecheck_info(){
|
2582 |
+
$sucuri_cache = new SucuriScanCache('sitecheck');
|
2583 |
+
$scan_results = $sucuri_cache->get( 'scan_results', SUCURISCAN_SITECHECK_LIFETIME, 'array' );
|
2584 |
+
$clean_domain = sucuriscan_get_domain();
|
2585 |
+
$display_results = FALSE;
|
2586 |
+
|
2587 |
+
ob_start();
|
2588 |
+
|
2589 |
+
if( !$scan_results ){
|
2590 |
+
$remote_url = 'http://sitecheck.sucuri.net/scanner/?serialized&clear&fromwp&scan='.$clean_domain;
|
2591 |
+
$scan_results = wp_remote_get($remote_url, array('timeout' => 180));
|
2592 |
+
|
2593 |
+
if( is_wp_error($scan_results) ){
|
2594 |
+
sucuriscan_error( $scan_results->get_error_message() );
|
2595 |
+
}
|
2596 |
+
|
2597 |
+
elseif( isset($scan_results['body']) ){
|
2598 |
+
if( preg_match('/^ERROR:(.*)/', $scan_results['body'], $error_m) ){
|
2599 |
+
sucuriscan_error( 'The site <code>' . $clean_domain . '</code> was not scanned: ' . $error_m[1] );
|
2600 |
+
}
|
2601 |
+
|
2602 |
+
else {
|
2603 |
+
$scan_results = @unserialize($scan_results['body']);
|
2604 |
+
$display_results = TRUE;
|
2605 |
+
|
2606 |
+
if( !$sucuri_cache->add( 'scan_results', $scan_results ) ){
|
2607 |
+
sucuriscan_error( 'Could not cache the results of the SiteCheck scanning' );
|
2608 |
+
}
|
2609 |
+
}
|
2610 |
+
}
|
2611 |
+
} else {
|
2612 |
+
$display_results = TRUE;
|
2613 |
+
// sucuriscan_info( 'SiteCheck results retrieved from cache.' );
|
2614 |
+
}
|
2615 |
+
?>
|
2616 |
+
|
2617 |
+
|
2618 |
+
<?php if( $display_results ): ?>
|
2619 |
+
|
2620 |
+
<?php
|
2621 |
+
$res = ( is_array($scan_results) ? $scan_results : array() );
|
2622 |
+
|
2623 |
+
// Check for general warnings, and return the information for Infected/Clean site.
|
2624 |
+
$malware_warns_exist = isset($res['MALWARE']['WARN']) ? TRUE : FALSE;
|
2625 |
+
$blacklist_warns_exist = isset($res['BLACKLIST']['WARN']) ? TRUE : FALSE;
|
2626 |
+
$outdated_warns_exist = isset($res['OUTDATEDSCAN']) ? TRUE : FALSE;
|
2627 |
+
$recommendations_exist = isset($res['RECOMMENDATIONS']) ? TRUE : FALSE;
|
2628 |
+
|
2629 |
+
// Check whether this WordPress installation needs an update.
|
2630 |
+
global $wp_version;
|
2631 |
+
$wordpress_updated = FALSE;
|
2632 |
+
$updates = function_exists('get_core_updates') ? get_core_updates() : array();
|
2633 |
+
|
2634 |
+
if( !is_array($updates) || empty($updates) || $updates[0]->response=='latest' ){
|
2635 |
$wordpress_updated = TRUE;
|
2636 |
}
|
2637 |
|
2638 |
+
if( TRUE ){
|
2639 |
+
// Initialize the CSS classes with default values.
|
2640 |
+
$sucuriscan_css_blacklist = 'sucuriscan-border-good';
|
2641 |
+
$sucuriscan_css_malware = 'sucuriscan-border-good';
|
2642 |
+
$sitecheck_results_tab = '';
|
2643 |
+
$blacklist_status_tab = '';
|
2644 |
+
$website_details_tab = '';
|
2645 |
+
|
2646 |
+
// Generate the CSS classes for the blacklist status.
|
2647 |
+
if( $blacklist_warns_exist ){
|
2648 |
+
$sucuriscan_css_blacklist = 'sucuriscan-border-bad';
|
2649 |
+
$blacklist_status_tab = 'sucuriscan-red-tab';
|
2650 |
+
}
|
2651 |
+
|
2652 |
+
// Generate the CSS classes for the SiteCheck scanning results.
|
2653 |
+
if( $malware_warns_exist ){
|
2654 |
+
$sucuriscan_css_malware = 'sucuriscan-border-bad';
|
2655 |
+
$sitecheck_results_tab = 'sucuriscan-red-tab';
|
2656 |
+
}
|
2657 |
+
|
2658 |
+
// Generate the CSS classes for the outdated/recommendations panel.
|
2659 |
+
if( $outdated_warns_exist || $recommendations_exist ){
|
2660 |
+
$website_details_tab = 'sucuriscan-red-tab';
|
2661 |
+
}
|
2662 |
+
|
2663 |
+
$sucuriscan_css_wpupdate = $wordpress_updated ? 'sucuriscan-border-good' : 'sucuriscan-border-bad';
|
2664 |
+
}
|
2665 |
+
?>
|
2666 |
+
|
2667 |
+
<div id="poststuff">
|
2668 |
+
<div class="postbox sucuriscan-border sucuriscan-border-info sucuriscan-malwarescan-message">
|
2669 |
+
<h3>SiteCheck Scanner</h3>
|
2670 |
+
|
2671 |
+
<div class="inside">
|
2672 |
+
<p>
|
2673 |
+
If your site was recently hacked, you can see which files were modified
|
2674 |
+
recently, to assist with any investigation.
|
2675 |
+
</p>
|
2676 |
+
</div>
|
2677 |
+
</div>
|
2678 |
+
</div>
|
2679 |
+
|
2680 |
+
|
2681 |
+
<div class="sucuriscan-tabs">
|
2682 |
+
|
2683 |
+
|
2684 |
+
<ul>
|
2685 |
+
<li class="<?php _e($sitecheck_results_tab) ?>">
|
2686 |
+
<a href="#" data-tabname="sitecheck-results">Remote Scanner Results</a>
|
2687 |
+
</li>
|
2688 |
+
<li class="<?php _e($website_details_tab) ?>">
|
2689 |
+
<a href="#" data-tabname="website-details">Website Details</a>
|
2690 |
+
</li>
|
2691 |
+
<li>
|
2692 |
+
<a href="#" data-tabname="website-links">IFrames / Links / Scripts</a>
|
2693 |
+
</li>
|
2694 |
+
<li class="<?php _e($blacklist_status_tab) ?>">
|
2695 |
+
<a href="#" data-tabname="blacklist-status">Blacklist Status</a>
|
2696 |
+
</li>
|
2697 |
+
<li>
|
2698 |
+
<a href="#" data-tabname="modified-files">Modified Files</a>
|
2699 |
+
</li>
|
2700 |
+
</ul>
|
2701 |
+
|
2702 |
+
|
2703 |
+
<div class="sucuriscan-tab-containers">
|
2704 |
+
|
2705 |
+
|
2706 |
+
<div id="sucuriscan-sitecheck-results">
|
2707 |
+
<div id="poststuff">
|
2708 |
+
<div class="postbox sucuriscan-border <?php _e($sucuriscan_css_malware) ?>">
|
2709 |
+
<h3>
|
2710 |
+
<?php if( $malware_warns_exist ): ?>
|
2711 |
+
Site compromised (malware was identified)
|
2712 |
+
<?php else: ?>
|
2713 |
+
Site clean (no malware was identified)
|
2714 |
+
<?php endif; ?>
|
2715 |
+
</h3>
|
2716 |
+
|
2717 |
+
<div class="inside">
|
2718 |
+
|
2719 |
+
<?php if( !$malware_warns_exist ): ?>
|
2720 |
+
<p>
|
2721 |
+
<span><strong>Malware:</strong> No.</span><br>
|
2722 |
+
<span><strong>Malicious javascript:</strong> No.</span><br>
|
2723 |
+
<span><strong>Malicious iframes:</strong> No.</span><br>
|
2724 |
+
<span><strong>Suspicious redirections (htaccess):</strong> No.</span><br>
|
2725 |
+
<span><strong>Blackhat SEO Spam:</strong> No.</span><br>
|
2726 |
+
<span><strong>Anomaly detection:</strong> Clean.</span>
|
2727 |
+
</p>
|
2728 |
+
<?php else: ?>
|
2729 |
+
<ul>
|
2730 |
+
<?php
|
2731 |
+
foreach( $res['MALWARE']['WARN'] as $malres ){
|
2732 |
+
if( !is_array($malres) ){
|
2733 |
+
echo '<li>' . htmlspecialchars($malres) . '</li>';
|
2734 |
+
} else {
|
2735 |
+
$mwdetails = explode("\n", htmlspecialchars($malres[1]));
|
2736 |
+
$mw_name_link = isset($mwdetails[0]) ? substr($mwdetails[0], 1) : '';
|
2737 |
+
|
2738 |
+
if( preg_match('/(.*)\. Details: (.*)/', $mw_name_link, $mw_match) ){
|
2739 |
+
$mw_name_link = sprintf(
|
2740 |
+
'%s. Details: <a href="%s" target="_blank">%s</a>',
|
2741 |
+
$mw_match[1], $mw_match[2], $mw_match[2]
|
2742 |
+
);
|
2743 |
+
}
|
2744 |
+
|
2745 |
+
echo '<li>'. htmlspecialchars($malres[0]) . "\n<br>" . $mw_name_link . "</li>\n";
|
2746 |
+
}
|
2747 |
+
}
|
2748 |
+
?>
|
2749 |
+
</ul>
|
2750 |
+
<?php endif; ?>
|
2751 |
+
|
2752 |
+
<p>
|
2753 |
+
<i>
|
2754 |
+
More details here: <a href="http://sitecheck.sucuri.net/results/<?php _e($clean_domain); ?>"
|
2755 |
+
target="_blank">http://sitecheck.sucuri.net/results/<?php _e($clean_domain); ?></a>
|
2756 |
+
</i>
|
2757 |
+
</p>
|
2758 |
+
|
2759 |
+
<hr />
|
2760 |
+
|
2761 |
+
<p>
|
2762 |
+
<i>
|
2763 |
+
If our free scanner did not detect any issue, you may have a more complicated
|
2764 |
+
and hidden problem. You can <a href="http://sucuri.net/signup" target="_blank">
|
2765 |
+
sign up</a> with Sucuri for a complete and in depth scan+cleanup (not included
|
2766 |
+
in the free checks).
|
2767 |
+
</i>
|
2768 |
+
</p>
|
2769 |
+
|
2770 |
+
</div>
|
2771 |
+
</div>
|
2772 |
+
</div>
|
2773 |
+
</div>
|
2774 |
+
|
2775 |
+
|
2776 |
+
<div id="sucuriscan-website-details">
|
2777 |
+
<table class="wp-list-table widefat sucuriscan-table sucuriscan-scanner-details">
|
2778 |
+
<thead>
|
2779 |
+
<tr>
|
2780 |
+
<th colspan="2" class="thead-with-button">
|
2781 |
+
<span>System Information</span>
|
2782 |
+
<?php if( !$wordpress_updated ): ?>
|
2783 |
+
<a href="<?php echo admin_url('update-core.php'); ?>" class="button button-primary thead-topright-action">
|
2784 |
+
Update to <?php _e($updates[0]->version) ?>
|
2785 |
+
</a>
|
2786 |
+
<?php endif; ?>
|
2787 |
+
</th>
|
2788 |
+
</tr>
|
2789 |
+
</thead>
|
2790 |
+
|
2791 |
+
<tbody>
|
2792 |
+
<!-- List of generic information from the site. -->
|
2793 |
+
<?php
|
2794 |
+
$possible_keys = array(
|
2795 |
+
'DOMAIN' => 'Domain Scanned',
|
2796 |
+
'IP' => 'Site IP Address',
|
2797 |
+
'HOSTING' => 'Hosting Company',
|
2798 |
+
'CMS' => 'CMS Found',
|
2799 |
+
);
|
2800 |
+
$possible_url_keys = array(
|
2801 |
+
'IFRAME' => 'List of iframes found',
|
2802 |
+
'JSEXTERNAL' => 'List of external scripts included',
|
2803 |
+
'JSLOCAL' => 'List of scripts included',
|
2804 |
+
'URL' => 'List of links found',
|
2805 |
+
);
|
2806 |
+
?>
|
2807 |
+
|
2808 |
+
<?php foreach( $possible_keys as $result_key=>$result_title ): ?>
|
2809 |
+
<?php if( isset($res['SCAN'][$result_key]) ): ?>
|
2810 |
+
<?php $result_value = implode(', ', $res['SCAN'][$result_key]); ?>
|
2811 |
+
<tr>
|
2812 |
+
<td><?php _e($result_title) ?></td>
|
2813 |
+
<td><span class="sucuriscan-monospace"><?php _e($result_value) ?></span></td>
|
2814 |
+
</tr>
|
2815 |
+
<?php endif; ?>
|
2816 |
+
<?php endforeach; ?>
|
2817 |
+
|
2818 |
+
<tr>
|
2819 |
+
<td>WordPress Version</td>
|
2820 |
+
<td><span class="sucuriscan-monospace"><?php _e($wp_version) ?></span></td>
|
2821 |
+
</tr>
|
2822 |
+
<tr>
|
2823 |
+
<td>PHP Version</td>
|
2824 |
+
<td><span class="sucuriscan-monospace"><?php _e(phpversion()) ?></span></td>
|
2825 |
+
</tr>
|
2826 |
+
|
2827 |
+
<!-- List of application details from the site. -->
|
2828 |
+
<tr>
|
2829 |
+
<th colspan="2">Web application details</th>
|
2830 |
+
</tr>
|
2831 |
+
<?php foreach( $res['WEBAPP'] as $webapp_key=>$webapp_details ): ?>
|
2832 |
+
<?php if( is_array($webapp_details) ): ?>
|
2833 |
+
<?php foreach( $webapp_details as $i=>$details ): ?>
|
2834 |
+
<?php if( is_array($details) ){ $details = isset($details[0]) ? $details[0] : ''; } ?>
|
2835 |
+
<tr>
|
2836 |
+
<td colspan="2">
|
2837 |
+
<span class="sucuriscan-monospace"><?php _e($details) ?></span>
|
2838 |
+
</td>
|
2839 |
+
</tr>
|
2840 |
+
<?php endforeach; ?>
|
2841 |
+
<?php endif; ?>
|
2842 |
+
<?php endforeach; ?>
|
2843 |
+
|
2844 |
+
<?php foreach( $res['SYSTEM']['NOTICE'] as $j=>$notice ): ?>
|
2845 |
+
<?php if( is_array($notice) ){ $notice = implode(', ', $notice); } ?>
|
2846 |
+
<tr>
|
2847 |
+
<td colspan="2">
|
2848 |
+
<span class="sucuriscan-monospace"><?php _e($notice) ?></span>
|
2849 |
+
</td>
|
2850 |
+
</tr>
|
2851 |
+
<?php endforeach; ?>
|
2852 |
+
|
2853 |
+
<!-- Possible recommendations or outdated software on the site. -->
|
2854 |
+
<?php if( $outdated_warns_exist || $recommendations_exist ): ?>
|
2855 |
+
<tr>
|
2856 |
+
<th colspan="2">Recommendations for the site</th>
|
2857 |
+
</tr>
|
2858 |
+
<?php endif; ?>
|
2859 |
+
|
2860 |
+
<!-- Possible outdated software on the site. -->
|
2861 |
+
<?php if( $outdated_warns_exist ): ?>
|
2862 |
+
<?php foreach( $res['OUTDATEDSCAN'] as $outdated ): ?>
|
2863 |
+
<?php if( count($outdated) >= 3 ): ?>
|
2864 |
+
<tr>
|
2865 |
+
<td colspan="2" class="sucuriscan-border-bad">
|
2866 |
+
<strong><?php _e($outdated[0]) ?></strong>
|
2867 |
+
<em>(<?php _e($outdated[2]) ?>)</em>
|
2868 |
+
<span><?php _e($outdated[1]) ?></span>
|
2869 |
+
</td>
|
2870 |
+
</tr>
|
2871 |
+
<?php endif; ?>
|
2872 |
+
<?php endforeach; ?>
|
2873 |
+
<?php endif; ?>
|
2874 |
+
|
2875 |
+
<!-- Possible recommendations for the site. -->
|
2876 |
+
<?php if( $recommendations_exist ): ?>
|
2877 |
+
<?php foreach( $res['RECOMMENDATIONS'] as $recommendation ): ?>
|
2878 |
+
<?php if( count($recommendation) >= 3 ): ?>
|
2879 |
+
<tr>
|
2880 |
+
<td colspan="2" class="sucuriscan-border-bad">
|
2881 |
+
<?php printf(
|
2882 |
+
'<strong>%s</strong><br><span>%s</span><br><a href="%s" target="_blank">%s</a>',
|
2883 |
+
$recommendation[0],
|
2884 |
+
$recommendation[1],
|
2885 |
+
$recommendation[2],
|
2886 |
+
$recommendation[2]
|
2887 |
+
); ?>
|
2888 |
+
</td>
|
2889 |
+
</tr>
|
2890 |
+
<?php endif; ?>
|
2891 |
+
<?php endforeach; ?>
|
2892 |
+
<?php endif; ?>
|
2893 |
+
</tbody>
|
2894 |
+
</table>
|
2895 |
+
</div>
|
2896 |
+
|
2897 |
+
|
2898 |
+
<div id="sucuriscan-website-links">
|
2899 |
+
<table class="wp-list-table widefat sucuriscan-table sucuriscan-scanner-links">
|
2900 |
+
<tbody>
|
2901 |
+
<?php foreach( $possible_url_keys as $result_url_key=>$result_url_title ): ?>
|
2902 |
+
|
2903 |
+
<?php if( isset($res['LINKS'][$result_url_key]) ): ?>
|
2904 |
+
<tr>
|
2905 |
+
<th colspan="2">
|
2906 |
+
<?php printf(
|
2907 |
+
'%s (%d found)',
|
2908 |
+
__($result_url_title),
|
2909 |
+
count($res['LINKS'][$result_url_key])
|
2910 |
+
) ?>
|
2911 |
+
</th>
|
2912 |
+
</tr>
|
2913 |
+
|
2914 |
+
<?php foreach( $res['LINKS'][$result_url_key] as $url_path ): ?>
|
2915 |
+
<tr>
|
2916 |
+
<td colspan="2">
|
2917 |
+
<span class="sucuriscan-monospace sucuriscan-wraptext"><?php _e($url_path) ?></span>
|
2918 |
+
</td>
|
2919 |
+
</tr>
|
2920 |
+
<?php endforeach; ?>
|
2921 |
+
<?php endif; ?>
|
2922 |
+
|
2923 |
+
<?php endforeach; ?>
|
2924 |
+
</tbody>
|
2925 |
+
</table>
|
2926 |
+
</div>
|
2927 |
+
|
2928 |
+
|
2929 |
+
<div id="sucuriscan-blacklist-status">
|
2930 |
+
<div id="poststuff">
|
2931 |
+
<div class="postbox sucuriscan-border <?php _e($sucuriscan_css_blacklist) ?>">
|
2932 |
+
<h3>
|
2933 |
+
<?php if( $blacklist_warns_exist ): ?>
|
2934 |
+
Site blacklisted
|
2935 |
+
<?php else: ?>
|
2936 |
+
Site blacklist-free
|
2937 |
+
<?php endif; ?>
|
2938 |
+
</h3>
|
2939 |
+
|
2940 |
+
<div class="inside">
|
2941 |
+
<ul>
|
2942 |
+
<?php
|
2943 |
+
foreach(array(
|
2944 |
+
'INFO' => 'CLEAN',
|
2945 |
+
'WARN' => 'WARNING'
|
2946 |
+
) as $type => $group_title){
|
2947 |
+
if( isset($res['BLACKLIST'][$type]) ){
|
2948 |
+
foreach( $res['BLACKLIST'][$type] as $blres ){
|
2949 |
+
$report_site = htmlspecialchars($blres[0]);
|
2950 |
+
$report_url = htmlspecialchars($blres[1]);
|
2951 |
+
printf(
|
2952 |
+
'<li><b>%s:</b> %s.<br>Details at <a href="%s" target="_blank">%s</a></li>',
|
2953 |
+
$group_title, $report_site, $report_url, $report_url
|
2954 |
+
);
|
2955 |
+
}
|
2956 |
+
}
|
2957 |
+
}
|
2958 |
+
?>
|
2959 |
+
</ul>
|
2960 |
+
</div>
|
2961 |
+
</div>
|
2962 |
+
</div>
|
2963 |
+
</div>
|
2964 |
+
|
2965 |
+
|
2966 |
+
<div id="sucuriscan-modified-files">
|
2967 |
+
<?php echo sucuriscan_modified_files(); ?>
|
2968 |
+
</div>
|
2969 |
+
|
2970 |
+
|
2971 |
+
</div>
|
2972 |
+
</div>
|
2973 |
+
|
2974 |
+
<?php if( $malware_warns_exist || $blacklist_warns_exist ): ?>
|
2975 |
+
<a href="http://sucuri.net/signup/" target="_blank" class="button button-primary button-hero sucuriscan-cleanup-btn">
|
2976 |
+
Get your site protected with Sucuri
|
2977 |
+
</a>
|
2978 |
+
<?php endif; ?>
|
2979 |
+
|
2980 |
+
<?php endif; ?>
|
2981 |
+
|
2982 |
+
|
2983 |
+
<?php
|
2984 |
+
$_html = ob_get_contents();
|
2985 |
+
ob_end_clean();
|
2986 |
+
echo sucuriscan_get_base_template($_html, array(
|
2987 |
+
'PageTitle' => 'Malware Scan',
|
2988 |
+
'PageContent' => $_html,
|
2989 |
+
'PageStyleClass' => 'scanner-results',
|
2990 |
+
));
|
2991 |
+
return;
|
2992 |
+
}
|
2993 |
+
|
2994 |
+
/**
|
2995 |
+
* Retrieves a URL using a changeable HTTP method, returning results in an
|
2996 |
+
* array. Results include HTTP headers and content.
|
2997 |
+
*
|
2998 |
+
* @see http://codex.wordpress.org/Function_Reference/wp_remote_post
|
2999 |
+
* @see http://codex.wordpress.org/Function_Reference/wp_remote_get
|
3000 |
+
*
|
3001 |
+
* @param string $url The target URL where the request will be sent.
|
3002 |
+
* @param string $method HTTP method that will be used to send the request.
|
3003 |
+
* @param array $params Parameters for the request defined in an associative array of key-value.
|
3004 |
+
* @param array $args Request arguments like the timeout, redirections, headers, cookies, etc.
|
3005 |
+
* @return array Array of results including HTTP headers or WP_Error if the request failed.
|
3006 |
+
*/
|
3007 |
+
function sucuriscan_api_call( $url='', $method='GET', $params=array(), $args=array() ){
|
3008 |
+
if( !$url ){ return FALSE; }
|
3009 |
+
|
3010 |
+
$req_args = array(
|
3011 |
+
'method' => $method,
|
3012 |
+
'timeout' => 90,
|
3013 |
+
'redirection' => 2,
|
3014 |
+
'httpversion' => '1.0',
|
3015 |
+
'user-agent' => sucuriscan_user_agent(),
|
3016 |
+
'blocking' => TRUE,
|
3017 |
+
'headers' => array(),
|
3018 |
+
'cookies' => array(),
|
3019 |
+
'compress' => FALSE,
|
3020 |
+
'decompress' => FALSE,
|
3021 |
+
'sslverify' => TRUE,
|
3022 |
+
);
|
3023 |
+
|
3024 |
+
// Update the request arguments with the values passed tot he function.
|
3025 |
+
foreach( $args as $arg_name => $arg_value ){
|
3026 |
+
if( array_key_exists($arg_name, $req_args) ){
|
3027 |
+
$req_args[$arg_name] = $arg_value;
|
3028 |
+
}
|
3029 |
+
}
|
3030 |
+
|
3031 |
+
if( $method == 'GET' ){
|
3032 |
+
$url = sprintf( '%s?%s', $url, http_build_query($params) );
|
3033 |
+
$response = wp_remote_get( $url, $req_args );
|
3034 |
+
}
|
3035 |
+
|
3036 |
+
elseif( $method == 'POST' ){
|
3037 |
+
$req_args['body'] = $params;
|
3038 |
+
$response = wp_remote_post( $url, $req_args );
|
3039 |
+
}
|
3040 |
+
|
3041 |
+
if( isset($response) ){
|
3042 |
+
if( is_wp_error($response) ){
|
3043 |
+
sucuriscan_error(sprintf(
|
3044 |
+
'Something went wrong with an API call (%s action): %s',
|
3045 |
+
( isset($params['a']) ? $params['a'] : 'unknown' ),
|
3046 |
+
$response->get_error_message()
|
3047 |
+
));
|
3048 |
+
} else {
|
3049 |
+
$response['body_raw'] = $response['body'];
|
3050 |
+
|
3051 |
+
if(
|
3052 |
+
isset($response['headers']['content-type'])
|
3053 |
+
&& $response['headers']['content-type'] = 'application/json'
|
3054 |
+
){
|
3055 |
+
$response['body'] = json_decode($response['body_raw']);
|
3056 |
+
}
|
3057 |
+
|
3058 |
+
return $response;
|
3059 |
+
}
|
3060 |
+
} else {
|
3061 |
+
sucuriscan_error( 'HTTP method not allowed: ' . $method );
|
3062 |
+
}
|
3063 |
+
|
3064 |
+
return FALSE;
|
3065 |
+
}
|
3066 |
+
|
3067 |
+
/**
|
3068 |
+
* Store the API key locally.
|
3069 |
+
*
|
3070 |
+
* @param string $api_key An unique string of characters to identify this installation.
|
3071 |
+
* @param boolean $validate Whether the format of the key should be validated before store it.
|
3072 |
+
* @return boolean Either TRUE or FALSE if the key was saved successfully or not respectively.
|
3073 |
+
*/
|
3074 |
+
function sucuriscan_set_api_key( $api_key='', $validate=FALSE ){
|
3075 |
+
if( $validate ){
|
3076 |
+
if( !preg_match('/^([a-z0-9]{32})$/', $api_key) ){
|
3077 |
+
sucuriscan_error( 'Invalid API key format' );
|
3078 |
+
return FALSE;
|
3079 |
+
}
|
3080 |
+
}
|
3081 |
+
|
3082 |
+
if( !empty($api_key) ){
|
3083 |
+
sucuriscan_notify_event( 'plugin_change', 'API key updated successfully: ' . $api_key );
|
3084 |
+
}
|
3085 |
+
|
3086 |
+
return (bool) update_option( 'sucuriscan_api_key', $api_key );
|
3087 |
+
}
|
3088 |
+
|
3089 |
+
/**
|
3090 |
+
* Retrieve the API key from the local storage.
|
3091 |
+
*
|
3092 |
+
* @return string|boolean The API key or FALSE if it does not exists.
|
3093 |
+
*/
|
3094 |
+
function sucuriscan_wordpress_apikey(){
|
3095 |
+
$api_key = get_option('sucuriscan_api_key');
|
3096 |
+
|
3097 |
+
if( $api_key && strlen($api_key) > 10 ){
|
3098 |
+
return $api_key;
|
3099 |
+
}
|
3100 |
+
|
3101 |
+
return FALSE;
|
3102 |
+
}
|
3103 |
+
|
3104 |
+
/**
|
3105 |
+
* Check whether the CloudProxy API key is valid or not.
|
3106 |
+
*
|
3107 |
+
* @param string $api_key The CloudProxy API key.
|
3108 |
+
* @param boolean $return_match Whether the parts of the API key must be returned or not.
|
3109 |
+
* @return boolean TRUE if the API key specified is valid, FALSE otherwise.
|
3110 |
+
*/
|
3111 |
+
function sucuriscan_valid_cloudproxy_apikey( $api_key='', $return_match=FALSE ){
|
3112 |
+
$pattern = '/^([a-z0-9]{32})\/([a-z0-9]{32})$/';
|
3113 |
+
|
3114 |
+
if( $api_key && preg_match($pattern, $api_key, $match) ){
|
3115 |
+
if( $return_match ){ return $match; }
|
3116 |
+
|
3117 |
+
return TRUE;
|
3118 |
+
}
|
3119 |
+
|
3120 |
+
return FALSE;
|
3121 |
+
}
|
3122 |
+
|
3123 |
+
/**
|
3124 |
+
* Check and return the API key for the plugin.
|
3125 |
+
*
|
3126 |
+
* In this plugin the key is a pair of two strings concatenated by a single
|
3127 |
+
* slash, the first part of it is in fact the key and the second part is the
|
3128 |
+
* unique identifier of the site in the remote server.
|
3129 |
+
*
|
3130 |
+
* @return array|boolean FALSE if the key is invalid or not present, an array otherwise.
|
3131 |
+
*/
|
3132 |
+
function sucuriscan_cloudproxy_apikey(){
|
3133 |
+
$api_key = get_option('sucuriscan_cloudproxy_apikey');
|
3134 |
+
$match = sucuriscan_valid_cloudproxy_apikey( $api_key, TRUE );
|
3135 |
+
|
3136 |
+
if( $match ){
|
3137 |
+
return array(
|
3138 |
+
'string' => $match[1].'/'.$match[2],
|
3139 |
+
'k' => $match[1],
|
3140 |
+
's' => $match[2]
|
3141 |
+
);
|
3142 |
+
}
|
3143 |
+
|
3144 |
+
return FALSE;
|
3145 |
+
}
|
3146 |
+
|
3147 |
+
/**
|
3148 |
+
* Call an action from the remote API interface of our WordPress service.
|
3149 |
+
*
|
3150 |
+
* @param string $method HTTP method that will be used to send the request.
|
3151 |
+
* @param array $params Parameters for the request defined in an associative array of key-value.
|
3152 |
+
* @param boolean $send_api_key Whether the API key should be added to the request parameters or not.
|
3153 |
+
* @param array $args Request arguments like the timeout, redirections, headers, cookies, etc.
|
3154 |
+
* @return array Array of results including HTTP headers or WP_Error if the request failed.
|
3155 |
+
*/
|
3156 |
+
function sucuriscan_api_call_wordpress( $method='GET', $params=array(), $send_api_key=TRUE, $args=array() ){
|
3157 |
+
$url = SUCURISCAN_API;
|
3158 |
+
$params[SUCURISCAN_API_VERSION] = 1;
|
3159 |
+
$params['p'] = 'wordpress';
|
3160 |
+
|
3161 |
+
if( $send_api_key ){
|
3162 |
+
$api_key = sucuriscan_wordpress_apikey();
|
3163 |
+
|
3164 |
+
if( !$api_key ){ return FALSE; }
|
3165 |
+
|
3166 |
+
$params['k'] = $api_key;
|
3167 |
+
}
|
3168 |
+
|
3169 |
+
$response = sucuriscan_api_call( $url, $method, $params, $args );
|
3170 |
+
|
3171 |
+
return $response;
|
3172 |
+
}
|
3173 |
+
|
3174 |
+
/**
|
3175 |
+
* Call an action from the remote API interface of our CloudProxy service.
|
3176 |
+
*
|
3177 |
+
* @param string $method HTTP method that will be used to send the request.
|
3178 |
+
* @param array $params Parameters for the request defined in an associative array of key-value.
|
3179 |
+
* @return array Array of results including HTTP headers or WP_Error if the request failed.
|
3180 |
+
*/
|
3181 |
+
function sucuriscan_api_call_cloudproxy( $method='GET', $params=array() ){
|
3182 |
+
$send_request = FALSE;
|
3183 |
+
|
3184 |
+
if( isset($params['k']) && isset($params['s']) ){
|
3185 |
+
$send_request = TRUE;
|
3186 |
+
} else {
|
3187 |
+
$api_key = sucuriscan_cloudproxy_apikey();
|
3188 |
+
|
3189 |
+
if( $api_key ){
|
3190 |
+
$send_request = TRUE;
|
3191 |
+
$params['k'] = $api_key['k'];
|
3192 |
+
$params['s'] = $api_key['s'];
|
3193 |
+
}
|
3194 |
+
}
|
3195 |
+
|
3196 |
+
if( $send_request ){
|
3197 |
+
$url = SUCURISCAN_CLOUDPROXY_API;
|
3198 |
+
$params[SUCURISCAN_CLOUDPROXY_API_VERSION] = 1;
|
3199 |
+
|
3200 |
+
$response = sucuriscan_api_call( $url, $method, $params );
|
3201 |
+
|
3202 |
+
return $response;
|
3203 |
+
}
|
3204 |
+
|
3205 |
+
return FALSE;
|
3206 |
+
}
|
3207 |
+
|
3208 |
+
/**
|
3209 |
+
* Determine whether an API response was successful or not checking the expected
|
3210 |
+
* generic variables and types, in case of an error a notification will appears
|
3211 |
+
* in the administrator panel explaining the result of the operation.
|
3212 |
+
*
|
3213 |
+
* @param array $response Array of results including HTTP headers or WP_Error if the request failed.
|
3214 |
+
* @return boolean Either TRUE or FALSE in case of success or failure of the API response (respectively).
|
3215 |
+
*/
|
3216 |
+
function sucuriscan_handle_response( $response=array() ){
|
3217 |
+
if( $response ){
|
3218 |
+
if( $response['body'] instanceof stdClass ){
|
3219 |
+
if( isset($response['body']->status) ){
|
3220 |
+
if( $response['body']->status == 1 ){
|
3221 |
+
return TRUE;
|
3222 |
+
} else {
|
3223 |
+
sucuriscan_error( ucwords($response['body']->action) . ': ' . $response['body']->messages[0] );
|
3224 |
+
}
|
3225 |
+
} else {
|
3226 |
+
sucuriscan_error( 'Could not determine the status of an API call.' );
|
3227 |
+
}
|
3228 |
+
} else {
|
3229 |
+
sucuriscan_error( 'Unknown API content-type, it was not a JSON-encoded response.' );
|
3230 |
+
}
|
3231 |
+
}
|
3232 |
+
|
3233 |
+
return FALSE;
|
3234 |
+
}
|
3235 |
+
|
3236 |
+
/**
|
3237 |
+
* Send a request to the API to register this site.
|
3238 |
+
*
|
3239 |
+
* @return boolean TRUE if the API key was generated, FALSE otherwise.
|
3240 |
+
*/
|
3241 |
+
function sucuriscan_register_site(){
|
3242 |
+
$response = sucuriscan_api_call_wordpress( 'POST', array(
|
3243 |
+
'e' => sucuriscan_get_site_email(),
|
3244 |
+
's' => sucuriscan_get_domain(),
|
3245 |
+
'a' => 'register_site',
|
3246 |
+
), FALSE );
|
3247 |
+
|
3248 |
+
if( sucuriscan_handle_response($response) ){
|
3249 |
+
sucuriscan_set_api_key( $response['body']->output->api_key );
|
3250 |
+
sucuriscan_create_scheduled_task();
|
3251 |
+
sucuriscan_notify_event( 'plugin_change', 'Site registered and API key generated' );
|
3252 |
+
sucuriscan_info( 'The API key for your site was successfully generated and saved.');
|
3253 |
+
|
3254 |
+
return TRUE;
|
3255 |
+
}
|
3256 |
+
|
3257 |
+
return FALSE;
|
3258 |
+
}
|
3259 |
+
|
3260 |
+
/**
|
3261 |
+
* Send a request to recover a previously registered API key.
|
3262 |
+
*
|
3263 |
+
* @return boolean TRUE if the API key was sent to the administrator email, FALSE otherwise.
|
3264 |
+
*/
|
3265 |
+
function sucuriscan_recover_api_key(){
|
3266 |
+
$clean_domain = sucuriscan_get_domain();
|
3267 |
+
|
3268 |
+
$response = sucuriscan_api_call_wordpress( 'GET', array(
|
3269 |
+
'e' => sucuriscan_get_site_email(),
|
3270 |
+
's' => $clean_domain,
|
3271 |
+
'a' => 'recover_key',
|
3272 |
+
), FALSE );
|
3273 |
+
|
3274 |
+
if( sucuriscan_handle_response($response) ){
|
3275 |
+
sucuriscan_notify_event( 'plugin_change', 'API key recovered for domain: ' . $clean_domain );
|
3276 |
+
sucuriscan_info( $response['body']->output->message );
|
3277 |
+
|
3278 |
+
return TRUE;
|
3279 |
+
}
|
3280 |
+
|
3281 |
+
return FALSE;
|
3282 |
+
}
|
3283 |
+
|
3284 |
+
/**
|
3285 |
+
* Send a request to the API to store and analyze the events of the site. An
|
3286 |
+
* event can be anything from a simple request, an internal modification of the
|
3287 |
+
* settings or files in the administrator panel, or a notification generated by
|
3288 |
+
* this plugin.
|
3289 |
+
*
|
3290 |
+
* @param string $event The information gathered through out the normal functioning of the site.
|
3291 |
+
* @return boolean TRUE if the event was logged in the monitoring service, FALSE otherwise.
|
3292 |
+
*/
|
3293 |
+
function sucuriscan_send_log( $event='' ){
|
3294 |
+
if( !empty($event) ){
|
3295 |
+
$response = sucuriscan_api_call_wordpress( 'POST', array(
|
3296 |
+
'a' => 'send_log',
|
3297 |
+
'm' => $event,
|
3298 |
+
), TRUE, array( 'timeout' => 20 ) );
|
3299 |
+
|
3300 |
+
if( sucuriscan_handle_response($response) ){
|
3301 |
+
return TRUE;
|
3302 |
+
}
|
3303 |
+
}
|
3304 |
+
|
3305 |
+
return FALSE;
|
3306 |
+
}
|
3307 |
+
|
3308 |
+
/**
|
3309 |
+
* Retrieve the event logs registered by the API service.
|
3310 |
+
*
|
3311 |
+
* @return string The response of the API service.
|
3312 |
+
*/
|
3313 |
+
function sucuriscan_get_logs(){
|
3314 |
+
$response = sucuriscan_api_call_wordpress( 'GET', array(
|
3315 |
+
'a' => 'get_logs',
|
3316 |
+
'l' => 50,
|
3317 |
+
) );
|
3318 |
+
|
3319 |
+
if( sucuriscan_handle_response($response) ){
|
3320 |
+
$response['body']->output_data = array();
|
3321 |
+
$log_pattern = '/^([0-9-: ]+) (.*) : (.*)/';
|
3322 |
+
$extra_pattern = '/(.+ \(multiple entries\):) (.+)/';
|
3323 |
+
|
3324 |
+
foreach( $response['body']->output as $log ){
|
3325 |
+
if( preg_match($log_pattern, $log, $log_match) ){
|
3326 |
+
$log_data = array(
|
3327 |
+
'datetime' => $log_match[1],
|
3328 |
+
'timestamp' => strtotime($log_match[1]),
|
3329 |
+
'account' => $log_match[2],
|
3330 |
+
'message' => $log_match[3],
|
3331 |
+
'extra' => FALSE,
|
3332 |
+
'extra_total' => 0,
|
3333 |
+
);
|
3334 |
+
|
3335 |
+
$log_data['message'] = str_replace( ', new size', '; new size', $log_data['message'] );
|
3336 |
+
|
3337 |
+
if( preg_match($extra_pattern, $log_data['message'], $log_extra) ){
|
3338 |
+
$log_data['message'] = $log_extra[1];
|
3339 |
+
$log_data['extra'] = explode(',', $log_extra[2]);
|
3340 |
+
$log_data['extra_total'] = count($log_data['extra']);
|
3341 |
+
}
|
3342 |
+
|
3343 |
+
$response['body']->output_data[] = $log_data;
|
3344 |
+
}
|
3345 |
+
}
|
3346 |
+
|
3347 |
+
return $response['body'];
|
3348 |
+
}
|
3349 |
+
|
3350 |
+
return FALSE;
|
3351 |
+
}
|
3352 |
+
|
3353 |
+
/**
|
3354 |
+
* Send a request to the API to store and analyze the file's hashes of the site.
|
3355 |
+
* This will be the core of the monitoring tools and will enhance the
|
3356 |
+
* information of the audit logs alerting the administrator of suspicious
|
3357 |
+
* changes in the system.
|
3358 |
+
*
|
3359 |
+
* @param string $hashes The information gathered after the scanning of the site's files.
|
3360 |
+
* @return boolean TRUE if the hashes were stored, FALSE otherwise.
|
3361 |
+
*/
|
3362 |
+
function sucuriscan_send_hashes( $hashes='' ){
|
3363 |
+
if( !empty($hashes) ){
|
3364 |
+
$response = sucuriscan_api_call_wordpress( 'POST', array(
|
3365 |
+
'a' => 'send_hashes',
|
3366 |
+
'h' => $hashes,
|
3367 |
+
) );
|
3368 |
+
|
3369 |
+
if( sucuriscan_handle_response($response) ){
|
3370 |
+
return TRUE;
|
3371 |
+
}
|
3372 |
+
}
|
3373 |
+
|
3374 |
+
return FALSE;
|
3375 |
+
}
|
3376 |
+
|
3377 |
+
/**
|
3378 |
+
* Checks last time we ran to avoid running twice (or too often).
|
3379 |
+
*
|
3380 |
+
* @param integer $runtime When the filesystem scan must be scheduled to run.
|
3381 |
+
* @param boolean $force_scan Whether the filesystem scan was forced by an administrator user or not.
|
3382 |
+
* @return boolean Either TRUE or FALSE representing the success or fail of the operation respectively.
|
3383 |
+
*/
|
3384 |
+
function sucuriscan_verify_run( $runtime=0, $force_scan=FALSE ){
|
3385 |
+
$runtime_name = 'sucuriscan_runtime';
|
3386 |
+
$last_run = get_option($runtime_name);
|
3387 |
+
$current_time = time();
|
3388 |
+
|
3389 |
+
if( $last_run && !$force_scan ){
|
3390 |
+
$runtime_diff = $current_time - $runtime;
|
3391 |
+
|
3392 |
+
if( $last_run >= $runtime_diff ){
|
3393 |
+
return FALSE;
|
3394 |
+
}
|
3395 |
+
}
|
3396 |
+
|
3397 |
+
update_option( $runtime_name, $current_time );
|
3398 |
+
return TRUE;
|
3399 |
+
}
|
3400 |
+
|
3401 |
+
/**
|
3402 |
+
* Check whether the current WordPress version must be reported to the API
|
3403 |
+
* service or not, this is to avoid duplicated information in the audit logs.
|
3404 |
+
*
|
3405 |
+
* @return boolean TRUE if the current WordPress version must be reported, FALSE otherwise.
|
3406 |
+
*/
|
3407 |
+
function sucuriscan_report_wpversion(){
|
3408 |
+
$option_name = 'sucuriscan_wp_version';
|
3409 |
+
$reported_version = get_option($option_name);
|
3410 |
+
$wp_version = sucuriscan_get_wpversion();
|
3411 |
+
|
3412 |
+
if( $reported_version != $wp_version ){
|
3413 |
+
sucuriscan_send_log( 'WordPress version: ' . $wp_version );
|
3414 |
+
update_option( $option_name, $wp_version );
|
3415 |
+
|
3416 |
+
return TRUE;
|
3417 |
+
}
|
3418 |
+
|
3419 |
+
return FALSE;
|
3420 |
+
}
|
3421 |
+
|
3422 |
+
/**
|
3423 |
+
* Schedule the task to run the first filesystem scan.
|
3424 |
+
*
|
3425 |
+
* @return void
|
3426 |
+
*/
|
3427 |
+
function sucuriscan_create_scheduled_task(){
|
3428 |
+
$task_name = 'sucuriscan_scheduled_scan';
|
3429 |
+
|
3430 |
+
if( !wp_next_scheduled($task_name) ){
|
3431 |
+
wp_schedule_event( time() + 10, 'twicedaily', $task_name );
|
3432 |
+
}
|
3433 |
+
|
3434 |
+
wp_schedule_single_event( time() + 300, $task_name );
|
3435 |
+
sucuriscan_info( 'The first filesystem scan was scheduled.' );
|
3436 |
+
}
|
3437 |
+
|
3438 |
+
/**
|
3439 |
+
* Gather all the checksums (aka. file hashes) of this site, send them, and
|
3440 |
+
* analyze them using the Sucuri Monitoring service, this will generate the
|
3441 |
+
* audit logs for this site and be part of the integrity checks.
|
3442 |
+
*
|
3443 |
+
* @param boolean $force_scan Whether the filesystem scan was forced by an administrator user or not.
|
3444 |
+
* @return boolean TRUE if the filesystem scan was successful, FALSE otherwise.
|
3445 |
+
*/
|
3446 |
+
function sucuriscan_filesystem_scan( $force_scan=FALSE ){
|
3447 |
+
$minimum_runtime = SUCURISCAN_MINIMUM_RUNTIME;
|
3448 |
+
|
3449 |
+
if(
|
3450 |
+
sucuriscan_wordpress_apikey()
|
3451 |
+
&& class_exists('SucuriScanFileInfo')
|
3452 |
+
&& sucuriscan_verify_run( $minimum_runtime, $force_scan )
|
3453 |
+
){
|
3454 |
+
sucuriscan_report_wpversion();
|
3455 |
+
|
3456 |
+
$sucuri_fileinfo = new SucuriScanFileInfo();
|
3457 |
+
$scan_interface = get_option('sucuriscan_scan_interface');
|
3458 |
+
$signatures = $sucuri_fileinfo->get_directory_tree_md5(ABSPATH, $scan_interface);
|
3459 |
+
|
3460 |
+
if( $signatures ){
|
3461 |
+
$hashes_sent = sucuriscan_send_hashes( $signatures );
|
3462 |
+
|
3463 |
+
if( $hashes_sent ){
|
3464 |
+
sucuriscan_info( 'Successful filesystem scan' );
|
3465 |
+
return TRUE;
|
3466 |
+
} else {
|
3467 |
+
sucuriscan_error( 'The file hashes could not be stored.' );
|
3468 |
+
}
|
3469 |
+
} else {
|
3470 |
+
sucuriscan_error( 'The file hashes could not be retrieved, the filesystem scan failed.' );
|
3471 |
+
}
|
3472 |
+
}
|
3473 |
+
|
3474 |
+
return FALSE;
|
3475 |
+
}
|
3476 |
+
|
3477 |
+
/**
|
3478 |
+
* Generates an audit event log (to be sent later).
|
3479 |
+
*
|
3480 |
+
* @param integer $severity Importance of the event that will be reported, values from one to five.
|
3481 |
+
* @param string $location In which part of the system was the event triggered.
|
3482 |
+
* @param string $message The explanation of the event.
|
3483 |
+
* @return boolean TRUE if the event was logged in the monitoring service, FALSE otherwise.
|
3484 |
+
*/
|
3485 |
+
function sucuriscan_report_event( $severity=0, $location='', $message='' ){
|
3486 |
+
$user = wp_get_current_user();
|
3487 |
+
$username = FALSE;
|
3488 |
+
$current_time = date( 'Y-m-d H:i:s' );
|
3489 |
+
$remote_ip = sucuriscan_get_remoteaddr();
|
3490 |
+
|
3491 |
+
// Fixing severity value.
|
3492 |
+
$severity = (int) $severity;
|
3493 |
+
if( $severity > 0 ){ $severity = 1; }
|
3494 |
+
elseif( $severity > 5 ){ $severity = 5; }
|
3495 |
+
|
3496 |
+
// Identify current user in session.
|
3497 |
+
if(
|
3498 |
+
$user instanceof WP_User
|
3499 |
+
&& isset($user->user_login)
|
3500 |
+
&& !empty($user->user_login)
|
3501 |
+
){
|
3502 |
+
if( $user->user_login != $user->display_name ){
|
3503 |
+
$username = sprintf( ' %s (%s),', $user->display_name, $user->user_login );
|
3504 |
+
} else {
|
3505 |
+
$username = sprintf( ' %s,', $user->user_login );
|
3506 |
+
}
|
3507 |
+
}
|
3508 |
+
|
3509 |
+
// Convert the severity number into a readable string.
|
3510 |
+
switch( $severity ){
|
3511 |
+
case 0: $severity_name = 'Debug'; break;
|
3512 |
+
case 1: $severity_name = 'Notice'; break;
|
3513 |
+
case 2: $severity_name = 'Info'; break;
|
3514 |
+
case 3: $severity_name = 'Warning'; break;
|
3515 |
+
case 4: $severity_name = 'Error'; break;
|
3516 |
+
case 5: $severity_name = 'Critical'; break;
|
3517 |
+
default: $severity_name = 'Info'; break;
|
3518 |
+
}
|
3519 |
+
|
3520 |
+
$message = str_replace( array("\n", "\r"), array('', ''), $message );
|
3521 |
+
$event_message = sprintf(
|
3522 |
+
'%s:%s %s; %s',
|
3523 |
+
$severity_name,
|
3524 |
+
$username,
|
3525 |
+
$remote_ip,
|
3526 |
+
$message
|
3527 |
+
);
|
3528 |
+
|
3529 |
+
return sucuriscan_send_log($event_message);
|
3530 |
+
}
|
3531 |
+
|
3532 |
+
/**
|
3533 |
+
* Send a notification to the administrator of the specified events, only if
|
3534 |
+
* the administrator accepted to receive alerts for this type of events.
|
3535 |
+
*
|
3536 |
+
* @param string $event The name of the event that was triggered.
|
3537 |
+
* @param string $content Body of the email that will be sent to the administrator.
|
3538 |
+
* @return void
|
3539 |
+
*/
|
3540 |
+
function sucuriscan_notify_event( $event='', $content='' ){
|
3541 |
+
$event_name = 'sucuriscan_notify_' . $event;
|
3542 |
+
$notify = sucuriscan_get_option($event_name);
|
3543 |
+
$email = sucuriscan_get_option('admin_email');
|
3544 |
+
|
3545 |
+
if( $notify == 'enabled' ){
|
3546 |
+
if( $event == 'post_publication' ){
|
3547 |
+
$event = 'post_update';
|
3548 |
+
}
|
3549 |
+
|
3550 |
+
$title = sprintf( 'Sucuri notification (%s)', str_replace('_', chr(32), $event) );
|
3551 |
+
$mail_sent = sucuriscan_send_mail( $email, $title, $content );
|
3552 |
+
|
3553 |
+
return $mail_sent;
|
3554 |
+
}
|
3555 |
+
|
3556 |
+
return FALSE;
|
3557 |
+
}
|
3558 |
+
|
3559 |
+
/**
|
3560 |
+
* Retrieve the public settings of the account associated with the API keys
|
3561 |
+
* registered by the administrator of the site. This function will send a HTTP
|
3562 |
+
* request to the remote API service and process its response, when successful
|
3563 |
+
* it will return an array/object containing the public attributes of the site.
|
3564 |
+
*
|
3565 |
+
* @param boolean $api_key The CloudProxy API key.
|
3566 |
+
* @return array A hash with the settings of a CloudProxy account.
|
3567 |
+
*/
|
3568 |
+
function sucuriscan_cloudproxy_settings( $api_key=FALSE ){
|
3569 |
+
$params = array( 'a' => 'show_settings' );
|
3570 |
+
|
3571 |
+
if( $api_key ){
|
3572 |
+
$params = array_merge( $params, $api_key );
|
3573 |
+
}
|
3574 |
+
|
3575 |
+
$response = sucuriscan_api_call_cloudproxy( 'GET', $params );
|
3576 |
+
|
3577 |
+
if( sucuriscan_handle_response($response) ){
|
3578 |
+
return $response['body']->output;
|
3579 |
+
}
|
3580 |
+
|
3581 |
+
return FALSE;
|
3582 |
+
}
|
3583 |
+
|
3584 |
+
/**
|
3585 |
+
* Flush the cache of the site(s) associated with the API key.
|
3586 |
+
*
|
3587 |
+
* @param boolean $api_key The CloudProxy API key.
|
3588 |
+
* @return string Message explaining the result of the operation.
|
3589 |
+
*/
|
3590 |
+
function sucuriscan_cloudproxy_clear_cache( $api_key=FALSE ){
|
3591 |
+
$params = array( 'a' => 'clear_cache' );
|
3592 |
+
|
3593 |
+
if( $api_key ){
|
3594 |
+
$params = array_merge( $params, $api_key );
|
3595 |
+
}
|
3596 |
+
|
3597 |
+
$response = sucuriscan_api_call_cloudproxy( 'GET', $params );
|
3598 |
+
|
3599 |
+
if( sucuriscan_handle_response($response) ){
|
3600 |
+
return $response['body'];
|
3601 |
+
}
|
3602 |
+
|
3603 |
+
return FALSE;
|
3604 |
+
}
|
3605 |
+
|
3606 |
+
/**
|
3607 |
+
* Retrieve the audit logs of the account associated with the API keys
|
3608 |
+
* registered b the administrator of the site. This function will send a HTTP
|
3609 |
+
* request to the remote API service and process its response, when successful
|
3610 |
+
* it will return an array/object containing a list of requests blocked by our
|
3611 |
+
* CloudProxy.
|
3612 |
+
*
|
3613 |
+
* By default the logs that will be retrieved are from today, if you need to see
|
3614 |
+
* the logs of previous days you will need to add a new parameter to the request
|
3615 |
+
* URL named "date" with format yyyy-mm-dd.
|
3616 |
+
*
|
3617 |
+
* @param boolean $api_key The CloudProxy API key.
|
3618 |
+
* @param string $date An optional date to filter the result to a specific timespan: yyyy-mm-dd.
|
3619 |
+
* @return array A list of objects with the detailed version of each request blocked by our service.
|
3620 |
+
*/
|
3621 |
+
function sucuriscan_cloudproxy_logs( $api_key=FALSE, $date='' ){
|
3622 |
+
$params = array(
|
3623 |
+
'a' => 'audit_trails',
|
3624 |
+
'date' => date('Y-m-d'),
|
3625 |
+
);
|
3626 |
+
|
3627 |
+
if( preg_match('/^([0-9]{4})\-([0-9]{2})\-([0-9]{2})$/', $date) ){
|
3628 |
+
$params['date'] = $date;
|
3629 |
+
}
|
3630 |
+
|
3631 |
+
if( $api_key ){
|
3632 |
+
$params = array_merge( $params, $api_key );
|
3633 |
+
}
|
3634 |
+
|
3635 |
+
$response = sucuriscan_api_call_cloudproxy( 'GET', $params );
|
3636 |
+
|
3637 |
+
if( sucuriscan_handle_response($response) ){
|
3638 |
+
return $response['body']->output;
|
3639 |
+
}
|
3640 |
+
|
3641 |
+
return FALSE;
|
3642 |
+
}
|
3643 |
+
|
3644 |
+
$sucuriscan_hooks = array(
|
3645 |
+
'add_attachment',
|
3646 |
+
'create_category',
|
3647 |
+
'delete_post',
|
3648 |
+
'private_to_published',
|
3649 |
+
'publish_page',
|
3650 |
+
'publish_post',
|
3651 |
+
'publish_phone',
|
3652 |
+
'xmlrpc_publish_post',
|
3653 |
+
'add_link',
|
3654 |
+
'switch_theme',
|
3655 |
+
'delete_user',
|
3656 |
+
'retrieve_password',
|
3657 |
+
'user_register',
|
3658 |
+
'wp_login',
|
3659 |
+
'wp_login_failed',
|
3660 |
+
'login_form_resetpass',
|
3661 |
+
);
|
3662 |
+
|
3663 |
+
/**
|
3664 |
+
* Send to Sucuri servers an alert advising that an attachment was added to a post.
|
3665 |
+
*
|
3666 |
+
* @param integer $id The post identifier.
|
3667 |
+
* @return void
|
3668 |
+
*/
|
3669 |
+
function sucuriscan_hook_add_attachment( $id=0 ){
|
3670 |
+
$data = ( is_int($id) ? get_post($id) : FALSE );
|
3671 |
+
$title = ( $data ? $data->post_title : 'Unknown' );
|
3672 |
+
|
3673 |
+
$message = 'Media file added #'.$id.' ('.$title.')';
|
3674 |
+
sucuriscan_report_event( 1, 'core', $message );
|
3675 |
+
sucuriscan_notify_event( 'post_publication', $message );
|
3676 |
+
}
|
3677 |
+
|
3678 |
+
/**
|
3679 |
+
* Send to Sucuri servers an alert advising that a category was created.
|
3680 |
+
*
|
3681 |
+
* @param integer $id The identifier of the category created.
|
3682 |
+
* @return void
|
3683 |
+
*/
|
3684 |
+
function sucuriscan_hook_create_category( $id=0 ){
|
3685 |
+
$title = ( is_int($id) ? get_cat_name($id) : 'Unknown' );
|
3686 |
+
|
3687 |
+
$message = 'Category created #'.$id.' ('.$title.')';
|
3688 |
+
sucuriscan_report_event( 1, 'core', $message );
|
3689 |
+
sucuriscan_notify_event( 'post_publication', $message );
|
3690 |
+
}
|
3691 |
+
|
3692 |
+
/**
|
3693 |
+
* Send to Sucuri servers an alert advising that a post was deleted.
|
3694 |
+
*
|
3695 |
+
* @param integer $id The identifier of the post deleted.
|
3696 |
+
* @return void
|
3697 |
+
*/
|
3698 |
+
function sucuriscan_hook_delete_post( $id=0 ){
|
3699 |
+
sucuriscan_report_event( 3, 'core', 'Post deleted #'.$id );
|
3700 |
+
}
|
3701 |
+
|
3702 |
+
/**
|
3703 |
+
* Send to Sucuri servers an alert advising that the state of a post was changed
|
3704 |
+
* from private to published. This will only applies for posts not pages.
|
3705 |
+
*
|
3706 |
+
* @param integer $id The identifier of the post changed.
|
3707 |
+
* @return void
|
3708 |
+
*/
|
3709 |
+
function sucuriscan_hook_private_to_published( $id=0 ){
|
3710 |
+
$data = ( is_int($id) ? get_post($id) : FALSE );
|
3711 |
+
|
3712 |
+
if( $data ){
|
3713 |
+
$title = $data->post_title;
|
3714 |
+
$p_type = ucwords($data->post_type);
|
3715 |
+
} else {
|
3716 |
+
$title = 'Unknown';
|
3717 |
+
$p_type = 'Publication';
|
3718 |
+
}
|
3719 |
+
|
3720 |
+
$message = $p_type.' changed from private to published #'.$id.' ('.$title.')';
|
3721 |
+
sucuriscan_report_event( 2, 'core', $message );
|
3722 |
+
sucuriscan_notify_event( 'post_publication', $message );
|
3723 |
+
}
|
3724 |
+
|
3725 |
+
/**
|
3726 |
+
* Send to Sucuri servers an alert advising that a post was published.
|
3727 |
+
*
|
3728 |
+
* @param integer $id The identifier of the post or page published.
|
3729 |
+
* @return void
|
3730 |
+
*/
|
3731 |
+
function sucuriscan_hook_publish( $id=0 ){
|
3732 |
+
$data = ( is_int($id) ? get_post($id) : FALSE );
|
3733 |
+
|
3734 |
+
if( $data ){
|
3735 |
+
$title = $data->post_title;
|
3736 |
+
$p_type = ucwords($data->post_type);
|
3737 |
+
$action = ( $data->post_date == $data->post_modified ? 'created' : 'updated' );
|
3738 |
+
} else {
|
3739 |
+
$title = 'Unknown';
|
3740 |
+
$p_type = 'Publication';
|
3741 |
+
$action = 'published';
|
3742 |
+
}
|
3743 |
+
|
3744 |
+
$message = $p_type.' was '.$action.' #'.$id.' ('.$title.')';
|
3745 |
+
sucuriscan_report_event( 2, 'core', $message );
|
3746 |
+
sucuriscan_notify_event( 'post_publication', $message );
|
3747 |
+
}
|
3748 |
+
|
3749 |
+
/**
|
3750 |
+
* Alias function for hook_publish()
|
3751 |
+
*
|
3752 |
+
* @param integer $id The identifier of the post or page published.
|
3753 |
+
* @return void
|
3754 |
+
*/
|
3755 |
+
function sucuriscan_hook_publish_page( $id=0 ){ sucuriscan_hook_publish($id); }
|
3756 |
+
|
3757 |
+
/**
|
3758 |
+
* Alias function for hook_publish()
|
3759 |
+
*
|
3760 |
+
* @param integer $id The identifier of the post or page published.
|
3761 |
+
* @return void
|
3762 |
+
*/
|
3763 |
+
function sucuriscan_hook_publish_post( $id=0 ){ sucuriscan_hook_publish($id); }
|
3764 |
+
|
3765 |
+
/**
|
3766 |
+
* Alias function for hook_publish()
|
3767 |
+
*
|
3768 |
+
* @param integer $id The identifier of the post or page published.
|
3769 |
+
* @return void
|
3770 |
+
*/
|
3771 |
+
function sucuriscan_hook_publish_phone( $id=0 ){ sucuriscan_hook_publish($id); }
|
3772 |
+
|
3773 |
+
/**
|
3774 |
+
* Alias function for hook_publish()
|
3775 |
+
*
|
3776 |
+
* @param integer $id The identifier of the post or page published.
|
3777 |
+
* @return void
|
3778 |
+
*/
|
3779 |
+
function sucuriscan_hook_xmlrpc_publish_post( $id=0 ){ sucuriscan_hook_publish($id); }
|
3780 |
+
|
3781 |
+
/**
|
3782 |
+
* Send to Sucuri servers an alert advising that a new link was added to the bookmarks.
|
3783 |
+
*
|
3784 |
+
* @param integer $id Identifier of the new link created;
|
3785 |
+
* @return void
|
3786 |
+
*/
|
3787 |
+
function sucuriscan_hook_add_link( $id=0 ){
|
3788 |
+
$data = ( is_int($id) ? get_bookmark($id) : FALSE );
|
3789 |
+
|
3790 |
+
if( $data ){
|
3791 |
+
$title = $data->link_name;
|
3792 |
+
$url = $data->link_url;
|
3793 |
+
} else {
|
3794 |
+
$title = 'Unknown';
|
3795 |
+
$url = 'undefined/url';
|
3796 |
+
}
|
3797 |
+
|
3798 |
+
$message = 'New link added #'.$id.' ('.$title.': '.$url.')';
|
3799 |
+
sucuriscan_report_event( 2, 'core', $message );
|
3800 |
+
sucuriscan_notify_event( 'post_publication', $message );
|
3801 |
+
}
|
3802 |
+
|
3803 |
+
/**
|
3804 |
+
* Send to Sucuri servers an alert advising that the theme of the site was changed.
|
3805 |
+
*
|
3806 |
+
* @param string $title The name of the new theme selected to used through out the site.
|
3807 |
+
* @return void
|
3808 |
+
*/
|
3809 |
+
function sucuriscan_hook_switch_theme( $title='' ){
|
3810 |
+
if( empty($title) ){ $title = 'Unknown'; }
|
3811 |
+
|
3812 |
+
$message = 'Theme switched to: '.$title;
|
3813 |
+
sucuriscan_report_event( 3, 'core', $message );
|
3814 |
+
sucuriscan_notify_event( 'theme_switched', $message );
|
3815 |
+
}
|
3816 |
+
|
3817 |
+
/**
|
3818 |
+
* Send to Sucuri servers an alert advising that a user account was deleted.
|
3819 |
+
*
|
3820 |
+
* @param integer $id The identifier of the user account deleted.
|
3821 |
+
* @return void
|
3822 |
+
*/
|
3823 |
+
function sucuriscan_hook_delete_user( $id=0 ){
|
3824 |
+
sucuriscan_report_event( 3, 'core', 'User account deleted #'.$id );
|
3825 |
+
}
|
3826 |
+
|
3827 |
+
/**
|
3828 |
+
* Send to Sucuri servers an alert advising that an attempt to retrieve the password
|
3829 |
+
* of an user account was tried.
|
3830 |
+
*
|
3831 |
+
* @param string $title The name of the user account involved in the trasaction.
|
3832 |
+
* @return void
|
3833 |
+
*/
|
3834 |
+
function sucuriscan_hook_retrieve_password( $title='' ){
|
3835 |
+
if( empty($title) ){ $title = 'Unknown'; }
|
3836 |
+
|
3837 |
+
sucuriscan_report_event( 3, 'core', 'Password retrieval attempt for user: '.$title );
|
3838 |
+
}
|
3839 |
+
|
3840 |
+
/**
|
3841 |
+
* Send to Sucuri servers an alert advising that a new user account was created.
|
3842 |
+
*
|
3843 |
+
* @param integer $id The identifier of the new user account created.
|
3844 |
+
* @return void
|
3845 |
+
*/
|
3846 |
+
function sucuriscan_hook_user_register( $id=0 ){
|
3847 |
+
$data = ( is_int($id) ? get_userdata($id) : FALSE );
|
3848 |
+
$title = ( $data ? $data->display_name : 'Unknown' );
|
3849 |
+
|
3850 |
+
$message = 'New user account registered #'.$id.' ('.$title.')';
|
3851 |
+
sucuriscan_report_event( 3, 'core', $message );
|
3852 |
+
sucuriscan_notify_event( 'user_registration', $message );
|
3853 |
+
}
|
3854 |
+
|
3855 |
+
/**
|
3856 |
+
* Send to Sucuri servers an alert advising that an attempt to login into the
|
3857 |
+
* administration panel was successful.
|
3858 |
+
*
|
3859 |
+
* @param string $title The name of the user account involved in the transaction.
|
3860 |
+
* @return void
|
3861 |
+
*/
|
3862 |
+
function sucuriscan_hook_wp_login( $title='' ){
|
3863 |
+
if( empty($title) ){ $title = 'Unknown'; }
|
3864 |
+
|
3865 |
+
$message = 'User logged in: '.$title;
|
3866 |
+
sucuriscan_report_event( 2, 'core', $message );
|
3867 |
+
sucuriscan_notify_event( 'success_login', $message );
|
3868 |
+
}
|
3869 |
+
|
3870 |
+
/**
|
3871 |
+
* Send to Sucuri servers an alert advising that an attempt to login into the
|
3872 |
+
* administration panel failed.
|
3873 |
+
*
|
3874 |
+
* @param string $title The name of the user account involved in the transaction.
|
3875 |
+
* @return void
|
3876 |
+
*/
|
3877 |
+
function sucuriscan_hook_wp_login_failed( $title='' ){
|
3878 |
+
if( empty($title) ){ $title = 'Unknown'; }
|
3879 |
+
|
3880 |
+
$message = 'User authentication failed: '.$title;
|
3881 |
+
sucuriscan_report_event( 2, 'core', $message );
|
3882 |
+
sucuriscan_notify_event( 'failed_login', $message );
|
3883 |
+
}
|
3884 |
+
|
3885 |
+
/**
|
3886 |
+
* Send to Sucuri servers an alert advising that an attempt to reset the password
|
3887 |
+
* of an user account was executed.
|
3888 |
+
*
|
3889 |
+
* @return void
|
3890 |
+
*/
|
3891 |
+
function sucuriscan_hook_login_form_resetpass(){
|
3892 |
+
// Detecting wordpress 2.8.3 vulnerability - $key is array.
|
3893 |
+
if( isset($_GET['key']) && is_array($_GET['key']) ){
|
3894 |
+
sucuriscan_report_event( 3, 'core', 'Attempt to reset password by attacking WP/2.8.3 bug' );
|
3895 |
+
}
|
3896 |
+
}
|
3897 |
+
|
3898 |
+
// Configure the hooks defined above to be triggered automatically.
|
3899 |
+
if( isset($sucuriscan_hooks) ){
|
3900 |
+
foreach( $sucuriscan_hooks as $hook_name ){
|
3901 |
+
$hook_func = 'sucuriscan_hook_' . $hook_name;
|
3902 |
+
|
3903 |
+
if( function_exists($hook_func) ){
|
3904 |
+
add_action( $hook_name, $hook_func, 50 );
|
3905 |
+
}
|
3906 |
+
}
|
3907 |
+
}
|
3908 |
+
|
3909 |
+
if( !function_exists('sucuriscan_hook_undefined_actions') ){
|
3910 |
+
|
3911 |
+
/**
|
3912 |
+
* Send a notifications to the administrator of some specific events that are
|
3913 |
+
* not triggered through an hooked action, but through a simple request in the
|
3914 |
+
* admin interface.
|
3915 |
+
*
|
3916 |
+
* @return integer Either one or zero representing the success or fail of the operation.
|
3917 |
+
*/
|
3918 |
+
function sucuriscan_hook_undefined_actions(){
|
3919 |
+
|
3920 |
+
// Plugin activation and/or deactivation.
|
3921 |
+
if(
|
3922 |
+
current_user_can('activate_plugins')
|
3923 |
+
&& (
|
3924 |
+
( isset($_GET['action']) && preg_match('/^(activate|deactivate)$/', $_GET['action']) ) ||
|
3925 |
+
( isset($_POST['action']) && preg_match('/^(activate|deactivate)-selected$/', $_POST['action']))
|
3926 |
+
)
|
3927 |
+
){
|
3928 |
+
$plugin_list = array();
|
3929 |
+
|
3930 |
+
if(
|
3931 |
+
isset($_GET['plugin'])
|
3932 |
+
&& !empty($_GET['plugin'])
|
3933 |
+
&& strpos($_SERVER['REQUEST_URI'], 'plugins.php') !== FALSE
|
3934 |
+
){
|
3935 |
+
$action_d = $_GET['action'] . 'd';
|
3936 |
+
$plugin_list[] = $_GET['plugin'];
|
3937 |
+
}
|
3938 |
+
|
3939 |
+
elseif( isset($_POST['checked']) ){
|
3940 |
+
$action_d = str_replace('-selected', 'd', $_POST['action']);
|
3941 |
+
$plugin_list = $_POST['checked'];
|
3942 |
+
}
|
3943 |
+
|
3944 |
+
foreach( $plugin_list as $plugin ){
|
3945 |
+
$plugin_info = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin );
|
3946 |
+
$message = sprintf(
|
3947 |
+
'Plugin %s: %s (v%s; %s)',
|
3948 |
+
$action_d,
|
3949 |
+
$plugin_info['Name'],
|
3950 |
+
$plugin_info['Version'],
|
3951 |
+
esc_attr($plugin)
|
3952 |
+
);
|
3953 |
+
|
3954 |
+
sucuriscan_report_event( 3, 'core', $message );
|
3955 |
+
sucuriscan_notify_event( 'plugin_' . $action_d, $message );
|
3956 |
+
}
|
3957 |
+
}
|
3958 |
+
|
3959 |
+
// Plugin update request.
|
3960 |
+
elseif(
|
3961 |
+
current_user_can('update_plugins')
|
3962 |
+
&& (
|
3963 |
+
( isset($_GET['action']) && preg_match('/(upgrade-plugin|do-plugin-upgrade)/', $_GET['action']) ) ||
|
3964 |
+
( isset($_POST['action']) && $_POST['action'] == 'update-selected' )
|
3965 |
+
)
|
3966 |
+
){
|
3967 |
+
$plugin_list = array();
|
3968 |
+
|
3969 |
+
if(
|
3970 |
+
isset($_GET['plugin'])
|
3971 |
+
&& !empty($_GET['plugin'])
|
3972 |
+
&& strpos($_SERVER['REQUEST_URI'], 'wp-admin/update.php') !== FALSE
|
3973 |
+
){
|
3974 |
+
$plugin_list[] = $_GET['plugin'];
|
3975 |
+
}
|
3976 |
+
|
3977 |
+
elseif( isset($_POST['checked']) ){
|
3978 |
+
$plugin_list = $_POST['checked'];
|
3979 |
+
}
|
3980 |
+
|
3981 |
+
foreach( $plugin_list as $plugin ){
|
3982 |
+
$plugin_info = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin );
|
3983 |
+
$message = sprintf(
|
3984 |
+
'Plugin request to be updated: %s (v%s; %s)',
|
3985 |
+
$plugin_info['Name'],
|
3986 |
+
$plugin_info['Version'],
|
3987 |
+
esc_attr($plugin)
|
3988 |
+
);
|
3989 |
+
|
3990 |
+
sucuriscan_report_event( 3, 'core', $message );
|
3991 |
+
sucuriscan_notify_event( 'plugin_updated', $message );
|
3992 |
+
}
|
3993 |
+
}
|
3994 |
+
|
3995 |
+
// Plugin installation request.
|
3996 |
+
elseif(
|
3997 |
+
current_user_can('install_plugins')
|
3998 |
+
&& isset($_GET['action'])
|
3999 |
+
&& preg_match('/^(install|upload)-plugin$/', $_GET['action'])
|
4000 |
+
&& current_user_can('install_plugins')
|
4001 |
+
){
|
4002 |
+
if( isset($_FILES['pluginzip']) ){
|
4003 |
+
$plugin = $_FILES['pluginzip']['name'];
|
4004 |
+
} elseif( isset($_GET['plugin']) ){
|
4005 |
+
$plugin = $_GET['plugin'];
|
4006 |
+
} else {
|
4007 |
+
$plugin = 'Unknown';
|
4008 |
+
}
|
4009 |
+
|
4010 |
+
$message = 'Plugin request to be installed: ' . esc_attr($plugin);
|
4011 |
+
sucuriscan_report_event( 3, 'core', $message );
|
4012 |
+
sucuriscan_notify_event( 'plugin_installed', $message );
|
4013 |
+
}
|
4014 |
+
|
4015 |
+
// Plugin deletion request.
|
4016 |
+
elseif(
|
4017 |
+
current_user_can('delete_plugins')
|
4018 |
+
&& isset($_POST['action'])
|
4019 |
+
&& $_POST['action'] == 'delete-selected'
|
4020 |
+
&& isset($_POST['verify-delete'])
|
4021 |
+
&& $_POST['verify-delete'] == 1
|
4022 |
+
){
|
4023 |
+
$plugin_list = (array) $_POST['checked'];
|
4024 |
+
|
4025 |
+
foreach( $plugin_list as $plugin ){
|
4026 |
+
$plugin_info = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin );
|
4027 |
+
$message = sprintf(
|
4028 |
+
'Plugin request to be deleted: %s (v%s; %s)',
|
4029 |
+
$plugin_info['Name'],
|
4030 |
+
$plugin_info['Version'],
|
4031 |
+
esc_attr($plugin)
|
4032 |
+
);
|
4033 |
+
|
4034 |
+
sucuriscan_report_event( 3, 'core', $message );
|
4035 |
+
sucuriscan_notify_event( 'plugin_deleted', $message );
|
4036 |
+
}
|
4037 |
+
}
|
4038 |
+
|
4039 |
+
// Plugin editor request.
|
4040 |
+
elseif(
|
4041 |
+
current_user_can('edit_plugins')
|
4042 |
+
&& isset($_POST['action'])
|
4043 |
+
&& $_POST['action'] == 'update'
|
4044 |
+
&& isset($_POST['file'])
|
4045 |
+
&& isset($_POST['plugin'])
|
4046 |
+
&& strpos($_SERVER['REQUEST_URI'], 'plugin-editor.php') !== FALSE
|
4047 |
+
){
|
4048 |
+
$message = 'Plugin editor modification: ' . esc_attr($_POST['file']);
|
4049 |
+
sucuriscan_report_event( 3, 'core', $message );
|
4050 |
+
sucuriscan_notify_event( 'theme_editor', $message );
|
4051 |
+
}
|
4052 |
+
|
4053 |
+
// Theme editor request.
|
4054 |
+
elseif(
|
4055 |
+
current_user_can('edit_themes')
|
4056 |
+
&& isset($_POST['action'])
|
4057 |
+
&& $_POST['action'] == 'update'
|
4058 |
+
&& isset($_POST['file'])
|
4059 |
+
&& isset($_POST['theme'])
|
4060 |
+
&& strpos($_SERVER['REQUEST_URI'], 'theme-editor.php') !== FALSE
|
4061 |
+
){
|
4062 |
+
$message = 'Theme editor modification: ' . esc_attr($_POST['theme']) . '/' . esc_attr($_POST['file']);
|
4063 |
+
sucuriscan_report_event( 3, 'core', $message );
|
4064 |
+
sucuriscan_notify_event( 'theme_editor', $message );
|
4065 |
+
}
|
4066 |
+
|
4067 |
+
// Theme activation and/or deactivation (same hook for switch_theme).
|
4068 |
+
// Theme installation request (hook not available).
|
4069 |
+
// Theme deletion request (hook not available).
|
4070 |
+
|
4071 |
+
// Theme update request.
|
4072 |
+
elseif(
|
4073 |
+
current_user_can('update_themes')
|
4074 |
+
&& isset($_GET['action'])
|
4075 |
+
&& preg_match('/^(upgrade-theme|do-theme-upgrade)$/', $_GET['action'])
|
4076 |
+
&& isset($_POST['checked'])
|
4077 |
+
){
|
4078 |
+
$theme_list = (array) $_POST['checked'];
|
4079 |
+
|
4080 |
+
foreach( $theme_list as $theme ){
|
4081 |
+
$theme_info = wp_get_theme($theme);
|
4082 |
+
$theme_name = ucwords($theme);
|
4083 |
+
$theme_version = '0.0';
|
4084 |
+
|
4085 |
+
if( $theme_info->exists() ){
|
4086 |
+
$theme_name = $theme_info->get('Name');
|
4087 |
+
$theme_version = $theme_info->get('Version');
|
4088 |
+
}
|
4089 |
+
|
4090 |
+
$message = sprintf(
|
4091 |
+
'Theme request to be updated: %s (v%s; %s)',
|
4092 |
+
$theme_name,
|
4093 |
+
$theme_version,
|
4094 |
+
esc_attr($theme)
|
4095 |
+
);
|
4096 |
+
|
4097 |
+
sucuriscan_report_event( 3, 'core', $message );
|
4098 |
+
sucuriscan_notify_event( 'theme_updated', $message );
|
4099 |
+
}
|
4100 |
+
}
|
4101 |
+
|
4102 |
+
// WordPress update request.
|
4103 |
+
elseif(
|
4104 |
+
current_user_can('update_core')
|
4105 |
+
&& isset($_GET['action'])
|
4106 |
+
&& $_GET['action'] == 'do-core-reinstall'
|
4107 |
+
&& isset($_POST['upgrade'])
|
4108 |
+
&& isset($_POST['version'])
|
4109 |
+
){
|
4110 |
+
$message = 'WordPress updated (or re-installed) to version: ' . esc_attr($_POST['version']);
|
4111 |
+
sucuriscan_report_event( 3, 'core', $message );
|
4112 |
+
sucuriscan_notify_event( 'website_updated', $message );
|
4113 |
+
}
|
4114 |
+
|
4115 |
+
// Widget addition or deletion.
|
4116 |
+
elseif(
|
4117 |
+
current_user_can('edit_theme_options')
|
4118 |
+
&& isset($_POST['action'])
|
4119 |
+
&& $_POST['action'] == 'save-widget'
|
4120 |
+
&& isset($_POST['id_base'])
|
4121 |
+
&& isset($_POST['sidebar'])
|
4122 |
+
){
|
4123 |
+
if(
|
4124 |
+
isset($_POST['delete_widget'])
|
4125 |
+
&& $_POST['delete_widget'] == 1
|
4126 |
+
){
|
4127 |
+
$action_d = 'deleted';
|
4128 |
+
$action_text = 'deleted from';
|
4129 |
+
} else {
|
4130 |
+
$action_d = 'added';
|
4131 |
+
$action_text = 'added to';
|
4132 |
+
}
|
4133 |
+
|
4134 |
+
$message = sprintf(
|
4135 |
+
'Widget %s (%s) %s %s (#%d; size %dx%d)',
|
4136 |
+
esc_attr($_POST['id_base']),
|
4137 |
+
esc_attr($_POST['widget-id']),
|
4138 |
+
$action_text,
|
4139 |
+
esc_attr($_POST['sidebar']),
|
4140 |
+
esc_attr($_POST['widget_number']),
|
4141 |
+
esc_attr($_POST['widget-width']),
|
4142 |
+
esc_attr($_POST['widget-height'])
|
4143 |
+
);
|
4144 |
+
|
4145 |
+
sucuriscan_report_event( 3, 'core', $message );
|
4146 |
+
sucuriscan_notify_event( 'widget_' . $action_d, $message );
|
4147 |
+
}
|
4148 |
+
|
4149 |
+
// Detect any Wordpress settings modification.
|
4150 |
+
elseif(
|
4151 |
+
isset($_POST['option_page'])
|
4152 |
+
&& current_user_can('manage_options')
|
4153 |
+
&& SucuriScan::sucuriscan_check_options_wpnonce()
|
4154 |
+
){
|
4155 |
+
// Get the settings available in the database and compare them with the submission.
|
4156 |
+
$all_options = sucuriscan_get_wp_options();
|
4157 |
+
$options_changed = sucuriscan_what_options_were_changed($_POST);
|
4158 |
+
$options_changed_str = '';
|
4159 |
+
$options_changed_count = 0;
|
4160 |
+
|
4161 |
+
// Generate the list of options changed.
|
4162 |
+
foreach( $options_changed['original'] as $option_name => $option_value ){
|
4163 |
+
$options_changed_count += 1;
|
4164 |
+
$options_changed_str .= sprintf(
|
4165 |
+
"The value of the option <b>%s</b> was changed from <b>'%s'</b> to <b>'%s'</b>.<br>\n",
|
4166 |
+
$option_name, $option_value, $options_changed['changed'][$option_name]
|
4167 |
+
);
|
4168 |
+
}
|
4169 |
+
|
4170 |
+
// Get the option group (name of the page where the request was originated).
|
4171 |
+
$option_page = isset($_POST['option_page']) ? $_POST['option_page'] : 'options';
|
4172 |
+
$page_referer = FALSE;
|
4173 |
+
|
4174 |
+
// Check which of these option groups where modified.
|
4175 |
+
switch( $option_page ){
|
4176 |
+
case 'options':
|
4177 |
+
$page_referer = 'Global';
|
4178 |
+
break;
|
4179 |
+
case 'general': /* no_break */
|
4180 |
+
case 'writing': /* no_break */
|
4181 |
+
case 'reading': /* no_break */
|
4182 |
+
case 'discussion': /* no_break */
|
4183 |
+
case 'media': /* no_break */
|
4184 |
+
case 'permalink':
|
4185 |
+
$page_referer = ucwords($option_page);
|
4186 |
+
break;
|
4187 |
+
default:
|
4188 |
+
$page_referer = 'Common';
|
4189 |
+
break;
|
4190 |
+
}
|
4191 |
+
|
4192 |
+
if( $page_referer && $options_changed_count > 0 ){
|
4193 |
+
$message = $page_referer.' settings changed';
|
4194 |
+
sucuriscan_report_event( 3, 'core', $message );
|
4195 |
+
sucuriscan_notify_event( 'settings_updated', $message . "<br>\n" . $options_changed_str );
|
4196 |
+
}
|
4197 |
+
}
|
4198 |
+
|
4199 |
+
}
|
4200 |
+
|
4201 |
+
add_action( 'admin_init', 'sucuriscan_hook_undefined_actions' );
|
4202 |
+
add_action( 'login_form', 'sucuriscan_hook_undefined_actions' );
|
4203 |
+
}
|
4204 |
+
|
4205 |
+
/**
|
4206 |
+
* CloudProxy monitoring page.
|
4207 |
+
*
|
4208 |
+
* It checks whether the WordPress core files are the original ones, and the state
|
4209 |
+
* of the themes and plugins reporting the availability of updates. It also checks
|
4210 |
+
* the user accounts under the administrator group.
|
4211 |
+
*
|
4212 |
+
* @return void
|
4213 |
+
*/
|
4214 |
+
function sucuriscan_monitoring_page(){
|
4215 |
+
if( !current_user_can('manage_options') ){
|
4216 |
+
wp_die(__('You do not have sufficient permissions to access this page: Firewall (WAF)') );
|
4217 |
+
}
|
4218 |
+
|
4219 |
+
// Process all form submissions.
|
4220 |
+
sucuriscan_monitoring_form_submissions();
|
4221 |
+
|
4222 |
+
// Get the dynamic values for the template variables.
|
4223 |
+
$api_key = sucuriscan_cloudproxy_apikey();
|
4224 |
+
|
4225 |
+
// Page pseudo-variables initialization.
|
4226 |
+
$template_variables = array(
|
4227 |
+
'PageTitle' => 'Firewall WAF',
|
4228 |
+
'Monitoring.InstructionsVisibility' => 'visible',
|
4229 |
+
'Monitoring.Settings' => sucuriscan_monitoring_settings($api_key),
|
4230 |
+
'Monitoring.Logs' => sucuriscan_monitoring_logs($api_key),
|
4231 |
+
|
4232 |
+
/* Pseudo-variables for the monitoring logs. */
|
4233 |
+
'AuditLogs.List' => '',
|
4234 |
+
'AuditLogs.CountText' => '',
|
4235 |
+
'AuditLogs.DenialTypeOptions' => '',
|
4236 |
+
'AuditLogs.NoItemsVisibility' => '',
|
4237 |
+
'AuditLogs.PaginationVisibility' => '',
|
4238 |
+
'AuditLogs.AuditPagination' => '',
|
4239 |
+
);
|
4240 |
+
|
4241 |
+
if( $api_key ){
|
4242 |
+
$template_variables['Monitoring.InstructionsVisibility'] = 'hidden';
|
4243 |
+
}
|
4244 |
+
|
4245 |
+
echo sucuriscan_get_template('monitoring', $template_variables);
|
4246 |
+
}
|
4247 |
+
|
4248 |
+
/**
|
4249 |
+
* Process the requests sent by the form submissions originated in the monitoring
|
4250 |
+
* page, all forms must have a nonce field that will be checked agains the one
|
4251 |
+
* generated in the template render function.
|
4252 |
+
*
|
4253 |
+
* @return void
|
4254 |
+
*/
|
4255 |
+
function sucuriscan_monitoring_form_submissions(){
|
4256 |
+
|
4257 |
+
if( sucuriscan_check_page_nonce() ){
|
4258 |
+
|
4259 |
+
// Add and/or Update the Sucuri WAF API Key (do it before anything else).
|
4260 |
+
$option_name = 'sucuriscan_cloudproxy_apikey';
|
4261 |
+
|
4262 |
+
if( isset($_POST[$option_name]) ){
|
4263 |
+
$api_key = $_POST[$option_name];
|
4264 |
+
|
4265 |
+
if( sucuriscan_valid_cloudproxy_apikey($api_key) ){
|
4266 |
+
update_option($option_name, $api_key);
|
4267 |
+
sucuriscan_info( 'Sucuri CloudProxy WAF API key saved successfully' );
|
4268 |
+
} elseif( empty($api_key) ){
|
4269 |
+
delete_option($option_name);
|
4270 |
+
sucuriscan_info( 'Sucuri CloudProxy WAF API key removed successfully' );
|
4271 |
+
} else {
|
4272 |
+
sucuriscan_error( 'Invalid CloudProxy API key, check your settings and try again.' );
|
4273 |
+
}
|
4274 |
+
}
|
4275 |
+
|
4276 |
+
// Flush the cache of the site(s) associated with the API key.
|
4277 |
+
if( isset($_POST['sucuriscan_clear_cache']) ){
|
4278 |
+
$clear_cache_resp = sucuriscan_cloudproxy_clear_cache();
|
4279 |
+
|
4280 |
+
if( $clear_cache_resp ){
|
4281 |
+
if( isset($clear_cache_resp->messages[0]) ){
|
4282 |
+
sucuriscan_info($clear_cache_resp->messages[0]);
|
4283 |
+
} else {
|
4284 |
+
sucuriscan_error('Could not clear the cache of your site, try later again.');
|
4285 |
+
}
|
4286 |
+
} else {
|
4287 |
+
sucuriscan_error( 'CloudProxy WAF is not enabled on your site, or your API key is invalid.' );
|
4288 |
+
}
|
4289 |
+
}
|
4290 |
+
|
4291 |
+
}
|
4292 |
+
|
4293 |
+
}
|
4294 |
+
|
4295 |
+
/**
|
4296 |
+
* Generate the HTML code for the monitoring settings panel.
|
4297 |
+
*
|
4298 |
+
* @param string $api_key The CloudProxy API key.
|
4299 |
+
* @return string The parsed-content of the monitoring settings panel.
|
4300 |
+
*/
|
4301 |
+
function sucuriscan_monitoring_settings( $api_key='' ){
|
4302 |
+
$template_variables = array(
|
4303 |
+
'Monitoring.APIKey' => '',
|
4304 |
+
'Monitoring.SettingsVisibility' => 'hidden',
|
4305 |
+
'Monitoring.SettingOptions' => '',
|
4306 |
+
);
|
4307 |
+
|
4308 |
+
if( $api_key ){
|
4309 |
+
$settings = sucuriscan_cloudproxy_settings($api_key);
|
4310 |
+
|
4311 |
+
$template_variables['Monitoring.APIKey'] = $api_key['string'];
|
4312 |
+
|
4313 |
+
if( $settings ){
|
4314 |
+
$counter = 0;
|
4315 |
+
$template_variables['Monitoring.SettingsVisibility'] = 'visible';
|
4316 |
+
$settings = sucuriscan_explain_monitoring_settings($settings);
|
4317 |
+
|
4318 |
+
foreach( $settings as $option_name => $option_value ){
|
4319 |
+
$css_class = ( $counter % 2 == 0 ) ? 'alternate' : '';
|
4320 |
+
$option_title = ucwords(str_replace('_', chr(32), $option_name));
|
4321 |
+
|
4322 |
+
// Generate a HTML list when the option's value is an array.
|
4323 |
+
if( is_array($option_value) ){
|
4324 |
+
$css_scrollable = count($option_value) > 10 ? 'sucuriscan-list-as-table-scrollable' : '';
|
4325 |
+
$html_list = '<ul class="sucuriscan-list-as-table ' . $css_scrollable . '">';
|
4326 |
+
|
4327 |
+
foreach( $option_value as $single_value ){
|
4328 |
+
$html_list .= '<li>' . $single_value . '</li>';
|
4329 |
+
}
|
4330 |
+
|
4331 |
+
$html_list .= '</ul>';
|
4332 |
+
$option_value = $html_list;
|
4333 |
+
}
|
4334 |
+
|
4335 |
+
// Parse the snippet template and replace the pseudo-variables.
|
4336 |
+
$template_variables['Monitoring.SettingOptions'] .= sucuriscan_get_snippet('monitoring-settings', array(
|
4337 |
+
'Monitoring.OptionCssClass' => $css_class,
|
4338 |
+
'Monitoring.OptionName' => $option_title,
|
4339 |
+
'Monitoring.OptionValue' => $option_value,
|
4340 |
+
));
|
4341 |
+
$counter += 1;
|
4342 |
+
}
|
4343 |
+
}
|
4344 |
+
}
|
4345 |
+
|
4346 |
+
return sucuriscan_get_section( 'monitoring-settings', $template_variables );
|
4347 |
+
}
|
4348 |
+
|
4349 |
+
/**
|
4350 |
+
* Converts the value of some of the monitoring settings into a human-readable
|
4351 |
+
* text, for example changing numbers or variable names into a more explicit
|
4352 |
+
* text so the administrator can understand the meaning of these settings.
|
4353 |
+
*
|
4354 |
+
* @param array $settings A hash with the settings of a CloudProxy account.
|
4355 |
+
* @return array The explained version of the CloudProxy settings.
|
4356 |
+
*/
|
4357 |
+
function sucuriscan_explain_monitoring_settings( $settings=array() ){
|
4358 |
+
if( $settings ){
|
4359 |
+
foreach( $settings as $option_name => $option_value ){
|
4360 |
+
switch( $option_name ){
|
4361 |
+
case 'security_level':
|
4362 |
+
$new_value = ucwords($option_value);
|
4363 |
+
break;
|
4364 |
+
case 'proxy_active':
|
4365 |
+
$new_value = ( $option_value == 1 ) ? 'Active' : 'not active';
|
4366 |
+
break;
|
4367 |
+
case 'cache_mode':
|
4368 |
+
$new_value = sucuriscan_cache_mode_title($option_value);
|
4369 |
+
break;
|
4370 |
+
}
|
4371 |
+
|
4372 |
+
if( isset($new_value) ){
|
4373 |
+
$settings->{$option_name} = $new_value;
|
4374 |
+
}
|
4375 |
+
}
|
4376 |
+
|
4377 |
+
return $settings;
|
4378 |
+
}
|
4379 |
+
|
4380 |
+
return FALSE;
|
4381 |
+
}
|
4382 |
+
|
4383 |
+
/**
|
4384 |
+
* Get an explaination of the meaning of the value set for the account's attribute cache_mode.
|
4385 |
+
*
|
4386 |
+
* @param string $mode The value set for the cache settings of the site.
|
4387 |
+
* @return string Explaination of the meaning of the cache_mode value.
|
4388 |
+
*/
|
4389 |
+
function sucuriscan_cache_mode_title( $mode='' ){
|
4390 |
+
$title = '';
|
4391 |
+
|
4392 |
+
switch( $mode ){
|
4393 |
+
case 'docache': $title = 'Enabled (recommended)'; break;
|
4394 |
+
case 'sitecache': $title = 'Site caching (using your site headers)'; break;
|
4395 |
+
case 'nocache': $title = 'Minimial (only for a few minutes)'; break;
|
4396 |
+
case 'nocacheatall': $title = 'Caching didabled (use with caution)'; break;
|
4397 |
+
default: $title = 'Unknown'; break;
|
4398 |
+
}
|
4399 |
+
|
4400 |
+
return $title;
|
4401 |
+
}
|
4402 |
+
|
4403 |
+
/**
|
4404 |
+
* Generate the HTML code for the monitoring logs panel.
|
4405 |
+
*
|
4406 |
+
* @param string $api_key The CloudProxy API key.
|
4407 |
+
* @return string The parsed-content of the monitoring logs panel.
|
4408 |
+
*/
|
4409 |
+
function sucuriscan_monitoring_logs( $api_key='' ){
|
4410 |
+
$template_variables = array(
|
4411 |
+
'AuditLogs.List' => '',
|
4412 |
+
'AuditLogs.CountText' => 0,
|
4413 |
+
'AuditLogs.DenialTypeOptions' => '',
|
4414 |
+
'AuditLogs.NoItemsVisibility' => 'visible',
|
4415 |
+
'AuditLogs.PaginationVisibility' => 'hidden',
|
4416 |
+
'AuditLogs.AuditPagination' => '',
|
4417 |
+
'AuditLogs.TargetDate' => '',
|
4418 |
+
'AuditLogs.DateYears' => sucuriscan_monitoring_dates('years'),
|
4419 |
+
'AuditLogs.DateMonths' => sucuriscan_monitoring_dates('months'),
|
4420 |
+
'AuditLogs.DateDays' => sucuriscan_monitoring_dates('days'),
|
4421 |
+
);
|
4422 |
+
|
4423 |
+
$date = date('Y-m-d');
|
4424 |
+
|
4425 |
+
if( $api_key ){
|
4426 |
+
// Retrieve the date filter from the request (if any).
|
4427 |
+
if( isset($_GET['date']) ){
|
4428 |
+
$date = $_GET['date'];
|
4429 |
+
}
|
4430 |
+
|
4431 |
+
elseif(
|
4432 |
+
isset($_POST['sucuriscan_year']) &&
|
4433 |
+
isset($_POST['sucuriscan_month']) &&
|
4434 |
+
isset($_POST['sucuriscan_day'])
|
4435 |
+
){
|
4436 |
+
$date = sprintf(
|
4437 |
+
'%s-%s-%s',
|
4438 |
+
$_POST['sucuriscan_year'],
|
4439 |
+
$_POST['sucuriscan_month'],
|
4440 |
+
$_POST['sucuriscan_day']
|
4441 |
+
);
|
4442 |
+
}
|
4443 |
+
|
4444 |
+
$logs_data = sucuriscan_cloudproxy_logs( $api_key, $date );
|
4445 |
+
|
4446 |
+
if( $logs_data ){
|
4447 |
+
add_thickbox(); /* Include the Thickbox library. */
|
4448 |
+
$template_variables['AuditLogs.NoItemsVisibility'] = 'hidden';
|
4449 |
+
$template_variables['AuditLogs.CountText'] = $logs_data->limit . '/' . $logs_data->total_lines;
|
4450 |
+
$template_variables['AuditLogs.List'] = sucuriscan_monitoring_access_logs($logs_data->access_logs);
|
4451 |
+
$template_variables['AuditLogs.DenialTypeOptions'] = sucuriscan_monitoring_denial_types($logs_data->access_logs);
|
4452 |
+
}
|
4453 |
+
}
|
4454 |
+
|
4455 |
+
$template_variables['AuditLogs.TargetDate'] = htmlentities($date);
|
4456 |
+
|
4457 |
+
return sucuriscan_get_section( 'monitoring-logs', $template_variables );
|
4458 |
+
}
|
4459 |
+
|
4460 |
+
/**
|
4461 |
+
* Generate the HTML code to show the table with the access-logs.
|
4462 |
+
*
|
4463 |
+
* @param array $access_logs The logs retrieved from the remote API service.
|
4464 |
+
* @return string The HTML code to show the access-logs in the page as a table.
|
4465 |
+
*/
|
4466 |
+
function sucuriscan_monitoring_access_logs( $access_logs=array() ){
|
4467 |
+
$logs_html = '';
|
4468 |
+
|
4469 |
+
if( $access_logs && !empty($access_logs) ){
|
4470 |
+
$counter = 0;
|
4471 |
+
$needed_attrs = array(
|
4472 |
+
'request_date',
|
4473 |
+
'request_time',
|
4474 |
+
'request_timezone',
|
4475 |
+
'remote_addr',
|
4476 |
+
'sucuri_block_reason',
|
4477 |
+
'resource_path',
|
4478 |
+
'request_method',
|
4479 |
+
'http_protocol',
|
4480 |
+
'http_status',
|
4481 |
+
'http_status_title',
|
4482 |
+
'http_bytes_sent',
|
4483 |
+
'http_referer',
|
4484 |
+
'http_user_agent',
|
4485 |
+
);
|
4486 |
+
|
4487 |
+
$filter_by_denial_type = FALSE;
|
4488 |
+
$filter_by_keyword = FALSE;
|
4489 |
+
$filter_query = FALSE;
|
4490 |
+
|
4491 |
+
if( isset($_POST['sucuriscan_monitoring_denial_type']) ){
|
4492 |
+
$filter_by_denial_type = TRUE;
|
4493 |
+
$filter_query = htmlentities($_POST['sucuriscan_monitoring_denial_type']);
|
4494 |
+
}
|
4495 |
+
|
4496 |
+
if( isset($_POST['sucuriscan_monitoring_log_filter']) ){
|
4497 |
+
$filter_by_keyword = TRUE;
|
4498 |
+
$filter_query = htmlentities($_POST['sucuriscan_monitoring_log_filter']);
|
4499 |
+
}
|
4500 |
+
|
4501 |
+
foreach( $access_logs as $access_log ){
|
4502 |
+
$css_class = ( $counter % 2 == 0 ) ? '' : 'alternate';
|
4503 |
+
$audit_log_snippet = array(
|
4504 |
+
'AuditLog.Id' => $counter,
|
4505 |
+
'AuditLog.CssClass' => $css_class,
|
4506 |
+
);
|
4507 |
+
|
4508 |
+
// If there is a filter, check the access_log data and break the operation if needed.
|
4509 |
+
if( $filter_query ){
|
4510 |
+
if( $filter_by_denial_type ){
|
4511 |
+
$denial_type_slug = sucuriscan_str_human2var($access_log->sucuri_block_reason);
|
4512 |
+
|
4513 |
+
if( $denial_type_slug != $filter_query ){ continue; }
|
4514 |
+
}
|
4515 |
+
|
4516 |
+
if(
|
4517 |
+
$filter_by_keyword
|
4518 |
+
&& strpos($access_log->remote_addr, $filter_query) === FALSE
|
4519 |
+
&& strpos($access_log->resource_path, $filter_query) === FALSE
|
4520 |
+
){
|
4521 |
+
continue;
|
4522 |
+
}
|
4523 |
+
}
|
4524 |
+
|
4525 |
+
// Generate (dynamically) the pseudo-variables for the template.
|
4526 |
+
foreach( $needed_attrs as $attr_name ){
|
4527 |
+
$attr_value = '';
|
4528 |
+
|
4529 |
+
$attr_title = str_replace('_', chr(32), $attr_name);
|
4530 |
+
$attr_title = ucwords($attr_title);
|
4531 |
+
$attr_title = str_replace(chr(32), '', $attr_title);
|
4532 |
+
$attr_title = 'AuditLog.' . $attr_title;
|
4533 |
+
|
4534 |
+
if( isset($access_log->{$attr_name}) ){
|
4535 |
+
$attr_value = $access_log->{$attr_name};
|
4536 |
+
}
|
4537 |
+
|
4538 |
+
$audit_log_snippet[$attr_title] = $attr_value;
|
4539 |
+
}
|
4540 |
+
|
4541 |
+
$logs_html .= sucuriscan_get_snippet('monitoring-logs', $audit_log_snippet);
|
4542 |
+
$counter += 1;
|
4543 |
+
}
|
4544 |
+
}
|
4545 |
+
|
4546 |
+
return $logs_html;
|
4547 |
+
}
|
4548 |
+
|
4549 |
+
/**
|
4550 |
+
* Get a list of denial types using the reason of the blocking of a request from
|
4551 |
+
* the from the audit logs. Examples of denial types can be: "Bad bot access
|
4552 |
+
* denied", "Access to restricted folder", "Blocked by IDS", etc.
|
4553 |
+
*
|
4554 |
+
* @param array $access_logs A list of objects with the detailed version of each request blocked by our service.
|
4555 |
+
* @param boolean $in_html Whether the list should be converted to a HTML select options or not.
|
4556 |
+
* @return array Either a list of unique blocking types, or a HTML code.
|
4557 |
+
*/
|
4558 |
+
function sucuriscan_monitoring_denial_types( $access_logs=array(), $in_html=TRUE ){
|
4559 |
+
$types = array();
|
4560 |
+
$selected = '';
|
4561 |
+
|
4562 |
+
if( $access_logs && !empty($access_logs) ){
|
4563 |
+
foreach( $access_logs as $access_log ){
|
4564 |
+
if( !array_key_exists($access_log->sucuri_block_reason, $types) ){
|
4565 |
+
$denial_type_k = sucuriscan_str_human2var($access_log->sucuri_block_reason);
|
4566 |
+
$types[$denial_type_k] = $access_log->sucuri_block_reason;
|
4567 |
+
}
|
4568 |
+
}
|
4569 |
+
}
|
4570 |
+
|
4571 |
+
if( $in_html ){
|
4572 |
+
$html_types = '<option value="">Filter</option>';
|
4573 |
+
|
4574 |
+
if( isset($_REQUEST['sucuriscan_monitoring_denial_type']) ){
|
4575 |
+
$selected = htmlentities($_REQUEST['sucuriscan_monitoring_denial_type']);
|
4576 |
+
}
|
4577 |
+
|
4578 |
+
foreach( $types as $type_key => $type_value ){
|
4579 |
+
$selected_tag = ( $type_key == $selected ) ? 'selected="selected"' : '';
|
4580 |
+
$html_types .= sprintf( '<option value="%s" %s>%s</option>', $type_key, $selected_tag, $type_value );
|
4581 |
+
}
|
4582 |
+
|
4583 |
+
return $html_types;
|
4584 |
+
}
|
4585 |
+
|
4586 |
+
return $types;
|
4587 |
+
}
|
4588 |
+
|
4589 |
+
/**
|
4590 |
+
* Get a list of years, months or days depending of the type specified.
|
4591 |
+
*
|
4592 |
+
* @param string $type Either years, months or days.
|
4593 |
+
* @param boolean $in_html Whether the list should be converted to a HTML select options or not.
|
4594 |
+
* @return array Either an array with the expected values, or a HTML code.
|
4595 |
+
*/
|
4596 |
+
function sucuriscan_monitoring_dates( $type='', $in_html=TRUE ){
|
4597 |
+
$options = array();
|
4598 |
+
$selected = '';
|
4599 |
+
|
4600 |
+
switch( $type ){
|
4601 |
+
case 'years':
|
4602 |
+
$current_year = (int) date('Y');
|
4603 |
+
$max_years = 5; /* Maximum number of years to keep the logs. */
|
4604 |
+
$options = range( ($current_year - $max_years), $current_year );
|
4605 |
+
|
4606 |
+
if( isset($_REQUEST['sucuriscan_year']) ){
|
4607 |
+
$selected = $_REQUEST['sucuriscan_year'];
|
4608 |
+
}
|
4609 |
+
break;
|
4610 |
+
case 'months':
|
4611 |
+
$options = array(
|
4612 |
+
'01' => 'January',
|
4613 |
+
'02' => 'February',
|
4614 |
+
'03' => 'March',
|
4615 |
+
'04' => 'April',
|
4616 |
+
'05' => 'May',
|
4617 |
+
'06' => 'June',
|
4618 |
+
'07' => 'July',
|
4619 |
+
'08' => 'August',
|
4620 |
+
'09' => 'September',
|
4621 |
+
'10' => 'October',
|
4622 |
+
'11' => 'November',
|
4623 |
+
'12' => 'December'
|
4624 |
+
);
|
4625 |
+
|
4626 |
+
if( isset($_REQUEST['sucuriscan_month']) ){
|
4627 |
+
$selected = $_REQUEST['sucuriscan_month'];
|
4628 |
+
}
|
4629 |
+
break;
|
4630 |
+
case 'days':
|
4631 |
+
$options = range(1, 31);
|
4632 |
+
|
4633 |
+
if( isset($_REQUEST['sucuriscan_day']) ){
|
4634 |
+
$selected = $_REQUEST['sucuriscan_day'];
|
4635 |
+
}
|
4636 |
+
break;
|
4637 |
+
}
|
4638 |
+
|
4639 |
+
if( $in_html ){
|
4640 |
+
$html_options = '';
|
4641 |
+
|
4642 |
+
foreach( $options as $key => $value ){
|
4643 |
+
if( is_numeric($value) ){ $value = str_pad($value, 2, 0, STR_PAD_LEFT); }
|
4644 |
+
|
4645 |
+
if( $type != 'months' ){ $key = $value; }
|
4646 |
+
|
4647 |
+
$selected_tag = ( $key == $selected ) ? 'selected="selected"' : '';
|
4648 |
+
$html_options .= sprintf( '<option value="%s" %s>%s</option>', $key, $selected_tag, $value );
|
4649 |
+
}
|
4650 |
+
|
4651 |
+
return $html_options;
|
4652 |
+
}
|
4653 |
+
|
4654 |
+
return $options;
|
4655 |
+
}
|
4656 |
+
|
4657 |
+
/**
|
4658 |
+
* Sucuri one-click hardening page.
|
4659 |
+
*
|
4660 |
+
* It loads all the functions defined in /lib/hardening.php and shows the forms
|
4661 |
+
* that the administrator can use to harden multiple parts of the site.
|
4662 |
+
*
|
4663 |
+
* @return void
|
4664 |
+
*/
|
4665 |
+
function sucuriscan_hardening_page(){
|
4666 |
+
|
4667 |
+
if( !current_user_can('manage_options') ){
|
4668 |
+
wp_die(__('You do not have sufficient permissions to access this page: Sucuri Hardening') );
|
4669 |
+
}
|
4670 |
+
|
4671 |
+
if( isset($_POST['wpsucuri-doharden']) ){
|
4672 |
+
if( !wp_verify_nonce($_POST['sucuriscan_hardening_nonce'], 'sucuriscan_hardening_nonce') ){
|
4673 |
+
unset($_POST['wpsucuri-doharden']);
|
4674 |
+
}
|
4675 |
+
}
|
4676 |
+
|
4677 |
+
ob_start();
|
4678 |
+
?>
|
4679 |
+
|
4680 |
+
<div id="poststuff">
|
4681 |
+
<form method="post">
|
4682 |
+
<input type="hidden" name="sucuriscan_hardening_nonce" value="<?php echo wp_create_nonce('sucuriscan_hardening_nonce'); ?>" />
|
4683 |
+
<input type="hidden" name="wpsucuri-doharden" value="wpsucuri-doharden" />
|
4684 |
+
|
4685 |
+
<?php
|
4686 |
+
sucuriscan_harden_version();
|
4687 |
+
sucuriscan_cloudproxy_enabled();
|
4688 |
+
sucuriscan_harden_removegenerator();
|
4689 |
+
sucuriscan_harden_upload();
|
4690 |
+
sucuriscan_harden_wpcontent();
|
4691 |
+
sucuriscan_harden_wpincludes();
|
4692 |
+
sucuriscan_harden_phpversion();
|
4693 |
+
sucuriscan_harden_secretkeys();
|
4694 |
+
sucuriscan_harden_readme();
|
4695 |
+
sucuriscan_harden_adminuser();
|
4696 |
+
sucuriscan_harden_fileeditor();
|
4697 |
+
sucuriscan_harden_dbtables();
|
4698 |
+
?>
|
4699 |
+
</form>
|
4700 |
+
</div>
|
4701 |
+
|
4702 |
+
<?php
|
4703 |
+
$_html = ob_get_contents();
|
4704 |
+
ob_end_clean();
|
4705 |
+
echo sucuriscan_get_base_template($_html, array(
|
4706 |
+
'PageTitle' => 'Hardening',
|
4707 |
+
'PageContent' => $_html,
|
4708 |
+
'PageStyleClass' => 'hardening'
|
4709 |
+
));
|
4710 |
+
return;
|
4711 |
+
}
|
4712 |
+
|
4713 |
+
/**
|
4714 |
+
* Generate the HTML code necessary to show a form with the options to harden
|
4715 |
+
* a specific part of the WordPress installation, if the Status variable is
|
4716 |
+
* set as a positive integer the button is shown as "unharden".
|
4717 |
+
*
|
4718 |
+
* @param string $title Title of the panel.
|
4719 |
+
* @param integer $status Either one or zero representing the state of the hardening, one for secure, zero for insecure.
|
4720 |
+
* @param string $type Name of the hardening option, this will be used through out the form generation.
|
4721 |
+
* @param string $messageok Message that will be shown if the hardening was executed.
|
4722 |
+
* @param string $messagewarn Message that will be shown if the hardening is not executed.
|
4723 |
+
* @param string $desc Optional description of the hardening.
|
4724 |
+
* @param string $updatemsg Optional explanation of the hardening after the submission of the form.
|
4725 |
+
* @return void
|
4726 |
+
*/
|
4727 |
+
function sucuriscan_harden_status( $title='', $status=0, $type='', $messageok='', $messagewarn='', $desc=NULL, $updatemsg=NULL ){ ?>
|
4728 |
+
<div class="postbox">
|
4729 |
+
<h3><?php _e($title) ?></h3>
|
4730 |
+
|
4731 |
+
<div class="inside">
|
4732 |
+
<?php if( $desc != NULL ): ?>
|
4733 |
+
<p><?php _e($desc) ?></p>
|
4734 |
+
<?php endif; ?>
|
4735 |
+
|
4736 |
+
<div class="sucuriscan-hstatus sucuriscan-hstatus-<?php _e($status) ?>">
|
4737 |
+
<?php if( $type != NULL ): ?>
|
4738 |
+
<?php if( $status == 1 ): ?>
|
4739 |
+
<input type="submit" name="<?php _e($type) ?>_unharden" value="Revert hardening" class="button-secondary" />
|
4740 |
+
<?php else: ?>
|
4741 |
+
<input type="submit" name="<?php _e($type) ?>" value="Harden" class="button-primary" />
|
4742 |
+
<?php endif; ?>
|
4743 |
+
<?php endif; ?>
|
4744 |
+
|
4745 |
+
<span>
|
4746 |
+
<?php if( $status == 1 ): ?>
|
4747 |
+
<?php _e($messageok) ?>
|
4748 |
+
<?php else: ?>
|
4749 |
+
<?php _e($messagewarn) ?>
|
4750 |
+
<?php endif; ?>
|
4751 |
+
</span>
|
4752 |
+
</div>
|
4753 |
+
|
4754 |
+
<?php if( $updatemsg != NULL ): ?>
|
4755 |
+
<p><?php _e($updatemsg) ?></p>
|
4756 |
+
<?php endif; ?>
|
4757 |
+
</div>
|
4758 |
+
</div>
|
4759 |
+
|
4760 |
+
<?php }
|
4761 |
+
|
4762 |
+
/**
|
4763 |
+
* Check whether the version number of the WordPress installed is the latest
|
4764 |
+
* version available officially.
|
4765 |
+
*
|
4766 |
+
* @return void
|
4767 |
+
*/
|
4768 |
+
function sucuriscan_harden_version(){
|
4769 |
+
global $wp_version;
|
4770 |
+
|
4771 |
+
$updates = get_core_updates();
|
4772 |
+
if(
|
4773 |
+
!is_array($updates)
|
4774 |
+
|| empty($updates)
|
4775 |
+
|| $updates[0]->response == 'latest'
|
4776 |
+
){
|
4777 |
+
$cp = 1;
|
4778 |
+
} else {
|
4779 |
+
$cp = 0;
|
4780 |
+
}
|
4781 |
+
|
4782 |
+
if(strcmp($wp_version, "3.7") < 0)
|
4783 |
+
{
|
4784 |
+
$cp = 0;
|
4785 |
+
}
|
4786 |
+
|
4787 |
+
$wp_version = htmlspecialchars($wp_version);
|
4788 |
+
$initial_msg = 'Why keep your site updated? WordPress is an open-source
|
4789 |
+
project which means that with every update the details of the changes made
|
4790 |
+
to the source code are made public, if there were security fixes then
|
4791 |
+
someone with malicious intent can use this information to attack any site
|
4792 |
+
that has not been upgraded.';
|
4793 |
+
$messageok = sprintf('Your WordPress installation (%s) is current.', $wp_version);
|
4794 |
+
$messagewarn = sprintf(
|
4795 |
+
'Your current version (%s) is not current.<br>
|
4796 |
+
<a href="update-core.php" class="button-primary">Update now!</a>',
|
4797 |
+
$wp_version
|
4798 |
+
);
|
4799 |
+
|
4800 |
+
sucuriscan_harden_status( 'Verify WordPress version', $cp, NULL, $messageok, $messagewarn, $initial_msg );
|
4801 |
+
}
|
4802 |
+
|
4803 |
+
/**
|
4804 |
+
* Notify the state of the hardening for the removal of the Generator tag in
|
4805 |
+
* HTML code printed by WordPress to show the current version number of the
|
4806 |
+
* installation.
|
4807 |
+
*
|
4808 |
+
* @return void
|
4809 |
+
*/
|
4810 |
+
function sucuriscan_harden_removegenerator(){
|
4811 |
+
sucuriscan_harden_status(
|
4812 |
+
'Remove WordPress version',
|
4813 |
+
1,
|
4814 |
+
NULL,
|
4815 |
+
'WordPress version properly hidden',
|
4816 |
+
NULL,
|
4817 |
+
'It checks if your WordPress version is being hidden from being displayed '
|
4818 |
+
.'in the generator tag (enabled by default with this plugin).'
|
4819 |
+
);
|
4820 |
+
}
|
4821 |
+
|
4822 |
+
/**
|
4823 |
+
* Check whether the WordPress upload folder is protected or not.
|
4824 |
+
*
|
4825 |
+
* A htaccess file is placed in the upload folder denying the access to any php
|
4826 |
+
* file that could be uploaded through a vulnerability in a Plugin, Theme or
|
4827 |
+
* WordPress itself.
|
4828 |
+
*
|
4829 |
+
* @return void
|
4830 |
+
*/
|
4831 |
+
function sucuriscan_harden_upload(){
|
4832 |
+
$cp = 1;
|
4833 |
+
$upmsg = NULL;
|
4834 |
+
$htaccess_upload = dirname(sucuriscan_dir_filepath())."/.htaccess";
|
4835 |
+
|
4836 |
+
if( !is_readable($htaccess_upload) ){
|
4837 |
+
$cp = 0;
|
4838 |
+
} else {
|
4839 |
+
$cp = 0;
|
4840 |
+
$fcontent = file($htaccess_upload);
|
4841 |
+
|
4842 |
+
foreach( $fcontent as $fline ){
|
4843 |
+
if( strpos($fline, 'deny from all') !== FALSE ){
|
4844 |
+
$cp = 1;
|
4845 |
+
break;
|
4846 |
+
}
|
4847 |
+
}
|
4848 |
+
}
|
4849 |
+
|
4850 |
+
if( isset($_POST['wpsucuri-doharden']) ){
|
4851 |
+
if( isset($_POST['sucuriscan_harden_upload']) && $cp == 0 ){
|
4852 |
+
if( @file_put_contents($htaccess_upload, "\n<Files *.php>\ndeny from all\n</Files>") === FALSE ){
|
4853 |
+
$upmsg = sucuriscan_error('ERROR: Unable to create <code>.htaccess</code> file, folder destination is not writable.');
|
4854 |
+
} else {
|
4855 |
+
$upmsg = sucuriscan_info('COMPLETE: Upload directory successfully hardened');
|
4856 |
+
$cp = 1;
|
4857 |
+
}
|
4858 |
+
}
|
4859 |
+
|
4860 |
+
elseif( isset($_POST['sucuriscan_harden_upload_unharden']) ){
|
4861 |
+
$htaccess_upload_writable = ( file_exists($htaccess_upload) && is_writable($htaccess_upload) ) ? TRUE : FALSE;
|
4862 |
+
$htaccess_content = $htaccess_upload_writable ? file_get_contents($htaccess_upload) : '';
|
4863 |
|
4864 |
+
if( $htaccess_upload_writable ){
|
4865 |
+
$cp = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4866 |
|
4867 |
+
if( preg_match('/<Files \*\.php>\ndeny from all\n<\/Files>/', $htaccess_content, $match) ){
|
4868 |
+
$htaccess_content = str_replace("<Files *.php>\ndeny from all\n</Files>", '', $htaccess_content);
|
4869 |
+
@file_put_contents($htaccess_upload, $htaccess_content, LOCK_EX);
|
4870 |
+
}
|
4871 |
|
4872 |
+
sucuriscan_info('Hardening removed for the WordPress upload directory <code>/wp-content/uploads</code>');
|
4873 |
+
} else {
|
4874 |
+
sucuriscan_error(
|
4875 |
+
'<code>wp-content/uploads/.htaccess</code> does not exists or is not
|
4876 |
+
writable, you will need to remove the following code (manually):
|
4877 |
+
<code><Files *.php>deny from all</Files></code>'
|
4878 |
+
);
|
4879 |
+
}
|
4880 |
+
}
|
4881 |
+
}
|
4882 |
|
4883 |
+
sucuriscan_harden_status(
|
4884 |
+
'Protect uploads directory',
|
4885 |
+
$cp,
|
4886 |
+
'sucuriscan_harden_upload',
|
4887 |
+
'Upload directory properly hardened',
|
4888 |
+
'Upload directory not hardened',
|
4889 |
+
'It checks if your upload directory allows PHP execution or if it is browsable.',
|
4890 |
+
$upmsg
|
4891 |
+
);
|
4892 |
+
}
|
4893 |
|
4894 |
+
/**
|
4895 |
+
* Check whether the WordPress content folder is protected or not.
|
4896 |
+
*
|
4897 |
+
* A htaccess file is placed in the content folder denying the access to any php
|
4898 |
+
* file that could be uploaded through a vulnerability in a Plugin, Theme or
|
4899 |
+
* WordPress itself.
|
4900 |
+
*
|
4901 |
+
* @return void
|
4902 |
+
*/
|
4903 |
+
function sucuriscan_harden_wpcontent(){
|
4904 |
+
$cp = 1;
|
4905 |
+
$upmsg = NULL;
|
4906 |
+
$htaccess_upload = ABSPATH . '/wp-content/.htaccess';
|
|
|
|
|
|
|
|
|
|
|
|
|
4907 |
|
4908 |
+
if( !is_readable($htaccess_upload) ){
|
4909 |
+
$cp = 0;
|
4910 |
+
} else {
|
4911 |
+
$cp = 0;
|
4912 |
+
$fcontent = file($htaccess_upload);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4913 |
|
4914 |
+
foreach( $fcontent as $fline ){
|
4915 |
+
if( strpos($fline, 'deny from all') !== FALSE ){
|
4916 |
+
$cp = 1;
|
4917 |
+
break;
|
4918 |
+
}
|
4919 |
+
}
|
4920 |
+
}
|
4921 |
|
4922 |
+
if( isset($_POST['wpsucuri-doharden']) ){
|
4923 |
+
if( isset($_POST['sucuriscan_harden_wpcontent']) && $cp == 0 ){
|
4924 |
+
if( @file_put_contents($htaccess_upload, "\n<Files *.php>\ndeny from all\n</Files>") === FALSE ){
|
4925 |
+
$upmsg = sucuriscan_error('ERROR: Unable to create <code>.htaccess</code> file, folder destination is not writable.');
|
4926 |
+
} else {
|
4927 |
+
$upmsg = sucuriscan_info('COMPLETE: wp-content directory successfully hardened');
|
4928 |
+
$cp = 1;
|
4929 |
+
}
|
4930 |
+
}
|
|
|
|
|
|
|
|
|
|
|
4931 |
|
4932 |
+
elseif( isset($_POST['sucuriscan_harden_wpcontent_unharden']) ){
|
4933 |
+
$htaccess_upload_writable = ( file_exists($htaccess_upload) && is_writable($htaccess_upload) ) ? TRUE : FALSE;
|
4934 |
+
$htaccess_content = $htaccess_upload_writable ? file_get_contents($htaccess_upload) : '';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4935 |
|
4936 |
+
if( $htaccess_upload_writable ){
|
4937 |
+
$cp = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4938 |
|
4939 |
+
if( preg_match('/<Files \*\.php>\ndeny from all\n<\/Files>/', $htaccess_content, $match) ){
|
4940 |
+
$htaccess_content = str_replace("<Files *.php>\ndeny from all\n</Files>", '', $htaccess_content);
|
4941 |
+
@file_put_contents($htaccess_upload, $htaccess_content, LOCK_EX);
|
4942 |
+
}
|
|
|
|
|
|
|
|
|
4943 |
|
4944 |
+
sucuriscan_info('WP-Content directory protection reverted.');
|
4945 |
+
} else {
|
4946 |
+
sucuriscan_info(
|
4947 |
+
'<code>wp-content/.htaccess</code> does not exists or is not writable,
|
4948 |
+
you will need to remove the following code manually there:
|
4949 |
+
<code><Files *.php>deny from all</Files></code>'
|
4950 |
+
);
|
4951 |
+
}
|
4952 |
+
}
|
4953 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
4954 |
|
4955 |
+
sucuriscan_harden_status(
|
4956 |
+
'Restrict wp-content access',
|
4957 |
+
$cp,
|
4958 |
+
'sucuriscan_harden_wpcontent',
|
4959 |
+
'WP-content directory properly hardened',
|
4960 |
+
'WP-content directory not hardened',
|
4961 |
+
'This option blocks direct PHP access to any file inside wp-content. If you experience any '
|
4962 |
+
.'issue after this with a theme or plugin in your site, like for example images not displaying, '
|
4963 |
+
.'remove the <code>.htaccess</code> file located at the <code>/wp-content/</code> directory.',
|
4964 |
+
$upmsg
|
4965 |
+
);
|
4966 |
+
}
|
4967 |
|
4968 |
+
/**
|
4969 |
+
* Check whether the WordPress includes folder is protected or not.
|
4970 |
+
*
|
4971 |
+
* A htaccess file is placed in the includes folder denying the access to any php
|
4972 |
+
* file that could be uploaded through a vulnerability in a Plugin, Theme or
|
4973 |
+
* WordPress itself, there are some exceptions for some specific files that must
|
4974 |
+
* be available publicly.
|
4975 |
+
*
|
4976 |
+
* @return void
|
4977 |
+
*/
|
4978 |
+
function sucuriscan_harden_wpincludes(){
|
4979 |
+
$cp = 1;
|
4980 |
+
$upmsg = NULL;
|
4981 |
+
$htaccess_upload = ABSPATH . '/wp-includes/.htaccess';
|
4982 |
|
4983 |
+
if( !is_readable($htaccess_upload) ){
|
4984 |
+
$cp = 0;
|
4985 |
+
} else {
|
4986 |
+
$cp = 0;
|
4987 |
+
$fcontent = file($htaccess_upload);
|
|
|
|
|
|
|
|
|
|
|
4988 |
|
4989 |
+
foreach( $fcontent as $fline ){
|
4990 |
+
if( strpos($fline, 'deny from all') !== FALSE ){
|
4991 |
+
$cp = 1;
|
4992 |
+
break;
|
4993 |
+
}
|
4994 |
+
}
|
4995 |
+
}
|
|
|
4996 |
|
4997 |
+
if( isset($_POST['wpsucuri-doharden']) ){
|
4998 |
+
if( isset($_POST['sucuriscan_harden_wpincludes']) && $cp == 0 ){
|
4999 |
+
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 ){
|
5000 |
+
$upmsg = sucuriscan_error('ERROR: Unable to create <code>.htaccess</code> file, folder destination is not writable.');
|
5001 |
+
} else {
|
5002 |
+
$upmsg = sucuriscan_info('COMPLETE: wp-includes directory successfully hardened.');
|
5003 |
+
$cp = 1;
|
5004 |
+
}
|
5005 |
+
}
|
5006 |
|
5007 |
+
elseif( isset($_POST['sucuriscan_harden_wpincludes_unharden']) ){
|
5008 |
+
$htaccess_upload_writable = ( file_exists($htaccess_upload) && is_writable($htaccess_upload) ) ? TRUE : FALSE;
|
5009 |
+
$htaccess_content = $htaccess_upload_writable ? file_get_contents($htaccess_upload) : '';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5010 |
|
5011 |
+
if( $htaccess_upload_writable ){
|
5012 |
+
$cp = 0;
|
5013 |
+
if( preg_match_all('/<Files (\*|wp-tinymce|ms-files)\.php>\n(deny|allow) from all\n<\/Files>/', $htaccess_content, $match) ){
|
5014 |
+
foreach($match[0] as $restriction){
|
5015 |
+
$htaccess_content = str_replace($restriction, '', $htaccess_content);
|
5016 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5017 |
|
5018 |
+
@file_put_contents($htaccess_upload, $htaccess_content, LOCK_EX);
|
5019 |
+
}
|
5020 |
+
sucuriscan_info('WP-Includes directory protection reverted.');
|
5021 |
+
} else {
|
5022 |
+
sucuriscan_error(
|
5023 |
+
'<code>wp-includes/.htaccess</code> does not exists or is not
|
5024 |
+
writable, you will need to remove the following code manually
|
5025 |
+
there: <code><Files *.php>deny from all</Files></code>'
|
5026 |
+
);
|
5027 |
+
}
|
5028 |
+
}
|
5029 |
+
}
|
5030 |
|
5031 |
+
sucuriscan_harden_status(
|
5032 |
+
'Restrict wp-includes access',
|
5033 |
+
$cp,
|
5034 |
+
'sucuriscan_harden_wpincludes',
|
5035 |
+
'WP-Includes directory properly hardened',
|
5036 |
+
'WP-Includes directory not hardened',
|
5037 |
+
'This option blocks direct PHP access to any file inside <code>wp-includes</code>.',
|
5038 |
+
$upmsg
|
5039 |
+
);
|
5040 |
+
}
|
5041 |
|
5042 |
+
/**
|
5043 |
+
* Check the version number of the PHP interpreter set to work with the site,
|
5044 |
+
* is considered that old versions of the PHP interpreter are insecure.
|
5045 |
+
*
|
5046 |
+
* @return void
|
5047 |
+
*/
|
5048 |
+
function sucuriscan_harden_phpversion(){
|
5049 |
+
$phpv = phpversion();
|
5050 |
+
$cp = ( strncmp($phpv, '5.', 2) < 0 ) ? 0 : 1;
|
5051 |
|
5052 |
+
sucuriscan_harden_status(
|
5053 |
+
'Verify PHP version',
|
5054 |
+
$cp,
|
5055 |
+
NULL,
|
5056 |
+
'Using an updated version of PHP (' . $phpv . ')',
|
5057 |
+
'The version of PHP you are using (' . $phpv . ') is not current, not recommended, and/or not supported',
|
5058 |
+
'This checks if you have the latest version of PHP installed.',
|
5059 |
+
NULL
|
5060 |
+
);
|
5061 |
}
|
5062 |
|
5063 |
/**
|
5064 |
+
* Check whether the site is behind a secure proxy server or not.
|
|
|
|
|
|
|
|
|
5065 |
*
|
5066 |
* @return void
|
5067 |
*/
|
5068 |
+
function sucuriscan_cloudproxy_enabled(){
|
5069 |
+
$btn_string = '';
|
5070 |
+
$enabled = sucuriscan_is_behind_cloudproxy();
|
5071 |
+
$status = 1;
|
5072 |
|
5073 |
+
if( $enabled !== TRUE ){
|
5074 |
+
$status = 0;
|
5075 |
+
$btn_string = '<a href="http://cloudproxy.sucuri.net/" target="_blank" class="button button-primary">Harden</a>';
|
5076 |
}
|
5077 |
|
5078 |
+
sucuriscan_harden_status(
|
5079 |
+
'Website Firewall protection',
|
5080 |
+
$status,
|
5081 |
+
NULL,
|
5082 |
+
'Your website is protected by a Website Firewall (WAF)',
|
5083 |
+
$btn_string . 'Your website is not protected by a Website Firewall (WAF)',
|
5084 |
+
'A WAF is a protection layer for your web site, blocking all sort of attacks (brute force attempts, DDoS, '
|
5085 |
+
.'SQL injections, etc) and helping it remain malware and blacklist free. This test checks if your site is '
|
5086 |
+
.'using <a href="http://cloudproxy.sucuri.net/" target="_blank">Sucuri\'s CloudProxy WAF</a> to protect your site. ',
|
5087 |
+
NULL
|
5088 |
+
);
|
5089 |
+
}
|
5090 |
|
5091 |
+
/**
|
5092 |
+
* Check whether the Wordpress configuration file has the security keys recommended
|
5093 |
+
* to avoid any unauthorized access to the interface.
|
5094 |
+
*
|
5095 |
+
* WordPress Security Keys is a set of random variables that improve encryption of
|
5096 |
+
* information stored in the user’s cookies. There are a total of four security
|
5097 |
+
* keys: AUTH_KEY, SECURE_AUTH_KEY, LOGGED_IN_KEY, and NONCE_KEY.
|
5098 |
+
*
|
5099 |
+
* @return void
|
5100 |
+
*/
|
5101 |
+
function sucuriscan_harden_secretkeys(){
|
5102 |
+
$wp_config_path = sucuriscan_get_wpconfig_path();
|
5103 |
|
5104 |
+
if( $wp_config_path ){
|
5105 |
+
$cp = 1;
|
5106 |
+
$message = 'The main configuration file was found at: <code>'.$wp_config_path.'</code><br>';
|
5107 |
+
|
5108 |
+
$secret_key_names = array(
|
5109 |
+
'AUTH_KEY',
|
5110 |
+
'SECURE_AUTH_KEY',
|
5111 |
+
'LOGGED_IN_KEY',
|
5112 |
+
'NONCE_KEY',
|
5113 |
+
'AUTH_SALT',
|
5114 |
+
'SECURE_AUTH_SALT',
|
5115 |
+
'LOGGED_IN_SALT',
|
5116 |
+
'NONCE_SALT',
|
5117 |
);
|
5118 |
|
5119 |
+
foreach( $secret_key_names as $key_name){
|
5120 |
+
if( !defined($key_name) ){
|
5121 |
+
$cp = 0;
|
5122 |
+
$message .= 'The secret key <strong>'.$key_name.'</strong> is not defined.<br>';
|
5123 |
+
} elseif( constant($key_name) == 'put your unique phrase here' ){
|
5124 |
+
$cp = 0;
|
5125 |
+
$message .= 'The secret key <strong>'.$key_name.'</strong> is not properly set.<br>';
|
5126 |
+
}
|
5127 |
+
}
|
5128 |
|
5129 |
+
if( $cp == 0 ){
|
5130 |
+
$admin_url = admin_url('admin.php?page=sucuriscan_posthack');
|
5131 |
+
$message .= '<br><a href="'.$admin_url.'" class="button button-primary">Update WP-Config Keys</a><br>';
|
5132 |
+
}
|
5133 |
+
}else{
|
5134 |
+
$cp = 0;
|
5135 |
+
$message = 'The <code>wp-config</code> file was not found.<br>';
|
5136 |
+
}
|
5137 |
|
5138 |
+
$message .= '<br>It checks whether you have proper random keys/salts created for WordPress. A
|
5139 |
+
<a href="http://codex.wordpress.org/Editing_wp-config.php#Security_Keys" target="_blank">
|
5140 |
+
secret key</a> makes your site harder to hack and access harder to crack by adding
|
5141 |
+
random elements to the password. In simple terms, a secret key is a password with
|
5142 |
+
elements that make it harder to generate enough options to break through your
|
5143 |
+
security barriers.';
|
|
|
5144 |
|
5145 |
+
sucuriscan_harden_status(
|
5146 |
+
'Secret keys validity',
|
5147 |
+
$cp,
|
5148 |
+
NULL,
|
5149 |
+
'WordPress secret keys and salts properly created',
|
5150 |
+
'WordPress secret keys and salts not set, we recommend creating them for security reasons',
|
5151 |
+
$message,
|
5152 |
+
NULL
|
5153 |
+
);
|
5154 |
}
|
5155 |
|
5156 |
/**
|
5157 |
+
* Check whether the "readme.html" file is still available in the root of the
|
5158 |
+
* site or not, which can lead to an attacker to know which version number of
|
5159 |
+
* Wordpress is being used and search for possible vulnerabilities.
|
5160 |
*
|
|
|
|
|
|
|
5161 |
* @return void
|
5162 |
*/
|
5163 |
+
function sucuriscan_harden_readme(){
|
5164 |
+
$upmsg = NULL;
|
5165 |
+
$cp = is_readable(ABSPATH.'/readme.html') ? 0 : 1;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5166 |
|
5167 |
+
if( isset($_POST['wpsucuri-doharden']) ){
|
5168 |
+
if( isset($_POST['sucuriscan_harden_readme']) && $cp == 0 ){
|
5169 |
+
if( @unlink(ABSPATH.'/readme.html') === FALSE ){
|
5170 |
+
$upmsg = sucuriscan_error('Unable to remove <code>readme.html</code> file.');
|
5171 |
+
} else {
|
5172 |
+
$cp = 1;
|
5173 |
+
$upmsg = sucuriscan_info('<code>readme.html</code> file removed successfully.');
|
5174 |
}
|
5175 |
+
}
|
5176 |
+
|
5177 |
+
elseif( isset($_POST['sucuriscan_harden_readme_unharden']) ){
|
5178 |
+
sucuriscan_error('We can not revert this action, you should create the <code>readme.html</code> file at your own.');
|
5179 |
+
}
|
5180 |
+
}
|
5181 |
+
|
5182 |
+
sucuriscan_harden_status(
|
5183 |
+
'Information leakage (readme.html)',
|
5184 |
+
$cp,
|
5185 |
+
'sucuriscan_harden_readme',
|
5186 |
+
'<code>readme.html</code> file properly deleted',
|
5187 |
+
'<code>readme.html</code> not deleted and leaking the WordPress version',
|
5188 |
+
'It checks whether you have the <code>readme.html</code> file available that leaks your WordPress version',
|
5189 |
+
$upmsg
|
5190 |
+
);
|
5191 |
+
}
|
5192 |
|
5193 |
/**
|
5194 |
+
* Check whether the main administrator user still has the default name "admin"
|
5195 |
+
* or not, which can lead to an attacker to perform a brute force attack.
|
5196 |
*
|
5197 |
* @return void
|
5198 |
*/
|
5199 |
+
function sucuriscan_harden_adminuser(){
|
5200 |
+
global $wpdb;
|
5201 |
+
|
5202 |
+
$upmsg = NULL;
|
5203 |
+
$res = $wpdb->get_results("SELECT user_login FROM {$wpdb->prefix}users WHERE user_login = 'admin'");
|
5204 |
+
$account_removed = ( count($res) == 0 ? 1 : 0 );
|
5205 |
+
|
5206 |
+
if( $account_removed == 0 ){
|
5207 |
+
$upmsg = '<i><strong>We do not offer the option</strong> to automatically change the user name.
|
5208 |
+
Go to the <a href="'.admin_url('users.php').'" target="_blank">user list</a> and create a new
|
5209 |
+
admin user name. Once created, log in as that user and remove the default "admin" from there
|
5210 |
+
(make sure to assign all the admin posts to the new user too!).</i>';
|
5211 |
+
}
|
5212 |
+
|
5213 |
+
sucuriscan_harden_status(
|
5214 |
+
'Default admin account',
|
5215 |
+
$account_removed,
|
5216 |
+
NULL,
|
5217 |
+
'Default admin user account (admin) not being used',
|
5218 |
+
'Default admin user account (admin) being used. Not recommended',
|
5219 |
+
'It checks whether you have the default <code>admin</code> account enabled, security guidelines recommend creating a new admin user name.',
|
5220 |
+
$upmsg
|
5221 |
+
);
|
5222 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5223 |
|
5224 |
/**
|
5225 |
+
* Enable or disable the user of the built-in Wordpress file editor.
|
|
|
5226 |
*
|
5227 |
+
* @return void
|
|
|
|
|
5228 |
*/
|
5229 |
+
function sucuriscan_harden_fileeditor(){
|
5230 |
+
$file_editor_disabled = defined('DISALLOW_FILE_EDIT') ? DISALLOW_FILE_EDIT : FALSE;
|
|
|
5231 |
|
5232 |
+
if( isset($_POST['wpsucuri-doharden']) ){
|
5233 |
+
$current_time = date('r');
|
5234 |
+
$wp_config_path = sucuriscan_get_wpconfig_path();
|
|
|
|
|
|
|
|
|
|
|
5235 |
|
5236 |
+
$wp_config_writable = ( file_exists($wp_config_path) && is_writable($wp_config_path) ) ? TRUE : FALSE;
|
5237 |
+
$new_wpconfig = $wp_config_writable ? file_get_contents($wp_config_path) : '';
|
5238 |
|
5239 |
+
if( isset($_POST['sucuriscan_harden_fileeditor']) ){
|
5240 |
+
if( $wp_config_writable ){
|
5241 |
+
if( preg_match('/(.*define\(.DB_COLLATE..*)/', $new_wpconfig, $match) ){
|
5242 |
+
$disallow_fileedit_definition = "\n\ndefine('DISALLOW_FILE_EDIT', TRUE); // Sucuri Security: {$current_time}\n";
|
5243 |
+
$new_wpconfig = str_replace($match[0], $match[0].$disallow_fileedit_definition, $new_wpconfig);
|
5244 |
}
|
5245 |
|
5246 |
+
@file_put_contents($wp_config_path, $new_wpconfig, LOCK_EX);
|
5247 |
+
sucuriscan_info( 'WP-Config file updated successfully, the plugin and theme editor was disabled.' );
|
5248 |
+
$file_editor_disabled = TRUE;
|
5249 |
+
} else {
|
5250 |
+
sucuriscan_error( 'The <code>wp-config.php</code> file is not in the default location
|
5251 |
+
or is not writable, you will need to put the following code manually there:
|
5252 |
+
<code>define("DISALLOW_FILE_EDIT", TRUE);</code>' );
|
5253 |
}
|
5254 |
+
}
|
5255 |
|
5256 |
+
elseif( isset($_POST['sucuriscan_harden_fileeditor_unharden']) ){
|
5257 |
+
if( preg_match("/(.*define\('DISALLOW_FILE_EDIT', TRUE\);.*)/", $new_wpconfig, $match) ){
|
5258 |
+
if( $wp_config_writable ){
|
5259 |
+
$new_wpconfig = str_replace("\n{$match[1]}", '', $new_wpconfig);
|
5260 |
+
file_put_contents($wp_config_path, $new_wpconfig, LOCK_EX);
|
5261 |
+
sucuriscan_info( 'WP-Config file updated successfully, the plugin and theme editor was enabled.' );
|
5262 |
+
$file_editor_disabled = FALSE;
|
5263 |
+
} else {
|
5264 |
+
sucuriscan_error( 'The <code>wp-config.php</code> file is not in the default location
|
5265 |
+
or is not writable, you will need to remove the following code manually from there:
|
5266 |
+
<code>define("DISALLOW_FILE_EDIT", TRUE);</code>' );
|
5267 |
+
}
|
5268 |
+
} else {
|
5269 |
+
sucuriscan_error( 'We did not find a definition to disallow the file editor.' );
|
5270 |
}
|
5271 |
}
|
5272 |
}
|
5273 |
|
5274 |
+
$message = 'Occasionally you may wish to disable the plugin or theme editor to prevent overzealous users
|
5275 |
+
from being able to edit sensitive files and potentially crash the site. Disabling these also
|
5276 |
+
provides an additional layer of security if a hacker gains access to a well-privileged user
|
5277 |
+
account.';
|
5278 |
+
|
5279 |
+
sucuriscan_harden_status(
|
5280 |
+
'Plugin & Theme editor',
|
5281 |
+
( $file_editor_disabled === FALSE ? 0 : 1 ),
|
5282 |
+
'sucuriscan_harden_fileeditor',
|
5283 |
+
'File editor for Plugins and Themes is disabled',
|
5284 |
+
'File editor for Plugins and Themes is enabled',
|
5285 |
+
$message,
|
5286 |
+
NULL
|
5287 |
+
);
|
5288 |
}
|
5289 |
|
5290 |
/**
|
5291 |
+
* Check whether the prefix of each table in the database designated for the site
|
5292 |
+
* is the same as the default prefix defined by Wordpress "_wp", in that case the
|
5293 |
+
* "harden" button will generate randomly a new prefix and rename all those tables.
|
5294 |
*
|
5295 |
* @return void
|
5296 |
*/
|
5297 |
+
function sucuriscan_harden_dbtables(){
|
5298 |
+
global $table_prefix;
|
|
|
5299 |
|
5300 |
+
$hardened = ( $table_prefix == 'wp_' ? 0 : 1 );
|
5301 |
|
5302 |
+
if(
|
5303 |
+
isset($_POST['wpsucuri-doharden'])
|
5304 |
+
&& (
|
5305 |
+
isset($_POST['sucuriscan_harden_dbtables']) ||
|
5306 |
+
isset($_POST['sucuriscan_harden_dbtables_unharden'])
|
5307 |
+
)
|
5308 |
+
){
|
5309 |
+
$sucuri_backup = new SucuriScanBackup();
|
5310 |
+
$dbbackup_filepath = $sucuri_backup->all_database();
|
5311 |
+
|
5312 |
+
if( $dbbackup_filepath ){
|
5313 |
+
sucuriscan_info( 'A new database table prefix change was initialized, if you have
|
5314 |
+
problems after this operation finishes you can find a backup of the current
|
5315 |
+
database here: <code>'.$dbbackup_filepath.'</code>' );
|
5316 |
+
|
5317 |
+
if( isset($_POST['sucuriscan_harden_dbtables']) ){
|
5318 |
+
$hardened = 1;
|
5319 |
+
$sucuri_backup->new_table_prefix();
|
5320 |
+
} elseif( isset($_POST['sucuriscan_harden_dbtables_unharden']) ){
|
5321 |
+
$hardened = 0;
|
5322 |
+
$sucuri_backup->reset_table_prefix();
|
5323 |
+
}
|
5324 |
+
} else {
|
5325 |
+
sucuriscan_error( 'Error generating a backup for your database.' );
|
5326 |
+
}
|
5327 |
}
|
|
|
5328 |
|
5329 |
+
sucuriscan_harden_status(
|
5330 |
+
'Database table prefix',
|
5331 |
+
$hardened,
|
5332 |
+
'sucuriscan_harden_dbtables',
|
5333 |
+
'Database table prefix properly modified',
|
5334 |
+
'Database table set to the default value <code>wp_</code>.',
|
5335 |
+
'It checks whether your database table prefix has been changed from the default <code>wp_</code>',
|
5336 |
+
'<strong>Be aware that this hardening procedure can cause your site to go down</strong>'
|
5337 |
+
);
|
5338 |
+
}
|
5339 |
+
|
5340 |
+
/**
|
5341 |
+
* WordPress core integrity page.
|
5342 |
+
*
|
5343 |
+
* It checks whether the WordPress core files are the original ones, and the state
|
5344 |
+
* of the themes and plugins reporting the availability of updates. It also checks
|
5345 |
+
* the user accounts under the administrator group.
|
5346 |
+
*
|
5347 |
+
* @return void
|
5348 |
+
*/
|
5349 |
+
function sucuriscan_page(){
|
5350 |
+
if( !current_user_can('manage_options') ){
|
5351 |
+
wp_die(__('You do not have sufficient permissions to access this page: Sucuri Integrity Check') );
|
5352 |
}
|
5353 |
+
|
5354 |
+
sucuriscan_integrity_form_submissions();
|
5355 |
+
|
5356 |
+
$template_variables = array(
|
5357 |
+
'WordpressVersion' => sucuriscan_wordpress_outdated(),
|
5358 |
+
'AuditLogs' => sucuriscan_auditlogs(),
|
5359 |
+
'CoreFiles' => sucuriscan_core_files(),
|
5360 |
+
);
|
5361 |
+
|
5362 |
+
echo sucuriscan_get_template('integrity', $template_variables);
|
5363 |
}
|
5364 |
|
5365 |
/**
|
5366 |
+
* Process the requests sent by the form submissions originated in the integrity
|
5367 |
+
* page, all forms must have a nonce field that will be checked agains the one
|
5368 |
+
* generated in the template render function.
|
5369 |
*
|
|
|
5370 |
* @return void
|
5371 |
*/
|
5372 |
+
function sucuriscan_integrity_form_submissions(){
|
5373 |
+
if( sucuriscan_check_page_nonce() ){
|
5374 |
+
|
5375 |
+
// Manually force a filesystem scan (by an administrator user).
|
5376 |
+
if( isset($_POST['sucuriscan_force_scan']) ){
|
5377 |
+
if( current_user_can('manage_options') ){
|
5378 |
+
sucuriscan_notify_event( 'plugin_change', 'Filesystem scan forced at: ' . date('r') );
|
5379 |
+
sucuriscan_filesystem_scan(TRUE);
|
5380 |
+
} else {
|
5381 |
+
sucuriscan_error( 'Your privileges are not sufficient to execute this action.' );
|
5382 |
+
}
|
5383 |
+
}
|
5384 |
+
|
5385 |
+
}
|
5386 |
+
}
|
|
|
|
|
|
|
|
|
5387 |
|
5388 |
/**
|
5389 |
+
* Retrieve a list of md5sum and last modification time of all the files in the
|
5390 |
+
* folder specified. This is a recursive function.
|
5391 |
*
|
5392 |
+
* @param string $dir The base path where the scanning will start.
|
5393 |
+
* @param boolean $recursive Either TRUE or FALSE if the scan should be performed recursively.
|
5394 |
+
* @return array List of arrays containing the md5sum and last modification time of the files found.
|
5395 |
+
*/
|
5396 |
+
function sucuriscan_get_integrity_tree( $dir='./', $recursive=FALSE ){
|
5397 |
+
$abs_path = rtrim( ABSPATH, '/' );
|
5398 |
+
|
5399 |
+
$sucuri_fileinfo = new SucuriScanFileInfo();
|
5400 |
+
$sucuri_fileinfo->ignore_files = FALSE;
|
5401 |
+
$sucuri_fileinfo->ignore_directories = FALSE;
|
5402 |
+
$sucuri_fileinfo->run_recursively = $recursive;
|
5403 |
+
$integrity_tree = $sucuri_fileinfo->get_directory_tree_md5( $dir, 'opendir', TRUE );
|
5404 |
+
|
5405 |
+
if( $integrity_tree ){
|
5406 |
+
return $integrity_tree;
|
5407 |
+
}
|
5408 |
+
|
5409 |
+
return FALSE;
|
5410 |
+
}
|
5411 |
+
|
5412 |
+
/**
|
5413 |
+
* Print a HTML code with the content of the logs audited by the remote Sucuri
|
5414 |
+
* API service, this page is part of the monitoring tool.
|
5415 |
*
|
5416 |
* @return void
|
5417 |
*/
|
5418 |
+
function sucuriscan_auditlogs(){
|
5419 |
|
5420 |
+
$audit_logs = sucuriscan_get_logs();
|
5421 |
+
$max_per_page = SUCURISCAN_AUDITLOGS_PER_PAGE;
|
5422 |
+
$show_all = isset($_GET['show_all']) ? TRUE : FALSE;
|
5423 |
|
|
|
5424 |
$template_variables = array(
|
5425 |
+
'PageTitle' => 'Audit Logs',
|
5426 |
+
'AuditLogs.List' => '',
|
5427 |
+
'AuditLogs.Count' => 0,
|
5428 |
+
'AuditLogs.NoItemsVisibility' => 'visible',
|
5429 |
+
'AuditLogs.MaxItemsVisibility' => 'hidden',
|
5430 |
+
'AuditLogs.MaxPerPage' => $max_per_page,
|
5431 |
);
|
5432 |
|
5433 |
+
if( $audit_logs ){
|
5434 |
+
$counter_i = 0;
|
5435 |
+
$total_items = count($audit_logs->output_data);
|
5436 |
|
5437 |
+
$template_variables['AuditLogs.Count'] = $total_items;
|
5438 |
+
$template_variables['AuditLogs.NoItemsVisibility'] = 'hidden';
|
5439 |
|
5440 |
+
if( $total_items > $max_per_page && !$show_all ){
|
5441 |
+
$template_variables['AuditLogs.MaxItemsVisibility'] = 'visible';
|
5442 |
+
}
|
|
|
|
|
|
|
5443 |
|
5444 |
+
foreach( $audit_logs->output_data as $audit_log ){
|
5445 |
+
if( $counter_i > $max_per_page && !$show_all ){ break; }
|
|
|
5446 |
|
5447 |
+
$css_class = ( $counter_i % 2 == 0 ) ? '' : 'alternate';
|
5448 |
+
$snippet_data = array(
|
5449 |
+
'AuditLog.CssClass' => $css_class,
|
5450 |
+
'AuditLog.DateTime' => date( 'd/M/Y H:i:s', $audit_log['timestamp'] ),
|
5451 |
+
'AuditLog.Account' => $audit_log['account'],
|
5452 |
+
'AuditLog.Message' => $audit_log['message'],
|
5453 |
+
'AuditLog.Extra' => '',
|
5454 |
+
);
|
5455 |
+
|
5456 |
+
// Print every extra information item in a separate table.
|
5457 |
+
if( $audit_log['extra'] ){
|
5458 |
+
$css_scrollable = $audit_log['extra_total'] > 10 ? 'sucuriscan-list-as-table-scrollable' : '';
|
5459 |
+
$snippet_data['AuditLog.Extra'] .= '<ul class="sucuriscan-list-as-table ' . $css_scrollable . '">';
|
5460 |
+
foreach( $audit_log['extra'] as $log_extra ){
|
5461 |
+
$snippet_data['AuditLog.Extra'] .= '<li>' . $log_extra . '</li>';
|
5462 |
+
}
|
5463 |
+
$snippet_data['AuditLog.Extra'] .= '</ul>';
|
5464 |
+
$snippet_data['AuditLog.Extra'] .= '<small>For Mac users, this is a scrollable container</small>';
|
5465 |
}
|
5466 |
+
|
5467 |
+
$template_variables['AuditLogs.List'] .= sucuriscan_get_snippet('integrity-auditlogs', $snippet_data);
|
5468 |
+
$counter_i += 1;
|
5469 |
}
|
5470 |
+
}
|
5471 |
+
|
5472 |
+
return sucuriscan_get_section('integrity-auditlogs', $template_variables);
|
5473 |
+
}
|
5474 |
+
|
5475 |
+
/**
|
5476 |
+
* Check whether the WordPress version is outdated or not.
|
5477 |
+
*
|
5478 |
+
* @return string Panel with a warning advising that WordPress is outdated.
|
5479 |
+
*/
|
5480 |
+
function sucuriscan_wordpress_outdated(){
|
5481 |
+
global $wp_version;
|
5482 |
+
|
5483 |
+
$cp = 0;
|
5484 |
+
$updates = get_core_updates();
|
5485 |
+
|
5486 |
+
if(
|
5487 |
+
!is_array($updates)
|
5488 |
+
|| empty($updates)
|
5489 |
+
|| $updates[0]->response=='latest'
|
5490 |
+
){
|
5491 |
+
$cp = 1;
|
5492 |
+
}
|
5493 |
+
|
5494 |
+
if( strcmp($wp_version, '3.7') < 0 ){
|
5495 |
+
$cp = 0;
|
5496 |
+
}
|
5497 |
+
|
5498 |
+
$template_variables = array(
|
5499 |
+
'WordPress.Version' => $wp_version,
|
5500 |
+
'WordPress.UpgradeURL' => admin_url('update-core.php'),
|
5501 |
+
'WordPress.UpdateVisibility' => 'hidden',
|
5502 |
+
);
|
5503 |
+
|
5504 |
+
$wp_version = htmlspecialchars($wp_version);
|
5505 |
|
5506 |
+
if( $cp == 0 ){
|
5507 |
+
$template_variables['WordPress.UpdateVisibility'] = 'visible';
|
5508 |
}
|
5509 |
|
5510 |
+
return sucuriscan_get_section('integrity-wpoutdate', $template_variables);
|
5511 |
}
|
5512 |
|
5513 |
/**
|
5514 |
+
* Compare the md5sum of the core files in the current site with the hashes hosted
|
5515 |
+
* remotely in Sucuri servers. These hashes are updated every time a new version
|
5516 |
+
* of WordPress is released.
|
5517 |
*
|
5518 |
* @return void
|
5519 |
*/
|
5520 |
+
function sucuriscan_core_files(){
|
5521 |
+
global $wp_version;
|
5522 |
|
5523 |
+
$template_variables = array(
|
5524 |
+
'CoreFiles.List' => '',
|
5525 |
+
'CoreFiles.ListCount' => 0,
|
5526 |
+
'CoreFiles.GoodVisibility' => 'visible',
|
5527 |
+
'CoreFiles.BadVisibility' => 'hidden',
|
5528 |
+
);
|
5529 |
|
5530 |
+
if( $wp_version ){
|
5531 |
+
$latest_hashes = sucuriscan_check_wp_integrity($wp_version);
|
|
|
|
|
|
|
|
|
|
|
5532 |
|
5533 |
+
if( $latest_hashes ){
|
5534 |
+
$counter = 0;
|
5535 |
+
|
5536 |
+
foreach( $latest_hashes as $list_type => $file_list ){
|
5537 |
+
if(
|
5538 |
+
$list_type == 'stable'
|
5539 |
+
|| empty($file_list)
|
5540 |
+
){
|
5541 |
+
continue;
|
5542 |
+
}
|
5543 |
+
|
5544 |
+
foreach( $file_list as $file_path ){
|
5545 |
+
if( $file_path == '.htaccess' ){
|
5546 |
+
$file_path = sprintf(
|
5547 |
+
'%s <a href="%s" target="_blank">%s</a>',
|
5548 |
+
$file_path,
|
5549 |
+
'%%SUCURI.URL.Infosys%%#htaccess-integrity',
|
5550 |
+
'<em>(Check HTAccess Integrity)</em>'
|
5551 |
+
);
|
5552 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5553 |
|
5554 |
+
elseif( $file_path == 'wp-config.php' ){
|
5555 |
+
$file_path = sprintf(
|
5556 |
+
'%s <a href="%s" target="_blank">%s</a>',
|
5557 |
+
$file_path,
|
5558 |
+
'%%SUCURI.URL.Infosys%%#wpconfig-rules',
|
5559 |
+
'<em>(Check WP Config Variables)</em>'
|
5560 |
+
);
|
5561 |
+
}
|
5562 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5563 |
$css_class = ( $counter % 2 == 0 ) ? '' : 'alternate';
|
5564 |
+
$template_variables['CoreFiles.List'] .= sucuriscan_get_snippet('integrity-corefiles', array(
|
5565 |
+
'CoreFiles.CssClass' => $css_class,
|
5566 |
+
'CoreFiles.StatusType' => $list_type,
|
5567 |
+
'CoreFiles.StatusAbbr' => substr($list_type, 0, 1),
|
5568 |
+
'CoreFiles.FilePath' => $file_path,
|
5569 |
+
));
|
5570 |
$counter += 1;
|
5571 |
+
}
|
5572 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5573 |
|
5574 |
+
if( $counter > 0 ){
|
5575 |
+
$template_variables['CoreFiles.ListCount'] = $counter;
|
5576 |
+
$template_variables['CoreFiles.GoodVisibility'] = 'hidden';
|
5577 |
+
$template_variables['CoreFiles.BadVisibility'] = 'visible';
|
5578 |
+
}
|
5579 |
+
} else {
|
5580 |
+
sucuriscan_error( 'Error retrieving the WordPress core hashes, try again.' );
|
5581 |
+
}
|
5582 |
+
}
|
5583 |
+
|
5584 |
+
return sucuriscan_get_section('integrity-corefiles', $template_variables);
|
5585 |
+
}
|
5586 |
|
5587 |
/**
|
5588 |
* Retrieve a list with the checksums of the files in a specific version of WordPress.
|
5589 |
*
|
5590 |
+
* @see Release Archive http://wordpress.org/download/release-archive/
|
5591 |
+
*
|
5592 |
* @param integer $version Valid version number of the WordPress project.
|
5593 |
* @return object Associative object with the relative filepath and the checksums of the project files.
|
5594 |
*/
|
5595 |
+
function sucuriscan_get_official_checksums( $version=0 ){
|
5596 |
$api_url = sprintf('http://api.wordpress.org/core/checksums/1.0/?version=%s&locale=en_US', $version);
|
|
|
5597 |
$request = wp_remote_get($api_url);
|
5598 |
+
|
5599 |
if( !is_wp_error($request) || wp_remote_retrieve_response_code($request) === 200 ){
|
5600 |
$json_data = json_decode($request['body']);
|
5601 |
+
|
5602 |
if( $json_data->checksums !== FALSE ){
|
5603 |
+
$checksums = $json_data->checksums;
|
5604 |
+
|
5605 |
+
// Convert the object list to an array for better handle of the data.
|
5606 |
+
if( $checksums instanceof stdClass ){
|
5607 |
+
$checksums = (array) $checksums;
|
5608 |
+
}
|
5609 |
+
|
5610 |
+
return $checksums;
|
5611 |
}
|
5612 |
}
|
5613 |
|
5620 |
* these keys:
|
5621 |
*
|
5622 |
* <ul>
|
5623 |
+
* <li>modified: Files with a different checksum according to the official files of the WordPress version filtered,</li>
|
5624 |
+
* <li>stable: Files with the same checksums than the official files,</li>
|
5625 |
* <li>removed: Official files which are not present in the local project,</li>
|
5626 |
* <li>added: Files present in the local project but not in the official WordPress packages.</li>
|
5627 |
* </ul>
|
5628 |
*
|
5629 |
* @param integer $version Valid version number of the WordPress project.
|
5630 |
+
* @return array Associative array with these keys: modified, stable, removed, added.
|
5631 |
*/
|
5632 |
+
function sucuriscan_check_wp_integrity( $version=0 ){
|
5633 |
$latest_hashes = sucuriscan_get_official_checksums($version);
|
5634 |
|
5635 |
if( !$latest_hashes ){ return FALSE; }
|
5636 |
|
5637 |
+
$output = array(
|
5638 |
+
'added' => array(),
|
5639 |
+
'removed' => array(),
|
5640 |
+
'modified' => array(),
|
5641 |
+
'stable' => array(),
|
5642 |
+
);
|
5643 |
|
5644 |
// Get current filesystem tree.
|
5645 |
+
$wp_top_hashes = sucuriscan_get_integrity_tree( ABSPATH , false);
|
5646 |
+
$wp_admin_hashes = sucuriscan_get_integrity_tree( ABSPATH . 'wp-admin', true);
|
5647 |
+
$wp_includes_hashes = sucuriscan_get_integrity_tree( ABSPATH . 'wp-includes', true);
|
5648 |
$wp_core_hashes = array_merge( $wp_top_hashes, $wp_admin_hashes, $wp_includes_hashes );
|
5649 |
|
5650 |
+
// Compare remote and local checksums and search removed files.
|
5651 |
+
foreach( $latest_hashes as $filepath => $remote_checksum ){
|
5652 |
+
if( sucuriscan_ignore_integrity_filepath($filepath) ){ continue; }
|
5653 |
+
|
5654 |
$full_filepath = sprintf('%s/%s', ABSPATH, $filepath);
|
5655 |
+
|
5656 |
if( file_exists($full_filepath) ){
|
5657 |
$local_checksum = @md5_file($full_filepath);
|
5658 |
+
|
5659 |
if( $local_checksum && $local_checksum == $remote_checksum ){
|
5660 |
+
$output['stable'][] = $filepath;
|
5661 |
+
} else {
|
5662 |
+
$output['modified'][] = $filepath;
|
5663 |
}
|
5664 |
+
} else {
|
5665 |
$output['removed'][] = $filepath;
|
5666 |
}
|
5667 |
}
|
5668 |
|
5669 |
// Search added files (files not common in a normal wordpress installation).
|
5670 |
+
foreach( $wp_core_hashes as $filepath => $extra_info ){
|
5671 |
$filepath = preg_replace('/^\.\/(.*)/', '$1', $filepath);
|
5672 |
+
|
5673 |
+
if( sucuriscan_ignore_integrity_filepath($filepath) ){ continue; }
|
5674 |
+
|
5675 |
+
if( !isset($latest_hashes[$filepath]) ){
|
5676 |
$output['added'][] = $filepath;
|
5677 |
}
|
5678 |
}
|
5681 |
}
|
5682 |
|
5683 |
/**
|
5684 |
+
* Ignore irrelevant files and directories from the integrity checking.
|
|
|
|
|
|
|
5685 |
*
|
5686 |
+
* @param string $filepath File path that will be compared.
|
5687 |
+
* @return boolean TRUE if the file should be ignored, FALSE otherwise.
|
5688 |
*/
|
5689 |
+
function sucuriscan_ignore_integrity_filepath( $filepath='' ){
|
5690 |
+
// List of files that will be ignored from the integrity checking.
|
5691 |
+
$ignore_files = array(
|
5692 |
+
'favicon.ico',
|
5693 |
+
'.htaccess',
|
5694 |
+
'wp-config.php',
|
5695 |
+
'wp-pass.php',
|
5696 |
+
'wp-rss.php',
|
5697 |
+
'wp-feed.php',
|
5698 |
+
'wp-register.php',
|
5699 |
+
'wp-atom.php',
|
5700 |
+
'wp-commentsrss2.php',
|
5701 |
+
'wp-rss2.php',
|
5702 |
+
'wp-rdf.php',
|
5703 |
+
);
|
5704 |
|
5705 |
+
if(
|
5706 |
+
in_array($filepath, $ignore_files)
|
5707 |
+
|| strpos($filepath, 'wp-content/themes') == 0
|
5708 |
+
|| strpos($filepath, 'wp-content/plugins') == 0
|
5709 |
+
){
|
5710 |
+
return TRUE;
|
5711 |
}
|
5712 |
|
5713 |
+
return FALSE;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5714 |
}
|
5715 |
|
5716 |
/**
|
5717 |
+
* List all files inside wp-content that have been modified in the last days.
|
5718 |
*
|
5719 |
* @return void
|
5720 |
*/
|
5721 |
+
function sucuriscan_modified_files(){
|
5722 |
+
$valid_day_ranges = array( 1, 3, 7, 30, 60 );
|
5723 |
+
$template_variables = array(
|
5724 |
+
'ModifiedFiles.List' => '',
|
5725 |
+
'ModifiedFiles.SelectOptions' => '',
|
5726 |
+
'ModifiedFiles.NoFilesVisibility' => 'visible',
|
5727 |
+
'ModifiedFiles.Days' => 0,
|
5728 |
+
);
|
5729 |
|
5730 |
+
// Find files modified in the last days.
|
5731 |
+
$back_days = 7;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5732 |
|
5733 |
+
// Correct the ranges of the search to be between one and sixty days.
|
5734 |
+
if( sucuriscan_check_page_nonce() && isset($_POST['sucuriscan_last_days']) ){
|
5735 |
+
$back_days = intval($_POST['sucuriscan_last_days']);
|
5736 |
+
if ( $back_days <= 0 ){ $back_days = 1; }
|
5737 |
+
elseif( $back_days >= 60 ){ $back_days = 60; }
|
5738 |
+
}
|
|
|
|
|
|
|
5739 |
|
5740 |
+
// Generate the options for the select field of the page form.
|
5741 |
+
foreach( $valid_day_ranges as $day ){
|
5742 |
+
$selected_option = ($back_days == $day) ? 'selected="selected"' : '';
|
5743 |
+
$template_variables['ModifiedFiles.SelectOptions'] .= sprintf(
|
5744 |
+
'<option value="%d" %s>%d</option>',
|
5745 |
+
$day, $selected_option, $day
|
5746 |
+
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5747 |
}
|
5748 |
|
5749 |
+
// Scan the files of the site.
|
5750 |
+
$template_variables['ModifiedFiles.Days'] = $back_days;
|
5751 |
+
$wp_content_hashes = sucuriscan_get_integrity_tree( ABSPATH.'wp-content', true );
|
5752 |
+
$back_days = current_time('timestamp') - ( $back_days * 86400);
|
5753 |
+
$counter = 0;
|
5754 |
+
|
5755 |
+
foreach( $wp_content_hashes as $file_path => $file_info ){
|
5756 |
+
if( $file_info['filetime'] >= $back_days ){
|
5757 |
+
$css_class = ( $counter % 2 == 0 ) ? '' : 'alternate';
|
5758 |
+
$mod_date = date('d/M/Y H:i:s', $file_info['filetime']);
|
5759 |
+
|
5760 |
+
$template_variables['ModifiedFiles.List'] .= sucuriscan_get_snippet('integrity-modifiedfiles', array(
|
5761 |
+
'ModifiedFiles.CssClass' => $css_class,
|
5762 |
+
'ModifiedFiles.CheckSum' => $file_info['checksum'],
|
5763 |
+
'ModifiedFiles.FilePath' => $file_path,
|
5764 |
+
'ModifiedFiles.DateTime' => $mod_date
|
5765 |
+
));
|
5766 |
+
$counter += 1;
|
5767 |
}
|
5768 |
}
|
5769 |
|
5770 |
+
if( $counter > 0 ){
|
5771 |
+
$template_variables['ModifiedFiles.NoFilesVisibility'] = 'hidden';
|
|
|
|
|
5772 |
}
|
5773 |
+
|
5774 |
+
return sucuriscan_get_section('integrity-modifiedfiles', $template_variables);
|
5775 |
}
|
5776 |
|
5777 |
/**
|
5778 |
+
* Generate and print the HTML code for the Post-Hack page.
|
|
|
5779 |
*
|
5780 |
* @return void
|
5781 |
*/
|
5782 |
+
function sucuriscan_posthack_page(){
|
5783 |
+
if( !current_user_can('manage_options') ){
|
5784 |
+
wp_die(__('You do not have sufficient permissions to access this page: Sucuri Post-Hack') );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5785 |
}
|
5786 |
|
5787 |
+
$process_form = sucuriscan_posthack_process_form();
|
|
|
|
|
|
|
5788 |
|
5789 |
+
// Page pseudo-variables initialization.
|
5790 |
+
$template_variables = array(
|
5791 |
+
'PageTitle' => 'Post-Hack',
|
5792 |
+
'UpdateSecretKeys' => sucuriscan_update_secret_keys($process_form),
|
5793 |
+
'ResetPassword' => sucuriscan_posthack_users($process_form),
|
5794 |
+
'DatabaseBackups' => sucuriscan_database_backups($process_form),
|
|
|
|
|
|
|
|
|
|
|
5795 |
);
|
5796 |
|
5797 |
+
echo sucuriscan_get_template('posthack', $template_variables);
|
|
|
|
|
5798 |
}
|
5799 |
|
5800 |
/**
|
5801 |
+
* Check whether the "I understand this operation" checkbox was marked or not.
|
|
|
|
|
5802 |
*
|
5803 |
+
* @return boolean TRUE if a form submission should be processed, FALSE otherwise.
|
5804 |
*/
|
5805 |
+
function sucuriscan_posthack_process_form(){
|
5806 |
+
if( sucuriscan_check_page_nonce() && isset($_POST['sucuriscan_process_form']) ){
|
5807 |
+
if( $_POST['sucuriscan_process_form'] == 1 ){
|
5808 |
+
return TRUE;
|
5809 |
+
} else {
|
5810 |
+
sucuriscan_error('You need to confirm that you understand the risk of this operation.');
|
5811 |
+
}
|
5812 |
+
}
|
|
|
|
|
|
|
5813 |
|
5814 |
+
return FALSE;
|
5815 |
}
|
5816 |
|
5817 |
/**
|
5818 |
+
* Update the WordPress secret keys.
|
|
|
|
|
|
|
|
|
5819 |
*
|
5820 |
+
* @param $process_form Whether a form was submitted or not.
|
5821 |
+
* @return string HTML code with the information of the process.
|
5822 |
*/
|
5823 |
+
function sucuriscan_update_secret_keys( $process_form=FALSE ){
|
5824 |
+
$template_variables = array(
|
5825 |
+
'WPConfigUpdate.Visibility' => 'hidden',
|
5826 |
+
'WPConfigUpdate.NewConfig' => '',
|
5827 |
+
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5828 |
|
5829 |
+
// Update all WordPress secret keys.
|
5830 |
+
if( $process_form && isset($_POST['sucuriscan_update_wpconfig']) ){
|
5831 |
+
$wpconfig_process = sucuriscan_set_new_config_keys();
|
5832 |
+
|
5833 |
+
if( $wpconfig_process ){
|
5834 |
+
$template_variables['WPConfigUpdate.Visibility'] = 'visible';
|
5835 |
+
|
5836 |
+
if( $wpconfig_process['updated'] === TRUE ){
|
5837 |
+
sucuriscan_info( 'WordPress secret keys updated successfully (check bellow the summary of the operation).' );
|
5838 |
+
$template_variables['WPConfigUpdate.NewConfig'] .= "// Old Keys\n";
|
5839 |
+
$template_variables['WPConfigUpdate.NewConfig'] .= $wpconfig_process['old_keys_string'];
|
5840 |
+
$template_variables['WPConfigUpdate.NewConfig'] .= "//\n";
|
5841 |
+
$template_variables['WPConfigUpdate.NewConfig'] .= "// New Keys\n";
|
5842 |
+
$template_variables['WPConfigUpdate.NewConfig'] .= $wpconfig_process['new_keys_string'];
|
5843 |
+
} else {
|
5844 |
+
sucuriscan_error( '<code>wp-config.php</code> file is not writable, replace the old configuration file with the new values shown bellow.' );
|
5845 |
+
$template_variables['WPConfigUpdate.NewConfig'] = $wpconfig_process['new_wpconfig'];
|
5846 |
}
|
5847 |
+
} else {
|
5848 |
+
sucuriscan_error('<code>wp-config.php</code> file was not found in the default location.' );
|
5849 |
}
|
5850 |
}
|
5851 |
|
5852 |
+
return sucuriscan_get_section('posthack-updatesecretkeys', $template_variables);
|
|
|
|
|
|
|
|
|
|
|
|
|
5853 |
}
|
5854 |
|
5855 |
/**
|
5856 |
+
* Display a list of users in a table that will be used to select the accounts
|
5857 |
+
* where a password reset action will be executed.
|
|
|
|
|
|
|
5858 |
*
|
5859 |
+
* @param $process_form Whether a form was submitted or not.
|
5860 |
+
* @return string HTML code for a table where a list of user accounts will be shown.
|
5861 |
*/
|
5862 |
+
function sucuriscan_posthack_users( $process_form=FALSE ){
|
5863 |
+
$template_variables = array(
|
5864 |
+
'ResetPassword.UserList' => '',
|
5865 |
+
);
|
5866 |
|
5867 |
+
// Process the form submission (if any).
|
5868 |
+
sucuriscan_reset_user_password($process_form);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5869 |
|
5870 |
+
// Fill the user list for ResetPassword action.
|
5871 |
+
$user_list = get_users();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5872 |
|
5873 |
+
if( $user_list ){
|
5874 |
+
$counter = 0;
|
|
|
5875 |
|
5876 |
+
foreach( $user_list as $user ){
|
5877 |
+
$user->user_registered_timestamp = strtotime($user->user_registered);
|
5878 |
+
$user->user_registered_formatted = date('D, M/Y H:i', $user->user_registered_timestamp);
|
5879 |
+
$css_class = ( $counter % 2 == 0 ) ? '' : 'alternate';
|
5880 |
+
|
5881 |
+
$user_snippet = sucuriscan_get_snippet('resetpassword', array(
|
5882 |
+
'ResetPassword.UserId' => $user->ID,
|
5883 |
+
'ResetPassword.Username' => $user->user_login,
|
5884 |
+
'ResetPassword.Displayname' => $user->display_name,
|
5885 |
+
'ResetPassword.Email' => $user->user_email,
|
5886 |
+
'ResetPassword.Registered' => $user->user_registered_formatted,
|
5887 |
+
'ResetPassword.Roles' => implode(', ', $user->roles),
|
5888 |
+
'ResetPassword.CssClass' => $css_class
|
5889 |
+
));
|
5890 |
+
|
5891 |
+
$template_variables['ResetPassword.UserList'] .= $user_snippet;
|
5892 |
+
$counter += 1;
|
5893 |
}
|
5894 |
}
|
5895 |
|
5896 |
+
return sucuriscan_get_section('posthack-resetpassword', $template_variables);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5897 |
}
|
5898 |
|
5899 |
/**
|
5900 |
+
* Update the password of the user accounts specified.
|
|
|
|
|
|
|
|
|
|
|
5901 |
*
|
5902 |
+
* @param $process_form Whether a form was submitted or not.
|
5903 |
* @return void
|
5904 |
*/
|
5905 |
+
function sucuriscan_reset_user_password( $process_form=FALSE ){
|
5906 |
+
if( $process_form && isset($_POST['sucuriscan_reset_password']) ){
|
5907 |
+
$user_identifiers = isset($_POST['user_ids']) ? $_POST['user_ids'] : array();
|
5908 |
+
$pwd_changed = $pwd_not_changed = array();
|
5909 |
+
|
5910 |
+
if( is_array($user_identifiers) && !empty($user_identifiers) ){
|
5911 |
+
arsort($user_identifiers);
|
5912 |
+
|
5913 |
+
foreach( $user_identifiers as $user_id ){
|
5914 |
+
if( sucuriscan_new_password($user_id) ){
|
5915 |
+
$pwd_changed[] = $user_id;
|
5916 |
+
} else {
|
5917 |
+
$pwd_not_changed[] = $user_id;
|
5918 |
+
}
|
5919 |
+
}
|
5920 |
|
5921 |
+
if( !empty($pwd_changed) ){
|
5922 |
+
sucuriscan_info( 'Password changed successfully for users: ' . implode(', ',$pwd_changed) );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5923 |
}
|
|
|
|
|
5924 |
|
5925 |
+
if( !empty($pwd_not_changed) ){
|
5926 |
+
sucuriscan_error( 'Password change failed for users: ' . implode(', ',$pwd_not_changed) );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5927 |
}
|
5928 |
+
} else {
|
5929 |
+
sucuriscan_error( 'You did not select a user from the list.' );
|
5930 |
}
|
5931 |
+
}
|
5932 |
+
}
|
5933 |
|
5934 |
+
/**
|
5935 |
+
* List and offer a way to download the database backups generates so far.
|
5936 |
+
*
|
5937 |
+
* @param $process_form Whether a form was submitted or not.
|
5938 |
+
* @return void
|
5939 |
+
*/
|
5940 |
+
function sucuriscan_database_backups( $process_form=FALSE ){
|
5941 |
+
$template_variables = array(
|
5942 |
+
'BackupList' => '',
|
5943 |
+
);
|
5944 |
|
5945 |
+
// Process the form submission (if any).
|
5946 |
+
sucuriscan_process_database_backups_form($process_form);
|
5947 |
+
|
5948 |
+
// Instantiate the database/backup library and get all files.
|
5949 |
+
$sucuri_backup = new SucuriScanBackup();
|
5950 |
+
$backup_files = $sucuri_backup->get_backup_files();
|
5951 |
+
|
5952 |
+
if( $backup_files ){
|
5953 |
+
$counter = 0;
|
5954 |
+
|
5955 |
+
foreach( $backup_files as $backup_file ){
|
5956 |
+
$backupfile_snippet = sucuriscan_get_snippet('posthack-databasebackups', array(
|
5957 |
+
'BackupList.FileURL' => admin_url('?sucuriscan_download=' . $backup_file->filename),
|
5958 |
+
'BackupList.Filename' => $backup_file->filename,
|
5959 |
+
'BackupList.Filetype' => strtoupper($backup_file->fileext),
|
5960 |
+
'BackupList.Filesize' => ( $backup_file->filesize>0 ? "{$backup_file->filesize} (~ {$backup_file->filehumansize})" : 0 ),
|
5961 |
+
'BackupList.Filetime' => date('Y/M/d H:i', $backup_file->filetime),
|
5962 |
+
'BackupList.CssClass' => ( $counter % 2 == 0 ) ? '' : 'alternate',
|
5963 |
+
));
|
5964 |
+
|
5965 |
+
$template_variables['BackupList'] .= $backupfile_snippet;
|
5966 |
+
$counter += 1;
|
5967 |
}
|
5968 |
}
|
5969 |
|
5970 |
+
return sucuriscan_get_section('posthack-databasebackups', $template_variables);
|
|
|
|
|
|
|
|
|
|
|
5971 |
}
|
5972 |
|
5973 |
/**
|
5974 |
+
* Process the form submissions of the database backups panel.
|
|
|
5975 |
*
|
5976 |
+
* @param $process_form Whether a form was submitted or not.
|
5977 |
* @return void
|
5978 |
*/
|
5979 |
+
function sucuriscan_process_database_backups_form( $process_form=FALSE ){
|
5980 |
+
if( $process_form && isset($_POST['sucuriscan_database_backup']) ){
|
5981 |
+
|
5982 |
+
if( isset($_POST['generate_dbbackup']) ){
|
5983 |
+
$sucuri_backup = new SucuriScanBackup();
|
5984 |
+
$dbbackup_filepath = $sucuri_backup->all_database();
|
5985 |
+
|
5986 |
+
if( $dbbackup_filepath ){
|
5987 |
+
$dbbackup_fileurl = admin_url( '?sucuriscan_download=' . basename($dbbackup_filepath) );
|
5988 |
+
sucuriscan_info( 'Database backup generated and stored in the plugin upload folder, you can download the
|
5989 |
+
file from here: <a href="'.$dbbackup_fileurl.'" target="_blank"><strong>Download DB Backup</strong></a>' );
|
5990 |
+
} else {
|
5991 |
+
sucuriscan_error( 'Could not generate a new database backup' );
|
5992 |
+
}
|
5993 |
+
}
|
5994 |
+
|
5995 |
+
elseif( isset($_POST['remove_dbbackup']) ){
|
5996 |
+
$sucuri_backup = new SucuriScanBackup();
|
5997 |
+
$backups_to_remove = isset($_POST['dbbackup_filenames']) ? $_POST['dbbackup_filenames'] : array();
|
5998 |
+
$sucuri_backup->remove_backup_file($backups_to_remove);
|
5999 |
+
}
|
6000 |
|
|
|
|
|
|
|
6001 |
}
|
6002 |
+
}
|
6003 |
+
|
6004 |
+
if( !function_exists('sucuriscan_download_file') ){
|
6005 |
+
/**
|
6006 |
+
* Download the SQL or Zip file generated to hold a backup of the database.
|
6007 |
+
*
|
6008 |
+
* @return void
|
6009 |
+
*/
|
6010 |
+
function sucuriscan_download_file(){
|
6011 |
+
if(
|
6012 |
+
current_user_can('manage_options')
|
6013 |
+
AND isset($_GET['sucuriscan_download'])
|
6014 |
+
){
|
6015 |
+
$sucuri_backup = new SucuriScanBackup();
|
6016 |
+
$backup_file = $sucuri_backup->get_backup_file_from_filename($_GET['sucuriscan_download']);
|
6017 |
+
|
6018 |
+
if( $backup_file ){
|
6019 |
+
switch($backup_file->fileext){
|
6020 |
+
case 'sql':
|
6021 |
+
$download_filename = sprintf('%s.sql', DB_NAME);
|
6022 |
+
header('Content-Type: application/x-sql');
|
6023 |
+
break;
|
6024 |
+
case 'zip':
|
6025 |
+
$download_filename = sprintf('%s.sql.zip', DB_NAME);
|
6026 |
+
header('Content-Type: application/zip');
|
6027 |
+
break;
|
6028 |
+
default:
|
6029 |
+
$download_filename = $backup_file->filename;
|
6030 |
+
header('Content-Type: application/octet-stream');
|
6031 |
+
break;
|
6032 |
+
}
|
6033 |
+
|
6034 |
+
header('Content-Disposition: attachment; filename='.$download_filename);
|
6035 |
+
header('Content-Length: '.$backup_file->filesize);
|
6036 |
+
header('Cache-Control: private');
|
6037 |
+
|
6038 |
+
if( $fd=fopen($backup_file->filepath,'r') ){
|
6039 |
+
while( !feof($fd) ){ echo fread($fd, 2048); }
|
6040 |
+
}
|
6041 |
+
|
6042 |
+
fclose($fd);
|
6043 |
+
}
|
6044 |
+
}
|
6045 |
}
|
6046 |
|
6047 |
+
add_action('admin_init', 'sucuriscan_download_file');
|
|
|
|
|
|
|
|
|
|
|
6048 |
}
|
6049 |
|
6050 |
/**
|
6051 |
+
* Generate and print the HTML code for the Last Logins page.
|
6052 |
*
|
6053 |
+
* This page will contains information of all the logins of the registered users.
|
6054 |
+
*
|
6055 |
+
* @return string Last-logings for the administrator accounts.
|
6056 |
*/
|
6057 |
+
function sucuriscan_lastlogins_page(){
|
6058 |
+
if( !current_user_can('manage_options') ){
|
6059 |
+
wp_die(__('You do not have sufficient permissions to access this page: Sucuri Last-Logins') );
|
|
|
|
|
6060 |
}
|
6061 |
|
6062 |
+
// Page pseudo-variables initialization.
|
6063 |
+
$template_variables = array(
|
6064 |
+
'PageTitle' => 'Last Logins',
|
6065 |
+
'LastLoginsNonce' => wp_create_nonce('sucuriscan_lastlogins_nonce'),
|
6066 |
+
'LastLogins.Admins' => sucuriscan_lastlogins_admins(),
|
6067 |
+
'LastLogins.AllUsers' => sucuriscan_lastlogins_all(),
|
6068 |
+
'UserList' => '',
|
6069 |
+
'UserListLimit' => SUCURISCAN_LASTLOGINS_USERSLIMIT,
|
|
|
6070 |
);
|
6071 |
+
|
6072 |
+
echo sucuriscan_get_template('lastlogins', $template_variables);
|
6073 |
}
|
6074 |
|
6075 |
/**
|
6076 |
+
* List all the user administrator accounts.
|
6077 |
+
*
|
6078 |
+
* @see http://codex.wordpress.org/Class_Reference/WP_User_Query
|
6079 |
*
|
6080 |
* @return void
|
6081 |
*/
|
6082 |
+
function sucuriscan_lastlogins_admins(){
|
|
|
|
|
|
|
|
|
|
|
6083 |
// Page pseudo-variables initialization.
|
6084 |
$template_variables = array(
|
6085 |
+
'AdminUsers.List' => ''
|
|
|
|
|
|
|
|
|
6086 |
);
|
6087 |
|
6088 |
+
$user_query = new WP_User_Query(array( 'role' => 'Administrator' ));
|
6089 |
+
$admins = $user_query->get_results();
|
|
|
|
|
|
|
6090 |
|
6091 |
+
foreach( (array)$admins as $admin ){
|
6092 |
+
$admin->lastlogins = sucuriscan_get_logins(5, $admin->ID);
|
|
|
6093 |
|
6094 |
+
$user_snippet = array(
|
6095 |
+
'AdminUsers.Username' => $admin->user_login,
|
6096 |
+
'AdminUsers.Email' => $admin->user_email,
|
6097 |
+
'AdminUsers.LastLogins' => '',
|
6098 |
+
'AdminUsers.UserURL' => admin_url('user-edit.php?user_id='.$admin->ID),
|
6099 |
+
'AdminUsers.NoLastLogins' => 'visible',
|
6100 |
+
'AdminUsers.NoLastLoginsTable' => 'hidden',
|
6101 |
+
);
|
6102 |
|
6103 |
+
if( !empty($admin->lastlogins) ){
|
6104 |
+
$user_snippet['AdminUsers.NoLastLogins'] = 'hidden';
|
6105 |
+
$user_snippet['AdminUsers.NoLastLoginsTable'] = 'visible';
|
6106 |
+
$counter = 0;
|
6107 |
+
|
6108 |
+
foreach( $admin->lastlogins as $lastlogin ){
|
6109 |
+
$css_class = ( $counter % 2 == 0 ) ? '' : 'alternate';
|
6110 |
+
$user_snippet['AdminUsers.LastLogins'] .= sucuriscan_get_snippet('lastlogins-admins-lastlogin', array(
|
6111 |
+
'AdminUsers.RemoteAddr' => $lastlogin->user_remoteaddr,
|
6112 |
+
'AdminUsers.Datetime' => $lastlogin->user_lastlogin,
|
6113 |
+
'AdminUsers.CssClass' => $css_class,
|
6114 |
+
));
|
6115 |
+
$counter += 1;
|
6116 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6117 |
}
|
|
|
6118 |
|
6119 |
+
$template_variables['AdminUsers.List'] .= sucuriscan_get_snippet('lastlogins-admins', $user_snippet);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6120 |
}
|
6121 |
|
6122 |
+
return sucuriscan_get_section('lastlogins-admins', $template_variables);
|
6123 |
}
|
6124 |
|
6125 |
/**
|
6126 |
+
* List the last-logins for all user accounts in the site.
|
6127 |
*
|
6128 |
* This page will contains information of all the logins of the registered users.
|
6129 |
*
|
6130 |
+
* @return string Last-logings for all user accounts.
|
6131 |
*/
|
6132 |
+
function sucuriscan_lastlogins_all(){
|
|
|
|
|
|
|
|
|
|
|
6133 |
$template_variables = array(
|
|
|
|
|
6134 |
'UserList' => '',
|
6135 |
'UserListLimit' => SUCURISCAN_LASTLOGINS_USERSLIMIT,
|
6136 |
);
|
6137 |
|
6138 |
if( !sucuriscan_lastlogins_datastore_is_writable() ){
|
6139 |
+
sucuriscan_error( 'Last-logins datastore file is not writable: <code>'.sucuriscan_lastlogins_datastore_filepath().'</code>' );
|
|
|
|
|
6140 |
}
|
6141 |
|
6142 |
$limit = isset($_GET['limit']) ? intval($_GET['limit']) : SUCURISCAN_LASTLOGINS_USERSLIMIT;
|
6144 |
|
6145 |
$counter = 0;
|
6146 |
$user_list = sucuriscan_get_logins($limit);
|
6147 |
+
|
6148 |
+
foreach( $user_list as $user ){
|
6149 |
$counter += 1;
|
6150 |
+
$css_class = ( $counter % 2 == 0 ) ? 'alternate' : '';
|
6151 |
+
|
6152 |
+
$user_dataset = array(
|
6153 |
'UserList.Number' => $counter,
|
6154 |
+
'UserList.UserId' => $user->user_id,
|
6155 |
+
'UserList.Username' => '<em>Unknown</em>',
|
6156 |
+
'UserList.Displayname' => '',
|
6157 |
+
'UserList.Email' => '',
|
6158 |
+
'UserList.Registered' => '',
|
6159 |
'UserList.RemoteAddr' => $user->user_remoteaddr,
|
6160 |
'UserList.Hostname' => $user->user_hostname,
|
6161 |
'UserList.Datetime' => $user->user_lastlogin,
|
6162 |
'UserList.TimeAgo' => sucuriscan_time_ago($user->user_lastlogin),
|
6163 |
+
'UserList.UserURL' => admin_url('user-edit.php?user_id='.$user->user_id),
|
6164 |
+
'UserList.CssClass' => $css_class,
|
6165 |
+
);
|
6166 |
+
|
6167 |
+
if( $user->user_exists ){
|
6168 |
+
$user_dataset['UserList.Username'] = $user->user_login;
|
6169 |
+
$user_dataset['UserList.Displayname'] = $user->display_name;
|
6170 |
+
$user_dataset['UserList.Email'] = $user->user_email;
|
6171 |
+
$user_dataset['UserList.Registered'] = $user->user_registered;
|
6172 |
+
}
|
6173 |
+
|
6174 |
+
$template_variables['UserList'] .= sucuriscan_get_snippet('lastlogins-all', $user_dataset);
|
6175 |
}
|
6176 |
|
6177 |
+
return sucuriscan_get_section('lastlogins-all', $template_variables);
|
6178 |
}
|
6179 |
|
6180 |
/**
|
6275 |
* @param integer $user_id Optional user identifier to filter the results.
|
6276 |
* @return array The list of all the user logins through the time until now.
|
6277 |
*/
|
6278 |
+
function sucuriscan_get_logins( $limit=10, $user_id=0 ){
|
6279 |
$lastlogins = array();
|
6280 |
$datastore_filepath = sucuriscan_lastlogins_datastore_is_readable();
|
6281 |
|
6282 |
+
if( $datastore_filepath ){
|
6283 |
$parsed_lines = 0;
|
6284 |
$lastlogins_lines = array_reverse(file($datastore_filepath));
|
6285 |
+
|
6286 |
+
foreach( $lastlogins_lines as $line ){
|
6287 |
$line = str_replace("\n", '', $line);
|
6288 |
+
|
6289 |
if( preg_match('/^a:/', $line) ){
|
6290 |
$user_lastlogin = unserialize($line);
|
6291 |
|
6301 |
}
|
6302 |
|
6303 |
/* Get the WP_User object and add extra information from the last-login data */
|
6304 |
+
$user_lastlogin['user_exists'] = FALSE;
|
6305 |
$user_account = get_userdata($user_lastlogin['user_id']);
|
6306 |
+
|
6307 |
+
if( $user_account ){
|
6308 |
+
$user_lastlogin['user_exists'] = TRUE;
|
6309 |
+
|
6310 |
+
foreach( $user_account->data as $var_name=>$var_value ){
|
6311 |
+
$user_lastlogin[$var_name] = $var_value;
|
6312 |
+
}
|
6313 |
}
|
6314 |
+
|
6315 |
+
$lastlogins[] = (object)$user_lastlogin;
|
6316 |
$parsed_lines += 1;
|
6317 |
}
|
6318 |
|
6335 |
* @param boolean $user WordPress user object with the information of the account involved in the operation.
|
6336 |
* @return string URL where the browser must be redirected to.
|
6337 |
*/
|
6338 |
+
function sucuriscan_login_redirect( $redirect_to='', $request=NULL, $user=FALSE ){
|
6339 |
$login_url = !empty($redirect_to) ? $redirect_to : admin_url();
|
6340 |
+
|
6341 |
if( $user instanceof WP_User && $user->ID ){
|
6342 |
+
$login_url = add_query_arg( 'sucuriscan_lastlogin', 1, $login_url );
|
6343 |
}
|
6344 |
+
|
6345 |
return $login_url;
|
6346 |
}
|
6347 |
+
|
6348 |
+
$lastlogin_redirection = sucuriscan_get_option('sucuriscan_lastlogin_redirection');
|
6349 |
+
if( $lastlogin_redirection == 'enabled' ){
|
6350 |
+
add_filter('login_redirect', 'sucuriscan_login_redirect', 10, 3);
|
6351 |
+
}
|
6352 |
}
|
6353 |
|
6354 |
if( !function_exists('sucuri_get_user_lastlogin') ){
|
6358 |
* @return void
|
6359 |
*/
|
6360 |
function sucuriscan_get_user_lastlogin(){
|
6361 |
+
if( isset($_GET['sucuriscan_lastlogin']) && current_user_can('manage_options') ){
|
6362 |
$current_user = wp_get_current_user();
|
6363 |
|
6364 |
// Select the penultimate entry, not the last one.
|
6369 |
$message_tpl = 'The last time you logged in was: %s, from %s - %s';
|
6370 |
$lastlogin_message = sprintf( $message_tpl, date('Y/M/d'), $row->user_remoteaddr, $row->user_hostname );
|
6371 |
$lastlogin_message .= chr(32).'(<a href="'.site_url('wp-admin/admin.php?page='.SUCURISCAN.'_lastlogins').'">View Last-Logins</a>)';
|
6372 |
+
sucuriscan_info( $lastlogin_message );
|
6373 |
}
|
6374 |
}
|
6375 |
}
|
6810 |
}
|
6811 |
|
6812 |
/**
|
6813 |
+
* Gather information from the server, database engine, and PHP interpreter.
|
6814 |
*
|
6815 |
+
* @return array A list of pseudo-variables and values that will replace them in the HTML template.
|
|
|
6816 |
*/
|
6817 |
function sucuriscan_server_info(){
|
6818 |
global $wpdb;
|
6822 |
$mysql_version = $wpdb->get_var('SELECT VERSION() AS version');
|
6823 |
$mysql_info = $wpdb->get_results('SHOW VARIABLES LIKE "sql_mode"');
|
6824 |
$sql_mode = ( is_array($mysql_info) && !empty($mysql_info[0]->Value) ) ? $mysql_info[0]->Value : 'Not set';
|
6825 |
+
$runtime_scan = sucuriscan_get_option('sucuriscan_runtime');
|
6826 |
+
$runtime_scan_human = date( 'd/M/Y H:i:s', $runtime_scan );
|
6827 |
|
6828 |
$template_variables = array(
|
6829 |
+
'PluginVersion' => SUCURISCAN_VERSION,
|
6830 |
+
'PluginMD5' => SUCURISCAN_PLUGIN_CHECKSUM,
|
6831 |
+
'PluginRuntimeDatetime' => $runtime_scan_human,
|
6832 |
+
'OperatingSystem' => sprintf('%s (%d Bit)', PHP_OS, PHP_INT_SIZE*8),
|
6833 |
+
'Server' => isset($_SERVER['SERVER_SOFTWARE']) ? $_SERVER['SERVER_SOFTWARE'] : 'Unknown',
|
6834 |
+
'MemoryUsage' => $memory_usage,
|
6835 |
+
'MySQLVersion' => $mysql_version,
|
6836 |
+
'SQLMode' => $sql_mode,
|
6837 |
+
'PHPVersion' => PHP_VERSION,
|
|
|
|
|
6838 |
);
|
6839 |
|
6840 |
$field_names = array(
|
6860 |
|
6861 |
|
6862 |
/**
|
6863 |
+
* Global variables used by the functions bellow.
|
6864 |
+
*
|
6865 |
+
* These are lists of options allowed to use in the execution of the monitoring
|
6866 |
+
* tool, and the administrator can select among them in the settings page.
|
6867 |
+
*
|
6868 |
+
* @var array
|
6869 |
+
*/
|
6870 |
+
$sucuriscan_notify_options = array(
|
6871 |
+
'sucuriscan_notify_user_registration' => 'Enable email alerts for new user registration',
|
6872 |
+
'sucuriscan_notify_success_login' => 'Enable email alerts for successful logins',
|
6873 |
+
'sucuriscan_notify_failed_login' => 'Enable email alerts for failed logins',
|
6874 |
+
'sucuriscan_notify_post_publication' => 'Enable email alerts for new site content',
|
6875 |
+
'sucuriscan_notify_theme_editor' => 'Enable email alerts when a file is modified via the theme/plugin editor',
|
6876 |
+
'sucuriscan_notify_website_updated' => 'Enable email alerts when your website is updated',
|
6877 |
+
'sucuriscan_notify_settings_updated' => 'Enable email alerts when your website settings are updated',
|
6878 |
+
'sucuriscan_notify_theme_switched' => 'Enable email alerts when the website theme is switched',
|
6879 |
+
'sucuriscan_notify_theme_updated' => 'Enable email alerts when a theme is updated',
|
6880 |
+
'sucuriscan_notify_widget_added' => 'Enable email alerts when a widget is added to a sidebar',
|
6881 |
+
'sucuriscan_notify_widget_deleted' => 'Enable email alerts when a widget is deleted from a sidebar',
|
6882 |
+
'sucuriscan_notify_plugin_change' => 'Enable email alerts for Sucuri plugin changes',
|
6883 |
+
'sucuriscan_notify_plugin_activated' => 'Enable email alerts when a plugin is activated',
|
6884 |
+
'sucuriscan_notify_plugin_deactivated' => 'Enable email alerts when a plugin is deactivated',
|
6885 |
+
'sucuriscan_notify_plugin_updated' => 'Enable email alerts when a plugin is updated',
|
6886 |
+
'sucuriscan_notify_plugin_installed' => 'Enable email alerts when a plugin is installed',
|
6887 |
+
'sucuriscan_notify_plugin_deleted' => 'Enable email alerts when a plugin is deleted',
|
6888 |
+
'sucuriscan_prettify_mails' => 'Enable email alerts in HTML (uncheck to get email in text/plain)',
|
6889 |
+
'sucuriscan_lastlogin_redirection' => 'Allow redirection after login to report the last-login information',
|
6890 |
+
);
|
6891 |
+
|
6892 |
+
$sucuriscan_schedule_allowed = array(
|
6893 |
+
'hourly' => 'Every three hours (3 hours)',
|
6894 |
+
'twicedaily' => 'Twice daily (12 hours)',
|
6895 |
+
'daily' => 'Once daily (24 hours)',
|
6896 |
+
'_oneoff' => 'Never',
|
6897 |
+
);
|
6898 |
+
|
6899 |
+
$sucuriscan_interface_allowed = array(
|
6900 |
+
'spl' => 'SPL (Standard PHP Library)',
|
6901 |
+
'opendir' => 'OpenDir (Medium performance)',
|
6902 |
+
'glob' => 'Glob (Low performance)',
|
6903 |
+
);
|
6904 |
+
|
6905 |
+
/**
|
6906 |
+
* Print a HTML code with the settings of the plugin.
|
6907 |
*
|
6908 |
* @return void
|
6909 |
*/
|
6910 |
+
function sucuriscan_settings_page(){
|
6911 |
|
6912 |
+
global $sucuriscan_schedule_allowed, $sucuriscan_interface_allowed, $sucuriscan_notify_options;
|
6913 |
+
|
6914 |
+
// Check the nonce here to populate the value through other functions.
|
6915 |
+
$page_nonce = sucuriscan_check_page_nonce();
|
6916 |
+
|
6917 |
+
// Process all form submissions.
|
6918 |
+
sucuriscan_settings_form_submissions($page_nonce);
|
6919 |
+
|
6920 |
+
// Register the site, get its API key, and store it locally for future usage.
|
6921 |
+
$api_registered_modal = '';
|
6922 |
+
|
6923 |
+
// Whether the form to manually add the API key should be shown or not.
|
6924 |
+
$display_manual_key_form = (bool) isset($_POST['sucuriscan_recover_api_key']);
|
6925 |
+
|
6926 |
+
if( $page_nonce && isset($_POST['sucuriscan_wordpress_apikey']) ){
|
6927 |
+
$registered = sucuriscan_register_site();
|
6928 |
+
|
6929 |
+
if( $registered ){
|
6930 |
+
$api_registered_modal = sucuriscan_get_modal('settings-apiregistered', array(
|
6931 |
+
'Title' => 'Site registered successfully',
|
6932 |
+
'CssClass' => 'sucuriscan-apikey-registered',
|
6933 |
+
));
|
6934 |
+
} else {
|
6935 |
+
$display_manual_key_form = TRUE;
|
6936 |
+
}
|
6937 |
+
}
|
6938 |
+
|
6939 |
+
// Get initial variables to decide some things bellow.
|
6940 |
+
$api_key = sucuriscan_wordpress_apikey();
|
6941 |
+
$scan_freq = sucuriscan_get_option('sucuriscan_scan_frequency');
|
6942 |
+
$scan_interface = sucuriscan_get_option('sucuriscan_scan_interface');
|
6943 |
+
$runtime_scan = sucuriscan_get_option('sucuriscan_runtime');
|
6944 |
+
$runtime_scan_human = date( 'd/M/Y H:i:s', $runtime_scan );
|
6945 |
+
|
6946 |
+
// Generate HTML code to configure the scanning frequency from the plugin settings.
|
6947 |
+
$scan_freq_options = '';
|
6948 |
+
foreach( $sucuriscan_schedule_allowed as $schedule => $schedule_label ){
|
6949 |
+
$selected = ( $scan_freq==$schedule ? 'selected="selected"' : '' );
|
6950 |
+
$scan_freq_options .= sprintf(
|
6951 |
+
'<option value="%s" %s>%s</option>',
|
6952 |
+
$schedule, $selected, $schedule_label
|
6953 |
+
);
|
6954 |
+
}
|
6955 |
+
|
6956 |
+
// Generate HTML code to configure the scanning interface from the plugin settings.
|
6957 |
+
$scan_interface_options = '';
|
6958 |
+
foreach( $sucuriscan_interface_allowed as $interface_name => $interface_desc ){
|
6959 |
+
$selected = ( $scan_interface==$interface_name ? 'selected="selected"' : '' );
|
6960 |
+
$scan_interface_options .= sprintf(
|
6961 |
+
'<option value="%s" %s>%s</option>',
|
6962 |
+
$interface_name, $selected, $interface_desc
|
6963 |
+
);
|
6964 |
+
}
|
6965 |
+
|
6966 |
+
// Generate HTML code to configure the notifications of the plugin.
|
6967 |
+
$notification_options = '';
|
6968 |
+
$counter = 0;
|
6969 |
+
|
6970 |
+
foreach( $sucuriscan_notify_options as $alert_type => $alert_label ){
|
6971 |
+
$alert_value = sucuriscan_get_option($alert_type);
|
6972 |
+
$checked = ( $alert_value == 'enabled' ? 'checked="checked"' : '' );
|
6973 |
+
$css_class = ( $counter % 2 == 0 ) ? '' : 'alternate';
|
6974 |
+
|
6975 |
+
$notification_options .= sucuriscan_get_snippet('settings-notification', array(
|
6976 |
+
'Notification.CssClass' => $css_class,
|
6977 |
+
'Notification.Name' => $alert_type,
|
6978 |
+
'Notification.Checked' => $checked,
|
6979 |
+
'Notification.Label' => $alert_label,
|
6980 |
+
));
|
6981 |
+
$counter += 1;
|
6982 |
}
|
6983 |
|
6984 |
$template_variables = array(
|
6985 |
+
'PageTitle' => 'Settings',
|
6986 |
+
'APIKey' => $api_key,
|
6987 |
+
'APIKey.RecoverVisibility' => ( $api_key || $display_manual_key_form ? 'hidden' : 'visible' ),
|
6988 |
+
'APIKey.ManualKeyFormVisibility' => ( $display_manual_key_form ? 'visible' : 'hidden' ),
|
6989 |
+
'APIKey.RemoveVisibility' => ( $api_key ? 'visible' : 'hidden' ),
|
6990 |
+
'ScanningFrequency' => 'Undefined',
|
6991 |
+
'ScanningFrequencyOptions' => $scan_freq_options,
|
6992 |
+
'ScanningInterface' => ( $scan_interface ? $sucuriscan_interface_allowed[$scan_interface] : 'Undefined' ),
|
6993 |
+
'ScanningInterfaceOptions' => $scan_interface_options,
|
6994 |
+
'ScanningInterfaceVisibility' => ( SucuriScanFileInfo::is_spl_available() ? 'hidden' : 'visible' ),
|
6995 |
+
'ScanningRuntime' => $runtime_scan,
|
6996 |
+
'ScanningRuntimeHuman' => $runtime_scan_human,
|
6997 |
+
'NotificationOptions' => $notification_options,
|
6998 |
+
'ModalWhenAPIRegistered' => $api_registered_modal,
|
6999 |
);
|
7000 |
|
7001 |
+
if( array_key_exists($scan_freq, $sucuriscan_schedule_allowed) ){
|
7002 |
+
$template_variables['ScanningFrequency'] = $sucuriscan_schedule_allowed[$scan_freq];
|
7003 |
+
}
|
7004 |
+
|
7005 |
+
echo sucuriscan_get_template('settings', $template_variables);
|
7006 |
+
}
|
7007 |
+
|
7008 |
+
/**
|
7009 |
+
* Process the requests sent by the form submissions originated in the settings
|
7010 |
+
* page, all forms must have a nonce field that will be checked against the one
|
7011 |
+
* generated in the template render function.
|
7012 |
+
*
|
7013 |
+
* @param boolean $page_nonce True if the nonce is valid, False otherwise.
|
7014 |
+
* @return void
|
7015 |
+
*/
|
7016 |
+
function sucuriscan_settings_form_submissions( $page_nonce=NULL ){
|
7017 |
+
|
7018 |
+
global $sucuriscan_schedule_allowed, $sucuriscan_interface_allowed, $sucuriscan_notify_options;
|
7019 |
+
|
7020 |
+
// Use this conditional to avoid double checking.
|
7021 |
+
if( is_null($page_nonce) ){
|
7022 |
+
$page_nonce = sucuriscan_check_page_nonce();
|
7023 |
+
}
|
7024 |
+
|
7025 |
+
if( $page_nonce ){
|
7026 |
+
|
7027 |
+
// Recover API key through the email registered previously.
|
7028 |
+
if( isset($_POST['sucuriscan_recover_api_key']) ){
|
7029 |
+
sucuriscan_recover_api_key();
|
7030 |
+
}
|
7031 |
+
|
7032 |
+
// Save API key after it was recovered by the administrator.
|
7033 |
+
if( isset($_POST['sucuriscan_manual_api_key']) ){
|
7034 |
+
sucuriscan_set_api_key( $_POST['sucuriscan_manual_api_key'], TRUE );
|
7035 |
+
sucuriscan_create_scheduled_task();
|
7036 |
+
}
|
7037 |
+
|
7038 |
+
// Remove API key from the local storage.
|
7039 |
+
if( isset($_POST['sucuriscan_remove_api_key']) ){
|
7040 |
+
sucuriscan_set_api_key('');
|
7041 |
+
wp_clear_scheduled_hook('sucuriscan_scheduled_scan');
|
7042 |
+
sucuriscan_notify_event( 'plugin_change', 'Sucuri API key removed' );
|
7043 |
+
}
|
7044 |
+
|
7045 |
+
// Modify the schedule of the filesystem scanner.
|
7046 |
+
if(
|
7047 |
+
isset($_POST['sucuriscan_scan_frequency'])
|
7048 |
+
&& isset($sucuriscan_schedule_allowed)
|
7049 |
+
){
|
7050 |
+
$frequency = $_POST['sucuriscan_scan_frequency'];
|
7051 |
+
$current_frequency = sucuriscan_get_option('sucuriscan_scan_frequency');
|
7052 |
+
$allowed_frequency = array_keys($sucuriscan_schedule_allowed);
|
7053 |
+
|
7054 |
+
if( in_array($frequency, $allowed_frequency) && $current_frequency != $frequency ){
|
7055 |
+
update_option('sucuriscan_scan_frequency', $frequency);
|
7056 |
+
wp_clear_scheduled_hook('sucuriscan_scheduled_scan');
|
7057 |
+
|
7058 |
+
if( $frequency != '_oneoff' ){
|
7059 |
+
wp_schedule_event( time()+10, $frequency, 'sucuriscan_scheduled_scan' );
|
7060 |
+
}
|
7061 |
+
|
7062 |
+
sucuriscan_notify_event( 'plugin_change', 'Filesystem scanning frequency changed to: ' . $frequency );
|
7063 |
+
sucuriscan_info( 'Filesystem scan scheduled to run <code>'.$frequency.'</code>' );
|
7064 |
+
}
|
7065 |
+
}
|
7066 |
+
|
7067 |
+
// Set the method (aka. interface) that will be used to scan the site.
|
7068 |
+
if(
|
7069 |
+
isset($_POST['sucuriscan_scan_interface'])
|
7070 |
+
&& isset($sucuriscan_interface_allowed)
|
7071 |
+
){
|
7072 |
+
$interface = trim($_POST['sucuriscan_scan_interface']);
|
7073 |
+
$allowed_values = array_keys($sucuriscan_interface_allowed);
|
7074 |
+
|
7075 |
+
if( in_array($interface, $allowed_values) ){
|
7076 |
+
update_option('sucuriscan_scan_interface', $interface);
|
7077 |
+
sucuriscan_notify_event( 'plugin_change', 'Filesystem scanning interface changed to: ' . $interface );
|
7078 |
+
sucuriscan_info( 'Filesystem scan interface set to <code>'.$interface.'</code>' );
|
7079 |
+
}
|
7080 |
+
}
|
7081 |
+
|
7082 |
+
// Update the notification settings.
|
7083 |
+
if(
|
7084 |
+
isset($_POST['sucuriscan_save_notification_settings'])
|
7085 |
+
&& isset($sucuriscan_notify_options)
|
7086 |
+
){
|
7087 |
+
foreach( $sucuriscan_notify_options as $alert_type => $alert_label ){
|
7088 |
+
if( isset($_POST[$alert_type]) ){
|
7089 |
+
$option_value = ( $_POST[$alert_type] == 1 ? 'enabled' : 'disabled' );
|
7090 |
+
update_option( $alert_type, $option_value );
|
7091 |
+
sucuriscan_notify_event( 'plugin_change', 'Email notification settings changed' );
|
7092 |
+
}
|
7093 |
+
}
|
7094 |
+
|
7095 |
+
sucuriscan_info( 'Notification settings updated.' );
|
7096 |
+
}
|
7097 |
+
|
7098 |
+
// Reset all the plugin's options.
|
7099 |
+
if( isset($_POST['sucuriscan_reset_options']) ){
|
7100 |
+
// Notify the event before the API key is removed.
|
7101 |
+
$event_msg = 'All plugins options were resetted';
|
7102 |
+
sucuriscan_report_event( 1, 'core', $event_msg );
|
7103 |
+
sucuriscan_notify_event( 'plugin_change', $event_msg );
|
7104 |
+
|
7105 |
+
// Remove all plugin's options from the database.
|
7106 |
+
$options = sucuriscan_get_options_from_db('all_sucuriscan_options');
|
7107 |
+
|
7108 |
+
foreach( $options as $option ){
|
7109 |
+
delete_option( $option->option_name );
|
7110 |
+
}
|
7111 |
+
|
7112 |
+
// Remove the scheduled tasks.
|
7113 |
+
wp_clear_scheduled_hook('sucuriscan_scheduled_scan');
|
7114 |
+
|
7115 |
+
sucuriscan_info( 'All plugin options were resetted successfully' );
|
7116 |
+
}
|
7117 |
+
|
7118 |
+
}
|
7119 |
+
|
7120 |
}
|
7121 |
|