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

Version Description

  • Added list of logged in users.
  • Added system page.
  • Change the integrity checking to use WP API.
Download this release

Release Info

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

Code changes from version 1.5.2 to 1.5.5

inc/css/sucuriscan-default-css.css CHANGED
@@ -3,21 +3,26 @@
3
  * Copyright (C) 2010-2012 Sucuri Security - http://sucuri.net
4
  * Released under the GPL - see LICENSE file for details.
5
  */
6
- .sucuriscan_header{background:#333;border-bottom-left-radius:5px;border-bottom-right-radius:5px;border-top-left-radius:5px;border-top-right-radius:5px;height:38px;margin:16px 0 8px;min-width:255px;padding:10px;position:relative}
7
  .sucuriscan_header img{float:left;height:38px;width:101px}
8
  .wrap .sucuriscan_header h2{color:#fff;float:left;margin-left:10px;padding:3px 0 0;text-shadow:#000 0 1px 0}
9
- .sucuriscan-maincontent{padding:10px 20px 0 0}
10
- #sidebar{padding-top:10px}
11
  #sidebar .sucuriscan-sidebar{border:1px solid #ccc;border-bottom-left-radius:5px;border-bottom-right-radius:5px;border-top-left-radius:5px;border-top-right-radius:5px;margin:0 0 10px;padding:10px 15px}
12
  #sitecleanup.sucuriscan-sidebar{background-color:#bbe8f5;border-color:#4393ac}
13
  #sucuri-latest-posts.sucuriscan-sidebar{background-color:#ececec;border-color:#999}
 
14
  .sucuriscan-maincontent .widefat tbody th.check-column{padding:6px 0 3px 0}
15
  .sucuriscan-maincontent .hardening-box .primary-secondary{margin:0 0 0 10px}
16
  .sucuriscan-maincontent a.lastlogins-showall{display:inline-block;float:right}
 
 
17
  .sucuri-alert{position:relative}
18
- .sucuri-alert-updated{background-color:#bbe8f5 !important;border-color:#4393ac !important}
19
  .sucuri-alert>a.close{position:absolute;top:8px;right:10px;font-size:18px;text-decoration:none}
20
- .sucuri-hidden{display:none !important}
 
 
 
21
  .sucuri-inline-error{font-weight:bold;color:red}
22
  .sucuri-list li{list-style:disc;margin:0 0 5px 15px}
23
  .sucuriscan-maincontent hr{border:none;border-top:1px solid #999}
@@ -28,9 +33,12 @@
28
  .sucuriscan-maincontent .thead-with-button span{line-height:24px}
29
  .sucuriscan-maincontent .thead-with-button .input-text{line-height:22px}
30
  .sucuriscan-maincontent .thead-topright-action{display:inline-block;float:right}
31
-
32
  .sucuriscan-monospace{font-family: Monaco, Monospace, Courier;line-height:26px}
33
  .sucuriscan-maincontent .sucuri-infosys-htaccess{margin:20px 0 0 0}
34
- .sucuriscan-maincontent .sucuri-full-textarea{width:100%;height:200px;line-height:normal;resize:vertical;padding:10px}
35
- .sucuriscan-maincontent .sucuri-notice-error{background:#ffebe8;margin:5px 0 15px;padding:0 .6em;border:1px solid #c00;border-radius:3px}
36
  .sucuriscan-wpconfig-textarea{width:600px;height:525px;background:#f5f5f5;line-height:1.4em;resize:none;margin:15px 0 0 0;padding:10px}
 
 
 
 
 
3
  * Copyright (C) 2010-2012 Sucuri Security - http://sucuri.net
4
  * Released under the GPL - see LICENSE file for details.
5
  */
6
+ .sucuriscan_header{background:#333;border-radius:5px;height:38px;margin:0 0 20px 0;min-width:255px;padding:10px;position:relative}
7
  .sucuriscan_header img{float:left;height:38px;width:101px}
8
  .wrap .sucuriscan_header h2{color:#fff;float:left;margin-left:10px;padding:3px 0 0;text-shadow:#000 0 1px 0}
9
+ .sucuriscan-maincontent{padding:0 20px 0 0}
10
+ #sidebar{}
11
  #sidebar .sucuriscan-sidebar{border:1px solid #ccc;border-bottom-left-radius:5px;border-bottom-right-radius:5px;border-top-left-radius:5px;border-top-right-radius:5px;margin:0 0 10px;padding:10px 15px}
12
  #sitecleanup.sucuriscan-sidebar{background-color:#bbe8f5;border-color:#4393ac}
13
  #sucuri-latest-posts.sucuriscan-sidebar{background-color:#ececec;border-color:#999}
14
+ .sucuriscan-maincontent #poststuff{padding-top:0}
15
  .sucuriscan-maincontent .widefat tbody th.check-column{padding:6px 0 3px 0}
16
  .sucuriscan-maincontent .hardening-box .primary-secondary{margin:0 0 0 10px}
17
  .sucuriscan-maincontent a.lastlogins-showall{display:inline-block;float:right}
18
+ .sucuri-visible{}
19
+ .sucuri-hidden{display:none !important}
20
  .sucuri-alert{position:relative}
 
21
  .sucuri-alert>a.close{position:absolute;top:8px;right:10px;font-size:18px;text-decoration:none}
22
+ .sucuri-alert-updated, .sucuri-alert-error{background:#fff;margin:5px 0 15px;padding:1px 12px;border:1px solid #e5e5e5;border-left:4px solid #ccc}
23
+ .sucuri-alert-updated{border-left:4px solid #7ad03a}
24
+ .sucuri-alert-error{border-left:4px solid #dd3d36}
25
+ .sucuri-alert-updated p, .sucuri-alert-error p{margin:.5em 0;padding:2px}
26
  .sucuri-inline-error{font-weight:bold;color:red}
27
  .sucuri-list li{list-style:disc;margin:0 0 5px 15px}
28
  .sucuriscan-maincontent hr{border:none;border-top:1px solid #999}
33
  .sucuriscan-maincontent .thead-with-button span{line-height:24px}
34
  .sucuriscan-maincontent .thead-with-button .input-text{line-height:22px}
35
  .sucuriscan-maincontent .thead-topright-action{display:inline-block;float:right}
 
36
  .sucuriscan-monospace{font-family: Monaco, Monospace, Courier;line-height:26px}
37
  .sucuriscan-maincontent .sucuri-infosys-htaccess{margin:20px 0 0 0}
38
+ .sucuriscan-maincontent .sucuri-full-textarea{width:100%;height:400px;line-height:normal;resize:vertical;padding:10px}
 
39
  .sucuriscan-wpconfig-textarea{width:600px;height:525px;background:#f5f5f5;line-height:1.4em;resize:none;margin:15px 0 0 0;padding:10px}
40
+ .sucuriscan-maincontent .sucuriscan-about-list{margin:20px 0}
41
+ .sucuriscan-maincontent .sucuriscan-about-list td+td{font-family:Monaco, Monspace, Courier;font-weight:bold}
42
+ .sucuriscan-maincontent .sucuriscan-wpcron-list{margin:20px 0 15px 0}
43
+ .sucuriscan-maincontent .sucuriscan-wpcron-list td+td+td+td{font-family:Monaco, Monspace, Courier;font-weight:bold}
44
+ .sucuriscan-results .icon-ok, .sucuriscan-results .icon-warn, .sucuriscan-results .icon-error{position:relative;top:5px;width:22px;height:22px}
{images → inc/images}/menu-icon.png RENAMED
File without changes
{images → inc/images}/ok.png RENAMED
File without changes
{images → inc/images}/warn.png RENAMED
File without changes
inc/tpl/about.html.tpl ADDED
@@ -0,0 +1,160 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div class="wrap">
2
+ <h2 id="warnings_hook"></h2>
3
+ <div class="sucuriscan_header">
4
+ <a href="http://sucuri.net/signup" target="_blank" title="Sucuri Security">
5
+ <img src="%%SUCURI.SucuriURL%%/inc/images/logo.png" alt="Sucuri Security" />
6
+ </a>
7
+ <h2>Sucuri Security WordPress Plugin (About)</h2>
8
+ </div>
9
+
10
+ <div class="postbox-container" style="width:75%;">
11
+ <div class="sucuriscan-maincontent">
12
+ <div id="poststuff">
13
+ <div class="postbox">
14
+ <h3>About</h3>
15
+ <div class="inside">
16
+ <p>
17
+ Our WordPress Security Plugin will monitor your site from the inside, creating
18
+ a complete audit trail, alerting you of possible security issues (file changes,
19
+ password guessing attacks, etc) and blocking the attackers. This is the perfect
20
+ complement for our external security scans.
21
+ </p>
22
+ </div>
23
+ </div>
24
+ </div><!-- End poststuff -->
25
+
26
+ <table class="wp-list-table widefat sucuriscan-about-list sucuri-%%SUCURI.SettingsDisplay%%">
27
+ <thead>
28
+ <tr>
29
+ <th colspan="2">Plugin & Server Information</th>
30
+ </tr>
31
+ </thead>
32
+
33
+ <tbody>
34
+ <tr><td>Sucuri Plugin version</td><td>%%SUCURI.PluginVersion%%</td></li>
35
+ <tr><td>Sucuri Plugin MD5Sum (sucuri.php)</td><td>%%SUCURI.PluginMD5%%</td></li>
36
+ <tr><td>Sucuri Plugin Last-time scan</td><td>%%SUCURI.PluginRuntimeDatetime%%</td></li>
37
+ <tr><td>Operating System</td><td>%%SUCURI.OperatingSystem%%</td></li>
38
+ <tr><td>Server</td><td>%%SUCURI.Server%%</td></li>
39
+ <tr><td>Memory usage</td><td>%%SUCURI.MemoryUsage%%</td></li>
40
+ <tr><td>MYSQL Version</td><td>%%SUCURI.MySQLVersion%%</td></li>
41
+ <tr><td>SQL Mode</td><td>%%SUCURI.SQLMode%%</td></li>
42
+ <tr><td>PHP Version</td><td>%%SUCURI.PHPVersion%%</td></li>
43
+ <tr><td>PHP Safe Mode</td><td>%%SUCURI.SafeMode%%</td></li>
44
+ <tr><td>PHP Allow URL fopen</td><td>%%SUCURI.AllowUrlFopen%%</td></li>
45
+ <tr><td>PHP Memory Limit</td><td>%%SUCURI.MemoryLimit%%</td></li>
46
+ <tr><td>PHP Max Upload Size</td><td>%%SUCURI.UploadMaxFilesize%%</td></li>
47
+ <tr><td>PHP Max Post Size</td><td>%%SUCURI.PostMaxSize%%</td></li>
48
+ <tr><td>PHP Max Script Execute Time</td><td>%%SUCURI.MaxExecutionTime%%</td></li>
49
+ <tr><td>PHP Max Input Time</td><td>%%SUCURI.MaxInputTime%%</td></li>
50
+ </tbody>
51
+ </table>
52
+
53
+ <div id="poststuff">
54
+ <div class="postbox">
55
+ <h3>How does it work?</h3>
56
+ <div class="inside">
57
+ <ul>
58
+ <li>Web Application Firewall. Block attacks before they reach your site.</li>
59
+ <li>Integrity Monitoring. Receive notifications if any of your files are modified.</li>
60
+ <li>Audit Logs. Keep track of everything that happens inside WordPress, including new users, posts, login failures and successful logins.</li>
61
+ <li>Activity Reporting</li>
62
+ <li>1-click Hardening. Easy-to-use hardening options for your site.</li>
63
+ </ul>
64
+ </div>
65
+ </div>
66
+ </div><!-- End poststuff -->
67
+
68
+ <div id="poststuff">
69
+ <div class="postbox">
70
+ <h3>Web Application Firewall (WAF)</h3>
71
+ <div class="inside">
72
+ <p>
73
+ The WAF is a unique feature that is designed to intelligently protect your sites
74
+ from brute-force attacks like dictionary attacks and other similar unauthorized
75
+ access attempts. When a bad IP is identified it is blacklisted in your admin
76
+ dashboard. If it was an unintentional block, you have the ability to white-list
77
+ access to any IP.
78
+ </p>
79
+ <p>
80
+ The WAF is not tied to your application, it communicates with our servers and
81
+ allows us to see malicious attacks across the network. When one client gets attacked
82
+ by one bad IP in Croatia, we are able to push preventive measures to every plugin
83
+ to protect against that IP.
84
+ </p>
85
+ </div>
86
+ </div>
87
+ </div><!-- End poststuff -->
88
+
89
+ <div id="poststuff">
90
+ <div class="postbox">
91
+ <h3>Integrity Monitoring</h3>
92
+ <div class="inside">
93
+ <p>
94
+ This feature compares your core install against a clean version of core. In other
95
+ words, if it is not a 1-to-1 match with core you will be notified of a problem.
96
+ Future add-ons include:
97
+ </p>
98
+ <ul>
99
+ <li>Theme Integrity Checks</li>
100
+ <li>Plugin Integrity Checks</li>
101
+ <li>Third-party Integrity Checks</li>
102
+ </ul>
103
+ </div>
104
+ </div>
105
+ </div><!-- End poststuff -->
106
+
107
+ <div id="poststuff">
108
+ <div class="postbox">
109
+ <h3>Audit Trails</h3>
110
+ <div class="inside">
111
+ <p>
112
+ This feature is great for proactive webmasters who want to monitor their website
113
+ to ensure no unauthorized access or changes are made without prior approval.
114
+ Monitor your site for changes. This feature monitors for a large number of actions,
115
+ including:
116
+ </p>
117
+ <ul>
118
+ <li>Login attempts</li>
119
+ <li>New Posts</li>
120
+ <li>Failed Logins</li>
121
+ <li>New Plugins</li>
122
+ <li>File Changes</li>
123
+ <li>New Users</li>
124
+ <li>New Attachments</li>
125
+ <li>Delete Actions (users and posts)</li>
126
+ <li>Revisions</li>
127
+ </ul>
128
+ </div>
129
+ </div>
130
+ </div><!-- End poststuff -->
131
+
132
+ <div id="poststuff">
133
+ <div class="postbox">
134
+ <h3>1-Click Hardening</h3>
135
+ <div class="inside">
136
+ <p>
137
+ In our experience a high-percentage of the infections we see every day come from
138
+ poor management on the end-user’s part. This feature uses common hardening
139
+ measures that can be taken at any time and helps reduce infection risk. This
140
+ feature performs the following:
141
+ </p>
142
+ <ul>
143
+ <li>Checks software core version</li>
144
+ <li>Hides your version (security through obscurity)</li>
145
+ <li>Upload directory protected</li>
146
+ <li>Secret keys and salts created</li>
147
+ <li>Configuration file hardening/location verification</li>
148
+ <li>Hardening of readme file</li>
149
+ <li>PHP verification</li>
150
+ </ul>
151
+ </div>
152
+ </div>
153
+ </div><!-- End poststuff -->
154
+
155
+ </div><!-- End sucuriscan-maincontent -->
156
+ </div><!-- End postbox-container -->
157
+
158
+ %%SUCURI.SucuriWPSidebar%%
159
+
160
+ </div><!-- End wrap -->
inc/tpl/infosys-cronjobs.html.tpl ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ <table class="wp-list-table widefat sucuriscan-wpcron-list">
3
+ <thead>
4
+ <tr>
5
+ <th colspan="4">Wordpress Cronjobs (%%SUCURI.Cronjobs.Total%% tasks)</th>
6
+ </tr>
7
+ <tr>
8
+ <th>Task</th>
9
+ <th>Schedule</th>
10
+ <th>Next due (GMT/UTC)</th>
11
+ <th>Wordpress Hook</th>
12
+ <!-- <th>Hook arguments</th> -->
13
+ </tr>
14
+ </thead>
15
+
16
+ <tbody>
17
+ %%SUCURI.Cronjobs.List%%
18
+ </tbody>
19
+ </table>
inc/tpl/infosys-cronjobs.snippet.tpl ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <tr>
2
+ <td>%%SUCURI.Cronjob.Task%%</td>
3
+ <td>%%SUCURI.Cronjob.Schedule%%</td>
4
+ <td>%%SUCURI.Cronjob.Nexttime%%</td>
5
+ <td>%%SUCURI.Cronjob.Hook%%</td>
6
+ <!-- <td>%%SUCURI.Cronjob.Arguments%%</td> -->
7
+ </tr>
inc/tpl/infosys-htaccess.html.tpl CHANGED
@@ -10,7 +10,7 @@
10
  modifies this file to be able to handle pretty permalinks.
11
  </p>
12
 
13
- <div class="sucuri-notice-error sucuri-alert sucuri-alert-%%SUCURI.HTAccess.MessageType%% %%SUCURI.HTAccess.MessageVisible%%">
14
  <p>%%SUCURI.HTAccess.Message%%</p>
15
  </div>
16
 
10
  modifies this file to be able to handle pretty permalinks.
11
  </p>
12
 
13
+ <div class="sucuri-alert-%%SUCURI.HTAccess.MessageType%% %%SUCURI.HTAccess.MessageVisible%%">
14
  <p>%%SUCURI.HTAccess.Message%%</p>
15
  </div>
16
 
inc/tpl/infosys.html.tpl CHANGED
@@ -4,7 +4,7 @@
4
  <a href="http://sucuri.net/signup" target="_blank" title="Sucuri Security">
5
  <img src="%%SUCURI.SucuriURL%%/inc/images/logo.png" alt="Sucuri Security" />
6
  </a>
7
- <h2>Sucuri Security WordPress Plugin (Info System)</h2>
8
  </div>
9
 
10
 
@@ -12,6 +12,8 @@
12
  <div class="sucuriscan-maincontent">
13
  %%SUCURI.LoggedInUsers%%
14
 
 
 
15
  %%SUCURI.HTAccessIntegrity%%
16
 
17
  %%SUCURI.WordpressConfig%%
4
  <a href="http://sucuri.net/signup" target="_blank" title="Sucuri Security">
5
  <img src="%%SUCURI.SucuriURL%%/inc/images/logo.png" alt="Sucuri Security" />
6
  </a>
7
+ <h2>Sucuri Security WordPress Plugin (Site Info)</h2>
8
  </div>
9
 
10
 
12
  <div class="sucuriscan-maincontent">
13
  %%SUCURI.LoggedInUsers%%
14
 
15
+ %%SUCURI.Cronjobs%%
16
+
17
  %%SUCURI.HTAccessIntegrity%%
18
 
19
  %%SUCURI.WordpressConfig%%
inc/tpl/integrity-admins.html.tpl CHANGED
@@ -1,12 +1,13 @@
1
  <table class="wp-list-table widefat">
2
  <thead>
3
  <tr>
4
- <th colspan="3">Administrator Users</th>
5
  </tr>
6
  <tr>
7
  <th class="manage-column">Username</th>
8
  <th class="manage-column">Email</th>
9
  <th class="manage-column">Last Logins (newest to oldest)</th>
 
10
  </tr>
11
  </thead>
12
 
@@ -14,4 +15,3 @@
14
  %%SUCURI.AdminUsers.UserList%%
15
  </tbody>
16
  </table>
17
- <br>
1
  <table class="wp-list-table widefat">
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>
9
  <th class="manage-column">Last Logins (newest to oldest)</th>
10
+ <th class="manage-column">&nbsp;</th>
11
  </tr>
12
  </thead>
13
 
15
  %%SUCURI.AdminUsers.UserList%%
16
  </tbody>
17
  </table>
 
inc/tpl/integrity-admins.snippet.tpl CHANGED
@@ -2,7 +2,10 @@
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="sucuri-%%SUCURI.AdminUsers.NoLastLogins%%">There isn't information available for this account.</div>
 
 
 
6
  <table class="widefat sucuri-%%SUCURI.AdminUsers.NoLastLoginsTable%%">
7
  <thead>
8
  <tr>
@@ -15,4 +18,7 @@
15
  </tbody>
16
  </table>
17
  </td>
 
 
 
18
  </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="sucuri-%%SUCURI.AdminUsers.NoLastLogins%%">
6
+ <i>There isn't information available for this account.</i>
7
+ </div>
8
+
9
  <table class="widefat sucuri-%%SUCURI.AdminUsers.NoLastLoginsTable%%">
10
  <thead>
11
  <tr>
18
  </tbody>
19
  </table>
20
  </td>
21
+ <td>
22
+ <a href="%%SUCURI.AdminUsers.UserURL%%" target="_blank" class="button-primary">Edit</a>
23
+ </td>
24
  </tr>
inc/tpl/sidebar.html.tpl CHANGED
@@ -21,4 +21,4 @@
21
  <a href="http://cloudproxy.sucuri.net/" target="_blank" class="button button-primary">Read more</a>
22
  </div>
23
  </div>
24
- </div>
21
  <a href="http://cloudproxy.sucuri.net/" target="_blank" class="button button-primary">Read more</a>
22
  </div>
23
  </div>
24
+ </div>
lib/core_integrity.php DELETED
@@ -1,269 +0,0 @@
1
- <?php
2
- /* Sucuri Security - WordPress Core Intherity check against the latest version
3
- * Copyright (C) 2010-2012 Sucuri Security - http://sucuri.net
4
- * Released under the GPL - see LICENSE file for details.
5
- */
6
- if(!defined('SUCURISCAN'))
7
- {
8
- return(0);
9
- }
10
-
11
- function read_dir_r($dir = "./", $recursiv = false)
12
- {
13
- $skipname = basename(__FILE__);
14
- $skipname .= ",_sucuribackup,wp-config.php";
15
-
16
- $files_info = array();
17
-
18
- $dir_handler = opendir($dir);
19
-
20
- while(($entry = readdir($dir_handler)) !== false) {
21
- if ($entry != "." && $entry != "..") {
22
- $dir = preg_replace("/^(.*)(\/)+$/", "$1", $dir);
23
- $item = $dir . "/" . $entry;
24
- if (is_file($item)) {
25
-
26
- $skip_parts = explode(",", $skipname);
27
- foreach ($skip_parts as $skip) {
28
- if (strpos($item,$skip) !== false) {
29
- continue 2;
30
- }
31
- }
32
-
33
- $md5 = @md5_file($item);
34
- $time_stamp = @filectime($item);
35
- $item_name = str_replace(ABSPATH, "./", $item);
36
- $files_info[$item_name] = array(
37
- 'md5' => $md5,
38
- 'time' => $time_stamp
39
- );
40
-
41
- }
42
- elseif (is_dir($item) && $recursiv) {
43
- $files_info = array_merge( $files_info , read_dir_r($item) );
44
- }
45
- }
46
- }
47
-
48
- closedir($dir_handler);
49
- return $files_info;
50
- }
51
-
52
- function sucuriwp_core_integrity_check()
53
- {
54
-
55
- global $wp_version;
56
-
57
- $curlang = get_bloginfo("language");
58
-
59
- $cp = 0;
60
- $updates = get_core_updates();
61
- if( !is_array($updates) || empty($updates) || $updates[0]->response=='latest' ){
62
- $cp = 1;
63
- }
64
- if(strcmp($wp_version, "3.7") < 0)
65
- {
66
- $cp = 0;
67
- }
68
- $wp_version = htmlspecialchars($wp_version);
69
-
70
- if($cp == 0)
71
- {
72
- echo '<p><img style="position:relative;top:5px" height="22" width="22" '
73
- .'src="'.SUCURI_URL.'images/warn.png" /> &nbsp; Your current version ('.$wp_version.') is not the latest. '
74
- .'<a class="button-primary" href="update-core.php">Update now!</a> to be able to run the integrity check.</p>';
75
- }
76
- else
77
- {
78
- $latest_hashes = @file_get_contents("http://wordpress.sucuri.net/wp_core_latest_hashes.json");
79
- if($latest_hashes){
80
- $wp_core_latest_hashes = json_decode($latest_hashes, true);
81
-
82
- $wp_includes_hashes = read_dir_r( ABSPATH . "wp-includes", true);
83
- $wp_admin_hashes = read_dir_r( ABSPATH . "wp-admin", true);
84
- $wp_top_hashes = read_dir_r( ABSPATH , false);
85
-
86
- $wp_core_hashes = array_merge( $wp_includes_hashes , $wp_admin_hashes );
87
- $wp_core_hashes = array_merge( $wp_core_hashes , $wp_top_hashes );
88
-
89
- $added = @array_diff_assoc( $wp_core_hashes, $wp_core_latest_hashes ); //files added
90
- $removed = @array_diff_assoc( $wp_core_latest_hashes, $wp_core_hashes ); //files deleted
91
- unset($removed['wp_version']); //ignore wp_version key
92
- $compcurrent = @array_diff_key( $wp_core_hashes, $added ); //remove all added files from current filelist
93
- $complog = @array_diff_key( $wp_core_latest_hashes, $removed ); //remove all deleted files from old file list
94
- $modified = array(); //array of modified files
95
-
96
- //compare file hashes and mod dates
97
- foreach ( $compcurrent as $currfile => $currattr) {
98
-
99
- if ( array_key_exists( $currfile, $complog ) ) {
100
-
101
- //if attributes differ added to modified files array
102
- if ( strcmp( $currattr['md5'], $complog[$currfile]['md5'] ) != 0 ) {
103
- $modified[$currfile]['md5'] = $currattr['md5'];
104
- }
105
-
106
- }
107
-
108
- }
109
-
110
- //ignore some junk files
111
- if($curlang != "en_US")
112
- {
113
- //ignore added files
114
- unset($added['./licencia.txt']);
115
-
116
- //ignore removed files
117
- unset($removed['./license.txt']);
118
-
119
- //ignore modified files
120
- unset($modified['./wp-includes/version.php']);
121
- unset($modified['./wp-admin/setup-config.php']);
122
- unset($modified['./readme.html']);
123
- unset($modified['./wp-config-sample.php']);
124
- }
125
-
126
- sucuriscan_draw_corefiles_status(array(
127
- 'added'=>$added,
128
- 'removed'=>$removed,
129
- 'modified'=>$modified
130
- ));
131
- }else{
132
- sucuriscan_admin_notice('error', 'Error retrieving the wordpress core hashes, try again.');
133
- }
134
- }
135
- }
136
-
137
- function sucuriscan_draw_corefiles_status($list=array()){
138
- if( is_array($list) && !empty($list) ): ?>
139
- <table class="wp-list-table widefat sucuriscan-corefiles">
140
- <thead>
141
- <tr><th>Core files altered</th></tr>
142
- </thead>
143
- <tbody>
144
- <?php
145
- foreach($list as $core_file_type=>$core_file_list){
146
- printf('<tr><th>Core File %s: %d</th></tr>', ucwords($core_file_type), sizeof($core_file_list));
147
- foreach($core_file_list as $filepath=>$extrainfo){
148
- printf('<tr><td>%s</td></tr>', $filepath);
149
- }
150
- }
151
- ?>
152
- </tbody>
153
- </table>
154
- <?php endif; ?>
155
- <?php }
156
-
157
- function sucuriwp_list_admins($userlevel = '10') {
158
-
159
- global $wpdb;
160
- /*
161
- 1 = subscriber
162
- 2 = editor
163
- 3 = author
164
- 7 = publisher
165
- 10 = administrator
166
- */
167
-
168
- // Page pseudo-variables initialization.
169
- $template_variables = array(
170
- 'SucuriURL'=>SUCURI_URL,
171
- 'AdminUsers.UserList'=>''
172
- );
173
-
174
- $admins = $wpdb->get_results("SELECT * FROM $wpdb->usermeta WHERE meta_value = '$userlevel'");
175
- foreach ( (array) $admins as $user ) {
176
- $admin = get_userdata( $user->user_id );
177
- $admin->lastlogins = sucuriscan_get_logins(4, $admin->ID);
178
- $userlevel = $admin->wp2_user_level;
179
- $name = $admin->nickname;
180
-
181
- $user_snippet = array(
182
- 'AdminUsers.Username'=>$admin->user_login,
183
- 'AdminUsers.Email'=>$admin->user_email,
184
- 'AdminUsers.LastLogins'=>''
185
- );
186
- if( !empty($admin->lastlogins) ){
187
- $user_snippet['AdminUsers.NoLastLogins'] = 'hidden';
188
- $user_snippet['AdminUsers.NoLastLoginsTable'] = 'visible';
189
- foreach($admin->lastlogins as $lastlogin){
190
- $user_snippet['AdminUsers.LastLogins'] .= sucuriscan_get_template('integrity-admins-lastlogin.snippet.tpl', array(
191
- 'AdminUsers.RemoteAddr'=>$lastlogin->user_remoteaddr,
192
- 'AdminUsers.Datetime'=>$lastlogin->user_lastlogin
193
- ));
194
- }
195
- }else{
196
- $user_snippet['AdminUsers.NoLastLogins'] = 'visible';
197
- $user_snippet['AdminUsers.NoLastLoginsTable'] = 'hidden';
198
- }
199
-
200
- $template_variables['AdminUsers.UserList'] .= sucuriscan_get_template('integrity-admins.snippet.tpl', $user_snippet);
201
- }
202
-
203
- echo sucuriscan_get_template('integrity-admins.html.tpl', $template_variables);
204
- }
205
-
206
- function sucuriwp_check_plugins()
207
- {
208
- do_action("wp_update_plugins"); // force WP to check plugins for updates
209
- wp_update_plugins();
210
- $update_plugins = get_site_transient('update_plugins'); // get information of updates
211
- $plugins_need_update = $update_plugins->response; // plugins that need updating
212
-
213
- echo '<div class="postbox">';
214
- echo "<h3>Outdated Plugins</h3>";
215
- echo '<div class="inside">';
216
- if (!empty($update_plugins->response)) { // any plugin updates available?
217
- $plugins_need_update = $update_plugins->response; // plugins that need updating
218
- $active_plugins = array_flip(get_option('active_plugins')); // find which plugins are active
219
- $plugins_need_update = array_intersect_key($plugins_need_update, $active_plugins); // only keep plugins that are active
220
- if(count($plugins_need_update) >= 1) { // any plugins need updating after all the filtering gone on above?
221
- require_once(ABSPATH . 'wp-admin/includes/plugin-install.php'); // Required for plugin API
222
- require_once(ABSPATH . WPINC . '/version.php' ); // Required for WP core version
223
- foreach($plugins_need_update as $key => $data) { // loop through the plugins that need updating
224
- $plugin_info = get_plugin_data(WP_PLUGIN_DIR . "/" . $key); // get local plugin info
225
- $info = plugins_api('plugin_information', array('slug' => $data->slug )); // get repository plugin info
226
- $message = "\n".sprintf(__("Plugin: %s is out of date. Please update from version %s to %s", "wp-updates-notifier"), $plugin_info['Name'], $plugin_info['Version'], $data->new_version)."\n";
227
- echo "<p>$message</p>";
228
- }
229
- }
230
- else
231
- {
232
- echo "<p>All plugins are up-to-date!</p>";
233
- }
234
- }
235
- else
236
- {
237
- echo "<p>All plugins are up-to-date!</p>";
238
- }
239
- echo '</div>';
240
- echo '</div>';
241
- }
242
-
243
- function sucuriwp_check_themes()
244
- {
245
- do_action("wp_update_themes"); // force WP to check for theme updates
246
- wp_update_themes();
247
- $update_themes = get_site_transient('update_themes'); // get information of updates
248
-
249
- echo '<div class="postbox">';
250
- echo "<h3>Outdated Themes</h3>";
251
- echo '<div class="inside">';
252
- if (!empty($update_themes->response)) { // any theme updates available?
253
- $themes_need_update = $update_themes->response; // themes that need updating
254
-
255
- if(count($themes_need_update) >= 1) { // any themes need updating after all the filtering gone on above?
256
- foreach($themes_need_update as $key => $data) { // loop through the themes that need updating
257
- $theme_info = get_theme_data(WP_CONTENT_DIR . "/themes/" . $key . "/style.css"); // get theme info
258
- $message = sprintf(__("Theme: %s is out of date. Please update from version %s to %s", "wp-updates-notifier"), $theme_info['Name'], $theme_info['Version'], $data['new_version'])."\n";
259
- echo "<p>$message</p>";
260
- }
261
- }
262
- }
263
- else
264
- {
265
- echo "<p>All themes are up-to-date!</p>";
266
- }
267
- echo '</div>';
268
- echo '</div>';
269
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/hardening.php DELETED
@@ -1,379 +0,0 @@
1
- <?php
2
- /* Sucuri Security - SiteCheck Malware Scanner
3
- * Copyright (C) 2010-2013 Sucuri Security - http://sucuri.net
4
- * Released under the GPL - see LICENSE file for details.
5
- */
6
- if(!defined('SUCURISCAN'))
7
- {
8
- return(0);
9
- }
10
-
11
- function sucuriscan_wrapper_open($msg)
12
- {
13
- ?>
14
- <div class="postbox">
15
- <h3><?php echo $msg; ?></h3>
16
- <div class="inside">
17
- <?php
18
- }
19
- function sucuriscan_wrapper_close()
20
- {
21
- ?>
22
- </div>
23
- </div>
24
- <?php
25
- }
26
-
27
- function sucuriscan_harden_error($message)
28
- {
29
- return('<div id="message" class="error"><p>'.$message.'</p></div>');
30
- }
31
-
32
- function sucuriscan_harden_ok($message)
33
- {
34
- return( '<div id="message" class="updated"><p>'.$message.'</p></div>');
35
- }
36
-
37
- function sucuriscan_harden_status($status, $type, $messageok, $messagewarn,
38
- $desc = NULL, $updatemsg = NULL)
39
- {
40
- if($desc != NULL)
41
- {
42
- echo "<p>$desc</p>";
43
- }
44
-
45
- if($status == 1)
46
- {
47
- echo '<h4>'.
48
- '<img style="position:relative;top:5px" height="22" width="22"'.
49
- 'src="'.SUCURI_URL.'images/ok.png" /> &nbsp; '.
50
- $messageok.'.</h4>';
51
-
52
- if($updatemsg != NULL){ echo $updatemsg; }
53
-
54
- if($type != NULL)
55
- {
56
- echo "<input type='submit' name='{$type}_unharden' value='Revert hardening' class='button-secondary' />";
57
- echo '<br /><br />';
58
- }
59
- }
60
- else
61
- {
62
- echo '<h4>'.
63
- '<img style="position:relative;top:5px" height="22" width="22"'.
64
- 'src="'.SUCURI_URL.'images/warn.png" /> &nbsp; '.
65
- $messagewarn. '.</h4>';
66
-
67
- if($updatemsg != NULL){ echo $updatemsg; }
68
-
69
- if($type != NULL)
70
- {
71
- echo '<input class="button-primary" type="submit" name="'.$type.'"
72
- value="Harden it!" />';
73
- }
74
- }
75
-
76
-
77
- }
78
-
79
- function sucuriscan_harden_version()
80
- {
81
- global $wp_version;
82
- $cp = 0;
83
- $updates = get_core_updates();
84
- if (!is_array($updates))
85
- {
86
- $cp = 1;
87
- }
88
- else if(empty($updates))
89
- {
90
- $cp = 1;
91
- }
92
- else if($updates[0]->response == 'latest')
93
- {
94
- $cp = 1;
95
- }
96
- if(strcmp($wp_version, "3.7") < 0)
97
- {
98
- $cp = 0;
99
- }
100
- $wp_version = htmlspecialchars($wp_version);
101
-
102
-
103
- sucuriscan_wrapper_open("Verify WordPress Version");
104
-
105
-
106
- sucuriscan_harden_status($cp, NULL,
107
- "WordPress is updated", "WordPress is not updated",
108
- NULL);
109
-
110
- if($cp == 0)
111
- {
112
- echo "<p>Your current version ($wp_version) is not current.</p><p><a class='button-primary' href='update-core.php'>Update now!</a></p>";
113
- }
114
- else
115
- {
116
- echo "<p>Your WordPress installation ($wp_version) is current.</p>";
117
- }
118
- sucuriscan_wrapper_close();
119
- }
120
-
121
- function sucuri_harden_removegenerator()
122
- {
123
- /* Enabled by default with this plugin. */
124
- $cp = 1;
125
-
126
- sucuriscan_wrapper_open("Remove WordPress Version");
127
-
128
- sucuriscan_harden_status($cp, NULL,
129
- "WordPress version properly hidden", NULL,
130
- "It checks if your WordPress version is being hidden".
131
- " from being displayed in the generator tag ".
132
- "(enabled by default with this plugin).");
133
-
134
- sucuriscan_wrapper_close();
135
- }
136
-
137
- function sucuriscan_harden_upload()
138
- {
139
- $cp = 1;
140
- $upmsg = NULL;
141
- $htaccess_upload = dirname(sucuriscan_dir_filepath())."/.htaccess";
142
-
143
- if(!is_readable($htaccess_upload))
144
- {
145
- $cp = 0;
146
- }
147
- else
148
- {
149
- $cp = 0;
150
- $fcontent = file($htaccess_upload);
151
- foreach($fcontent as $fline)
152
- {
153
- if(strpos($fline, "deny from all") !== FALSE)
154
- {
155
- $cp = 1;
156
- break;
157
- }
158
- }
159
- }
160
-
161
- if( isset($_POST['wpsucuri-doharden']) ){
162
- if( isset($_POST['sucuriscan_harden_upload']) && $cp == 0 )
163
- {
164
- if(@file_put_contents($htaccess_upload,
165
- "\n<Files *.php>\ndeny from all\n</Files>")===FALSE)
166
- {
167
- $upmsg = sucuriscan_harden_error("ERROR: Unable to create <code>.htaccess</code> file, folder destination is not writable.");
168
- }
169
- else
170
- {
171
- $upmsg = sucuriscan_harden_ok("COMPLETE: Upload directory successfully hardened");
172
- $cp = 1;
173
- }
174
- }
175
-
176
- elseif( isset($_POST['sucuriscan_harden_upload_unharden']) ){
177
- $htaccess_upload_writable = ( file_exists($htaccess_upload) && is_writable($htaccess_upload) ) ? TRUE : FALSE;
178
- $htaccess_content = $htaccess_upload_writable ? file_get_contents($htaccess_upload) : '';
179
-
180
- if( $htaccess_upload_writable ){
181
- $cp = 0;
182
- if( preg_match('/<Files \*\.php>\ndeny from all\n<\/Files>/', $htaccess_content, $match) ){
183
- $htaccess_content = str_replace("<Files *.php>\ndeny from all\n</Files>", '', $htaccess_content);
184
- @file_put_contents($htaccess_upload, $htaccess_content, LOCK_EX);
185
- }
186
- sucuriscan_admin_notice('updated', '<strong>OK.</strong> WP-Content Uploads directory protection reverted.');
187
- }else{
188
- $harden_process = '<strong>Error.</strong> The <code>wp-content/uploads/.htaccess</code> does
189
- not exists or is not writable, you will need to remove the following code manually there:
190
- <code>&lt;Files *.php&gt;deny from all&lt;/Files&gt;</code>';
191
- sucuriscan_admin_notice('error', $harden_process);
192
- }
193
- }
194
- }
195
-
196
- sucuriscan_wrapper_open("Protect Uploads Directory");
197
- sucuriscan_harden_status($cp, "sucuriscan_harden_upload",
198
- "Upload directory properly hardened",
199
- "Upload directory not hardened",
200
- "It checks if your upload directory allows PHP ".
201
- "execution or if it is browsable.", $upmsg);
202
- sucuriscan_wrapper_close();
203
- }
204
-
205
- function sucuriscan_harden_wpcontent()
206
- {
207
- $cp = 1;
208
- $upmsg = NULL;
209
- $htaccess_upload = ABSPATH."/wp-content/.htaccess";
210
-
211
- if(!is_readable($htaccess_upload))
212
- {
213
- $cp = 0;
214
- }
215
- else
216
- {
217
- $cp = 0;
218
- $fcontent = file($htaccess_upload);
219
- foreach($fcontent as $fline)
220
- {
221
- if(strpos($fline, "deny from all") !== FALSE)
222
- {
223
- $cp = 1;
224
- break;
225
- }
226
- }
227
- }
228
-
229
- if( isset($_POST['wpsucuri-doharden']) ){
230
- if( isset($_POST['sucuriscan_harden_wpcontent']) && $cp == 0 )
231
- {
232
- if(@file_put_contents($htaccess_upload,
233
- "\n<Files *.php>\ndeny from all\n</Files>")===FALSE)
234
- {
235
- $upmsg = sucuriscan_harden_error("ERROR: Unable to create <code>.htaccess</code> file, folder destination is not writable.");
236
- }
237
- else
238
- {
239
- $upmsg = sucuriscan_harden_ok("COMPLETE: wp-content directory successfully hardened");
240
- $cp = 1;
241
- }
242
- }
243
-
244
- elseif( isset($_POST['sucuriscan_harden_wpcontent_unharden']) ){
245
- $htaccess_upload_writable = ( file_exists($htaccess_upload) && is_writable($htaccess_upload) ) ? TRUE : FALSE;
246
- $htaccess_content = $htaccess_upload_writable ? file_get_contents($htaccess_upload) : '';
247
-
248
- if( $htaccess_upload_writable ){
249
- $cp = 0;
250
- if( preg_match('/<Files \*\.php>\ndeny from all\n<\/Files>/', $htaccess_content, $match) ){
251
- $htaccess_content = str_replace("<Files *.php>\ndeny from all\n</Files>", '', $htaccess_content);
252
- @file_put_contents($htaccess_upload, $htaccess_content, LOCK_EX);
253
- }
254
- sucuriscan_admin_notice('updated', '<strong>OK.</strong> WP-Content directory protection reverted.');
255
- }else{
256
- $harden_process = '<strong>Error.</strong> The <code>wp-content/.htaccess</code> does
257
- not exists or is not writable, you will need to remove the following code manually there:
258
- <code>&lt;Files *.php&gt;deny from all&lt;/Files&gt;</code>';
259
- sucuriscan_admin_notice('error', $harden_process);
260
- }
261
- }
262
- }
263
-
264
- sucuriscan_wrapper_open("Restrict wp-content Access");
265
- sucuriscan_harden_status($cp, "sucuriscan_harden_wpcontent",
266
- "WP-content directory properly hardened",
267
- "WP-content directory not hardened",
268
- "This option blocks direct PHP access to any file inside wp-content. <p><strong>WARN: <span class='error-message'>Do not enable this option if ".
269
- "your site uses TimThumb or similar scripts.</span> If you enable and you need to disable, please remove the .htaccess from wp-content.</strong></p>", $upmsg);
270
- sucuriscan_wrapper_close();
271
- }
272
-
273
- function sucuriscan_harden_wpincludes()
274
- {
275
- $cp = 1;
276
- $upmsg = NULL;
277
- $htaccess_upload = ABSPATH."/wp-includes/.htaccess";
278
-
279
- if(!is_readable($htaccess_upload))
280
- {
281
- $cp = 0;
282
- }
283
- else
284
- {
285
- $cp = 0;
286
- $fcontent = file($htaccess_upload);
287
- foreach($fcontent as $fline)
288
- {
289
- if(strpos($fline, "deny from all") !== FALSE)
290
- {
291
- $cp = 1;
292
- break;
293
- }
294
- }
295
- }
296
-
297
- if( isset($_POST['wpsucuri-doharden']) ){
298
- if( isset($_POST['sucuriscan_harden_wpincludes']) && $cp == 0 )
299
- {
300
- if(@file_put_contents($htaccess_upload,
301
- "\n<Files *.php>\ndeny from all\n</Files>\n<Files wp-tinymce.php>\nallow from all\n</Files>\n")===FALSE)
302
- {
303
- $upmsg = sucuriscan_harden_error("ERROR: Unable to create <code>.htaccess</code> file, folder destination is not writable.");
304
- }
305
- else
306
- {
307
- $upmsg = sucuriscan_harden_ok("COMPLETE: wp-includes directory successfully hardened.");
308
- $cp = 1;
309
- }
310
- }
311
-
312
- elseif( isset($_POST['sucuriscan_harden_wpincludes_unharden']) ){
313
- $htaccess_upload_writable = ( file_exists($htaccess_upload) && is_writable($htaccess_upload) ) ? TRUE : FALSE;
314
- $htaccess_content = $htaccess_upload_writable ? file_get_contents($htaccess_upload) : '';
315
-
316
- if( $htaccess_upload_writable ){
317
- $cp = 0;
318
- if( preg_match_all('/<Files (\*|wp-tinymce|ms-files)\.php>\n(deny|allow) from all\n<\/Files>/', $htaccess_content, $match) ){
319
- foreach($match[0] as $restriction){
320
- $htaccess_content = str_replace($restriction, '', $htaccess_content);
321
- }
322
- @file_put_contents($htaccess_upload, $htaccess_content, LOCK_EX);
323
- }
324
- sucuriscan_admin_notice('updated', '<strong>OK.</strong> WP-Includes directory protection reverted.');
325
- }else{
326
- $harden_process = '<strong>Error.</strong> The <code>wp-includes/.htaccess</code> does
327
- not exists or is not writable, you will need to remove the following code manually there:
328
- <code>&lt;Files *.php&gt;deny from all&lt;/Files&gt;</code>';
329
- sucuriscan_admin_notice('error', $harden_process);
330
- }
331
- }
332
- }
333
-
334
- sucuriscan_wrapper_open("Restrict wp-includes Access");
335
- sucuriscan_harden_status($cp, "sucuriscan_harden_wpincludes",
336
- "wp-includes directory properly hardened",
337
- "wp-includes directory not hardened",
338
- "This option blocks direct PHP access to any file inside wp-includes. ", $upmsg);
339
- sucuriscan_wrapper_close();
340
- }
341
-
342
- function sucuriscan_harden_phpversion()
343
- {
344
- $phpv = phpversion();
345
-
346
- if(strncmp($phpv, "5.", 2) < 0)
347
- {
348
- $cp = 0;
349
- }
350
- else
351
- {
352
- $cp = 1;
353
- }
354
-
355
- sucuriscan_wrapper_open("Verify PHP Version");
356
- sucuriscan_harden_status($cp, NULL,
357
- "Using an updated version of PHP (v $phpv)",
358
- "The version of PHP you are using ($phpv) is not current, not recommended, and/or not supported",
359
- "This checks if you have the latest version of PHP installed.", NULL);
360
- sucuriscan_wrapper_close();
361
- }
362
-
363
- function sucuriscan_cloudproxy_enabled(){
364
- $enabled = sucuriscan_is_behind_cloudproxy();
365
-
366
- sucuriscan_wrapper_open('Verify if your site is protected by a Web Firewall');
367
- sucuriscan_harden_status(
368
- $enabled, NULL,
369
- 'Your website is protected by a Website Firewall (WAF)',
370
- 'Your website is not protected by a Website Firewall (WAF)',
371
- 'A WAF is a protection layer for your web site, blocking all sort of attacks (brute force attempts, DDoS, SQL injections, etc) and helping it remain
372
- malware and blacklist free. This test checks if your site is using <a href="http://sucuri.net/services/preventive">Sucuri\'s CloudProxy WAF</a> to protect your site. ',
373
- NULL
374
- );
375
- if( $enabled!==TRUE ){
376
- echo '<a href="https://login.sucuri.net/signup2/create?CloudProxy" target="_blank" class="button button-primary">Harden it!</a>';
377
- }
378
- sucuriscan_wrapper_close();
379
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
readme.txt CHANGED
@@ -3,16 +3,16 @@ Contributors: dd@sucuri.net, dremeda
3
  Donate Link: http://sitecheck.sucuri.net
4
  Tags: malware, security, scan, spam, virus, sucuri, WordPress,
5
  Requires at least:3.2
6
- Stable tag:1.5.2
7
- Tested up to: 3.7.1
8
 
9
- The Sucuri Security - SiteCheck Malware Scanner plugin enables you to scan your WordPress site using Sucuri SiteCheck and verify the integrity of your core files right in your dashboard. It also includes post-hack options to help you reset passwords and secret keys in case it has been already hacked.
10
 
11
  == Description ==
12
 
13
  Sucuri SiteCheck will check your site 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.
14
 
15
- You can also scan your site online at <a href="http://sitecheck.sucuri.net">SiteCheck.Sucuri.net</a>.
16
 
17
  Sucuri SiteCheck detects various types of malware, SPAM injections, website errors, disabled sites, database connection issues and code anomalies that require special attention to include:
18
 
@@ -66,6 +66,13 @@ the compromise on your site).
66
 
67
  == Changelog ==
68
 
 
 
 
 
 
 
 
69
  = 1.5.2 =
70
  * Adding additional information about .htaccess hacks and the server environment.
71
 
3
  Donate Link: http://sitecheck.sucuri.net
4
  Tags: malware, security, scan, spam, virus, sucuri, WordPress,
5
  Requires at least:3.2
6
+ Stable tag:1.5.5
7
+ Tested up to: 3.8
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
 
13
  Sucuri SiteCheck will check your site 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.
14
 
15
+ You can also check for malware, blacklisting, and overall security status by scanning for free at <a href="http://sitecheck.sucuri.net">SiteCheck.Sucuri.net</a>.
16
 
17
  Sucuri SiteCheck detects various types of malware, SPAM injections, website errors, disabled sites, database connection issues and code anomalies that require special attention to include:
18
 
66
 
67
  == Changelog ==
68
 
69
+ = 1.5.5 =
70
+ * Added list of logged in users.
71
+ * Added system page.
72
+ * Change the integrity checking to use WP API.
73
+
74
+ = 1.5.4 = Bug fixes.
75
+
76
  = 1.5.2 =
77
  * Adding additional information about .htaccess hacks and the server environment.
78
 
sucuri.php CHANGED
@@ -7,28 +7,78 @@ Description: The <a href="http://sucuri.net">Sucuri Security</a> - SiteCheck Mal
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.5.2
11
  Author URI: http://sucuri.net
12
  */
13
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  /* No direct access. */
15
  if(!function_exists('add_action'))
16
  {
17
  exit(0);
18
  }
19
 
20
- @set_time_limit(0);
21
- @ini_set('memory_limit', '2048M');
22
- @ini_set('max_execution_time', 0);
23
- @ignore_user_abort(TRUE);
24
-
25
  define('SUCURISCAN','sucuriscan');
26
- define('SUCURISCAN_VERSION','1.5.2');
 
 
 
 
 
 
 
 
27
  define('SUCURI_URL',plugin_dir_url( __FILE__ ));
 
 
 
 
 
 
 
 
 
28
  define('SUCURISCAN_PLUGIN_FOLDER', 'sucuri-scanner');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  define('SUCURISCAN_LASTLOGINS_USERSLIMIT', 100);
30
 
31
  if( !function_exists('sucuriscan_create_uploaddir') ){
 
 
 
 
 
 
32
  function sucuriscan_create_uploaddir(){
33
  $plugin_upload_folder = sucuriscan_dir_filepath();
34
  if( !file_exists($plugin_upload_folder) ){
@@ -45,8 +95,10 @@ if( !function_exists('sucuriscan_create_uploaddir') ){
45
  add_action('admin_init', 'sucuriscan_create_uploaddir');
46
  }
47
 
48
- /* Requires files. */
49
- add_action( 'admin_enqueue_scripts', 'sucuriscan_admin_script_style_registration', 1 );
 
 
50
  function sucuriscan_admin_script_style_registration() { ?>
51
  <link rel="stylesheet" href="<?php echo SUCURI_URL; ?>/inc/css/sucuriscan-default-css.css" type="text/css" media="all" />
52
  <script type="text/javascript">
@@ -56,10 +108,14 @@ function sucuriscan_admin_script_style_registration() { ?>
56
  }
57
  </script>
58
  <?php }
 
59
 
60
- /* sucuri_dir_filepath:
61
- * Returns the system filepath to the relevant user uploads
62
- * directory for this site. Multisite capable.
 
 
 
63
  */
64
  function sucuriscan_dir_filepath($path = '')
65
  {
@@ -68,11 +124,15 @@ function sucuriscan_dir_filepath($path = '')
68
  return($wp_dir_array['basedir']."/sucuri/$path");
69
  }
70
 
71
- /* Starting Sucuri Scan side bar. */
 
 
 
 
72
  function sucuriscan_menu()
73
  {
74
  add_menu_page('Sucuri Free', 'Sucuri Free', 'manage_options',
75
- 'sucuriscan', 'sucuri_scan_page', SUCURI_URL.'images/menu-icon.png');
76
  add_submenu_page('sucuriscan', 'Sucuri Scanner', 'Sucuri Scanner', 'manage_options',
77
  'sucuriscan', 'sucuri_scan_page');
78
 
@@ -88,209 +148,22 @@ function sucuriscan_menu()
88
  add_submenu_page('sucuriscan', 'Last Logins', 'Last Logins', 'manage_options',
89
  'sucuriscan_lastlogins', 'sucuriscan_lastlogins_page');
90
 
91
- add_submenu_page('sucuriscan', 'Info System', 'Info System', 'manage_options',
92
  'sucuriscan_infosys', 'sucuriscan_infosys_page');
93
- }
94
-
95
- /* Sucuri malware scan page. */
96
-
97
- function sucuri_scan_page()
98
- {
99
- $U_ERROR = NULL;
100
- if( !current_user_can('manage_options') ){
101
- wp_die(__('You do not have sufficient permissions to access this page: Sucuri Malware Scanner') );
102
- }
103
-
104
- $template_variables = array(
105
- 'PluginURL'=>SUCURI_URL,
106
- 'Sidebar'=>sucuriscan_get_template('sidebar.html.tpl')
107
- );
108
-
109
- if( isset($_POST['wpsucuri-doscan']) ){
110
- sucuriscan_print_scan();
111
- return(1);
112
- }
113
-
114
- echo sucuriscan_get_template('initial-page.html.tpl', $template_variables);
115
- }
116
-
117
- function sucuriscan_print_scan()
118
- {
119
- $website_scanned = home_url();
120
- $myresults = wp_remote_get('http://sitecheck.sucuri.net/scanner/?serialized&clear&fromwp&scan='.$website_scanned, array('timeout' => 180));
121
-
122
- echo '<div class="wrap">';
123
- echo '<h2 id="warnings_hook"></h2>';
124
- echo '<div class="sucuriscan_header">';
125
- echo '<a href="http://sucuri.net/signup" target="_blank" title="Sucuri Security">';
126
- echo '<img src="'.SUCURI_URL.'/inc/images/logo.png" alt="Sucuri Security" />';
127
- echo '</a>';
128
- sucuriscan_pagestop("Sucuri SiteCheck Malware Scanner");
129
- echo '</div>';
130
-
131
- echo '<div class="postbox-container" style="width:75%;">';
132
- echo '<div class="sucuriscan-maincontent">';
133
-
134
- if(is_wp_error($myresults))
135
- {
136
- echo '<div id="poststuff">';
137
- echo '<div class="postbox">';
138
- echo '<h3>Error retrieving the scan report</h3>';
139
-
140
- echo '<div class="inside">';
141
- print_r($myresults);
142
- echo '</div>';
143
- echo '</div>';
144
- echo '</div>';
145
- }else if( preg_match('/^ERROR:/', $myresults['body']) ){
146
- sucuriscan_admin_notice('error', $myresults['body'].' The URL scanned was: <code>'.$website_scanned.'</code>');
147
- }else{
148
- $res = unserialize($myresults['body']);
149
-
150
-
151
- // Check for general warnings, and return the information for Infected/Clean site.
152
- $malware_warns_exists = isset($res['MALWARE']['WARN']) ? TRUE : FALSE;
153
- echo '<div id="poststuff">';
154
- echo '<div class="postbox">';
155
- echo '<h3>';
156
- if( !$malware_warns_exists ){
157
- echo '<img style="position:relative;top:5px" height="22" width="22" src="
158
- '.site_url().'/wp-content/plugins/sucuri-scanner/images/ok.png" /> &nbsp;
159
- No malware was identified';
160
- }else{
161
- echo '<img style="position:relative;top:5px" height="22" width="22" src="
162
- '.site_url().'/wp-content/plugins/sucuri-scanner/images/warn.png" /> &nbsp;
163
- Site compromised (malware was identified)';
164
- }
165
- echo '</h3>';
166
- echo '<div class="inside">';
167
- if( !$malware_warns_exists ){
168
- echo "<span><strong>Malware:</strong> No.</span><br>";
169
- echo "<span><strong>Malicious javascript:</strong> No.</span><br>";
170
- echo "<span><strong>Malicious iframes:</strong> No.</span><br>";
171
- echo "<span><strong>Suspicious redirections (htaccess):</strong> No.</span><br>";
172
- echo "<span><strong>Blackhat SEO Spam:</strong> No.</span><br>";
173
- echo "<span><strong>Anomaly detection:</strong> Clean.</span><br>";
174
- }else{
175
- foreach($res['MALWARE']['WARN'] as $malres)
176
- {
177
- if(!is_array($malres))
178
- {
179
- echo htmlspecialchars($malres);
180
- }
181
- else
182
- {
183
- $mwdetails = explode("\n", htmlspecialchars($malres[1]));
184
- echo htmlspecialchars($malres[0])."\n<br />". substr($mwdetails[0], 1)."<br />\n";
185
- }
186
- }
187
- }
188
- echo "<br />";
189
- echo '<i>More details here: <a href="http://sitecheck.sucuri.net/scanner/?scan='.$website_scanned.'">http://sitecheck.sucuri.net/scanner/?scan='.$website_scanned.'</a></i>';
190
- echo "<hr />\n";
191
- echo '<i>If our free scanner did not detect any issue, you may have a more complicated and hidden problem. You can try our <a href="admin.php?page=sucuriscan_core_integrity">WordPress integrity checks</a> or sign up with Sucuri <a target="_blank" href="http://sucuri.net/signup">here</a> for a complete and in depth scan+cleanup (not included in the free checks).</i>';
192
- echo "<hr />\n";
193
- echo '</div>';
194
- echo '</div>';
195
- echo '</div>';
196
-
197
-
198
- // Check for blacklist reports, and return the information retrieved from multiple blacklist services.
199
- echo '<div id="poststuff">';
200
- echo '<div class="postbox">';
201
- echo '<h3>';
202
- if(isset($res['BLACKLIST']['WARN']))
203
- {
204
- echo '<img style="position:relative;top:5px" height="22" width="22" src="
205
- '.site_url().'/wp-content/plugins/sucuri-scanner/images/warn.png" /> &nbsp;
206
- Site blacklisted';
207
- }
208
- else
209
- {
210
- echo '<img style="position:relative;top:5px" height="22" width="22" src="
211
- '.site_url().'/wp-content/plugins/sucuri-scanner/images/ok.png" /> &nbsp;
212
- Site blacklist-free';
213
- }
214
- echo '</h3>';
215
- echo '<div class="inside">';
216
- foreach(array(
217
- 'INFO'=>'CLEAN',
218
- 'WARN'=>'WARNING'
219
- ) as $type=>$group_title){
220
- if( isset($res['BLACKLIST'][$type]) ){
221
- foreach($res['BLACKLIST'][$type] as $blres){
222
- $report_site = htmlspecialchars($blres[0]);
223
- $report_url = htmlspecialchars($blres[1]);
224
- echo "<b>{$group_title}: </b>{$report_site} <a href='{$report_url}' target='_blank'>{$report_url}</a><br />";
225
- }
226
- }
227
- }
228
- echo '</div>';
229
- echo '</div>';
230
- echo '</div>';
231
-
232
-
233
- // Check for general versions in some common services/software used to serve this website.
234
- global $wp_version;
235
- $wordpress_updated = FALSE;
236
- $updates = function_exists('get_core_updates') ? get_core_updates() : array();
237
- if( !is_array($updates) || empty($updates) || $updates[0]->response=='latest' ){
238
- $wordpress_updated = TRUE;
239
- }
240
-
241
- echo '<div id="poststuff">';
242
- echo '<div class="postbox">';
243
- echo '<h3>';
244
- if($wordpress_updated)
245
- {
246
- echo '<img style="position:relative;top:5px" height="22" width="22" src="
247
- '.site_url().'/wp-content/plugins/sucuri-scanner/images/ok.png" /> &nbsp;
248
- System info (WordPress upgraded)';
249
- }
250
- else
251
- {
252
- echo '<img style="position:relative;top:5px" height="22" width="22" src="
253
- '.site_url().'/wp-content/plugins/sucuri-scanner/images/warn.png" /> &nbsp;
254
- System info (WordPress outdated)';
255
- }
256
- echo '</h3>';
257
- echo '<div class="inside">';
258
- echo "<b>Site:</b> ".$res['SCAN']['SITE'][0]." (".$res['SCAN']['IP'][0].")<br />\n";
259
- echo "<b>WordPress: </b> $wp_version<br />\n";
260
- echo "<b>PHP: </b> ".phpversion()."<br />\n";
261
- if(isset($res['SYSTEM']['NOTICE']))
262
- {
263
- foreach($res['SYSTEM']['NOTICE'] as $notres)
264
- {
265
- if(is_array($notres))
266
- {
267
- echo htmlspecialchars($notres[0]). " ".htmlspecialchars($notres[1]);
268
- }
269
- else
270
- {
271
- echo htmlspecialchars($notres)."<br />\n";
272
- }
273
- }
274
- }
275
- echo '</div>';
276
- echo '</div>';
277
- echo '</div>';
278
- }
279
- ?>
280
-
281
- <p>If you have any questions about these checks or this plugin, contact us at support@sucuri.net or visit <a href="http://sucuri.net">http://sucuri.net</a></p>
282
- </div><!-- End sucuriscan-maincontent -->
283
- </div><!-- End postbox-container -->
284
-
285
- <?php echo sucuriscan_get_template('sidebar.html.tpl') ?>
286
 
287
- </div><!-- End Wrap -->
288
-
289
- <?php
290
  }
291
 
292
- /* Sucuri Header Function */
 
293
 
 
 
 
 
 
 
294
  function sucuriscan_pagestop($sucuri_title = 'Sucuri Plugin')
295
  {
296
  if(!current_user_can('manage_options'))
@@ -303,87 +176,16 @@ function sucuriscan_pagestop($sucuri_title = 'Sucuri Plugin')
303
  <?php
304
  }
305
 
306
- /* Sucuri one-click hardening page. */
307
-
308
- function sucuriscan_hardening_page()
309
-
310
- {
311
-
312
- /* Hardening page. */
313
-
314
- echo '<div class="wrap">';
315
- echo '<h2 id="warnings_hook"></h2>';
316
- echo '<div class="sucuriscan_header">';
317
- echo '<a href="http://sucuri.net/signup" target="_blank" title="Sucuri Security">';
318
- echo '<img src="'.SUCURI_URL.'/inc/images/logo.png" alt="Sucuri Security" />';
319
- echo '</a>';
320
- sucuriscan_pagestop("Sucuri 1-Click Hardening Options");
321
- echo '</div>';
322
-
323
- if(!current_user_can('manage_options'))
324
- {
325
- wp_die(__('You do not have sufficient permissions to access this page: Sucuri Hardening') );
326
- }
327
-
328
- include_once("sucuriscan_hardening.php");
329
-
330
- sucuriscan_hardening_lib()
331
-
332
- ?>
333
-
334
- </div><!-- End sucuriscan-maincontent -->
335
- </div><!-- End postbox-container -->
336
-
337
- <?php echo sucuriscan_get_template('sidebar.html.tpl') ?>
338
-
339
- </div><!-- End Wrap -->
340
-
341
- <?php
342
- }
343
-
344
- /* Sucuri WordPress Integrity page. */
345
-
346
- function sucuriscan_core_integrity_page()
347
-
348
- {
349
-
350
- /* WordPress Integrity page. */
351
-
352
- echo '<div class="wrap">';
353
- echo '<h2 id="warnings_hook"></h2>';
354
- echo '<div class="sucuriscan_header">';
355
- echo '<a href="http://sucuri.net/signup" target="_blank" title="Sucuri Security">';
356
- echo '<img src="'.SUCURI_URL.'/inc/images/logo.png" alt="Sucuri Security" />';
357
- echo '</a>';
358
- sucuriscan_pagestop("Sucuri WordPress Integrity");
359
- echo '</div>';
360
-
361
- if(!current_user_can('manage_options'))
362
- {
363
- wp_die(__('You do not have sufficient permissions to access this page: Sucuri Integrity Check') );
364
- }
365
-
366
- include_once("sucuriscan_core_integrity.php");
367
-
368
- sucuriscan_core_integrity_lib()
369
-
370
- ?>
371
-
372
- </div><!-- End sucuriscan-maincontent -->
373
- </div><!-- End postbox-container -->
374
-
375
- <?php echo sucuriscan_get_template('sidebar.html.tpl') ?>
376
-
377
- </div><!-- End Wrap -->
378
-
379
- <?php
380
- }
381
-
382
- /* Sucuri's admin menu. */
383
-
384
- add_action('admin_menu', 'sucuriscan_menu');
385
- remove_action('wp_head', 'wp_generator');
386
-
387
  function sucuriscan_send_mail($to='', $subject='', $message='', $data_set=array(), $debug=FALSE)
388
  {
389
  $headers = array();
@@ -402,6 +204,13 @@ function sucuriscan_send_mail($to='', $subject='', $message='', $data_set=array(
402
  }
403
  }
404
 
 
 
 
 
 
 
 
405
  function sucuriscan_admin_notice($type='updated', $message='')
406
  {
407
  $alert_id = rand(100, 999);
@@ -413,6 +222,14 @@ function sucuriscan_admin_notice($type='updated', $message='')
413
  <?php endif;
414
  }
415
 
 
 
 
 
 
 
 
 
416
  function sucuriscan_prettify_mail($subject='', $message='', $data_set=array())
417
  {
418
  $current_user = wp_get_current_user();
@@ -433,109 +250,1479 @@ function sucuriscan_prettify_mail($subject='', $message='', $data_set=array())
433
  $mail_variables[$var_key] = $var_value;
434
  }
435
 
436
- return sucuriscan_get_template("notification.{$prettify_type}.tpl", $mail_variables);
437
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
438
 
439
- function sucuriscan_get_template($template='', $template_variables=array()){
440
- $template_content = '';
441
- $template_path = WP_PLUGIN_DIR.'/'.SUCURISCAN_PLUGIN_FOLDER."/inc/tpl/{$template}";
442
 
443
- if( file_exists($template_path) && is_readable($template_path) ){
444
- $template_content = file_get_contents($template_path);
445
- foreach($template_variables as $tpl_key=>$tpl_value){
446
- $template_content = str_replace("%%SUCURI.{$tpl_key}%%", $tpl_value, $template_content);
 
 
 
 
 
 
 
 
 
447
  }
448
  }
449
- return $template_content;
450
- }
451
 
452
- function sucuriscan_wp_sidebar_gen()
453
- {
454
- return sucuriscan_get_template('sidebar.html.tpl');
 
 
 
 
455
  }
456
 
457
- function sucuriscan_get_new_config_keys()
 
 
 
 
 
 
 
 
 
 
458
  {
459
- $request = wp_remote_get('https://api.wordpress.org/secret-key/1.1/salt/');
460
- if( !is_wp_error($request) || wp_remote_retrieve_response_code($request) === 200 ){
461
- if( preg_match_all("/define\('([A-Z_]+)',[ ]+'(.*)'\);/", $request['body'], $match) ){
462
- $new_keys = array();
463
- foreach($match[1] as $i=>$value){
464
- $new_keys[$value] = $match[2][$i];
 
 
 
 
 
 
 
 
 
 
 
 
465
  }
466
- return $new_keys;
467
  }
468
  }
469
- return FALSE;
470
- }
471
-
472
- function sucuriscan_set_new_config_keys()
473
- {
474
- $new_wpconfig = '';
475
- $wp_config_path = ABSPATH.'wp-config.php';
476
- if( file_exists($wp_config_path) ){
477
- $wp_config_lines = file($wp_config_path);
478
- $new_keys = sucuriscan_get_new_config_keys();
479
- $old_keys = array();
480
- $old_keys_string = $new_keys_string = '';
481
 
482
- foreach($wp_config_lines as $wp_config_line){
483
- $wp_config_line = str_replace("\n", '', $wp_config_line);
 
 
 
 
 
 
 
 
 
 
 
 
484
 
485
- if( preg_match("/define\('([A-Z_]+)',([ ]+)'(.*)'\);/", $wp_config_line, $match) ){
486
- $key_name = $match[1];
487
- if( array_key_exists($key_name, $new_keys) ){
488
- $white_spaces = $match[2];
489
- $old_keys[$key_name] = $match[3];
490
- $wp_config_line = "define('{$key_name}',{$white_spaces}'{$new_keys[$key_name]}');";
491
 
492
- $old_keys_string .= "define('{$key_name}',{$white_spaces}'{$old_keys[$key_name]}');\n";
493
- $new_keys_string .= "{$wp_config_line}\n";
 
 
 
 
 
494
  }
 
 
 
 
 
 
495
  }
496
-
497
- $new_wpconfig .= "{$wp_config_line}\n";
498
- }
499
-
500
- $response = array(
501
- 'updated'=>is_writable($wp_config_path),
502
- 'old_keys'=>$old_keys,
503
- 'old_keys_string'=>$old_keys_string,
504
- 'new_keys'=>$new_keys,
505
- 'new_keys_string'=>$new_keys_string,
506
- 'new_wpconfig'=>$new_wpconfig
507
- );
508
- if( $response['updated'] ){
509
- file_put_contents($wp_config_path, $new_wpconfig, LOCK_EX);
510
  }
511
- return $response;
512
  }
513
- return FALSE;
 
 
 
 
 
 
514
  }
515
 
516
- function sucuriscan_new_password($user_id=0)
 
 
 
 
 
 
517
  {
518
- $user_id = intval($user_id);
519
- $current_user = wp_get_current_user();
520
-
521
- if( $user_id>0 && $user_id!=$current_user->ID ){
522
- $user = get_userdata($user_id);
523
- $new_password = wp_generate_password(15, TRUE, FALSE);
524
 
525
- $data_set = array( 'User'=>$user->display_name );
526
- $message = "The password for your user account in the website mentioned has been changed by an administrator,
527
- this is the new password automatically generated by the system, please update ASAP.<br>
528
- <div style='display:inline-block;background:#ddd;font-family:monaco,monospace,courier;
529
- font-size:30px;margin:0;padding:15px;border:1px solid #999'>{$new_password}</div>";
530
- sucuriscan_send_mail($user->user_email, 'Changed password', $message, $data_set);
 
 
531
 
532
- wp_set_password($new_password, $user_id);
 
 
 
 
 
 
533
 
534
- return TRUE;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
535
  }
536
- return FALSE;
537
  }
538
 
 
 
 
 
 
539
  function sucuriscan_posthack_page()
540
  {
541
  if( !current_user_can('manage_options') )
@@ -637,49 +1824,13 @@ function sucuriscan_posthack_page()
637
  echo sucuriscan_get_template('posthack.html.tpl', $template_variables);
638
  }
639
 
640
- function sucuriscan_get_remoteaddr()
641
- {
642
- $alternatives = array(
643
- 'HTTP_X_REAL_IP',
644
- 'HTTP_CLIENT_IP',
645
- 'HTTP_X_FORWARDED_FOR',
646
- 'HTTP_X_FORWARDED',
647
- 'HTTP_FORWARDED_FOR',
648
- 'HTTP_FORWARDED',
649
- 'REMOTE_ADDR',
650
- 'SUCURI_RIP',
651
- );
652
- foreach($alternatives as $alternative){
653
- if( !isset($_SERVER[$alternative]) ){ continue; }
654
-
655
- $remote_addr = preg_replace('/[^0-9., ]/', '', $_SERVER[$alternative]);
656
- if($remote_addr) break;
657
- }
658
-
659
- return $remote_addr;
660
- }
661
-
662
- function sucuriscan_is_behind_cloudproxy(){
663
- $http_host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : '127.0.0.1';
664
- if( preg_match('/^(.*):.*/', $http_host, $match) ){ $http_host = $match[1]; }
665
- $host = gethostbyaddr(gethostbyname($http_host));
666
-
667
- if(
668
- isset($_SERVER['SUCURIREAL_REMOTE_ADDR'])
669
- || preg_match('/cloudproxy.*\.sucuri\.net/', $host)
670
- ){
671
- return TRUE;
672
- }
673
-
674
- return FALSE;
675
- }
676
-
677
-
678
  /**
679
- * Sucuri Scanner - Last Logins
680
- * @return Functions associated to the Last Logins page.
 
 
 
681
  */
682
-
683
  function sucuriscan_lastlogins_page()
684
  {
685
  if( !current_user_can('manage_options') )
@@ -720,12 +1871,23 @@ function sucuriscan_lastlogins_page()
720
  echo sucuriscan_get_template('lastlogins.html.tpl', $template_variables);
721
  }
722
 
 
 
 
 
 
723
  function sucuriscan_lastlogins_datastore_filepath(){
724
  $plugin_upload_folder = sucuriscan_dir_filepath();
725
  $datastore_filepath = rtrim($plugin_upload_folder,'/').'/sucuri-lastlogins.php';
726
  return $datastore_filepath;
727
  }
728
 
 
 
 
 
 
 
729
  function sucuriscan_lastlogins_datastore_exists(){
730
  $datastore_filepath = sucuriscan_lastlogins_datastore_filepath();
731
 
@@ -738,6 +1900,12 @@ function sucuriscan_lastlogins_datastore_exists(){
738
  return file_exists($datastore_filepath) ? $datastore_filepath : FALSE;
739
  }
740
 
 
 
 
 
 
 
741
  function sucuriscan_lastlogins_datastore_is_writable(){
742
  $datastore_filepath = sucuriscan_lastlogins_datastore_exists();
743
  if($datastore_filepath){
@@ -749,6 +1917,12 @@ function sucuriscan_lastlogins_datastore_is_writable(){
749
  return FALSE;
750
  }
751
 
 
 
 
 
 
 
752
  function sucuriscan_lastlogins_datastore_is_readable(){
753
  $datastore_filepath = sucuriscan_lastlogins_datastore_exists();
754
  if( $datastore_filepath && is_readable($datastore_filepath) ){
@@ -758,6 +1932,12 @@ function sucuriscan_lastlogins_datastore_is_readable(){
758
  }
759
 
760
  if( !function_exists('sucuri_set_lastlogin') ){
 
 
 
 
 
 
761
  function sucuriscan_set_lastlogin($user_login=''){
762
  $datastore_filepath = sucuriscan_lastlogins_datastore_is_writable();
763
 
@@ -779,6 +1959,16 @@ if( !function_exists('sucuri_set_lastlogin') ){
779
  add_action('wp_login', 'sucuriscan_set_lastlogin', 50);
780
  }
781
 
 
 
 
 
 
 
 
 
 
 
782
  function sucuriscan_get_logins($limit=10, $user_id=0){
783
  $lastlogins = array();
784
  $datastore_filepath = sucuriscan_lastlogins_datastore_is_readable();
@@ -821,6 +2011,15 @@ function sucuriscan_get_logins($limit=10, $user_id=0){
821
  }
822
 
823
  if( !function_exists('sucuri_login_redirect') ){
 
 
 
 
 
 
 
 
 
824
  function sucuriscan_login_redirect($redirect_to='', $request=NULL, $user=FALSE){
825
  $login_url = !empty($redirect_to) ? $redirect_to : admin_url();
826
  if( $user instanceof WP_User && $user->ID ){
@@ -832,6 +2031,11 @@ if( !function_exists('sucuri_login_redirect') ){
832
  }
833
 
834
  if( !function_exists('sucuri_get_user_lastlogin') ){
 
 
 
 
 
835
  function sucuriscan_get_user_lastlogin(){
836
  if( isset($_GET['sucuriscan_lastlogin_message']) && current_user_can('manage_options') ){
837
  $current_user = wp_get_current_user();
@@ -851,38 +2055,15 @@ if( !function_exists('sucuri_get_user_lastlogin') ){
851
  add_action('admin_notices', 'sucuriscan_get_user_lastlogin');
852
  }
853
 
854
-
855
  /**
856
- * Sucuri Scanner - Info System
857
- * @return Functions associated to the Info System page.
 
 
 
 
 
858
  */
859
-
860
- function sucuriscan_is_multisite(){
861
- if( function_exists('is_multisite') && is_multisite() ){ return TRUE; }
862
- return FALSE;
863
- }
864
-
865
-
866
- function sucuriscan_get_wpconfig_path(){
867
- $wp_config_path = ABSPATH.'wp-config.php';
868
-
869
- // if wp-config.php doesn't exist/not readable check one directory up
870
- if( !is_readable($wp_config_path)){
871
- $wp_config_path = ABSPATH.'/../wp-config.php';
872
- }
873
- return $wp_config_path;
874
- }
875
-
876
-
877
- function sucuriscan_get_htaccess_path(){
878
- $htaccess_path = ABSPATH.'.htaccess';
879
- if( file_exists($htaccess_path) ){
880
- return $htaccess_path;
881
- }
882
- return FALSE;
883
- }
884
-
885
-
886
  function sucuriscan_infosys_page(){
887
  if( !current_user_can('manage_options') )
888
  {
@@ -897,15 +2078,22 @@ function sucuriscan_infosys_page(){
897
  );
898
 
899
  $template_variables['LoggedInUsers'] = sucuriscan_infosys_loggedin();
 
900
  $template_variables['HTAccessIntegrity'] = sucuriscan_infosys_htaccess();
901
  $template_variables['WordpressConfig'] = sucuriscan_infosys_wpconfig();
902
 
903
  echo sucuriscan_get_template('infosys.html.tpl', $template_variables);
904
  }
905
 
906
-
 
 
 
 
 
907
  function sucuriscan_infosys_htaccess(){
908
  $htaccess_path = sucuriscan_get_htaccess_path();
 
909
  $template_variables = array(
910
  'HTAccess.Content' => '',
911
  'HTAccess.Message' => '',
@@ -916,18 +2104,23 @@ function sucuriscan_infosys_htaccess(){
916
 
917
  if( $htaccess_path ){
918
  $htaccess_rules = file_get_contents($htaccess_path);
 
 
 
919
  $template_variables['HTAccess.TextareaVisible'] = 'visible';
920
  $template_variables['HTAccess.Content'] = $htaccess_rules;
 
921
 
 
 
 
 
922
  if( sucuriscan_htaccess_is_standard($htaccess_rules) ){
923
- $template_variables['HTAccess.Message'] = '
924
  The main <code>.htaccess</code> file in your site has the standard rules for a WordPress installation. You can customize it to improve the
925
  performance and change the behaviour of the redirections for pages and posts in your site. To get more information visit the official documentation at
926
  <a href="http://codex.wordpress.org/Using_Permalinks#Creating_and_editing_.28.htaccess.29" target="_blank">Codex WordPrexx - Creating and editing (.htaccess)</a>';
927
- $template_variables['HTAccess.MessageType'] = 'updated';
928
- $template_variables['HTAccess.MessageVisible'] = 'visible';
929
  }
930
-
931
  }else{
932
  $template_variables['HTAccess.Message'] = 'Your website does not contains a <code>.htaccess</code> file or it was not found in the default location.';
933
  $template_variables['HTAccess.MessageType'] = 'error';
@@ -937,7 +2130,13 @@ function sucuriscan_infosys_htaccess(){
937
  return sucuriscan_get_template('infosys-htaccess.html.tpl', $template_variables);
938
  }
939
 
940
-
 
 
 
 
 
 
941
  function sucuriscan_htaccess_is_standard($rules=FALSE){
942
  if( $rules===FALSE ){
943
  $htaccess_path = sucuriscan_get_htaccess_path();
@@ -976,13 +2175,20 @@ function sucuriscan_htaccess_is_standard($rules=FALSE){
976
  return FALSE;
977
  }
978
 
979
-
 
 
 
 
 
 
980
  function sucuriscan_infosys_wpconfig(){
981
  $template_variables = array(
982
  'WordpressConfig.Rules' => '',
983
  'WordpressConfig.Total' => 0,
984
  'WordpressConfig.Content' => '',
985
  );
 
986
 
987
  $wp_config_path = sucuriscan_get_wpconfig_path();
988
  if( $wp_config_path ){
@@ -998,7 +2204,7 @@ function sucuriscan_infosys_wpconfig(){
998
  // Ignore useless lines and append to the clean string the important lines.
999
  if( preg_match('/^define\(/', $line) ){
1000
  $line = str_replace('define(', '', $line);
1001
- $line = str_replace(');', '', $line);
1002
  $line_parts = explode(',', $line, 2);
1003
  }
1004
  else if( preg_match('/^\$[a-zA-Z_]+/', $line) ){
@@ -1024,7 +2230,10 @@ function sucuriscan_infosys_wpconfig(){
1024
  if( $i==0 ){ $key_name = $line_part; }
1025
  if( $i==1 ){ $key_value = $line_part; }
1026
  }
1027
- $wp_config_rules[$key_name] = $key_value;
 
 
 
1028
  }
1029
  }
1030
 
@@ -1041,7 +2250,11 @@ function sucuriscan_infosys_wpconfig(){
1041
  return sucuriscan_get_template('infosys-wpconfig.html.tpl', $template_variables);
1042
  }
1043
 
1044
-
 
 
 
 
1045
  function sucuriscan_infosys_loggedin(){
1046
  // Get user logged in list.
1047
  $template_variables = array(
@@ -1049,7 +2262,7 @@ function sucuriscan_infosys_loggedin(){
1049
  'LoggedInUsers.Total' => 0,
1050
  );
1051
 
1052
- $logged_in_users = sucuriscan_get_online_users();
1053
  if( is_array($logged_in_users) && !empty($logged_in_users) ){
1054
  $template_variables['LoggedInUsers.Total'] = count($logged_in_users);
1055
 
@@ -1072,16 +2285,41 @@ function sucuriscan_infosys_loggedin(){
1072
  return sucuriscan_get_template('infosys-loggedin.html.tpl', $template_variables);
1073
  }
1074
 
 
 
 
 
 
 
 
 
1075
 
1076
- function sucuriscan_get_online_users(){
1077
  if( sucuriscan_is_multisite() ){
1078
- return get_site_transient('online_users');
1079
  }else{
1080
- return get_transient('online_users');
 
 
 
 
 
 
 
 
 
1081
  }
1082
- }
1083
 
 
 
1084
 
 
 
 
 
 
 
 
 
1085
  function sucuriscan_save_online_users($logged_in_users=array()){
1086
  $expiration = 30 * 60;
1087
  if( sucuriscan_is_multisite() ){
@@ -1091,8 +2329,13 @@ function sucuriscan_save_online_users($logged_in_users=array()){
1091
  }
1092
  }
1093
 
1094
-
1095
  if( !function_exists('sucuriscan_unset_online_user_on_logout') ){
 
 
 
 
 
 
1096
  function sucuriscan_unset_online_user_on_logout(){
1097
  $current_user = wp_get_current_user();
1098
  $user_id = $current_user->ID;
@@ -1104,6 +2347,14 @@ if( !function_exists('sucuriscan_unset_online_user_on_logout') ){
1104
  add_action('wp_logout', 'sucuriscan_unset_online_user_on_logout');
1105
  }
1106
 
 
 
 
 
 
 
 
 
1107
  function sucuriscan_unset_online_user($user_id=0, $remote_addr=0){
1108
  $logged_in_users = sucuriscan_get_online_users();
1109
 
@@ -1123,8 +2374,14 @@ function sucuriscan_unset_online_user($user_id=0, $remote_addr=0){
1123
  return sucuriscan_save_online_users($logged_in_users);
1124
  }
1125
 
1126
-
1127
  if( !function_exists('sucuriscan_set_online_user') ){
 
 
 
 
 
 
 
1128
  function sucuriscan_set_online_user($user_login='', $user=FALSE){
1129
  if( $user ){
1130
  // Get logged in user information.
@@ -1185,3 +2442,115 @@ if( !function_exists('sucuriscan_set_online_user') ){
1185
  add_action('wp_login', 'sucuriscan_set_online_user', 10, 2);
1186
  }
1187
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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.5.5
11
  Author URI: http://sucuri.net
12
  */
13
 
14
+
15
+ /**
16
+ * Main file to control the plugin.
17
+ *
18
+ * @category Bootstrap
19
+ * @package Sucuri Security - SiteCheck Malware Scanner
20
+ * @author Daniel <dcid@sucuri.net>
21
+ * @copyright Since 2010 Sucuri Inc.
22
+ * @license Released under the GPL - see LICENSE file for details.
23
+ * @version HG: $Id$
24
+ * @link https://wordpress.sucuri.net/
25
+ * @since File available since Release 0.1
26
+ */
27
+
28
+
29
  /* No direct access. */
30
  if(!function_exists('add_action'))
31
  {
32
  exit(0);
33
  }
34
 
35
+ /**
36
+ * Unique name of the plugin through out all the code.
37
+ */
 
 
38
  define('SUCURISCAN','sucuriscan');
39
+
40
+ /**
41
+ * Current version of the plugin's code.
42
+ */
43
+ define('SUCURISCAN_VERSION','1.5.5');
44
+
45
+ /**
46
+ * The local URL where the plugin's files and assets are served.
47
+ */
48
  define('SUCURI_URL',plugin_dir_url( __FILE__ ));
49
+
50
+ /**
51
+ * The name of the Sucuri plugin main file.
52
+ */
53
+ define('SUCURISCAN_PLUGIN_FILE', 'sucuri.php');
54
+
55
+ /**
56
+ * The name of the folder where the plugin's files will be located.
57
+ */
58
  define('SUCURISCAN_PLUGIN_FOLDER', 'sucuri-scanner');
59
+
60
+ /**
61
+ * The fullpath where the plugin's files will be located.
62
+ */
63
+ define('SUCURISCAN_PLUGIN_PATH', WP_PLUGIN_DIR.'/'.SUCURISCAN_PLUGIN_FOLDER);
64
+
65
+ /**
66
+ * The fullpath of the main plugin file.
67
+ */
68
+ define('SUCURISCAN_PLUGIN_FILEPATH', SUCURISCAN_PLUGIN_PATH.'/'.SUCURISCAN_PLUGIN_FILE);
69
+
70
+ /**
71
+ * The maximum quantity of entries that will be displayed in the last login page.
72
+ */
73
  define('SUCURISCAN_LASTLOGINS_USERSLIMIT', 100);
74
 
75
  if( !function_exists('sucuriscan_create_uploaddir') ){
76
+ /**
77
+ * Create a folder in the Wordpress upload directory where the plugin will
78
+ * store all the temporal or dynamic information.
79
+ *
80
+ * @return void
81
+ */
82
  function sucuriscan_create_uploaddir(){
83
  $plugin_upload_folder = sucuriscan_dir_filepath();
84
  if( !file_exists($plugin_upload_folder) ){
95
  add_action('admin_init', 'sucuriscan_create_uploaddir');
96
  }
97
 
98
+ /**
99
+ * Define which javascript and css files will be loaded in the header of the page.
100
+ * @return void
101
+ */
102
  function sucuriscan_admin_script_style_registration() { ?>
103
  <link rel="stylesheet" href="<?php echo SUCURI_URL; ?>/inc/css/sucuriscan-default-css.css" type="text/css" media="all" />
104
  <script type="text/javascript">
108
  }
109
  </script>
110
  <?php }
111
+ add_action( 'admin_enqueue_scripts', 'sucuriscan_admin_script_style_registration', 1 );
112
 
113
+ /**
114
+ * Returns the system filepath to the relevant user uploads directory for this
115
+ * site. This is a multisite capable function.
116
+ *
117
+ * @param string $path The relative path that needs to be completed to get the absolute path.
118
+ * @return string The full filesystem path including the directory specified.
119
  */
120
  function sucuriscan_dir_filepath($path = '')
121
  {
124
  return($wp_dir_array['basedir']."/sucuri/$path");
125
  }
126
 
127
+ /**
128
+ * Generate the menu and submenus for the plugin in the admin interface.
129
+ *
130
+ * @return void
131
+ */
132
  function sucuriscan_menu()
133
  {
134
  add_menu_page('Sucuri Free', 'Sucuri Free', 'manage_options',
135
+ 'sucuriscan', 'sucuri_scan_page', SUCURI_URL.'inc/images/menu-icon.png');
136
  add_submenu_page('sucuriscan', 'Sucuri Scanner', 'Sucuri Scanner', 'manage_options',
137
  'sucuriscan', 'sucuri_scan_page');
138
 
148
  add_submenu_page('sucuriscan', 'Last Logins', 'Last Logins', 'manage_options',
149
  'sucuriscan_lastlogins', 'sucuriscan_lastlogins_page');
150
 
151
+ add_submenu_page('sucuriscan', 'Site Info', 'Site Info', 'manage_options',
152
  'sucuriscan_infosys', 'sucuriscan_infosys_page');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
153
 
154
+ add_submenu_page('sucuriscan', 'About', 'About', 'manage_options',
155
+ 'sucuriscan_about', 'sucuriscan_about_page');
 
156
  }
157
 
158
+ add_action('admin_menu', 'sucuriscan_menu');
159
+ remove_action('wp_head', 'wp_generator');
160
 
161
+ /**
162
+ * Print the HTML code for the header of each plugin's page.
163
+ *
164
+ * @param string $sucuri_title Title of the page that will be loaded.
165
+ * @return void
166
+ */
167
  function sucuriscan_pagestop($sucuri_title = 'Sucuri Plugin')
168
  {
169
  if(!current_user_can('manage_options'))
176
  <?php
177
  }
178
 
179
+ /**
180
+ * Send a message to a specific email address.
181
+ *
182
+ * @param string $to The email address of the recipient that will receive the message.
183
+ * @param string $subject The reason of the message that will be sent.
184
+ * @param string $message Body of the message that will be sent.
185
+ * @param array $data_set Optional parameter to add more information to the notification.
186
+ * @param boolean $debug TRUE if you want to test the function printing the email before sending it.
187
+ * @return void
188
+ */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
189
  function sucuriscan_send_mail($to='', $subject='', $message='', $data_set=array(), $debug=FALSE)
190
  {
191
  $headers = array();
204
  }
205
  }
206
 
207
+ /**
208
+ * Prints a HTML alert in the Wordpress admin interface.
209
+ *
210
+ * @param string $type The type of alert, it can be either Updated or Error.
211
+ * @param string $message The message that will be printed in the alert.
212
+ * @return void
213
+ */
214
  function sucuriscan_admin_notice($type='updated', $message='')
215
  {
216
  $alert_id = rand(100, 999);
222
  <?php endif;
223
  }
224
 
225
+ /**
226
+ * Generate a HTML version of the message that will be sent through an email.
227
+ *
228
+ * @param string $subject The reason of the message that will be sent.
229
+ * @param string $message Body of the message that will be sent.
230
+ * @param array $data_set Optional parameter to add more information to the notification.
231
+ * @return string The message formatted in a HTML template.
232
+ */
233
  function sucuriscan_prettify_mail($subject='', $message='', $data_set=array())
234
  {
235
  $current_user = wp_get_current_user();
250
  $mail_variables[$var_key] = $var_value;
251
  }
252
 
253
+ return sucuriscan_get_template("notification.{$prettify_type}.tpl", $mail_variables);
254
+ }
255
+
256
+ /**
257
+ * Generate a HTML code using a template and replacing all the pseudo-variables
258
+ * by the dynamic variables provided by the developer through one of the parameters
259
+ * of the function.
260
+ *
261
+ * @param string $template Filename of the template that will be used to generate the page.
262
+ * @param array $template_variables A hash containing the pseudo-variable name as the key and the value that will replace it.
263
+ * @return string The formatted HTML page after replace all the pseudo-variables.
264
+ */
265
+ function sucuriscan_get_template($template='', $template_variables=array()){
266
+ $template_content = '';
267
+ $template_path = WP_PLUGIN_DIR.'/'.SUCURISCAN_PLUGIN_FOLDER."/inc/tpl/{$template}";
268
+
269
+ if( file_exists($template_path) && is_readable($template_path) ){
270
+ $template_content = file_get_contents($template_path);
271
+ foreach($template_variables as $tpl_key=>$tpl_value){
272
+ $template_content = str_replace("%%SUCURI.{$tpl_key}%%", $tpl_value, $template_content);
273
+ }
274
+ }
275
+ return $template_content;
276
+ }
277
+
278
+ /**
279
+ * Get the HTML content of the sidebar for the plugin interface.
280
+ *
281
+ * @return string HTML of the side for the plugin interface.
282
+ */
283
+ function sucuriscan_wp_sidebar_gen()
284
+ {
285
+ return sucuriscan_get_template('sidebar.html.tpl');
286
+ }
287
+
288
+ /**
289
+ * Retrieve a new set of keys for the Wordpress configuration file using the
290
+ * official API provided by Wordpress itself.
291
+ *
292
+ * @return array A list of the new set of keys generated by Wordpress API.
293
+ */
294
+ function sucuriscan_get_new_config_keys()
295
+ {
296
+ $request = wp_remote_get('https://api.wordpress.org/secret-key/1.1/salt/');
297
+ if( !is_wp_error($request) || wp_remote_retrieve_response_code($request) === 200 ){
298
+ if( preg_match_all("/define\('([A-Z_]+)',[ ]+'(.*)'\);/", $request['body'], $match) ){
299
+ $new_keys = array();
300
+ foreach($match[1] as $i=>$value){
301
+ $new_keys[$value] = $match[2][$i];
302
+ }
303
+ return $new_keys;
304
+ }
305
+ }
306
+ return FALSE;
307
+ }
308
+
309
+ /**
310
+ * Modify the Wordpress configuration file and change the keys that were defined
311
+ * by a new random-generated list of keys retrieved from the official Wordpress
312
+ * API. The result of the operation will be either FALSE in case of error, or an
313
+ * array containing multiple indexes explaining the modification, among them you
314
+ * will find the old and new keys.
315
+ *
316
+ * @return false|array Either FALSE in case of error, or an array with the old and new keys.
317
+ */
318
+ function sucuriscan_set_new_config_keys()
319
+ {
320
+ $new_wpconfig = '';
321
+ $wp_config_path = ABSPATH.'wp-config.php';
322
+
323
+ if( file_exists($wp_config_path) ){
324
+ $wp_config_lines = file($wp_config_path);
325
+ $new_keys = sucuriscan_get_new_config_keys();
326
+ $old_keys = array();
327
+ $old_keys_string = $new_keys_string = '';
328
+
329
+ foreach($wp_config_lines as $wp_config_line){
330
+ $wp_config_line = str_replace("\n", '', $wp_config_line);
331
+
332
+ if( preg_match("/define\('([A-Z_]+)',([ ]+)'(.*)'\);/", $wp_config_line, $match) ){
333
+ $key_name = $match[1];
334
+ if( array_key_exists($key_name, $new_keys) ){
335
+ $white_spaces = $match[2];
336
+ $old_keys[$key_name] = $match[3];
337
+ $wp_config_line = "define('{$key_name}',{$white_spaces}'{$new_keys[$key_name]}');";
338
+
339
+ $old_keys_string .= "define('{$key_name}',{$white_spaces}'{$old_keys[$key_name]}');\n";
340
+ $new_keys_string .= "{$wp_config_line}\n";
341
+ }
342
+ }
343
+
344
+ $new_wpconfig .= "{$wp_config_line}\n";
345
+ }
346
+
347
+ $response = array(
348
+ 'updated'=>is_writable($wp_config_path),
349
+ 'old_keys'=>$old_keys,
350
+ 'old_keys_string'=>$old_keys_string,
351
+ 'new_keys'=>$new_keys,
352
+ 'new_keys_string'=>$new_keys_string,
353
+ 'new_wpconfig'=>$new_wpconfig
354
+ );
355
+ if( $response['updated'] ){
356
+ file_put_contents($wp_config_path, $new_wpconfig, LOCK_EX);
357
+ }
358
+ return $response;
359
+ }
360
+ return FALSE;
361
+ }
362
+
363
+ /**
364
+ * Generate and set a new password for a specific user not in session.
365
+ *
366
+ * @param integer $user_id The user identifier that will be changed, this must be different than the user in session.
367
+ * @return boolean Either TRUE or FALSE in case of success or error respectively.
368
+ */
369
+ function sucuriscan_new_password($user_id=0)
370
+ {
371
+ $user_id = intval($user_id);
372
+ $current_user = wp_get_current_user();
373
+
374
+ if( $user_id>0 && $user_id!=$current_user->ID ){
375
+ $user = get_userdata($user_id);
376
+ $new_password = wp_generate_password(15, TRUE, FALSE);
377
+
378
+ $data_set = array( 'User'=>$user->display_name );
379
+ $message = "The password for your user account in the website mentioned has been changed by an administrator,
380
+ this is the new password automatically generated by the system, please update ASAP.<br>
381
+ <div style='display:inline-block;background:#ddd;font-family:monaco,monospace,courier;
382
+ font-size:30px;margin:0;padding:15px;border:1px solid #999'>{$new_password}</div>";
383
+ sucuriscan_send_mail($user->user_email, 'Changed password', $message, $data_set);
384
+
385
+ wp_set_password($new_password, $user_id);
386
+
387
+ return TRUE;
388
+ }
389
+ return FALSE;
390
+ }
391
+
392
+ /**
393
+ * Retrieve the real ip address of the user in the current request.
394
+ *
395
+ * @return string The real ip address of the user in the current request.
396
+ */
397
+ function sucuriscan_get_remoteaddr()
398
+ {
399
+ $alternatives = array(
400
+ 'HTTP_X_REAL_IP',
401
+ 'HTTP_CLIENT_IP',
402
+ 'HTTP_X_FORWARDED_FOR',
403
+ 'HTTP_X_FORWARDED',
404
+ 'HTTP_FORWARDED_FOR',
405
+ 'HTTP_FORWARDED',
406
+ 'REMOTE_ADDR',
407
+ 'SUCURI_RIP',
408
+ );
409
+ foreach($alternatives as $alternative){
410
+ if( !isset($_SERVER[$alternative]) ){ continue; }
411
+
412
+ $remote_addr = preg_replace('/[^0-9., ]/', '', $_SERVER[$alternative]);
413
+ if($remote_addr) break;
414
+ }
415
+
416
+ return $remote_addr;
417
+ }
418
+
419
+ /**
420
+ * Check whether the site is behing the Sucuri CloudProxy network.
421
+ *
422
+ * @return boolean Either TRUE or FALSE if the site is behind CloudProxy.
423
+ */
424
+ function sucuriscan_is_behind_cloudproxy(){
425
+ $http_host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : 'localhost';
426
+ if( preg_match('/^(.*):([0-9]+)/', $http_host, $match) ){ $http_host = $match[1]; }
427
+ $host_by_name = gethostbyname($http_host);
428
+ $host_by_addr = gethostbyaddr($host_by_name);
429
+
430
+ if(
431
+ isset($_SERVER['SUCURIREAL_REMOTE_ADDR'])
432
+ || preg_match('/^cloudproxy([0-9]+)\.sucuri\.net$/', $host_by_addr)
433
+ ){
434
+ return TRUE;
435
+ }
436
+
437
+ return FALSE;
438
+ }
439
+
440
+ /**
441
+ * Check whether the current site is working as a multi-site instance.
442
+ *
443
+ * @return boolean Either TRUE or FALSE in case Wordpress is being used as a multi-site instance.
444
+ */
445
+ function sucuriscan_is_multisite(){
446
+ if( function_exists('is_multisite') && is_multisite() ){ return TRUE; }
447
+ return FALSE;
448
+ }
449
+
450
+ /**
451
+ * Find and retrieve the absolute path of the Wordpress configuration file.
452
+ *
453
+ * @return string Absolute path of the Wordpress configuration file.
454
+ */
455
+ function sucuriscan_get_wpconfig_path(){
456
+ $wp_config_path = ABSPATH.'wp-config.php';
457
+
458
+ // if wp-config.php doesn't exist/not readable check one directory up
459
+ if( !is_readable($wp_config_path)){
460
+ $wp_config_path = ABSPATH.'/../wp-config.php';
461
+ }
462
+ return $wp_config_path;
463
+ }
464
+
465
+ /**
466
+ * Find and retrieve the absolute path of the main Wordpress htaccess file.
467
+ *
468
+ * @return string Absolute path of the main Wordpress htaccess file.
469
+ */
470
+ function sucuriscan_get_htaccess_path(){
471
+ $base_dirs = array(
472
+ rtrim(ABSPATH, '/'),
473
+ dirname(ABSPATH),
474
+ dirname(dirname(ABSPATH))
475
+ );
476
+
477
+ foreach($base_dirs as $base_dir){
478
+ $htaccess_path = sprintf('%s/.htaccess', $base_dir);
479
+ if( file_exists($htaccess_path) ){
480
+ return $htaccess_path;
481
+ }
482
+ }
483
+
484
+ return FALSE;
485
+ }
486
+
487
+ /**
488
+ * Print a HTML code with a form from where the administrator can check the state
489
+ * of this site through Sucuri SiteCheck.
490
+ *
491
+ * @return void
492
+ */
493
+ function sucuri_scan_page()
494
+ {
495
+ $U_ERROR = NULL;
496
+ if( !current_user_can('manage_options') ){
497
+ wp_die(__('You do not have sufficient permissions to access this page: Sucuri Malware Scanner') );
498
+ }
499
+
500
+ $template_variables = array(
501
+ 'PluginURL'=>SUCURI_URL,
502
+ 'Sidebar'=>sucuriscan_get_template('sidebar.html.tpl')
503
+ );
504
+
505
+ if( isset($_POST['wpsucuri-doscan']) ){
506
+ sucuriscan_print_scan();
507
+ return(1);
508
+ }
509
+
510
+ echo sucuriscan_get_template('initial-page.html.tpl', $template_variables);
511
+ }
512
+
513
+ /**
514
+ * Display the result of site scan made through SiteCheck.
515
+ *
516
+ * @return void
517
+ */
518
+ function sucuriscan_print_scan()
519
+ {
520
+ $website_scanned = home_url();
521
+ $remote_url = 'http://sitecheck.sucuri.net/scanner/?serialized&clear&fromwp&scan='.$website_scanned;
522
+ $myresults = wp_remote_get($remote_url, array('timeout' => 180));
523
+ ?>
524
+ <div class="wrap">
525
+ <h2 id="warnings_hook"></h2>
526
+ <div class="sucuriscan_header">
527
+ <a href="http://sucuri.net/signup" target="_blank" title="Sucuri Security">
528
+ <img src="<?php echo SUCURI_URL; ?>/inc/images/logo.png" alt="Sucuri Security" />
529
+ </a>
530
+ <?php sucuriscan_pagestop('Sucuri SiteCheck Malware Scanner'); ?>
531
+ </div>
532
+
533
+ <div class="postbox-container sucuriscan-results" style="width:75%;">
534
+ <div class="sucuriscan-maincontent">
535
+ <?php if( is_wp_error($myresults) ){ ?>
536
+ <div id="poststuff">
537
+ <div class="postbox">
538
+ <h3>Error retrieving the scan report</h3>
539
+ <div class="inside">
540
+ <?php print_r($myresults); ?>
541
+ </div>
542
+ </div>
543
+ </div>
544
+ <?php
545
+ }else if( preg_match('/^ERROR:/', $myresults['body']) ){
546
+ sucuriscan_admin_notice('error', $myresults['body'].' The URL scanned was: <code>'.$website_scanned.'</code>');
547
+ }else{
548
+ $res = unserialize($myresults['body']);
549
+
550
+ // Check for general warnings, and return the information for Infected/Clean site.
551
+ $malware_warns_exists = isset($res['MALWARE']['WARN']) ? TRUE : FALSE;
552
+ ?>
553
+ <div id="poststuff">
554
+ <div class="postbox">
555
+ <h3>
556
+ <?php if( !$malware_warns_exists ): ?>
557
+ <img src="<?php echo SUCURI_URL; ?>/inc/images/ok.png" class="icon-ok" /> &nbsp;
558
+ No malware was identified
559
+ <?php else: ?>
560
+ <img src="<?php echo SUCURI_URL; ?>/inc/images/warn.png" class="icon-warn" /> &nbsp;
561
+ Site compromised (malware was identified)
562
+ <?php endif; ?>
563
+ </h3>
564
+ <div class="inside">
565
+ <?php if( !$malware_warns_exists ): ?>
566
+ <span><strong>Malware:</strong> No.</span><br>
567
+ <span><strong>Malicious javascript:</strong> No.</span><br>
568
+ <span><strong>Malicious iframes:</strong> No.</span><br>
569
+ <span><strong>Suspicious redirections (htaccess):</strong> No.</span><br>
570
+ <span><strong>Blackhat SEO Spam:</strong> No.</span><br>
571
+ <span><strong>Anomaly detection:</strong> Clean.</span><br>
572
+ <?php else: ?>
573
+ <?php
574
+ foreach( $res['MALWARE']['WARN'] as $malres ){
575
+ if( !is_array($malres) ){
576
+ echo htmlspecialchars($malres);
577
+ }else{
578
+ $mwdetails = explode("\n", htmlspecialchars($malres[1]));
579
+ echo htmlspecialchars($malres[0])."\n<br />". substr($mwdetails[0], 1)."<br />\n";
580
+ }
581
+ }
582
+ ?>
583
+ <?php endif; ?>
584
+ <br />
585
+ <i>
586
+ More details here: <a href="http://sitecheck.sucuri.net/scanner/?scan=<?php echo $website_scanned; ?>">
587
+ http://sitecheck.sucuri.net/scanner/?scan=<?php echo $website_scanned; ?></a>
588
+ </i>
589
+ <hr />
590
+ <i>
591
+ If our free scanner did not detect any issue, you may have a more complicated and hidden
592
+ problem. You can try our <a href="admin.php?page=sucuriscan_core_integrity">WordPress integrity
593
+ checks</a> or sign up with Sucuri <a target="_blank" href="http://sucuri.net/signup">here</a>
594
+ for a complete and in depth scan+cleanup (not included in the free checks).
595
+ </i>
596
+ <hr />
597
+ </div>
598
+ </div>
599
+ </div>
600
+
601
+ <div id="poststuff">
602
+ <div class="postbox">
603
+ <h3>
604
+ <?php if( isset($res['BLACKLIST']['WARN']) ): ?>
605
+ <img src="<?php echo SUCURI_URL; ?>/inc/images/warn.png" class="icon-warn" /> &nbsp;
606
+ Site blacklisted
607
+ <?php else: ?>
608
+ <img src="<?php echo SUCURI_URL; ?>/inc/images/ok.png" class="icon-ok" /> &nbsp;
609
+ Site blacklist-free
610
+ <?php endif; ?>
611
+ </h3>
612
+ <div class="inside">
613
+ <?php
614
+ foreach(array(
615
+ 'INFO'=>'CLEAN',
616
+ 'WARN'=>'WARNING'
617
+ ) as $type=>$group_title){
618
+ if( isset($res['BLACKLIST'][$type]) ){
619
+ foreach($res['BLACKLIST'][$type] as $blres){
620
+ $report_site = htmlspecialchars($blres[0]);
621
+ $report_url = htmlspecialchars($blres[1]);
622
+ echo "<b>{$group_title}: </b>{$report_site} <a href='{$report_url}' target='_blank'>{$report_url}</a><br />";
623
+ }
624
+ }
625
+ }
626
+ ?>
627
+ </div>
628
+ </div>
629
+ </div>
630
+
631
+ <?php
632
+ global $wp_version;
633
+ $wordpress_updated = FALSE;
634
+ $updates = function_exists('get_core_updates') ? get_core_updates() : array();
635
+ if( !is_array($updates) || empty($updates) || $updates[0]->response=='latest' ){
636
+ $wordpress_updated = TRUE;
637
+ }
638
+ ?>
639
+ <div id="poststuff">
640
+ <div class="postbox">
641
+ <h3>
642
+ <?php if($wordpress_updated): ?>
643
+ <img src="<?php echo SUCURI_URL; ?>/inc/images/ok.png" class="icon-ok" /> &nbsp;
644
+ System info (WordPress upgraded)
645
+ <?php else: ?>
646
+ <img src="<?php echo SUCURI_URL; ?>/inc/images/warn.png" class="icon-warn" /> &nbsp;
647
+ System info (WordPress outdated)
648
+ <?php endif; ?>
649
+ </h3>
650
+ <div class="inside">
651
+ <b>Site:</b> <?php echo $res['SCAN']['SITE'][0]; ?> (<?php echo $res['SCAN']['IP'][0]; ?>)<br />
652
+ <b>PHP (version installed): </b> <?php echo phpversion(); ?><br />
653
+ <b>WordPress (installed):</b> <?php echo $wp_version; ?><br />
654
+ <?php if( !$wordpress_updated ): ?>
655
+ <b>WordPress (update):</b> <?php echo $updates[0]->version; ?><br />
656
+ <a href="<?php echo admin_url('update-core.php'); ?>" class="button button-primary">Update</a>
657
+ <?php endif; ?>
658
+ <?php
659
+ if( isset($res['SYSTEM']['NOTICE']) ){
660
+ foreach( $res['SYSTEM']['NOTICE'] as $notres ){
661
+ if( is_array($notres) ){
662
+ echo htmlspecialchars($notres[0]).chr(32).htmlspecialchars($notres[1]);
663
+ }else{
664
+ echo htmlspecialchars($notres)."<br />\n";
665
+ }
666
+ }
667
+ }
668
+ ?>
669
+ </div>
670
+ </div>
671
+ </div>
672
+ <?php } ?>
673
+
674
+ <p>If you have any questions about these checks or this plugin, contact us at support@sucuri.net or visit <a href="http://sucuri.net">http://sucuri.net</a></p>
675
+ </div><!-- End sucuriscan-maincontent -->
676
+ </div><!-- End postbox-container -->
677
+
678
+ <?php echo sucuriscan_get_template('sidebar.html.tpl') ?>
679
+
680
+ </div><!-- End Wrap -->
681
+
682
+ <?php
683
+ }
684
+
685
+ /**
686
+ * Wordpress core integrity page.
687
+ *
688
+ * It checks whether the Wordpress core files are the original ones, and the state
689
+ * of the themes and plugins reporting the availability of updates. It also checks
690
+ * the user accounts under the administrator group.
691
+ *
692
+ * @return void
693
+ */
694
+ function sucuriscan_core_integrity_page()
695
+ {
696
+
697
+ /* WordPress Integrity page. */
698
+
699
+ echo '<div class="wrap">';
700
+ echo '<h2 id="warnings_hook"></h2>';
701
+ echo '<div class="sucuriscan_header">';
702
+ echo '<a href="http://sucuri.net/signup" target="_blank" title="Sucuri Security">';
703
+ echo '<img src="'.SUCURI_URL.'/inc/images/logo.png" alt="Sucuri Security" />';
704
+ echo '</a>';
705
+ sucuriscan_pagestop("Sucuri WordPress Integrity");
706
+ echo '</div>';
707
+
708
+ if(!current_user_can('manage_options'))
709
+ {
710
+ wp_die(__('You do not have sufficient permissions to access this page: Sucuri Integrity Check') );
711
+ }
712
+ ?>
713
+
714
+ <div class="postbox-container" style="width:75%;">
715
+ <div class="sucuriscan-maincontent">
716
+ <div class="postbox">
717
+ <div class="inside">
718
+ <h2 align="center">Sucuri WordPress Integrity Checks</h2>
719
+ </div>
720
+ </div>
721
+
722
+ <?php
723
+ if( isset($_POST['wpsucuri-core-integrity']) ){
724
+ if(!wp_verify_nonce($_POST['sucuriscan_core_integritynonce'], 'sucuriscan_core_integritynonce'))
725
+ {
726
+ unset($_POST['wpsucuri-core_integrity']);
727
+ }
728
+ }
729
+ ?>
730
+
731
+ <div id="poststuff">
732
+ <?php
733
+ sucuriscan_core_integrity_function_wrapper(
734
+ 'sucuriwp_core_integrity_check',
735
+ 'Verify Integrity of WordPress Core Files',
736
+ 'This test will check wp-includes, wp-admin, and the top directory files against the latest WordPress
737
+ hashing database. If any of those files were modified, it is a big sign of a possible compromise.'
738
+ );
739
+
740
+ sucuriscan_core_integrity_wp_content_wrapper();
741
+
742
+ sucuriscan_core_integrity_function_wrapper(
743
+ 'sucuriwp_list_admins',
744
+ 'Admin User Dump',
745
+ 'List all administrator users and their latest login time.'
746
+ );
747
+
748
+ sucuriscan_core_integrity_function_wrapper(
749
+ 'sucuriwp_check_plugins',
750
+ 'Outdated Plugin list',
751
+ 'This test will list any outdated (active) plugins.'
752
+ );
753
+
754
+ sucuriscan_core_integrity_function_wrapper(
755
+ 'sucuriwp_check_themes',
756
+ 'Outdated Theme List',
757
+ 'This test will list any outdated theme.'
758
+ );
759
+ ?>
760
+ </div>
761
+
762
+ <p align="center">
763
+ <strong>If you have any questions about these tests or this plugin, contact us at <a href="mailto:info@sucuri.net">
764
+ info@sucuri.net</a> or visit <a href="http://sucuri.net">Sucuri Security</a></strong>
765
+ </p>
766
+ </div><!-- End sucuriscan-maincontent -->
767
+ </div><!-- End postbox-container -->
768
+
769
+ <?php echo sucuriscan_get_template('sidebar.html.tpl') ?>
770
+
771
+ </div><!-- End Wrap -->
772
+
773
+ <?php
774
+ }
775
+
776
+ /**
777
+ * Print the HTML code with the form needed to check the integrity of specific
778
+ * parts of the site and administrator panel.
779
+ *
780
+ * @param string $function_name Name of the function that will be executed on form submission.
781
+ * @param string $stitle Title of the HTML panel.
782
+ * @param string $description Explanation of the action that will be performed once the form is submitted.
783
+ * @return void
784
+ */
785
+ function sucuriscan_core_integrity_function_wrapper($function_name='', $stitle='', $description=''){ ?>
786
+ <div class="postbox">
787
+ <h3><?php echo $stitle; ?></h3>
788
+ <div class="inside">
789
+ <form method="post">
790
+ <input type="hidden" name="<?php echo $function_name; ?>nonce" value="<?php echo wp_create_nonce($function_name.'nonce'); ?>" />
791
+ <input type="hidden" name="<?php echo $function_name; ?>" value="1" />
792
+ <p><?php echo $description; ?></p>
793
+ <input class="button-primary" type="submit" name="<?php echo $function_name; ?>" value="Check" />
794
+ </form>
795
+ <br />
796
+ <?php
797
+ if (isset($_POST[$function_name.'nonce']) && isset($_POST[$function_name])) {
798
+ if( function_exists($function_name) ){
799
+ $function_name();
800
+ }
801
+ }
802
+ ?>
803
+ </div>
804
+ </div>
805
+ <?php }
806
+
807
+ /**
808
+ * List all files inside wp-content that have been modified in the last days.
809
+ *
810
+ * @return void
811
+ */
812
+ function sucuriscan_core_integrity_wp_content_wrapper(){ ?>
813
+ <div class="postbox">
814
+ <h3>Latest modified files</h3>
815
+ <div class="inside">
816
+ <form method="post">
817
+ <input type="hidden" name="sucuriwp_content_checknonce" value="<?php echo wp_create_nonce('sucuriwp_content_checknonce'); ?>" />
818
+ <input type="hidden" name="sucuriwp_content_check" value="sucuriwp_content_check" />
819
+ <p>
820
+ This test will list all files inside wp-content that have been modified in the past
821
+ <select name="sucuriwp_content_check_back">
822
+ <?php foreach(array( 1,3,7,30 ) as $days): ?>
823
+ <?php $selected =
824
+ ( isset($_POST['sucuriwp_content_check_back']) && $_POST['sucuriwp_content_check_back']==$days )
825
+ ? 'selected="selected"' : ''; ?>
826
+ <option value="<?php echo $days; ?>" <?php echo $selected; ?>><?php echo $days; ?></option>
827
+ <?php endforeach; ?>
828
+ </select> days. (select the number of days first)
829
+ </p>
830
+ <input class="button-primary" type="submit" name="sucuriwp_content_check" value="Check">
831
+ </form>
832
+
833
+ <?php if (
834
+ isset($_POST['sucuriwp_content_checknonce'])
835
+ // && wp_verify_nonce($_POST['sucuriwp_content_checknonce'], 'sucuriwp_content_checknonce')
836
+ && isset($_POST['sucuriwp_content_check'])
837
+ ): ?>
838
+ <br />
839
+ <table class="wp-list-table widefat sucuriscan-lastmodified">
840
+ <thead>
841
+ <tr>
842
+ <th colspan="2">wp_content latest modified files</th>
843
+ </tr>
844
+ <tr>
845
+ <th class="manage-column">Filepath</th>
846
+ <th class="manage-column">Modification date/time</th>
847
+ </tr>
848
+ </thead>
849
+ <tbody>
850
+ <?php
851
+ $wp_content_hashes = read_dir_r(ABSPATH.'wp-content', true);
852
+ $days = htmlspecialchars(trim((int)$_POST['sucuriwp_content_check_back']));
853
+ $back_days = current_time( 'timestamp' ) - ( $days * 86400);
854
+
855
+ foreach ( $wp_content_hashes as $key => $value) {
856
+ if ($value['time'] >= $back_days ){
857
+ $date = date('d-m-Y H:i:s', $value['time']);
858
+ printf('<tr><td>%s</td><td>%s</td></tr>', $key, $date);
859
+ }
860
+ }
861
+ ?>
862
+ </tbody>
863
+ </table>
864
+ <?php endif; ?>
865
+ </div>
866
+ </div>
867
+ <?php }
868
+
869
+ /**
870
+ * Retrieve a list of md5sum and last modification time of all the files in the
871
+ * folder specified. This is a recursive function.
872
+ *
873
+ * @param string $dir The base path where the scanning will start.
874
+ * @param boolean $recursiv Either TRUE or FALSE if the scan should be performed recursively.
875
+ * @return array List of arrays containing the md5sum and last modification time of the files found.
876
+ */
877
+ function read_dir_r($dir = "./", $recursiv = false)
878
+ {
879
+ $skipname = basename(__FILE__);
880
+ $skipname .= ",_sucuribackup,wp-config.php";
881
+
882
+ $files_info = array();
883
+
884
+ $dir_handler = opendir($dir);
885
+
886
+ while(($entry = readdir($dir_handler)) !== false) {
887
+ if ($entry != "." && $entry != "..") {
888
+ $dir = preg_replace("/^(.*)(\/)+$/", "$1", $dir);
889
+ $item = $dir . "/" . $entry;
890
+ if (is_file($item)) {
891
+
892
+ $skip_parts = explode(",", $skipname);
893
+ foreach ($skip_parts as $skip) {
894
+ if (strpos($item,$skip) !== false) {
895
+ continue 2;
896
+ }
897
+ }
898
+
899
+ $md5 = @md5_file($item);
900
+ $time_stamp = @filectime($item);
901
+ $item_name = str_replace(ABSPATH, "./", $item);
902
+ $files_info[$item_name] = array(
903
+ 'md5' => $md5,
904
+ 'time' => $time_stamp
905
+ );
906
+
907
+ }
908
+ elseif (is_dir($item) && $recursiv) {
909
+ $files_info = array_merge( $files_info , read_dir_r($item) );
910
+ }
911
+ }
912
+ }
913
+
914
+ closedir($dir_handler);
915
+ return $files_info;
916
+ }
917
+
918
+ /**
919
+ * Compare the md5sum of the core files in the current site with the hashes hosted
920
+ * remotely in Sucuri servers. These hashes are updated every time a new version
921
+ * of Wordpress is released.
922
+ *
923
+ * @return void
924
+ */
925
+ function sucuriwp_core_integrity_check()
926
+ {
927
+
928
+ global $wp_version;
929
+
930
+ $curlang = get_bloginfo("language");
931
+
932
+ $cp = 0;
933
+ $updates = get_core_updates();
934
+ if( !is_array($updates) || empty($updates) || $updates[0]->response=='latest' ){
935
+ $cp = 1;
936
+ }
937
+ if(strcmp($wp_version, "3.7") < 0)
938
+ {
939
+ $cp = 0;
940
+ }
941
+ $wp_version = htmlspecialchars($wp_version);
942
+
943
+ if($cp == 0)
944
+ {
945
+ echo '<p><img style="position:relative;top:5px" height="22" width="22" src="'.SUCURI_URL.'inc/images/warn.png" />'
946
+ .'&nbsp; The current version of your site was detected as <code>'.$wp_version.'</code> which is different to the '
947
+ .'official latest version. The integrity check can not run using this version number <a href="'.admin_url('update-core.php').'">'
948
+ .'update now</a> to be able to run the integrity check.</p>';
949
+ }
950
+ else
951
+ {
952
+ $latest_hashes = sucuriscan_check_wp_integrity($wp_version);
953
+ if($latest_hashes){
954
+ sucuriscan_draw_corefiles_status(array(
955
+ 'added'=>$latest_hashes['added'],
956
+ 'removed'=>$latest_hashes['removed'],
957
+ 'modified'=>$latest_hashes['bad']
958
+ ));
959
+ }else{
960
+ sucuriscan_admin_notice('error', 'Error retrieving the wordpress core hashes, try again.');
961
+ }
962
+ }
963
+ }
964
+
965
+ /**
966
+ * List all the Wordpress core files modified until now.
967
+ *
968
+ * @param array $list List of Wordpress core files modified.
969
+ * @return void
970
+ */
971
+ function sucuriscan_draw_corefiles_status($list=array()){
972
+ if( is_array($list) && !empty($list) ): ?>
973
+ <table class="wp-list-table widefat sucuriscan-corefiles">
974
+ <tbody>
975
+ <?php
976
+ foreach($list as $diff_type=>$file_list){
977
+ printf('<tr><th>Core File %s: %d</th></tr>', ucwords($diff_type), sizeof($file_list));
978
+ foreach($file_list as $filepath){
979
+ printf('<tr><td>%s</td></tr>', $filepath);
980
+ }
981
+ }
982
+ ?>
983
+ </tbody>
984
+ </table>
985
+ <?php endif; ?>
986
+ <?php }
987
+
988
+ /**
989
+ * List all the user accounts under the user level specified, by default the
990
+ * users analyzed are the administrator accounts.
991
+ *
992
+ * @param string $userlevel Identifier of the user level that will be filtered in the search.
993
+ * @return void
994
+ */
995
+ function sucuriwp_list_admins($userlevel = '10') {
996
+
997
+ global $wpdb;
998
+ /*
999
+ 1 = subscriber
1000
+ 2 = editor
1001
+ 3 = author
1002
+ 7 = publisher
1003
+ 10 = administrator
1004
+ */
1005
+
1006
+ // Page pseudo-variables initialization.
1007
+ $template_variables = array(
1008
+ 'SucuriURL'=>SUCURI_URL,
1009
+ 'AdminUsers.UserList'=>''
1010
+ );
1011
+
1012
+ $admins = $wpdb->get_results("SELECT DISTINCT(user_id) AS user_id FROM `$wpdb->usermeta` WHERE meta_value = '$userlevel'");
1013
+ foreach ( (array) $admins as $user ) {
1014
+ $admin = get_userdata( $user->user_id );
1015
+ $admin->lastlogins = sucuriscan_get_logins(4, $admin->ID);
1016
+ $userlevel = $admin->wp2_user_level;
1017
+ $name = $admin->nickname;
1018
+
1019
+ $user_snippet = array(
1020
+ 'AdminUsers.Username'=>$admin->user_login,
1021
+ 'AdminUsers.Email'=>$admin->user_email,
1022
+ 'AdminUsers.LastLogins'=>'',
1023
+ 'AdminUsers.UserURL'=>admin_url('user-edit.php?user_id='.$user->user_id)
1024
+ );
1025
+ if( !empty($admin->lastlogins) ){
1026
+ $user_snippet['AdminUsers.NoLastLogins'] = 'hidden';
1027
+ $user_snippet['AdminUsers.NoLastLoginsTable'] = 'visible';
1028
+ foreach($admin->lastlogins as $lastlogin){
1029
+ $user_snippet['AdminUsers.LastLogins'] .= sucuriscan_get_template('integrity-admins-lastlogin.snippet.tpl', array(
1030
+ 'AdminUsers.RemoteAddr'=>$lastlogin->user_remoteaddr,
1031
+ 'AdminUsers.Datetime'=>$lastlogin->user_lastlogin
1032
+ ));
1033
+ }
1034
+ }else{
1035
+ $user_snippet['AdminUsers.NoLastLogins'] = 'visible';
1036
+ $user_snippet['AdminUsers.NoLastLoginsTable'] = 'hidden';
1037
+ }
1038
+
1039
+ $template_variables['AdminUsers.UserList'] .= sucuriscan_get_template('integrity-admins.snippet.tpl', $user_snippet);
1040
+ }
1041
+
1042
+ echo sucuriscan_get_template('integrity-admins.html.tpl', $template_variables);
1043
+ }
1044
+
1045
+ /**
1046
+ * Check if any installed plugin has an update available.
1047
+ *
1048
+ * @return void
1049
+ */
1050
+ function sucuriwp_check_plugins()
1051
+ {
1052
+ do_action("wp_update_plugins"); // force WP to check plugins for updates
1053
+ wp_update_plugins();
1054
+ $update_plugins = get_site_transient('update_plugins'); // get information of updates
1055
+ $plugins_need_update = $update_plugins->response; // plugins that need updating
1056
+
1057
+ echo '<div class="postbox">';
1058
+ echo "<h3>Outdated Plugins</h3>";
1059
+ echo '<div class="inside">';
1060
+ if (!empty($update_plugins->response)) { // any plugin updates available?
1061
+ $plugins_need_update = $update_plugins->response; // plugins that need updating
1062
+ $active_plugins = array_flip(get_option('active_plugins')); // find which plugins are active
1063
+ $plugins_need_update = array_intersect_key($plugins_need_update, $active_plugins); // only keep plugins that are active
1064
+ if(count($plugins_need_update) >= 1) { // any plugins need updating after all the filtering gone on above?
1065
+ require_once(ABSPATH . 'wp-admin/includes/plugin-install.php'); // Required for plugin API
1066
+ require_once(ABSPATH . WPINC . '/version.php' ); // Required for WP core version
1067
+ foreach($plugins_need_update as $key => $data) { // loop through the plugins that need updating
1068
+ $plugin_info = get_plugin_data(WP_PLUGIN_DIR . "/" . $key); // get local plugin info
1069
+ $info = plugins_api('plugin_information', array('slug' => $data->slug )); // get repository plugin info
1070
+ $message = "\n".sprintf(__("Plugin: %s is out of date. Please update from version %s to %s", "wp-updates-notifier"), $plugin_info['Name'], $plugin_info['Version'], $data->new_version)."\n";
1071
+ echo "<p>$message</p>";
1072
+ }
1073
+ }
1074
+ else
1075
+ {
1076
+ echo "<p>All plugins are up-to-date!</p>";
1077
+ }
1078
+ }
1079
+ else
1080
+ {
1081
+ echo "<p>All plugins are up-to-date!</p>";
1082
+ }
1083
+ echo '</div>';
1084
+ echo '</div>';
1085
+ }
1086
+
1087
+ /**
1088
+ * Check if any installed theme has an update available.
1089
+ *
1090
+ * @return void
1091
+ */
1092
+ function sucuriwp_check_themes()
1093
+ {
1094
+ do_action("wp_update_themes"); // force WP to check for theme updates
1095
+ wp_update_themes();
1096
+ $update_themes = get_site_transient('update_themes'); // get information of updates
1097
+
1098
+ echo '<div class="postbox">';
1099
+ echo "<h3>Outdated Themes</h3>";
1100
+ echo '<div class="inside">';
1101
+ if (!empty($update_themes->response)) { // any theme updates available?
1102
+ $themes_need_update = $update_themes->response; // themes that need updating
1103
+
1104
+ if(count($themes_need_update) >= 1) { // any themes need updating after all the filtering gone on above?
1105
+ foreach($themes_need_update as $key => $data) { // loop through the themes that need updating
1106
+ $theme_info = get_theme_data(WP_CONTENT_DIR . "/themes/" . $key . "/style.css"); // get theme info
1107
+ $message = sprintf(__("Theme: %s is out of date. Please update from version %s to %s", "wp-updates-notifier"), $theme_info['Name'], $theme_info['Version'], $data['new_version'])."\n";
1108
+ echo "<p>$message</p>";
1109
+ }
1110
+ }
1111
+ }
1112
+ else
1113
+ {
1114
+ echo "<p>All themes are up-to-date!</p>";
1115
+ }
1116
+ echo '</div>';
1117
+ echo '</div>';
1118
+ }
1119
+
1120
+ /**
1121
+ * Retrieve a list with the checksums of the files in a specific version of Wordpress.
1122
+ *
1123
+ * @param integer $version Valid version number of the Wordpress project.
1124
+ * @return object Associative object with the relative filepath and the checksums of the project files.
1125
+ */
1126
+ function sucuriscan_get_official_checksums($version=0){
1127
+ $api_url = sprintf('http://api.wordpress.org/core/checksums/1.0/?version=%s&locale=en_US', $version);
1128
+
1129
+ $request = wp_remote_get($api_url);
1130
+ if( !is_wp_error($request) || wp_remote_retrieve_response_code($request) === 200 ){
1131
+ $json_data = json_decode($request['body']);
1132
+ if( $json_data->checksums !== FALSE ){
1133
+ return $json_data->checksums;
1134
+ }
1135
+ }
1136
+
1137
+ return FALSE;
1138
+ }
1139
+
1140
+ /**
1141
+ * Check whether the core Wordpress files where modified, removed or if any file
1142
+ * was added to the core folders. This function returns an associative array with
1143
+ * these keys:
1144
+ *
1145
+ * <ul>
1146
+ * <li>bad: Files with a different checksum according to the official files of the Wordpress version filtered,</li>
1147
+ * <li>good: Files with the same checksums than the official files,</li>
1148
+ * <li>removed: Official files which are not present in the local project,</li>
1149
+ * <li>added: Files present in the local project but not in the official Wordpress packages.</li>
1150
+ * </ul>
1151
+ *
1152
+ * @param integer $version Valid version number of the Wordpress project.
1153
+ * @return array Associative array with these keys: bad, good, removed, added.
1154
+ */
1155
+ function sucuriscan_check_wp_integrity($version=0){
1156
+ $latest_hashes = sucuriscan_get_official_checksums($version);
1157
+
1158
+ if( !$latest_hashes ){ return FALSE; }
1159
+
1160
+ $output = array( 'bad'=>array(), 'good'=>array(), 'removed'=>array(), 'added'=>array() );
1161
+
1162
+ // Get current filesystem tree.
1163
+ $wp_top_hashes = read_dir_r( ABSPATH , false);
1164
+ $wp_admin_hashes = read_dir_r( ABSPATH . 'wp-admin', true);
1165
+ $wp_includes_hashes = read_dir_r( ABSPATH . 'wp-includes', true);
1166
+ $wp_core_hashes = array_merge( $wp_top_hashes, $wp_admin_hashes, $wp_includes_hashes );
1167
+
1168
+ // Compare remote and local md5sums and search removed files.
1169
+ foreach( $latest_hashes as $filepath=>$remote_checksum ){
1170
+ $full_filepath = sprintf('%s/%s', ABSPATH, $filepath);
1171
+ if( file_exists($full_filepath) ){
1172
+ $local_checksum = @md5_file($full_filepath);
1173
+ if( $local_checksum && $local_checksum == $remote_checksum ){
1174
+ $output['good'][] = $filepath;
1175
+ }else{
1176
+ $output['bad'][] = $filepath;
1177
+ }
1178
+ }else{
1179
+ $output['removed'][] = $filepath;
1180
+ }
1181
+ }
1182
+
1183
+ // Search added files (files not common in a normal wordpress installation).
1184
+ foreach( $wp_core_hashes as $filepath=>$extra_info ){
1185
+ $filepath = preg_replace('/^\.\/(.*)/', '$1', $filepath);
1186
+ if( !property_exists($latest_hashes, $filepath) ){
1187
+ $output['added'][] = $filepath;
1188
+ }
1189
+ }
1190
+
1191
+ return $output;
1192
+ }
1193
+
1194
+ /**
1195
+ * Sucuri one-click hardening page.
1196
+ *
1197
+ * It loads all the functions defined in /lib/hardening.php and shows the forms
1198
+ * that the administrator can use to harden multiple parts of the site.
1199
+ *
1200
+ * @return void
1201
+ */
1202
+ function sucuriscan_hardening_page(){
1203
+ echo '<div class="wrap">';
1204
+ echo '<h2 id="warnings_hook"></h2>';
1205
+ echo '<div class="sucuriscan_header">';
1206
+ echo '<a href="http://sucuri.net/signup" target="_blank" title="Sucuri Security">';
1207
+ echo '<img src="'.SUCURI_URL.'/inc/images/logo.png" alt="Sucuri Security" />';
1208
+ echo '</a>';
1209
+ sucuriscan_pagestop("Sucuri 1-Click Hardening Options");
1210
+ echo '</div>';
1211
+
1212
+ if(!current_user_can('manage_options'))
1213
+ {
1214
+ wp_die(__('You do not have sufficient permissions to access this page: Sucuri Hardening') );
1215
+ }
1216
+ ?>
1217
+
1218
+ <div class="postbox-container" style="width:75%">
1219
+ <div class="sucuriscan-maincontent">
1220
+ <div class="postbox">
1221
+ <div class="inside">
1222
+ <h2 align="center">Help secure your WordPress install with <a href="http://sucuri.net/signup">Sucuri</a> 1-Click Hardening Options.</h2>
1223
+ </div>
1224
+ </div>
1225
+
1226
+ <?php
1227
+ if( isset($_POST['wpsucuri-doharden']) ){
1228
+ if(!wp_verify_nonce($_POST['sucuriscan_wphardeningnonce'], 'sucuriscan_wphardeningnonce'))
1229
+ {
1230
+ unset($_POST['wpsucuri-doharden']);
1231
+ }
1232
+ }
1233
+ ?>
1234
+
1235
+ <div id="poststuff">
1236
+ <form method="post">
1237
+ <input type="hidden" name="sucuriscan_wphardeningnonce" value="<?php echo wp_create_nonce('sucuriscan_wphardeningnonce'); ?>" />
1238
+ <input type="hidden" name="wpsucuri-doharden" value="wpsucuri-doharden" />
1239
+ <?php
1240
+ sucuriscan_harden_version();
1241
+ sucuriscan_cloudproxy_enabled();
1242
+ sucuri_harden_removegenerator();
1243
+ sucuriscan_harden_upload();
1244
+ sucuriscan_harden_wpcontent();
1245
+ sucuriscan_harden_wpincludes();
1246
+ sucuriscan_harden_phpversion();
1247
+ ?>
1248
+ </form>
1249
+
1250
+ <p align="center">
1251
+ <strong>If you have any questions about these checks or this plugin, contact us at
1252
+ <a href="mailto:info@sucuri.net">info@sucuri.net</a> or visit <a href="http://sucuri.net">
1253
+ Sucuri Security</a></strong>
1254
+ </p>
1255
+ </div><!-- End poststuff -->
1256
+ </div><!-- End sucuriscan-maincontent -->
1257
+ </div><!-- End postbox-container -->
1258
+
1259
+ <?php echo sucuriscan_get_template('sidebar.html.tpl') ?>
1260
+
1261
+ </div><!-- End Wrap -->
1262
+
1263
+ <?php
1264
+ }
1265
+
1266
+ /**
1267
+ * Print the HTML code to show the title of a hardening option box.
1268
+ *
1269
+ * @param string $msg The title of the hardening option.
1270
+ * @return void
1271
+ */
1272
+ function sucuriscan_wrapper_open($msg)
1273
+ {
1274
+ ?>
1275
+ <div class="postbox">
1276
+ <h3><?php echo $msg; ?></h3>
1277
+ <div class="inside">
1278
+ <?php
1279
+ }
1280
+
1281
+ /**
1282
+ * Close the HTML tags of the containers opened with __ss_wraphardeningboxopen()
1283
+ *
1284
+ * @return void
1285
+ */
1286
+ function sucuriscan_wrapper_close()
1287
+ {
1288
+ ?>
1289
+ </div>
1290
+ </div>
1291
+ <?php
1292
+ }
1293
+
1294
+ /**
1295
+ * Print an error message in the interface.
1296
+ *
1297
+ * @param string $message The text string that will be shown inside the error box.
1298
+ * @return void
1299
+ */
1300
+ function sucuriscan_harden_error($message)
1301
+ {
1302
+ return('<div id="message" class="error"><p>'.$message.'</p></div>');
1303
+ }
1304
+
1305
+ /**
1306
+ * Print a success message in the interface.
1307
+ *
1308
+ * @param string $message The text string that will be shown inside the success box.
1309
+ * @return void
1310
+ */
1311
+ function sucuriscan_harden_ok($message)
1312
+ {
1313
+ return( '<div id="message" class="updated"><p>'.$message.'</p></div>');
1314
+ }
1315
+
1316
+ /**
1317
+ * Generate the HTML code necessary to show a form with the options to harden
1318
+ * a specific part of the Wordpress installation, if the Status variable is
1319
+ * set as a positive integer the button is shown as "unharden".
1320
+ *
1321
+ * @param integer $status Either one or zero representing the state of the hardening, one for secure, zero for insecure.
1322
+ * @param string $type Name of the hardening option, this will be used through out the form generation.
1323
+ * @param string $messageok Message that will be shown if the hardening was executed.
1324
+ * @param string $messagewarn Message that will be shown if the hardening is not executed.
1325
+ * @param string $desc Optional description of the hardening.
1326
+ * @param string $updatemsg Optional explanation of the hardening after the submission of the form.
1327
+ * @return void
1328
+ */
1329
+ function sucuriscan_harden_status($status=0, $type='', $messageok='', $messagewarn='', $desc = NULL, $updatemsg = NULL){
1330
+ if($desc != NULL)
1331
+ {
1332
+ echo "<p>$desc</p>";
1333
+ }
1334
+
1335
+ if($status == 1)
1336
+ {
1337
+ echo '<h4>'.
1338
+ '<img style="position:relative;top:5px" height="22" width="22"'.
1339
+ 'src="'.SUCURI_URL.'inc/images/ok.png" /> &nbsp; '.
1340
+ $messageok.'.</h4>';
1341
+
1342
+ if($updatemsg != NULL){ echo $updatemsg; }
1343
+
1344
+ if($type != NULL)
1345
+ {
1346
+ echo "<input type='submit' name='{$type}_unharden' value='Revert hardening' class='button-secondary' />";
1347
+ echo '<br /><br />';
1348
+ }
1349
+ }
1350
+ else
1351
+ {
1352
+ echo '<h4>'.
1353
+ '<img style="position:relative;top:5px" height="22" width="22"'.
1354
+ 'src="'.SUCURI_URL.'inc/images/warn.png" /> &nbsp; '.
1355
+ $messagewarn. '.</h4>';
1356
+
1357
+ if($updatemsg != NULL){ echo $updatemsg; }
1358
+
1359
+ if($type != NULL)
1360
+ {
1361
+ echo '<input class="button-primary" type="submit" name="'.$type.'"
1362
+ value="Harden it!" />';
1363
+ }
1364
+ }
1365
+ }
1366
+
1367
+ /**
1368
+ * Check whether the version number of the Wordpress installed is the latest
1369
+ * version available officially.
1370
+ *
1371
+ * @return void
1372
+ */
1373
+ function sucuriscan_harden_version()
1374
+ {
1375
+ global $wp_version;
1376
+ $cp = 0;
1377
+ $updates = get_core_updates();
1378
+ if (!is_array($updates))
1379
+ {
1380
+ $cp = 1;
1381
+ }
1382
+ else if(empty($updates))
1383
+ {
1384
+ $cp = 1;
1385
+ }
1386
+ else if($updates[0]->response == 'latest')
1387
+ {
1388
+ $cp = 1;
1389
+ }
1390
+ if(strcmp($wp_version, "3.7") < 0)
1391
+ {
1392
+ $cp = 0;
1393
+ }
1394
+ $wp_version = htmlspecialchars($wp_version);
1395
+
1396
+
1397
+ sucuriscan_wrapper_open("Verify WordPress Version");
1398
+
1399
+
1400
+ sucuriscan_harden_status($cp, NULL,
1401
+ "WordPress is updated", "WordPress is not updated",
1402
+ NULL);
1403
+
1404
+ if($cp == 0)
1405
+ {
1406
+ echo "<p>Your current version ($wp_version) is not current.</p><p><a class='button-primary' href='update-core.php'>Update now!</a></p>";
1407
+ }
1408
+ else
1409
+ {
1410
+ echo "<p>Your WordPress installation ($wp_version) is current.</p>";
1411
+ }
1412
+ sucuriscan_wrapper_close();
1413
+ }
1414
+
1415
+ /**
1416
+ * Notify the state of the hardening for the removal of the Generator tag in
1417
+ * HTML code printed by Wordpress to show the current version number of the
1418
+ * installation.
1419
+ *
1420
+ * @return void
1421
+ */
1422
+ function sucuri_harden_removegenerator()
1423
+ {
1424
+ /* Enabled by default with this plugin. */
1425
+ $cp = 1;
1426
+
1427
+ sucuriscan_wrapper_open("Remove WordPress Version");
1428
+
1429
+ sucuriscan_harden_status($cp, NULL,
1430
+ "WordPress version properly hidden", NULL,
1431
+ "It checks if your WordPress version is being hidden".
1432
+ " from being displayed in the generator tag ".
1433
+ "(enabled by default with this plugin).");
1434
+
1435
+ sucuriscan_wrapper_close();
1436
+ }
1437
+
1438
+ /**
1439
+ * Check whether the Wordpress upload folder is protected or not.
1440
+ *
1441
+ * A htaccess file is placed in the upload folder denying the access to any php
1442
+ * file that could be uploaded through a vulnerability in a Plugin, Theme or
1443
+ * Wordpress itself.
1444
+ *
1445
+ * @return void
1446
+ */
1447
+ function sucuriscan_harden_upload()
1448
+ {
1449
+ $cp = 1;
1450
+ $upmsg = NULL;
1451
+ $htaccess_upload = dirname(sucuriscan_dir_filepath())."/.htaccess";
1452
+
1453
+ if(!is_readable($htaccess_upload))
1454
+ {
1455
+ $cp = 0;
1456
+ }
1457
+ else
1458
+ {
1459
+ $cp = 0;
1460
+ $fcontent = file($htaccess_upload);
1461
+ foreach($fcontent as $fline)
1462
+ {
1463
+ if(strpos($fline, "deny from all") !== FALSE)
1464
+ {
1465
+ $cp = 1;
1466
+ break;
1467
+ }
1468
+ }
1469
+ }
1470
+
1471
+ if( isset($_POST['wpsucuri-doharden']) ){
1472
+ if( isset($_POST['sucuriscan_harden_upload']) && $cp == 0 )
1473
+ {
1474
+ if(@file_put_contents($htaccess_upload,
1475
+ "\n<Files *.php>\ndeny from all\n</Files>")===FALSE)
1476
+ {
1477
+ $upmsg = sucuriscan_harden_error("ERROR: Unable to create <code>.htaccess</code> file, folder destination is not writable.");
1478
+ }
1479
+ else
1480
+ {
1481
+ $upmsg = sucuriscan_harden_ok("COMPLETE: Upload directory successfully hardened");
1482
+ $cp = 1;
1483
+ }
1484
+ }
1485
+
1486
+ elseif( isset($_POST['sucuriscan_harden_upload_unharden']) ){
1487
+ $htaccess_upload_writable = ( file_exists($htaccess_upload) && is_writable($htaccess_upload) ) ? TRUE : FALSE;
1488
+ $htaccess_content = $htaccess_upload_writable ? file_get_contents($htaccess_upload) : '';
1489
+
1490
+ if( $htaccess_upload_writable ){
1491
+ $cp = 0;
1492
+ if( preg_match('/<Files \*\.php>\ndeny from all\n<\/Files>/', $htaccess_content, $match) ){
1493
+ $htaccess_content = str_replace("<Files *.php>\ndeny from all\n</Files>", '', $htaccess_content);
1494
+ @file_put_contents($htaccess_upload, $htaccess_content, LOCK_EX);
1495
+ }
1496
+ sucuriscan_admin_notice('updated', '<strong>OK.</strong> WP-Content Uploads directory protection reverted.');
1497
+ }else{
1498
+ $harden_process = '<strong>Error.</strong> The <code>wp-content/uploads/.htaccess</code> does
1499
+ not exists or is not writable, you will need to remove the following code manually there:
1500
+ <code>&lt;Files *.php&gt;deny from all&lt;/Files&gt;</code>';
1501
+ sucuriscan_admin_notice('error', $harden_process);
1502
+ }
1503
+ }
1504
+ }
1505
+
1506
+ sucuriscan_wrapper_open("Protect Uploads Directory");
1507
+ sucuriscan_harden_status($cp, "sucuriscan_harden_upload",
1508
+ "Upload directory properly hardened",
1509
+ "Upload directory not hardened",
1510
+ "It checks if your upload directory allows PHP ".
1511
+ "execution or if it is browsable.", $upmsg);
1512
+ sucuriscan_wrapper_close();
1513
+ }
1514
+
1515
+ /**
1516
+ * Check whether the Wordpress content folder is protected or not.
1517
+ *
1518
+ * A htaccess file is placed in the content folder denying the access to any php
1519
+ * file that could be uploaded through a vulnerability in a Plugin, Theme or
1520
+ * Wordpress itself.
1521
+ *
1522
+ * @return void
1523
+ */
1524
+ function sucuriscan_harden_wpcontent()
1525
+ {
1526
+ $cp = 1;
1527
+ $upmsg = NULL;
1528
+ $htaccess_upload = ABSPATH."/wp-content/.htaccess";
1529
+
1530
+ if(!is_readable($htaccess_upload))
1531
+ {
1532
+ $cp = 0;
1533
+ }
1534
+ else
1535
+ {
1536
+ $cp = 0;
1537
+ $fcontent = file($htaccess_upload);
1538
+ foreach($fcontent as $fline)
1539
+ {
1540
+ if(strpos($fline, "deny from all") !== FALSE)
1541
+ {
1542
+ $cp = 1;
1543
+ break;
1544
+ }
1545
+ }
1546
+ }
1547
+
1548
+ if( isset($_POST['wpsucuri-doharden']) ){
1549
+ if( isset($_POST['sucuriscan_harden_wpcontent']) && $cp == 0 )
1550
+ {
1551
+ if(@file_put_contents($htaccess_upload,
1552
+ "\n<Files *.php>\ndeny from all\n</Files>")===FALSE)
1553
+ {
1554
+ $upmsg = sucuriscan_harden_error("ERROR: Unable to create <code>.htaccess</code> file, folder destination is not writable.");
1555
+ }
1556
+ else
1557
+ {
1558
+ $upmsg = sucuriscan_harden_ok("COMPLETE: wp-content directory successfully hardened");
1559
+ $cp = 1;
1560
+ }
1561
+ }
1562
 
1563
+ elseif( isset($_POST['sucuriscan_harden_wpcontent_unharden']) ){
1564
+ $htaccess_upload_writable = ( file_exists($htaccess_upload) && is_writable($htaccess_upload) ) ? TRUE : FALSE;
1565
+ $htaccess_content = $htaccess_upload_writable ? file_get_contents($htaccess_upload) : '';
1566
 
1567
+ if( $htaccess_upload_writable ){
1568
+ $cp = 0;
1569
+ if( preg_match('/<Files \*\.php>\ndeny from all\n<\/Files>/', $htaccess_content, $match) ){
1570
+ $htaccess_content = str_replace("<Files *.php>\ndeny from all\n</Files>", '', $htaccess_content);
1571
+ @file_put_contents($htaccess_upload, $htaccess_content, LOCK_EX);
1572
+ }
1573
+ sucuriscan_admin_notice('updated', '<strong>OK.</strong> WP-Content directory protection reverted.');
1574
+ }else{
1575
+ $harden_process = '<strong>Error.</strong> The <code>wp-content/.htaccess</code> does
1576
+ not exists or is not writable, you will need to remove the following code manually there:
1577
+ <code>&lt;Files *.php&gt;deny from all&lt;/Files&gt;</code>';
1578
+ sucuriscan_admin_notice('error', $harden_process);
1579
+ }
1580
  }
1581
  }
 
 
1582
 
1583
+ sucuriscan_wrapper_open("Restrict wp-content Access");
1584
+ sucuriscan_harden_status($cp, "sucuriscan_harden_wpcontent",
1585
+ "WP-content directory properly hardened",
1586
+ "WP-content directory not hardened",
1587
+ "This option blocks direct PHP access to any file inside wp-content. <p><strong>WARN: <span class='error-message'>Do not enable this option if ".
1588
+ "your site uses TimThumb or similar scripts.</span> If you enable and you need to disable, please remove the .htaccess from wp-content.</strong></p>", $upmsg);
1589
+ sucuriscan_wrapper_close();
1590
  }
1591
 
1592
+ /**
1593
+ * Check whether the Wordpress includes folder is protected or not.
1594
+ *
1595
+ * A htaccess file is placed in the includes folder denying the access to any php
1596
+ * file that could be uploaded through a vulnerability in a Plugin, Theme or
1597
+ * Wordpress itself, there are some exceptions for some specific files that must
1598
+ * be available publicly.
1599
+ *
1600
+ * @return void
1601
+ */
1602
+ function sucuriscan_harden_wpincludes()
1603
  {
1604
+ $cp = 1;
1605
+ $upmsg = NULL;
1606
+ $htaccess_upload = ABSPATH."/wp-includes/.htaccess";
1607
+
1608
+ if(!is_readable($htaccess_upload))
1609
+ {
1610
+ $cp = 0;
1611
+ }
1612
+ else
1613
+ {
1614
+ $cp = 0;
1615
+ $fcontent = file($htaccess_upload);
1616
+ foreach($fcontent as $fline)
1617
+ {
1618
+ if(strpos($fline, "deny from all") !== FALSE)
1619
+ {
1620
+ $cp = 1;
1621
+ break;
1622
  }
 
1623
  }
1624
  }
 
 
 
 
 
 
 
 
 
 
 
 
1625
 
1626
+ if( isset($_POST['wpsucuri-doharden']) ){
1627
+ if( isset($_POST['sucuriscan_harden_wpincludes']) && $cp == 0 )
1628
+ {
1629
+ if(@file_put_contents($htaccess_upload,
1630
+ "\n<Files *.php>\ndeny from all\n</Files>\n<Files wp-tinymce.php>\nallow from all\n</Files>\n")===FALSE)
1631
+ {
1632
+ $upmsg = sucuriscan_harden_error("ERROR: Unable to create <code>.htaccess</code> file, folder destination is not writable.");
1633
+ }
1634
+ else
1635
+ {
1636
+ $upmsg = sucuriscan_harden_ok("COMPLETE: wp-includes directory successfully hardened.");
1637
+ $cp = 1;
1638
+ }
1639
+ }
1640
 
1641
+ elseif( isset($_POST['sucuriscan_harden_wpincludes_unharden']) ){
1642
+ $htaccess_upload_writable = ( file_exists($htaccess_upload) && is_writable($htaccess_upload) ) ? TRUE : FALSE;
1643
+ $htaccess_content = $htaccess_upload_writable ? file_get_contents($htaccess_upload) : '';
 
 
 
1644
 
1645
+ if( $htaccess_upload_writable ){
1646
+ $cp = 0;
1647
+ if( preg_match_all('/<Files (\*|wp-tinymce|ms-files)\.php>\n(deny|allow) from all\n<\/Files>/', $htaccess_content, $match) ){
1648
+ foreach($match[0] as $restriction){
1649
+ $htaccess_content = str_replace($restriction, '', $htaccess_content);
1650
+ }
1651
+ @file_put_contents($htaccess_upload, $htaccess_content, LOCK_EX);
1652
  }
1653
+ sucuriscan_admin_notice('updated', '<strong>OK.</strong> WP-Includes directory protection reverted.');
1654
+ }else{
1655
+ $harden_process = '<strong>Error.</strong> The <code>wp-includes/.htaccess</code> does
1656
+ not exists or is not writable, you will need to remove the following code manually there:
1657
+ <code>&lt;Files *.php&gt;deny from all&lt;/Files&gt;</code>';
1658
+ sucuriscan_admin_notice('error', $harden_process);
1659
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1660
  }
 
1661
  }
1662
+
1663
+ sucuriscan_wrapper_open("Restrict wp-includes Access");
1664
+ sucuriscan_harden_status($cp, "sucuriscan_harden_wpincludes",
1665
+ "wp-includes directory properly hardened",
1666
+ "wp-includes directory not hardened",
1667
+ "This option blocks direct PHP access to any file inside wp-includes. ", $upmsg);
1668
+ sucuriscan_wrapper_close();
1669
  }
1670
 
1671
+ /**
1672
+ * Check the version number of the PHP interpreter set to work with the site,
1673
+ * is considered that old versions of the PHP interpreter are insecure.
1674
+ *
1675
+ * @return void
1676
+ */
1677
+ function sucuriscan_harden_phpversion()
1678
  {
1679
+ $phpv = phpversion();
 
 
 
 
 
1680
 
1681
+ if(strncmp($phpv, "5.", 2) < 0)
1682
+ {
1683
+ $cp = 0;
1684
+ }
1685
+ else
1686
+ {
1687
+ $cp = 1;
1688
+ }
1689
 
1690
+ sucuriscan_wrapper_open("Verify PHP Version");
1691
+ sucuriscan_harden_status($cp, NULL,
1692
+ "Using an updated version of PHP (v $phpv)",
1693
+ "The version of PHP you are using ($phpv) is not current, not recommended, and/or not supported",
1694
+ "This checks if you have the latest version of PHP installed.", NULL);
1695
+ sucuriscan_wrapper_close();
1696
+ }
1697
 
1698
+ /**
1699
+ * Check whether the site is behind a secure proxy server or not.
1700
+ *
1701
+ * @return void
1702
+ */
1703
+ function sucuriscan_cloudproxy_enabled(){
1704
+ $enabled = sucuriscan_is_behind_cloudproxy();
1705
+
1706
+ sucuriscan_wrapper_open('Verify if your site is protected by a Web Firewall');
1707
+ sucuriscan_harden_status(
1708
+ $enabled, NULL,
1709
+ 'Your website is protected by a Website Firewall (WAF)',
1710
+ 'Your website is not protected by a Website Firewall (WAF)',
1711
+ 'A WAF is a protection layer for your web site, blocking all sort of attacks (brute force attempts, DDoS, SQL injections, etc) and helping it remain
1712
+ malware and blacklist free. This test checks if your site is using <a href="http://cloudproxy.sucuri.net/" target="_blank">Sucuri\'s CloudProxy WAF</a> to protect your site. ',
1713
+ NULL
1714
+ );
1715
+ if( $enabled!==TRUE ){
1716
+ echo '<a href="http://cloudproxy.sucuri.net" target="_blank" class="button button-primary">Harden it!</a>';
1717
  }
1718
+ sucuriscan_wrapper_close();
1719
  }
1720
 
1721
+ /**
1722
+ * Generate and print the HTML code for the Post-Hack page.
1723
+ *
1724
+ * @return void
1725
+ */
1726
  function sucuriscan_posthack_page()
1727
  {
1728
  if( !current_user_can('manage_options') )
1824
  echo sucuriscan_get_template('posthack.html.tpl', $template_variables);
1825
  }
1826
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1827
  /**
1828
+ * Generate and print the HTML code for the Last Logins page.
1829
+ *
1830
+ * This page will contains information of all the logins of the registered users.
1831
+ *
1832
+ * @return void
1833
  */
 
1834
  function sucuriscan_lastlogins_page()
1835
  {
1836
  if( !current_user_can('manage_options') )
1871
  echo sucuriscan_get_template('lastlogins.html.tpl', $template_variables);
1872
  }
1873
 
1874
+ /**
1875
+ * Get the filepath where the information of the last logins of all users is stored.
1876
+ *
1877
+ * @return string Absolute filepath where the user's last login information is stored.
1878
+ */
1879
  function sucuriscan_lastlogins_datastore_filepath(){
1880
  $plugin_upload_folder = sucuriscan_dir_filepath();
1881
  $datastore_filepath = rtrim($plugin_upload_folder,'/').'/sucuri-lastlogins.php';
1882
  return $datastore_filepath;
1883
  }
1884
 
1885
+ /**
1886
+ * Check whether the user's last login datastore file exists or not, if not then
1887
+ * we try to create the file and check again the success of the operation.
1888
+ *
1889
+ * @return string Absolute filepath where the user's last login information is stored.
1890
+ */
1891
  function sucuriscan_lastlogins_datastore_exists(){
1892
  $datastore_filepath = sucuriscan_lastlogins_datastore_filepath();
1893
 
1900
  return file_exists($datastore_filepath) ? $datastore_filepath : FALSE;
1901
  }
1902
 
1903
+ /**
1904
+ * Check whether the user's last login datastore file is writable or not, if not
1905
+ * we try to set the right permissions and check again the success of the operation.
1906
+ *
1907
+ * @return boolean Whether the user's last login datastore file is writable or not.
1908
+ */
1909
  function sucuriscan_lastlogins_datastore_is_writable(){
1910
  $datastore_filepath = sucuriscan_lastlogins_datastore_exists();
1911
  if($datastore_filepath){
1917
  return FALSE;
1918
  }
1919
 
1920
+ /**
1921
+ * Check whether the user's last login datastore file is readable or not, if not
1922
+ * we try to set the right permissions and check again the success of the operation.
1923
+ *
1924
+ * @return boolean Whether the user's last login datastore file is readable or not.
1925
+ */
1926
  function sucuriscan_lastlogins_datastore_is_readable(){
1927
  $datastore_filepath = sucuriscan_lastlogins_datastore_exists();
1928
  if( $datastore_filepath && is_readable($datastore_filepath) ){
1932
  }
1933
 
1934
  if( !function_exists('sucuri_set_lastlogin') ){
1935
+ /**
1936
+ * Add a new user session to the list of last user logins.
1937
+ *
1938
+ * @param string $user_login The name of the user account involved in the operation.
1939
+ * @return void
1940
+ */
1941
  function sucuriscan_set_lastlogin($user_login=''){
1942
  $datastore_filepath = sucuriscan_lastlogins_datastore_is_writable();
1943
 
1959
  add_action('wp_login', 'sucuriscan_set_lastlogin', 50);
1960
  }
1961
 
1962
+ /**
1963
+ * Retrieve the list of all the user logins from the datastore file.
1964
+ *
1965
+ * The results of this operation can be filtered by specific user identifiers,
1966
+ * or limiting the quantity of entries.
1967
+ *
1968
+ * @param integer $limit How many entries will be returned from the operation.
1969
+ * @param integer $user_id Optional user identifier to filter the results.
1970
+ * @return array The list of all the user logins through the time until now.
1971
+ */
1972
  function sucuriscan_get_logins($limit=10, $user_id=0){
1973
  $lastlogins = array();
1974
  $datastore_filepath = sucuriscan_lastlogins_datastore_is_readable();
2011
  }
2012
 
2013
  if( !function_exists('sucuri_login_redirect') ){
2014
+ /**
2015
+ * Hook for the wp-login action to redirect the user to a specific URL after
2016
+ * his successfully login to the administrator interface.
2017
+ *
2018
+ * @param string $redirect_to URL where the browser must be originally redirected to, set by Wordpress itself.
2019
+ * @param object $request Optional parameter set by Wordpress itself through the event triggered.
2020
+ * @param boolean $user Wordpress user object with the information of the account involved in the operation.
2021
+ * @return string URL where the browser must be redirected to.
2022
+ */
2023
  function sucuriscan_login_redirect($redirect_to='', $request=NULL, $user=FALSE){
2024
  $login_url = !empty($redirect_to) ? $redirect_to : admin_url();
2025
  if( $user instanceof WP_User && $user->ID ){
2031
  }
2032
 
2033
  if( !function_exists('sucuri_get_user_lastlogin') ){
2034
+ /**
2035
+ * Display the last user login at the top of the admin interface.
2036
+ *
2037
+ * @return void
2038
+ */
2039
  function sucuriscan_get_user_lastlogin(){
2040
  if( isset($_GET['sucuriscan_lastlogin_message']) && current_user_can('manage_options') ){
2041
  $current_user = wp_get_current_user();
2055
  add_action('admin_notices', 'sucuriscan_get_user_lastlogin');
2056
  }
2057
 
 
2058
  /**
2059
+ * Generate and print the HTML code for the InfoSys page.
2060
+ *
2061
+ * This page will contains information of the system where the site is hosted,
2062
+ * also information about users in session, htaccess rules and configuration
2063
+ * options.
2064
+ *
2065
+ * @return void
2066
  */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2067
  function sucuriscan_infosys_page(){
2068
  if( !current_user_can('manage_options') )
2069
  {
2078
  );
2079
 
2080
  $template_variables['LoggedInUsers'] = sucuriscan_infosys_loggedin();
2081
+ $template_variables['Cronjobs'] = sucuriscan_show_cronjobs();
2082
  $template_variables['HTAccessIntegrity'] = sucuriscan_infosys_htaccess();
2083
  $template_variables['WordpressConfig'] = sucuriscan_infosys_wpconfig();
2084
 
2085
  echo sucuriscan_get_template('infosys.html.tpl', $template_variables);
2086
  }
2087
 
2088
+ /**
2089
+ * Find the main htaccess file for the site and check whether the rules of the
2090
+ * main htaccess file of the site are the default rules generated by Wordpress.
2091
+ *
2092
+ * @return string The HTML code displaying the information about the HTAccess rules.
2093
+ */
2094
  function sucuriscan_infosys_htaccess(){
2095
  $htaccess_path = sucuriscan_get_htaccess_path();
2096
+
2097
  $template_variables = array(
2098
  'HTAccess.Content' => '',
2099
  'HTAccess.Message' => '',
2104
 
2105
  if( $htaccess_path ){
2106
  $htaccess_rules = file_get_contents($htaccess_path);
2107
+
2108
+ $template_variables['HTAccess.MessageType'] = 'updated';
2109
+ $template_variables['HTAccess.MessageVisible'] = 'visible';
2110
  $template_variables['HTAccess.TextareaVisible'] = 'visible';
2111
  $template_variables['HTAccess.Content'] = $htaccess_rules;
2112
+ $template_variables['HTAccess.Message'] .= 'HTAccess file found in this path <code>'.$htaccess_path.'</code>';
2113
 
2114
+ if( empty($htaccess_rules) ){
2115
+ $template_variables['HTAccess.TextareaVisible'] = 'hidden';
2116
+ $template_variables['HTAccess.Message'] .= '</p><p>The HTAccess file found is completely empty.';
2117
+ }
2118
  if( sucuriscan_htaccess_is_standard($htaccess_rules) ){
2119
+ $template_variables['HTAccess.Message'] .= '</p><p>
2120
  The main <code>.htaccess</code> file in your site has the standard rules for a WordPress installation. You can customize it to improve the
2121
  performance and change the behaviour of the redirections for pages and posts in your site. To get more information visit the official documentation at
2122
  <a href="http://codex.wordpress.org/Using_Permalinks#Creating_and_editing_.28.htaccess.29" target="_blank">Codex WordPrexx - Creating and editing (.htaccess)</a>';
 
 
2123
  }
 
2124
  }else{
2125
  $template_variables['HTAccess.Message'] = 'Your website does not contains a <code>.htaccess</code> file or it was not found in the default location.';
2126
  $template_variables['HTAccess.MessageType'] = 'error';
2130
  return sucuriscan_get_template('infosys-htaccess.html.tpl', $template_variables);
2131
  }
2132
 
2133
+ /**
2134
+ * Check whether the rules in a htaccess file are the default options generated
2135
+ * by Wordpress or if the file has custom options added by other Plugins.
2136
+ *
2137
+ * @param string $rules Optional parameter containing a text string with the content of the main htaccess file.
2138
+ * @return boolean Either TRUE or FALSE if the rules found in the htaccess file specified are the default ones or not.
2139
+ */
2140
  function sucuriscan_htaccess_is_standard($rules=FALSE){
2141
  if( $rules===FALSE ){
2142
  $htaccess_path = sucuriscan_get_htaccess_path();
2175
  return FALSE;
2176
  }
2177
 
2178
+ /**
2179
+ * Retrieve all the constants and variables with their respective values defined
2180
+ * in the Wordpress configuration file, only the database password constant is
2181
+ * omitted for security reasons.
2182
+ *
2183
+ * @return string The HTML code displaying the constants and variables found in the wp-config file.
2184
+ */
2185
  function sucuriscan_infosys_wpconfig(){
2186
  $template_variables = array(
2187
  'WordpressConfig.Rules' => '',
2188
  'WordpressConfig.Total' => 0,
2189
  'WordpressConfig.Content' => '',
2190
  );
2191
+ $ignore_wp_rules = array('DB_PASSWORD');
2192
 
2193
  $wp_config_path = sucuriscan_get_wpconfig_path();
2194
  if( $wp_config_path ){
2204
  // Ignore useless lines and append to the clean string the important lines.
2205
  if( preg_match('/^define\(/', $line) ){
2206
  $line = str_replace('define(', '', $line);
2207
+ $line = preg_replace('/\);.*/', '', $line);
2208
  $line_parts = explode(',', $line, 2);
2209
  }
2210
  else if( preg_match('/^\$[a-zA-Z_]+/', $line) ){
2230
  if( $i==0 ){ $key_name = $line_part; }
2231
  if( $i==1 ){ $key_value = $line_part; }
2232
  }
2233
+
2234
+ if( !in_array($key_name, $ignore_wp_rules) ){
2235
+ $wp_config_rules[$key_name] = $key_value;
2236
+ }
2237
  }
2238
  }
2239
 
2250
  return sucuriscan_get_template('infosys-wpconfig.html.tpl', $template_variables);
2251
  }
2252
 
2253
+ /**
2254
+ * Print a list of all the registered users that are currently in session.
2255
+ *
2256
+ * @return string The HTML code displaying a list of all the users logged in at the moment.
2257
+ */
2258
  function sucuriscan_infosys_loggedin(){
2259
  // Get user logged in list.
2260
  $template_variables = array(
2262
  'LoggedInUsers.Total' => 0,
2263
  );
2264
 
2265
+ $logged_in_users = sucuriscan_get_online_users(TRUE);
2266
  if( is_array($logged_in_users) && !empty($logged_in_users) ){
2267
  $template_variables['LoggedInUsers.Total'] = count($logged_in_users);
2268
 
2285
  return sucuriscan_get_template('infosys-loggedin.html.tpl', $template_variables);
2286
  }
2287
 
2288
+ /**
2289
+ * Get a list of all the registered users that are currently in session.
2290
+ *
2291
+ * @param boolean $add_current_user Whether the current user should be added to the list or not.
2292
+ * @return array List of registered users currently in session.
2293
+ */
2294
+ function sucuriscan_get_online_users($add_current_user=FALSE){
2295
+ $users = array();
2296
 
 
2297
  if( sucuriscan_is_multisite() ){
2298
+ $users = get_site_transient('online_users');
2299
  }else{
2300
+ $users = get_transient('online_users');
2301
+ }
2302
+
2303
+ // If not online users but current user is logged in, add it to the list.
2304
+ if( empty($users) && $add_current_user ){
2305
+ $current_user = wp_get_current_user();
2306
+ if( $current_user->ID > 0 ){
2307
+ sucuriscan_set_online_user($current_user->user_login, $current_user);
2308
+ return sucuriscan_get_online_users();
2309
+ }
2310
  }
 
2311
 
2312
+ return $users;
2313
+ }
2314
 
2315
+ /**
2316
+ * Update the list of the registered users currently in session.
2317
+ *
2318
+ * Useful when you are removing users and need the list of the remaining users.
2319
+ *
2320
+ * @param array $logged_in_users List of registered users currently in session.
2321
+ * @return boolean Either TRUE or FALSE representing the success or fail of the operation.
2322
+ */
2323
  function sucuriscan_save_online_users($logged_in_users=array()){
2324
  $expiration = 30 * 60;
2325
  if( sucuriscan_is_multisite() ){
2329
  }
2330
  }
2331
 
 
2332
  if( !function_exists('sucuriscan_unset_online_user_on_logout') ){
2333
+ /**
2334
+ * Remove a logged in user from the list of registered users in session when
2335
+ * the logout page is requested.
2336
+ *
2337
+ * @return void
2338
+ */
2339
  function sucuriscan_unset_online_user_on_logout(){
2340
  $current_user = wp_get_current_user();
2341
  $user_id = $current_user->ID;
2347
  add_action('wp_logout', 'sucuriscan_unset_online_user_on_logout');
2348
  }
2349
 
2350
+ /**
2351
+ * Remove a logged in user from the list of registered users in session using
2352
+ * the user identifier and the ip address of the last computer used to login.
2353
+ *
2354
+ * @param integer $user_id User identifier of the account that will be logged out.
2355
+ * @param integer $remote_addr IP address of the computer where the user logged in.
2356
+ * @return boolean Either TRUE or FALSE representing the success or fail of the operation.
2357
+ */
2358
  function sucuriscan_unset_online_user($user_id=0, $remote_addr=0){
2359
  $logged_in_users = sucuriscan_get_online_users();
2360
 
2374
  return sucuriscan_save_online_users($logged_in_users);
2375
  }
2376
 
 
2377
  if( !function_exists('sucuriscan_set_online_user') ){
2378
+ /**
2379
+ * Add an user account to the list of registered users in session.
2380
+ *
2381
+ * @param string $user_login The name of the user account that just logged in the site.
2382
+ * @param boolean $user The Wordpress object containing all the information associated to the user.
2383
+ * @return void
2384
+ */
2385
  function sucuriscan_set_online_user($user_login='', $user=FALSE){
2386
  if( $user ){
2387
  // Get logged in user information.
2442
  add_action('wp_login', 'sucuriscan_set_online_user', 10, 2);
2443
  }
2444
 
2445
+ /**
2446
+ * Retrieve a list with the scheduled tasks configured for the site.
2447
+ *
2448
+ * @return array A list of pseudo-variables and values that will replace them in the HTML template.
2449
+ */
2450
+ function sucuriscan_show_cronjobs(){
2451
+ $template_variables = array(
2452
+ 'Cronjobs.List' => '',
2453
+ 'Cronjobs.Total' => 0,
2454
+ );
2455
+
2456
+ $cronjobs = _get_cron_array();
2457
+ $schedules = wp_get_schedules();
2458
+ $date_format = _x('M j, Y - H:i', 'Publish box date format', 'cron-view' );
2459
+
2460
+ foreach( $cronjobs as $timestamp=>$cronhooks ){
2461
+ foreach( (array)$cronhooks as $hook=>$events ){
2462
+ foreach( (array)$events as $key=>$event ){
2463
+ $cronjob_snippet = '';
2464
+ $template_variables['Cronjobs.Total'] += 1;
2465
+ $template_variables['Cronjobs.List'] .= sucuriscan_get_template('infosys-cronjobs.snippet.tpl', array(
2466
+ 'Cronjob.Task' => ucwords(str_replace('_',chr(32),$hook)),
2467
+ 'Cronjob.Schedule' => $event['schedule'],
2468
+ 'Cronjob.Nexttime' => date_i18n($date_format, $timestamp),
2469
+ 'Cronjob.Hook' => $hook,
2470
+ 'Cronjob.Arguments' => implode(', ', $event['args'])
2471
+ ));
2472
+ }
2473
+ }
2474
+ }
2475
+
2476
+ return sucuriscan_get_template('infosys-cronjobs.html.tpl', $template_variables);
2477
+ }
2478
+
2479
+
2480
+ /**
2481
+ * Print the HTML code for the plugin about page with information of the plugin,
2482
+ * the scheduled tasks, and some settings from the PHP environment and server.
2483
+ *
2484
+ * @return void
2485
+ */
2486
+ function sucuriscan_about_page()
2487
+ {
2488
+ if( !current_user_can('manage_options') )
2489
+ {
2490
+ wp_die(__('You do not have sufficient permissions to access this page: Sucuri Last-Logins') );
2491
+ }
2492
+
2493
+ // Page pseudo-variables initialization.
2494
+ $template_variables = array(
2495
+ 'SucuriURL'=>SUCURI_URL,
2496
+ 'SucuriWPSidebar'=>sucuriscan_wp_sidebar_gen(),
2497
+ 'CurrentURL'=>site_url().'/wp-admin/admin.php?page='.$_GET['page'],
2498
+ 'SettingsDisplay'=>'hidden'
2499
+ );
2500
+
2501
+ $template_variables = sucuriscan_about_information($template_variables);
2502
+
2503
+ echo sucuriscan_get_template('about.html.tpl', $template_variables);
2504
+ }
2505
+
2506
+ /**
2507
+ * Gather information from the server, database engine and PHP interpreter.
2508
+ *
2509
+ * @param array $template_variables The hash for the template system, keys are pseudo-variables.
2510
+ * @return array A list of pseudo-variables and values that will replace them in the HTML template.
2511
+ */
2512
+ function sucuriscan_about_information($template_variables=array())
2513
+ {
2514
+ global $wpdb;
2515
+
2516
+ if( current_user_can('manage_options') ){
2517
+ $memory_usage = function_exists('memory_get_usage') ? round(memory_get_usage()/1024/1024,2).' MB' : 'N/A';
2518
+ $mysql_version = $wpdb->get_var('SELECT VERSION() AS version');
2519
+ $mysql_info = $wpdb->get_results('SHOW VARIABLES LIKE "sql_mode"');
2520
+ $sql_mode = ( is_array($mysql_info) && !empty($mysql_info[0]->Value) ) ? $mysql_info[0]->Value : 'Not set';
2521
+ $plugin_runtime_filepath = sucuriscan_dir_filepath('.runtime');
2522
+ $plugin_runtime_datetime = file_exists($plugin_runtime_filepath) ? date('r',filemtime($plugin_runtime_filepath)) : 'N/A';
2523
+
2524
+ $template_variables = array_merge($template_variables, array(
2525
+ 'SettingsDisplay'=>'block',
2526
+ 'PluginVersion'=>SUCURISCAN_VERSION,
2527
+ 'PluginForceUpdate'=>admin_url('admin.php?page=sucurisec_settings&sucuri_force_update=1'),
2528
+ 'PluginMD5'=>md5_file(SUCURISCAN_PLUGIN_FILEPATH),
2529
+ 'PluginRuntimeDatetime'=>$plugin_runtime_datetime,
2530
+ 'OperatingSystem'=>sprintf('%s (%d Bit)', PHP_OS, PHP_INT_SIZE*8),
2531
+ 'Server'=>isset($_SERVER['SERVER_SOFTWARE']) ? $_SERVER['SERVER_SOFTWARE'] : 'Unknown',
2532
+ 'MemoryUsage'=>$memory_usage,
2533
+ 'MySQLVersion'=>$mysql_version,
2534
+ 'SQLMode'=>$sql_mode,
2535
+ 'PHPVersion'=>PHP_VERSION,
2536
+ ));
2537
+
2538
+ foreach(array(
2539
+ 'safe_mode',
2540
+ 'allow_url_fopen',
2541
+ 'memory_limit',
2542
+ 'upload_max_filesize',
2543
+ 'post_max_size',
2544
+ 'max_execution_time',
2545
+ 'max_input_time',
2546
+ ) as $php_flag){
2547
+ $php_flag_name = ucwords(str_replace('_', chr(32), $php_flag) );
2548
+ $tpl_varname = str_replace(chr(32), '', $php_flag_name);
2549
+ $php_flag_value = ini_get($php_flag);
2550
+ $template_variables[$tpl_varname] = $php_flag_value ? $php_flag_value : 'N/A';
2551
+ }
2552
+ }
2553
+
2554
+ return $template_variables;
2555
+ }
2556
+
sucuriscan_core_integrity.php DELETED
@@ -1,152 +0,0 @@
1
- <?php
2
- /* Sucuri Security - SiteCheck Malware Scanner
3
- * Copyright (C) 2010-2012 Sucuri Security - http://sucuri.net
4
- * Released under the GPL - see LICENSE file for details.
5
- */
6
-
7
-
8
- if(!defined('SUCURISCAN'))
9
- {
10
- return(0);
11
- }
12
-
13
- /* Sucuri WordPress Integrity page. */
14
-
15
- function sucuriscan_core_integrity_function_wrapper($function_name, $stitle, $description){ ?>
16
- <div class="postbox">
17
- <div class="inside">
18
- <form method="post">
19
- <input type="hidden" name="<?php echo $function_name; ?>nonce" value="<?php echo wp_create_nonce($function_name.'nonce'); ?>" />
20
- <input type="hidden" name="<?php echo $function_name; ?>" value="1" />
21
- <h4><?php echo $stitle; ?></h4>
22
- <p><?php echo $description; ?></p>
23
- <input class="button-primary" type="submit" name="<?php echo $function_name; ?>" value="Check" />
24
- </form>
25
- <br />
26
- <?php
27
- if (isset($_POST[$function_name.'nonce']) && isset($_POST[$function_name])) {
28
- if( function_exists($function_name) ){
29
- $function_name();
30
- }
31
- }
32
- ?>
33
- </div>
34
- </div>
35
- <?php }
36
-
37
- function sucuriscan_core_integrity_wp_content_wrapper(){ ?>
38
- <div class="postbox">
39
- <h3>Latest modified files</h3>
40
- <div class="inside">
41
- <form method="post">
42
- <input type="hidden" name="sucuriwp_content_checknonce" value="<?php echo wp_create_nonce('sucuriwp_content_checknonce'); ?>" />
43
- <input type="hidden" name="sucuriwp_content_check" value="sucuriwp_content_check" />
44
- <p>
45
- This test will list all files inside wp-content that have been modified in the past
46
- <select name="sucuriwp_content_check_back">
47
- <?php foreach(array( 1,3,7,30 ) as $days): ?>
48
- <?php $selected =
49
- ( isset($_POST['sucuriwp_content_check_back']) && $_POST['sucuriwp_content_check_back']==$days )
50
- ? 'selected="selected"' : ''; ?>
51
- <option value="<?php echo $days; ?>" <?php echo $selected; ?>><?php echo $days; ?></option>
52
- <?php endforeach; ?>
53
- </select> days. (select the number of days first)
54
- </p>
55
- <input class="button-primary" type="submit" name="sucuriwp_content_check" value="Check">
56
- </form>
57
-
58
- <?php if (
59
- isset($_POST['sucuriwp_content_checknonce'])
60
- // && wp_verify_nonce($_POST['sucuriwp_content_checknonce'], 'sucuriwp_content_checknonce')
61
- && isset($_POST['sucuriwp_content_check'])
62
- ): ?>
63
- <br />
64
- <table class="wp-list-table widefat sucuriscan-lastmodified">
65
- <thead>
66
- <tr>
67
- <th colspan="2">wp_content latest modified files</th>
68
- </tr>
69
- <tr>
70
- <th class="manage-column">Filepath</th>
71
- <th class="manage-column">Modification date/time</th>
72
- </tr>
73
- </thead>
74
- <tbody>
75
- <?php
76
- $wp_content_hashes = read_dir_r(ABSPATH.'wp-content', true);
77
- $days = htmlspecialchars(trim((int)$_POST['sucuriwp_content_check_back']));
78
- $back_days = current_time( 'timestamp' ) - ( $days * 86400);
79
-
80
- foreach ( $wp_content_hashes as $key => $value) {
81
- if ($value['time'] >= $back_days ){
82
- $date = date('d-m-Y H:i:s', $value['time']);
83
- printf('<tr><td>%s</td><td>%s</td></tr>', $key, $date);
84
- }
85
- }
86
- ?>
87
- </tbody>
88
- </table>
89
- <?php endif; ?>
90
- </div>
91
- </div>
92
- <?php }
93
-
94
- function sucuriscan_core_integrity_lib()
95
- {
96
- echo '<h2 id="warnings_hook"></h2>';
97
- echo '<div class="postbox-container" style="width:75%;">';
98
- echo '<div class="sucuriscan-maincontent">';
99
-
100
- echo '<div class="postbox">';
101
- echo '<div class="inside">';
102
- echo '<h2 align="center">Sucuri WordPress Integrity Checks</h2>';
103
- echo '</div>';
104
- echo '</div>';
105
-
106
- include_once("lib/core_integrity.php");
107
-
108
- if(isset($_POST['wpsucuri-core-integrity']))
109
- {
110
- if(!wp_verify_nonce($_POST['sucuriscan_core_integritynonce'], 'sucuriscan_core_integritynonce'))
111
- {
112
- unset($_POST['wpsucuri-core_integrity']);
113
- }
114
- }
115
-
116
- ?>
117
-
118
- <div id="poststuff">
119
-
120
- <?php
121
-
122
- sucuriscan_core_integrity_function_wrapper(
123
- 'sucuriwp_core_integrity_check',
124
- 'Verify Integrity of WordPress Core Files',
125
- 'This test will check wp-includes, wp-admin, and the top directory files against the latest WordPress hashing database. If any of those files were modified, it is a big sign of a possible compromise.'
126
- );
127
-
128
- sucuriscan_core_integrity_wp_content_wrapper();
129
-
130
- sucuriscan_core_integrity_function_wrapper(
131
- 'sucuriwp_list_admins',
132
- 'Admin User Dump',
133
- 'List all administrator users and their latest login time.'
134
- );
135
- sucuriscan_core_integrity_function_wrapper(
136
- 'sucuriwp_check_plugins',
137
- 'Outdated Plugin list',
138
- 'This test will list any outdated (active) plugins.'
139
- );
140
- sucuriscan_core_integrity_function_wrapper(
141
- 'sucuriwp_check_themes',
142
- 'Outdated Theme List',
143
- 'This test will list any outdated theme.'
144
- );
145
- ?>
146
-
147
- </div>
148
-
149
- <p align="center"><strong>If you have any questions about these tests or this plugin, contact us at info@sucuri.net or visit <a href="http://sucuri.net">Sucuri Security</a></strong></p>
150
-
151
- <?php
152
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
sucuriscan_hardening.php DELETED
@@ -1,57 +0,0 @@
1
- <?php
2
- /* Sucuri Security - SiteCheck Malware Scanner
3
- * Copyright (C) 2010-2012 Sucuri Security - http://sucuri.net
4
- * Released under the GPL - see LICENSE file for details.
5
- */
6
-
7
-
8
- if(!defined('SUCURISCAN'))
9
- {
10
- return(0);
11
- }
12
-
13
- /* Sucuri one-click hardening page. */
14
-
15
- function sucuriscan_hardening_lib(){ ?>
16
- <h2 id="warnings_hook"></h2>
17
- <div class="postbox-container" style="width:75%">
18
- <div class="sucuriscan-maincontent">
19
- <div class="postbox">
20
- <div class="inside">
21
- <h2 align="center">Help secure your WordPress install with <a href="http://sucuri.net/signup">Sucuri</a> 1-Click Hardening Options.</h2>
22
- </div>
23
- </div>
24
-
25
- <?php
26
- include_once('lib/hardening.php');
27
- if( isset($_POST['wpsucuri-doharden']) ){
28
- if(!wp_verify_nonce($_POST['sucuriscan_wphardeningnonce'], 'sucuriscan_wphardeningnonce'))
29
- {
30
- unset($_POST['wpsucuri-doharden']);
31
- }
32
- }
33
- ?>
34
-
35
- <div id="poststuff">
36
- <form method="post">
37
- <input type="hidden" name="sucuriscan_wphardeningnonce" value="<?php echo wp_create_nonce('sucuriscan_wphardeningnonce'); ?>" />
38
- <input type="hidden" name="wpsucuri-doharden" value="wpsucuri-doharden" />
39
- <?php
40
- sucuriscan_harden_version();
41
- sucuriscan_cloudproxy_enabled();
42
- sucuri_harden_removegenerator();
43
- sucuriscan_harden_upload();
44
- sucuriscan_harden_wpcontent();
45
- sucuriscan_harden_wpincludes();
46
- sucuriscan_harden_phpversion();
47
- ?>
48
- </form>
49
-
50
- <p align="center">
51
- <strong>If you have any questions about these checks or this plugin, contact us at
52
- <a href="mailto:info@sucuri.net">info@sucuri.net</a> or visit <a href="http://sucuri.net">
53
- Sucuri Security</a></strong>
54
- </p>
55
- </div><!-- End poststuff -->
56
- <?php
57
- }