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("/^(.*)(\/)+#x2F;", "$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