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

Version Description

  • Added post-hack options (reset all passwords).
  • Added last-login.
  • Added more hardening and the option to revert any hardening done.
Download this release

Release Info

Developer yorman
Plugin Icon 128x128 Sucuri Security – Auditing, Malware Scanner and Security Hardening
Version 1.4
Comparing to
See all releases

Code changes from version 1.3 to 1.4

inc/css/sucuriscan-default-css.css CHANGED
@@ -2,14 +2,14 @@
2
* Copyright (C) 2010-2012 Sucuri Security - http://sucuri.net
3
* Released under the GPL - see LICENSE file for details.
4
*/
5
-
6
.sucuriscan_header {
7
background: #333;
8
border-bottom-left-radius:5px;
9
border-bottom-right-radius:5px;
10
border-top-left-radius:5px;
11
border-top-right-radius:5px;
12
- height: 38px;
13
margin: 16px 0 8px;
14
min-width: 255px;
15
padding: 10px;
@@ -27,7 +27,7 @@
27
float: left;
28
margin-left: 10px;
29
padding: 3px 0 0;
30
- text-shadow:#000 0 1px 0;
31
}
32
33
.sucuriscan-maincontent {
@@ -56,4 +56,8 @@
56
#sucuri-latest-posts.sucuriscan-sidebar {
57
background-color:#ececec;
58
border-color:#999;
59
- }
2
* Copyright (C) 2010-2012 Sucuri Security - http://sucuri.net
3
* Released under the GPL - see LICENSE file for details.
4
*/
5
+
6
.sucuriscan_header {
7
background: #333;
8
border-bottom-left-radius:5px;
9
border-bottom-right-radius:5px;
10
border-top-left-radius:5px;
11
border-top-right-radius:5px;
12
+ height: 38px;
13
margin: 16px 0 8px;
14
min-width: 255px;
15
padding: 10px;
27
float: left;
28
margin-left: 10px;
29
padding: 3px 0 0;
30
+ text-shadow:#000 0 1px 0;
31
}
32
33
.sucuriscan-maincontent {
56
#sucuri-latest-posts.sucuriscan-sidebar {
57
background-color:#ececec;
58
border-color:#999;
59
+ }
60
+
61
+ .sucuriscan-maincontent a.lastlogins-showall{
62
+ margin: 10px auto 0 auto;
63
+ }
inc/tpl/sucuri-wp-lastlogins.html.tpl ADDED
@@ -0,0 +1,48 @@
1
+ <div class="wrap">
2
+ <h2 id="warnings_hook"></h2>
3
+ <div class="sucuriscan_header"><img src="%%SUCURI.SucuriURL%%/inc/images/logo.png">
4
+ <h2>Sucuri Security WordPress Plugin</h2>
5
+ </div>
6
+
7
+ <div class="postbox-container" style="width:75%;">
8
+ <div class="sucuriscan-maincontent">
9
+ <div class="postbox">
10
+ <div class="inside">
11
+ <h2 align="center">Sucuri Plugin Last-Logins</h2>
12
+ </div>
13
+ </div>
14
+
15
+ <div id="poststuff">
16
+ <div class="postbox">
17
+ <h3>Post-Hack - User logins (latest 10, newest to oldest)</h3>
18
+ <div class="inside">
19
+ <table class="wp-list-table widefat">
20
+ <thead>
21
+ <tr>
22
+ <th class="manage-column column-cb check-column">
23
+ <label class="screen-reader-text" for="cb-select-all-1">Select All</label>
24
+ <input id="cb-select-all-1" type="checkbox">
25
+ </th>
26
+ <th class="manage-column">Username</th>
27
+ <th class="manage-column">Email</th>
28
+ <th class="manage-column">IP Address</th>
29
+ <th class="manage-column">Date/Time</th>
30
+ </tr>
31
+ </thead>
32
+
33
+ <tbody>
34
+ %%SUCURI.UserList%%
35
+ </tbody>
36
+ </table>
37
+
38
+ <a href="%%SUCURI.CurrentURL%%&limit=0" class="button button-primary lastlogins-showall" style="%%SUCURI.UserList.ShowAll%%">Show all results</a>
39
+ </div>
40
+ </div>
41
+ </div><!-- End poststuff -->
42
+
43
+ </div><!-- End sucuriscan-maincontent -->
44
+ </div><!-- End postbox-container -->
45
+
46
+ %%SUCURI.SucuriWPSidebar%%
47
+
48
+ </div><!-- End wrap -->
inc/tpl/sucuri-wp-lastlogins.snippet.tpl ADDED
@@ -0,0 +1,9 @@
1
+ <tr>
2
+ <th class="check-column">
3
+ <input type="checkbox" name="user_ids[]" value="%%SUCURI.UserList.UserId%%" />
4
+ </th>
5
+ <td>%%SUCURI.UserList.Username%%</td>
6
+ <td><a href="mailto:%%SUCURI.UserList.Email%%">%%SUCURI.UserList.Email%%</a></td>
7
+ <td>%%SUCURI.UserList.RemoteAddr%%</td>
8
+ <td>%%SUCURI.UserList.Datetime%%</td>
9
+ </tr>
inc/tpl/sucuri-wp-posthack.html.tpl ADDED
@@ -0,0 +1,93 @@
1
+ <div class="wrap">
2
+ <h2 id="warnings_hook"></h2>
3
+ <div class="sucuriscan_header"><img src="%%SUCURI.SucuriURL%%/inc/images/logo.png">
4
+ <h2>Sucuri Security WordPress Plugin</h2>
5
+ </div>
6
+
7
+ <div class="postbox-container" style="width:75%;">
8
+ <div class="sucuriscan-maincontent">
9
+ <div class="postbox">
10
+ <div class="inside">
11
+ <h2 align="center">Sucuri Plugin Post-Hack</h2>
12
+ </div>
13
+ </div>
14
+
15
+ <div id="poststuff">
16
+ <div class="postbox">
17
+ <h3>Post-Hack - Update WP-Config Keys</h3>
18
+ <div class="inside">
19
+ <form method="post">
20
+ <input type="hidden" name="sucuri_posthack_nonce" value="%%SUCURI.PosthackNonce%%" />
21
+ <input type="hidden" name="sucuri_posthack_action" value="update_wpconfig" />
22
+
23
+ <p>
24
+ Use this button to update the security keys stored in the <code>wp-config.php</code>
25
+ file, we will use the official Wordpress Secret-Key API Generator. After the
26
+ update your current session will be closed and you'll need to login again.
27
+ </p>
28
+
29
+ <p>
30
+ <input type="hidden" name="sucuri_update_wpconfig" value="0" />
31
+ <input type="checkbox" name="sucuri_update_wpconfig" value="1" />
32
+ <label for="sucuri_update_wpconfig">I understand that this operation can not be reverted.</label>
33
+ </p>
34
+
35
+ <input type="submit" value="Update WP-Config Keys" class="button button-primary" />
36
+ </form>
37
+
38
+ <div style="%%SUCURI.WPConfigUpdate.Display%%" class="sucuri_update_wpconfig_process">
39
+ <textarea>%%SUCURI.WPConfigUpdate.NewConfig%%</textarea>
40
+ </div>
41
+ </div>
42
+ </div>
43
+
44
+ <div class="postbox">
45
+ <h3>Post-Hack - Reset user password</h3>
46
+ <div class="inside">
47
+ <form method="post">
48
+ <input type="hidden" name="sucuri_posthack_nonce" value="%%SUCURI.PosthackNonce%%" />
49
+ <input type="hidden" name="sucuri_posthack_action" value="reset_password" />
50
+
51
+ <p>
52
+ Use this button to reset the current password for some specific users or for all
53
+ of them. We will send an email to each of those users adivising the password change
54
+ that includes the new password automatically generated by Wordpress. After the
55
+ password reset your current session will be closed and you'll need to login again.
56
+ </p>
57
+
58
+ <table class="wp-list-table widefat">
59
+ <thead>
60
+ <tr>
61
+ <th class="manage-column column-cb check-column">
62
+ <label class="screen-reader-text" for="cb-select-all-1">Select All</label>
63
+ <input id="cb-select-all-1" type="checkbox">
64
+ </th>
65
+ <th class="manage-column column-name">Username</th>
66
+ <th class="manage-column column-description">Display name</th>
67
+ <th class="manage-column column-description">Email address</th>
68
+ </tr>
69
+ </thead>
70
+
71
+ <tbody>
72
+ %%SUCURI.ResetPassword.UserList%%
73
+ </tbody>
74
+ </table>
75
+
76
+ <p>
77
+ <input type="hidden" name="sucuri_reset_password" value="0" />
78
+ <input type="checkbox" name="sucuri_reset_password" value="1" />
79
+ <label for="sucuri_reset_password">I understand that this operation can not be reverted.</label>
80
+ </p>
81
+
82
+ <input type="submit" value="Reset User Password" class="button button-primary" />
83
+ </form>
84
+ </div>
85
+ </div>
86
+ </div><!-- End poststuff -->
87
+
88
+ </div><!-- End sucuriscan-maincontent -->
89
+ </div><!-- End postbox-container -->
90
+
91
+ %%SUCURI.SucuriWPSidebar%%
92
+
93
+ </div><!-- End wrap -->
inc/tpl/sucuri-wp-resetpassword.snippet.tpl ADDED
@@ -0,0 +1,8 @@
1
+ <tr>
2
+ <th class="check-column">
3
+ <input type="checkbox" name="user_ids[]" value="%%SUCURI.ResetPassword.UserId%%" />
4
+ </th>
5
+ <td>%%SUCURI.ResetPassword.Username%%</td>
6
+ <td>%%SUCURI.ResetPassword.Displayname%%</td>
7
+ <td><a href="mailto:%%SUCURI.ResetPassword.Email%%">%%SUCURI.ResetPassword.Email%%</a></td>
8
+ </tr>
inc/tpl/sucuri-wp-sidebar.html.tpl ADDED
@@ -0,0 +1,22 @@
1
+ <div class="postbox-container" style="width:25%;min-width:200px;max-width:350px;">
2
+ <div id="sidebar">
3
+ <div id="sitecleanup" class="sucuriscan-sidebar">
4
+ <h2><span class="promo">Is your website infected with malware? Blacklisted by Google?</span></h2>
5
+ <p>Don't know where to start? Get cleared today by <a href="http://sucuri.net/signup">Sucuri Security</a>!
6
+ </p>
7
+ <p>
8
+ <a class="button-primary" href="http://sucuri.net/tour">Read more &#187;</a>
9
+ </p>
10
+ </div>
11
+
12
+ <div id="sucuri-latest-posts" class="sucuriscan-sidebar">
13
+ <h2><span class="promo">Stay updated with WordPress security news. </span></h2>
14
+ <p>Check out the <a href="http://blog.sucuri.net/">Sucuri Blog</a>!
15
+ </p>
16
+ <p>
17
+ <a class="button-primary" href="http://blog.sucuri.net/">Read more &#187;</a>
18
+ </p>
19
+ </div>
20
+
21
+ </div>
22
+ </div>
lib/core_integrity.php CHANGED
@@ -65,6 +65,9 @@ function sucuriwp_core_integrity_check()
65
{
66
67
global $wp_version;
68
$cp = 0;
69
$updates = get_core_updates();
70
if (!is_array($updates))
@@ -104,32 +107,49 @@ function sucuriwp_core_integrity_check()
104
105
$added = @array_diff_assoc( $wp_core_hashes, $wp_core_latest_hashes ); //files added
106
$removed = @array_diff_assoc( $wp_core_latest_hashes, $wp_core_hashes ); //files deleted
107
$compcurrent = @array_diff_key( $wp_core_hashes, $added ); //remove all added files from current filelist
108
$complog = @array_diff_key( $wp_core_latest_hashes, $removed ); //remove all deleted files from old file list
109
- $changed = array(); //array of changed files
110
111
//compare file hashes and mod dates
112
foreach ( $compcurrent as $currfile => $currattr) {
113
114
if ( array_key_exists( $currfile, $complog ) ) {
115
116
- //if attributes differ added to changed files array
117
if ( strcmp( $currattr['md5'], $complog[$currfile]['md5'] ) != 0 ) {
118
- $changed[$currfile]['md5'] = $currattr['md5'];
119
}
120
121
}
122
123
}
124
125
//get count of changes
126
$addcount = sizeof( $added );
127
$removecount = sizeof( $removed );
128
- $changecount = sizeof( $changed );
129
130
sucuriscan_core_integrity_wrapper($added, "Core File Added: $addcount");
131
sucuriscan_core_integrity_wrapper($removed, "Core File Removed: $removecount");
132
- sucuriscan_core_integrity_wrapper($changed, "Core File Modified: $changecount");
133
}
134
}
135
65
{
66
67
global $wp_version;
68
+
69
+ $curlang = get_bloginfo("language");
70
+
71
$cp = 0;
72
$updates = get_core_updates();
73
if (!is_array($updates))
107
108
$added = @array_diff_assoc( $wp_core_hashes, $wp_core_latest_hashes ); //files added
109
$removed = @array_diff_assoc( $wp_core_latest_hashes, $wp_core_hashes ); //files deleted
110
+ unset($removed['wp_version']); //ignore wp_version key
111
$compcurrent = @array_diff_key( $wp_core_hashes, $added ); //remove all added files from current filelist
112
$complog = @array_diff_key( $wp_core_latest_hashes, $removed ); //remove all deleted files from old file list
113
+ $modified = array(); //array of modified files
114
115
//compare file hashes and mod dates
116
foreach ( $compcurrent as $currfile => $currattr) {
117
118
if ( array_key_exists( $currfile, $complog ) ) {
119
120
+ //if attributes differ added to modified files array
121
if ( strcmp( $currattr['md5'], $complog[$currfile]['md5'] ) != 0 ) {
122
+ $modified[$currfile]['md5'] = $currattr['md5'];
123
}
124
125
}
126
127
}
128
129
+ //ignore some junk files
130
+ if($curlang != "en_US")
131
+ {
132
+ //ignore added files
133
+ unset($added['./licencia.txt']);
134
+
135
+ //ignore removed files
136
+ unset($removed['./license.txt']);
137
+
138
+ //ignore modified files
139
+ unset($modified['./wp-includes/version.php']);
140
+ unset($modified['./wp-admin/setup-config.php']);
141
+ unset($modified['./readme.html']);
142
+ unset($modified['./wp-config-sample.php']);
143
+ }
144
+
145
//get count of changes
146
$addcount = sizeof( $added );
147
$removecount = sizeof( $removed );
148
+ $changecount = sizeof( $modified );
149
150
sucuriscan_core_integrity_wrapper($added, "Core File Added: $addcount");
151
sucuriscan_core_integrity_wrapper($removed, "Core File Removed: $removecount");
152
+ sucuriscan_core_integrity_wrapper($modified, "Core File Modified: $changecount");
153
}
154
}
155
lib/hardening.php CHANGED
@@ -34,7 +34,7 @@ function sucuriscan_harden_ok($message)
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)
@@ -45,16 +45,22 @@ function sucuriscan_harden_status($status, $type, $messageok, $messagewarn,
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
else
55
{
56
echo '<h4>'.
57
- '<img style="position:relative;top:5px" height="22" width="22"'.
58
'src="'.SUCURI_URL.'images/warn.png" /> &nbsp; '.
59
$messagewarn. '.</h4>';
60
@@ -62,7 +68,7 @@ function sucuriscan_harden_status($status, $type, $messageok, $messagewarn,
62
63
if($type != NULL)
64
{
65
- echo '<input class="button-primary" type="submit" name="'.$type.'"
66
value="Harden it!" />';
67
}
68
}
@@ -97,7 +103,7 @@ function sucuriscan_harden_version()
97
sucuriscan_wrapper_open("Verify WordPress Version");
98
99
100
- sucuriscan_harden_status($cp, NULL,
101
"WordPress is updated", "WordPress is not updated",
102
NULL);
103
@@ -116,10 +122,10 @@ function sucuri_harden_removegenerator()
116
{
117
/* Enabled by default with this plugin. */
118
$cp = 1;
119
-
120
sucuriscan_wrapper_open("Remove WordPress Version");
121
122
- sucuriscan_harden_status($cp, "sucuri_harden_removegenerator",
123
"WordPress version properly hidden", NULL,
124
"It checks if your WordPress version is being hidden".
125
" from being displayed in the generator tag ".
@@ -152,45 +158,64 @@ function sucuriscan_harden_upload()
152
}
153
}
154
155
- if(isset($_POST['sucuriscan_harden_upload']) &&
156
- isset($_POST['wpsucuri-doharden']) &&
157
- $cp == 0)
158
- {
159
- if(file_put_contents("$htaccess_upload",
160
- "\n<Files *.php>\ndeny from all\n</Files>")===FALSE)
161
{
162
- $upmsg = sucuriscan_harden_error("ERROR: Unable to create .htaccess file.");
163
}
164
- else
165
- {
166
- $upmsg = sucuriscan_harden_ok("COMPLETE: Upload directory successfully hardened");
167
- $cp = 1;
168
}
169
}
170
171
sucuriscan_wrapper_open("Protect Uploads Directory");
172
- sucuriscan_harden_status($cp, "sucuriscan_harden_upload",
173
"Upload directory properly hardened",
174
"Upload directory not hardened",
175
"It checks if your upload directory allows PHP ".
176
"execution or if it is browsable.", $upmsg);
177
sucuriscan_wrapper_close();
178
- }
179
180
function sucuriscan_harden_wpcontent()
181
{
182
$cp = 1;
183
$upmsg = NULL;
184
- $htaccess_content = ABSPATH."/wp-content/.htaccess";
185
186
- if(!is_readable($htaccess_content))
187
{
188
$cp = 0;
189
}
190
else
191
{
192
$cp = 0;
193
- $fcontent = file($htaccess_content);
194
foreach($fcontent as $fline)
195
{
196
if(strpos($fline, "deny from all") !== FALSE)
@@ -201,45 +226,64 @@ function sucuriscan_harden_wpcontent()
201
}
202
}
203
204
- if(isset($_POST['sucuriscan_harden_wpcontent']) &&
205
- isset($_POST['wpsucuri-doharden']) &&
206
- $cp == 0)
207
- {
208
- if(file_put_contents("$htaccess_content",
209
- "\n<Files *.php>\ndeny from all\n</Files>")===FALSE)
210
{
211
- $upmsg = sucuriscan_harden_error("ERROR: Unable to create .htaccess file.");
212
}
213
- else
214
- {
215
- $upmsg = sucuriscan_harden_ok("COMPLETE: wp-content directory successfully hardened");
216
- $cp = 1;
217
}
218
}
219
220
sucuriscan_wrapper_open("Restrict wp-content Access");
221
- sucuriscan_harden_status($cp, "sucuriscan_harden_wpcontent",
222
"WP-content directory properly hardened",
223
"WP-content directory not hardened",
224
"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 ".
225
"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);
226
sucuriscan_wrapper_close();
227
- }
228
229
function sucuriscan_harden_wpincludes()
230
{
231
$cp = 1;
232
$upmsg = NULL;
233
- $htaccess_content = ABSPATH."/wp-includes/.htaccess";
234
235
- if(!is_readable($htaccess_content))
236
{
237
$cp = 0;
238
}
239
else
240
{
241
$cp = 0;
242
- $fcontent = file($htaccess_content);
243
foreach($fcontent as $fline)
244
{
245
if(strpos($fline, "deny from all") !== FALSE)
@@ -250,29 +294,50 @@ function sucuriscan_harden_wpincludes()
250
}
251
}
252
253
- if(isset($_POST['sucuriscan_harden_wpincludes']) &&
254
- isset($_POST['wpsucuri-doharden']) &&
255
- $cp == 0)
256
- {
257
- if(file_put_contents("$htaccess_content",
258
- "\n<Files *.php>\ndeny from all\n</Files>\n<Files wp-tinymce.php>\nallow from all\n</Files>\n")===FALSE)
259
{
260
- $upmsg = sucuriscan_harden_error("ERROR: Unable to create .htaccess file.");
261
}
262
- else
263
- {
264
- $upmsg = sucuriscan_harden_ok("COMPLETE: wp-includes directory successfully hardened.");
265
- $cp = 1;
266
}
267
}
268
269
sucuriscan_wrapper_open("Restrict wp-includes Access");
270
- sucuriscan_harden_status($cp, "sucuriscan_harden_wpincludes",
271
"wp-includes directory properly hardened",
272
"wp-includes directory not hardened",
273
"This option blocks direct PHP access to any file inside wp-includes. ", $upmsg);
274
sucuriscan_wrapper_close();
275
- }
276
277
function sucuriscan_harden_phpversion()
278
{
@@ -288,7 +353,7 @@ function sucuriscan_harden_phpversion()
288
}
289
290
sucuriscan_wrapper_open("Verify PHP Version");
291
- sucuriscan_harden_status($cp, NULL,
292
"Using an updated version of PHP (v $phpv)",
293
"The version of PHP you are using ($phpv) is not current, not recommended, and/or not supported",
294
"This checks if you have the latest version of PHP installed.", NULL);
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)
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
68
69
if($type != NULL)
70
{
71
+ echo '<input class="button-primary" type="submit" name="'.$type.'"
72
value="Harden it!" />';
73
}
74
}
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
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 ".
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 .htaccess file.");
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
+ sucuri_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
+ sucuri_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)
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 .htaccess file.");
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
+ sucuri_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
+ sucuri_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)
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 .htaccess file.");
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
+ sucuri_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
+ sucuri_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
{
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);
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.3
7
Tested up to: 3.6
8
9
- The Sucuri Security - SiteCheck Malware Scanner plugin enables you to scan your WordPress site using Sucuri SiteCheck right in your dashboard.
10
11
== Description ==
12
13
- Sucuri SiteCheck will check for malware, spam, blacklisting and other security issues like .htaccess redirects, hidden eval code, etc. The best thing about it is it's completely free.
14
15
- You can also scan your site 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
@@ -37,6 +37,7 @@ There are a number of blacklisting authorities that monitor for malware, SPAM, a
37
* Norton
38
* AVG
39
* Phish Tank (Phishing Specifically)
40
* McAfee SiteAdvisor
41
* Yandex
42
@@ -47,6 +48,14 @@ We augment the SiteCheck Malware Scanner with various. 1-click hardening options
47
* Restrict wp-content Access
48
* Restrict wp-includes Access
49
* Verify PHP Version
50
51
52
== Installation ==
@@ -58,6 +67,11 @@ We augment the SiteCheck Malware Scanner with various. 1-click hardening options
58
59
== Changelog ==
60
61
= 1.3 =
62
* Removed some PHP warnings and code clean up.
63
* Added WordPress integrity checks.
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.4
7
Tested up to: 3.6
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
37
* Norton
38
* AVG
39
* Phish Tank (Phishing Specifically)
40
+ * ESET
41
* McAfee SiteAdvisor
42
* Yandex
43
48
* Restrict wp-content Access
49
* Restrict wp-includes Access
50
* Verify PHP Version
51
+ * Disable the theme and plugin editors
52
+
53
+ On the newest versions of the plugin we also added an option to verify all WordPress core files for changes,
54
+ which can be useful to detect hidden backdoors.
55
+
56
+ Note that if your site is compromised and you need urgent help, you can leverage the
57
+ Sucuri plans here: http://sucuri.net (even if our free options are not finding
58
+ the compromise on your site).
59
60
61
== Installation ==
67
68
== Changelog ==
69
70
+ = 1.4 =
71
+ * Added post-hack options (reset all passwords).
72
+ * Added last-login.
73
+ * Added more hardening and the option to revert any hardening done.
74
+
75
= 1.3 =
76
* Removed some PHP warnings and code clean up.
77
* Added WordPress integrity checks.
sucuri.php CHANGED
@@ -7,7 +7,7 @@ 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 Security
10
- Version: 1.3
11
Author URI: http://sucuri.net
12
*/
13
@@ -18,8 +18,11 @@ if(!function_exists('add_action'))
18
}
19
20
define('SUCURISCAN','sucuriscan');
21
- define('SUCURISCAN_VERSION','1.3');
22
define( 'SUCURI_URL',plugin_dir_url( __FILE__ ));
23
24
/* Requires files. */
25
//require_once(dirname(__FILE__ ) . '/inc/scripts.php');
@@ -54,6 +57,12 @@ function sucuriscan_menu()
54
55
add_submenu_page('sucuriscan', 'WordPress Integrity', 'WordPress Integrity', 'manage_options',
56
'sucuriscan_core_integrity', 'sucuriscan_core_integrity_page');
57
}
58
59
/* Sucuri malware scan page. */
@@ -91,15 +100,15 @@ function sucuri_scan_page()
91
92
<form action="" method="post">
93
<input type="hidden" name="wpsucuri-doscan" value="wpsucuri-doscan" />
94
- <input class="button-primary" type="submit" name="wpsucuri_doscanrun" value="Scan this site now!" />
95
</form>
96
97
- <p><strong>If you have any questions about these checks or this plugin, contact us at support@sucuri.net or visit <a href="http://sucuri.net">sucuri.net</a></strong></p>
98
99
</div><!-- End sucuriscan-maincontent -->
100
</div><!-- End postbox-container -->
101
102
- <?php include_once("lib/sidebar.php"); ?>
103
104
</div><!-- End Wrap -->
105
@@ -159,8 +168,10 @@ function sucuriscan_print_scan()
159
}
160
echo "<br />";
161
}
162
- echo '<i>More details here <a href="http://sitecheck.sucuri.net/scanner/?&scan='.home_url().'">http://sitecheck.sucuri.net/scanner/?&scan='.home_url().'</a></i>';
163
164
echo "<hr />\n";
165
if(isset($res['BLACKLIST']['WARN']))
166
{
@@ -229,7 +240,7 @@ function sucuriscan_print_scan()
229
</div><!-- End sucuriscan-maincontent -->
230
</div><!-- End postbox-container -->
231
232
- <?php include_once("lib/sidebar.php"); ?>
233
234
</div><!-- End Wrap -->
235
@@ -278,7 +289,7 @@ function sucuriscan_hardening_page()
278
</div><!-- End sucuriscan-maincontent -->
279
</div><!-- End postbox-container -->
280
281
- <?php include_once("lib/sidebar.php"); ?>
282
283
</div><!-- End Wrap -->
284
@@ -313,7 +324,7 @@ function sucuriscan_core_integrity_page()
313
</div><!-- End sucuriscan-maincontent -->
314
</div><!-- End postbox-container -->
315
316
- <?php include_once("lib/sidebar.php"); ?>
317
318
</div><!-- End Wrap -->
319
@@ -325,4 +336,363 @@ function sucuriscan_core_integrity_page()
325
add_action('admin_menu', 'sucuriscan_menu');
326
remove_action('wp_head', 'wp_generator');
327
328
?>
7
You can also scan your site at <a href="http://sitecheck.sucuri.net">SiteCheck.Sucuri.net</a>.
8
9
Author: Sucuri Security
10
+ Version: 1.4
11
Author URI: http://sucuri.net
12
*/
13
18
}
19
20
define('SUCURISCAN','sucuriscan');
21
+ define('SUCURISCAN_VERSION','1.4');
22
define( 'SUCURI_URL',plugin_dir_url( __FILE__ ));
23
+ define('SUCURISCAN_PLUGIN_FOLDER', 'sucuri-scanner');
24
+ /* Sucuri Free/Paid Plugin will use the same tablename, check: sucuriscan_lastlogins_table_exists() */
25
+ define('SUCURISCAN_LASTLOGINS_TABLENAME', "{$table_prefix}sucuri_lastlogins");
26
27
/* Requires files. */
28
//require_once(dirname(__FILE__ ) . '/inc/scripts.php');
57
58
add_submenu_page('sucuriscan', 'WordPress Integrity', 'WordPress Integrity', 'manage_options',
59
'sucuriscan_core_integrity', 'sucuriscan_core_integrity_page');
60
+
61
+ add_submenu_page('sucuriscan', 'Post-Hack', 'Post-Hack', 'manage_options',
62
+ 'sucuriscan_posthack', 'sucuriscan_posthack_page');
63
+
64
+ add_submenu_page('sucuriscan', 'Last Logins', 'Last Logins', 'manage_options',
65
+ 'sucuriscan_lastlogins', 'sucuriscan_lastlogins_page');
66
}
67
68
/* Sucuri malware scan page. */
100
101
<form action="" method="post">
102
<input type="hidden" name="wpsucuri-doscan" value="wpsucuri-doscan" />
103
+ <input class="button button-primary button-hero load-customize" type="submit" name="wpsucuri_doscanrun" value="Scan this site now!" />
104
</form>
105
106
+ <p><strong>If you have any questions about these checks or this plugin, contact us at <a href="mailto:info@sucuri.net">info@sucuri.net</a> or visit <a href="http://sucuri.net">sucuri.net</a></strong></p>
107
108
</div><!-- End sucuriscan-maincontent -->
109
</div><!-- End postbox-container -->
110
111
+ <?php echo sucuriscan_get_template('sucuri-wp-sidebar.html.tpl') ?>
112
113
</div><!-- End Wrap -->
114
168
}
169
echo "<br />";
170
}
171
+ echo '<i>More details here: <a href="http://sitecheck.sucuri.net/scanner/?&scan='.home_url().'">http://sitecheck.sucuri.net/scanner/?&scan='.home_url().'</a></i>';
172
173
+ echo "<hr />\n";
174
+ 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>';
175
echo "<hr />\n";
176
if(isset($res['BLACKLIST']['WARN']))
177
{
240
</div><!-- End sucuriscan-maincontent -->
241
</div><!-- End postbox-container -->
242
243
+ <?php echo sucuriscan_get_template('sucuri-wp-sidebar.html.tpl') ?>
244
245
</div><!-- End Wrap -->
246
289
</div><!-- End sucuriscan-maincontent -->
290
</div><!-- End postbox-container -->
291
292
+ <?php echo sucuriscan_get_template('sucuri-wp-sidebar.html.tpl') ?>
293
294
</div><!-- End Wrap -->
295
324
</div><!-- End sucuriscan-maincontent -->
325
</div><!-- End postbox-container -->
326
327
+ <?php echo sucuriscan_get_template('sucuri-wp-sidebar.html.tpl') ?>
328
329
</div><!-- End Wrap -->
330
336
add_action('admin_menu', 'sucuriscan_menu');
337
remove_action('wp_head', 'wp_generator');
338
339
+ function sucuriscan_send_mail($to='', $subject='', $message='', $data_set=array(), $debug=FALSE)
340
+ {
341
+ $headers = array();
342
+ $subject = ucwords(strtolower($subject));
343
+ $wp_domain = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : get_option('siteurl');
344
+ if( get_option('sucuri_wp_prettify_mails')!='disabled' ){
345
+ $headers = array( 'Content-type: text/html' );
346
+ $data_set['PrettifyType'] = 'html';
347
+ }
348
+ $message = sucuriscan_prettify_mail($subject, $message, $data_set);
349
+
350
+ if($debug){
351
+ die($message);
352
+ }else{
353
+ wp_mail($to, "Sucuri WP Notification: {$wp_domain}: {$subject}" , $message, $headers);
354
+ }
355
+ }
356
+
357
+ function sucuriscan_admin_notice($type='updated', $message='')
358
+ {
359
+ if( !empty($message) ): ?>
360
+ <div class="<?php echo $type; ?>"><p><?php _e($message); ?></p></div>
361
+ <?php endif;
362
+ }
363
+
364
+ function sucuriscan_prettify_mail($subject='', $message='', $data_set=array())
365
+ {
366
+ $current_user = wp_get_current_user();
367
+
368
+ $prettify_type = isset($data_set['PrettifyType']) ? $data_set['PrettifyType'] : 'txt';
369
+ $real_ip = isset($_SERVER['SUCURI_RIP']) ? $_SERVER['SUCURI_RIP'] : $_SERVER['REMOTE_ADDR'];
370
+
371
+ $mail_variables = array(
372
+ 'TemplateTitle'=>'Sucuri WP Notification',
373
+ 'Subject'=>$subject,
374
+ 'Website'=>get_option('siteurl'),
375
+ 'RemoteAddress'=>$real_ip,
376
+ 'Message'=>$message,
377
+ 'User'=>$current_user->display_name,
378
+ 'Time'=>current_time('mysql')
379
+ );
380
+ foreach($data_set as $var_key=>$var_value){
381
+ $mail_variables[$var_key] = $var_value;
382
+ }
383
+
384
+ return sucuriscan_get_template("sucuri-wp-notification.{$prettify_type}.tpl", $mail_variables);
385
+ }
386
+
387
+ function sucuriscan_get_template($template='', $template_variables=array()){
388
+ $template_content = '';
389
+ $template_path = WP_PLUGIN_DIR.'/'.SUCURISCAN_PLUGIN_FOLDER."/inc/tpl/{$template}";
390
+
391
+ if( file_exists($template_path) && is_readable($template_path) ){
392
+ $template_content = file_get_contents($template_path);
393
+ foreach($template_variables as $tpl_key=>$tpl_value){
394
+ $template_content = str_replace("%%SUCURI.{$tpl_key}%%", $tpl_value, $template_content);
395
+ }
396
+ }
397
+ return $template_content;
398
+ }
399
+
400
+ function sucuriscan_wp_sidebar_gen()
401
+ {
402
+ return sucuriscan_get_template('sucuri-wp-sidebar.html.tpl');
403
+ }
404
+
405
+ function sucuriscan_get_new_config_keys()
406
+ {
407
+ $request = wp_remote_get('https://api.wordpress.org/secret-key/1.1/salt/');
408
+ if( !is_wp_error($request) || wp_remote_retrieve_response_code($request) === 200 ){
409
+ if( preg_match_all("/define\('([A-Z_]+)',[ ]+'(.*)'\);/", $request['body'], $match) ){
410
+ $new_keys = array();
411
+ foreach($match[1] as $i=>$value){
412
+ $new_keys[$value] = $match[2][$i];
413
+ }
414
+ return $new_keys;
415
+ }
416
+ }
417
+ return FALSE;
418
+ }
419
+
420
+ function sucuriscan_set_new_config_keys()
421
+ {
422
+ $new_wpconfig = '';
423
+ $wp_config_path = ABSPATH.'wp-config.php';
424
+ $wp_config_lines = file($wp_config_path);
425
+ $new_keys = sucuriscan_get_new_config_keys();
426
+ $old_keys = array();
427
+ $old_keys_string = $new_keys_string = '';
428
+
429
+ foreach($wp_config_lines as $wp_config_line){
430
+ $wp_config_line = str_replace("\n", '', $wp_config_line);
431
+
432
+ if( preg_match("/define\('([A-Z_]+)',([ ]+)'(.*)'\);/", $wp_config_line, $match) ){
433
+ $key_name = $match[1];
434
+ if( array_key_exists($key_name, $new_keys) ){
435
+ $white_spaces = $match[2];
436
+ $old_keys[$key_name] = $match[3];
437
+ $wp_config_line = "define('{$key_name}',{$white_spaces}'{$new_keys[$key_name]}');";
438
+
439
+ $old_keys_string .= "define('{$key_name}',{$white_spaces}'{$old_keys[$key_name]}');\n";
440
+ $new_keys_string .= "{$wp_config_line}\n";
441
+ }
442
+ }
443
+
444
+ $new_wpconfig .= "{$wp_config_line}\n";
445
+ }
446
+
447
+ $response = array(
448
+ 'updated'=>is_writable($wp_config_path),
449
+ 'old_keys'=>$old_keys,
450
+ 'old_keys_string'=>$old_keys_string,
451
+ 'new_keys'=>$new_keys,
452
+ 'new_keys_string'=>$new_keys_string,
453
+ 'new_wpconfig'=>$new_wpconfig
454
+ );
455
+ if( $response['updated'] ){
456
+ file_put_contents($wp_config_path, $new_wpconfig, LOCK_EX);
457
+ }
458
+ return $response;
459
+ }
460
+
461
+ function sucuriscan_new_password($user_id=0)
462
+ {
463
+ $user_id = intval($user_id);
464
+ $current_user = wp_get_current_user();
465
+
466
+ if( $user_id>0 && $user_id!=$current_user->ID ){
467
+ $user = get_userdata($user_id);
468
+ $new_password = wp_generate_password(15, TRUE, FALSE);
469
+
470
+ $data_set = array( 'User'=>$user->display_name );
471
+ $message = "The password for your user account in the website mentioned has been changed by an administrator,
472
+ this is the new password automatically generated by the system, please update ASAP.<br>
473
+ <div style='display:inline-block;background:#ddd;font-family:monaco,monospace,courier;
474
+ font-size:30px;margin:0;padding:15px;border:1px solid #999'>{$new_password}</div>";
475
+ sucuriscan_send_mail($user->user_email, 'Changed password', $message, $data_set);
476
+
477
+ wp_set_password($new_password, $user_id);
478
+
479
+ return TRUE;
480
+ }
481
+ return FALSE;
482
+ }
483
+
484
+ function sucuriscan_posthack_page()
485
+ {
486
+ if( !current_user_can('manage_options') )
487
+ {
488
+ wp_die(__('You do not have sufficient permissions to access this page.') );
489
+ }
490
+
491
+ // Page pseudo-variables initialization.
492
+ $template_variables = array(
493
+ 'SucuriURL'=>SUCURI_URL,
494
+ 'PosthackNonce'=>wp_create_nonce('sucuri_posthack_nonce'),
495
+ 'SucuriWPSidebar'=>sucuriscan_wp_sidebar_gen(),
496
+ 'WPConfigUpdate.Display'=>'display:none',
497
+ 'WPConfigUpdate.NewConfig'=>'',
498
+ 'ResetPassword.UserList'=>''
499
+ );
500
+
501
+ // Process form submission
502
+ if( isset($_POST['sucuri_posthack_action']) ){
503
+ if( !wp_verify_nonce($_POST['sucuri_posthack_nonce'], 'sucuri_posthack_nonce') )
504
+ {
505
+ wp_die(__('Wordpress Nonce verification failed, try again going back and checking the form.') );
506
+ }
507
+
508
+ switch($_POST['sucuri_posthack_action']){
509
+ case 'update_wpconfig':
510
+ $update_wpconfig = ( isset($_POST['sucuri_update_wpconfig']) && $_POST['sucuri_update_wpconfig']==1 ) ? TRUE : FALSE;
511
+
512
+ if( $update_wpconfig ){
513
+ $wpconfig_process = sucuriscan_set_new_config_keys();
514
+ $template_variables['WPConfigUpdate.Display'] = 'display:block';
515
+
516
+ if( $wpconfig_process['updated']===TRUE ){
517
+ sucuriscan_admin_notice('updated', '<strong>OK.</strong> WP-Config keys updated successfully. In the textarea bellow you will see the old-keys and the new-keys updated.');
518
+ $template_variables['WPConfigUpdate.NewConfig'] .= "// Old Keys\n";
519
+ $template_variables['WPConfigUpdate.NewConfig'] .= $wpconfig_process['old_keys_string'];
520
+ $template_variables['WPConfigUpdate.NewConfig'] .= "//\n";
521
+ $template_variables['WPConfigUpdate.NewConfig'] .= "// New Keys\n";
522
+ $template_variables['WPConfigUpdate.NewConfig'] .= $wpconfig_process['new_keys_string'];
523
+ }else{
524
+ sucuriscan_admin_notice('error', '<strong>Error.</strong> The wp-config.php file is not writable, please copy and paste the code shown bellow in the textarea into that file manually.');
525
+ $template_variables['WPConfigUpdate.NewConfig'] = $wpconfig_process['new_wpconfig'];
526
+ }
527
+ }else{
528
+ sucuriscan_admin_notice('error', '<strong>Error.</strong> You need to confirm that you understand the risk of this operation');
529
+ }
530
+ break;
531
+ case 'reset_password':
532
+ $reset_password = ( isset($_POST['sucuri_reset_password']) && $_POST['sucuri_reset_password']==1 ) ? TRUE : FALSE;
533
+
534
+ if( $reset_password ){
535
+ $user_identifiers = $_POST['user_ids'];
536
+ $pwd_changed = $pwd_not_changed = array();
537
+ arsort($user_identifiers);
538
+
539
+ foreach($user_identifiers as $user_id){
540
+ if( sucuriscan_new_password($user_id) ){
541
+ $passwords_changed[] = $user_id;
542
+ }else{
543
+ $pwd_not_changed[] = $user_id;
544
+ }
545
+ }
546
+ if( !empty($pwd_changed) ){
547
+ sucuriscan_admin_notice('updated', '<strong>OK.</strong> Password changed successfully for users: '.implode(', ',$pwd_changed));
548
+ }
549
+ if( !empty($pwd_not_changed) ){
550
+ sucuriscan_admin_notice('error', '<strong>Error.</strong> Password change failed for users: '.implode(', ',$pwd_not_changed));
551
+ }
552
+ }else{
553
+ sucuriscan_admin_notice('error', '<strong>Error.</strong> You need to confirm that you understand the risk of this operation');
554
+ }
555
+ break;
556
+ default:
557
+ wp_die(__('Sucuri WP Plugin, invalid form action, go back and try again.'));
558
+ break;
559
+ }
560
+ }
561
+
562
+ // Fill the user list for ResetPassword action.
563
+ $user_list = get_users();
564
+ foreach($user_list as $user){
565
+ $user_snippet = sucuriscan_get_template('sucuri-wp-resetpassword.snippet.tpl', array(
566
+ 'ResetPassword.UserId'=>$user->ID,
567
+ 'ResetPassword.Username'=>$user->user_login,
568
+ 'ResetPassword.Displayname'=>$user->display_name,
569
+ 'ResetPassword.Email'=>$user->user_email
570
+ ));
571
+ $template_variables['ResetPassword.UserList'] .= $user_snippet;
572
+ }
573
+
574
+ echo sucuriscan_get_template('sucuri-wp-posthack.html.tpl', $template_variables);
575
+ }
576
+
577
+ function sucuriscan_lastlogins_page()
578
+ {
579
+ if( !current_user_can('manage_options') )
580
+ {
581
+ wp_die(__('You do not have sufficient permissions to access this page.') );
582
+ }
583
+
584
+ // Page pseudo-variables initialization.
585
+ $template_variables = array(
586
+ 'SucuriURL'=>SUCURI_URL,
587
+ 'PosthackNonce'=>wp_create_nonce('sucuri_posthack_nonce'),
588
+ 'SucuriWPSidebar'=>sucuriscan_wp_sidebar_gen(),
589
+ 'UserList'=>'',
590
+ 'CurrentURL'=>site_url().'/wp-admin/admin.php?page='.$_GET['page']
591
+ );
592
+
593
+ $limit = isset($_GET['limit']) ? intval($_GET['limit']) : 10;
594
+ $template_variables['UserList.ShowAll'] = $limit>0 ? 'display:table' : 'display:none';
595
+
596
+ $user_list = sucuriscan_get_logins($limit);
597
+ foreach($user_list as $user){
598
+ $user_snippet = sucuriscan_get_template('sucuri-wp-lastlogins.snippet.tpl', array(
599
+ 'UserList.UserId'=>$user->ID,
600
+ 'UserList.Username'=>$user->user_login,
601
+ 'UserList.Email'=>$user->user_email,
602
+ 'UserList.RemoteAddr'=>$user->user_remoteaddr,
603
+ 'UserList.Datetime'=>$user->user_lastlogin
604
+ ));
605
+ $template_variables['UserList'] .= $user_snippet;
606
+ }
607
+
608
+ echo sucuriscan_get_template('sucuri-wp-lastlogins.html.tpl', $template_variables);
609
+ }
610
+
611
+ function sucuriscan_set_flashdata($key='', $value='')
612
+ {
613
+ /* Use wp-sucuri_ to give compatibility between Sucuri Free/Paid Plugin */
614
+ $session_name = "wp-sucuri_{$key}";
615
+ $expire = time() + 60*5;
616
+ setcookie($session_name, $value, $expire, SITECOOKIEPATH.'wp-admin');
617
+ }
618
+
619
+ function sucuriscan_get_flashdata()
620
+ {
621
+ /* Use wp-sucuri_ to give compatibility between Sucuri Free/Paid Plugin */
622
+ foreach($_COOKIE as $key=>$value){
623
+ if( preg_match('/^(wp\-sucuri_.*)#x2F;', $key) ){
624
+ sucuriscan_admin_notice('updated', $value);
625
+ setcookie($key, NULL, time()-3600);
626
+ }
627
+ }
628
+ }
629
+ add_action('admin_init', 'sucuriscan_get_flashdata');
630
+
631
+ function sucuriscan_lastlogins_table_exists()
632
+ {
633
+ global $wpdb;
634
+ if( defined('SUCURISCAN_LASTLOGINS_TABLENAME') ){
635
+ $table_name = SUCURISCAN_LASTLOGINS_TABLENAME;
636
+
637
+ if( $wpdb->get_var("SHOW TABLES LIKE '{$table_name}'")!=$table_name ){
638
+ $sql = 'CREATE TABLE '.$table_name.' (
639
+ id int(11) NOT NULL AUTO_INCREMENT,
640
+ user_id bigint(20) NOT NULL,
641
+ user_login varchar(60),
642
+ user_remoteaddr varchar(255),
643
+ user_lastlogin DATETIME DEFAULT "0000-00-00 00:00:00" NOT NULL,
644
+ UNIQUE KEY id(id)
645
+ )';
646
+
647
+ require_once(ABSPATH.'wp-admin/includes/upgrade.php');
648
+ dbDelta($sql);
649
+ }
650
+ }
651
+ }
652
+ add_action('plugins_loaded', 'sucuriscan_lastlogins_table_exists');
653
+
654
+ function sucuriscan_set_lastlogin($user_login='')
655
+ {
656
+ global $wpdb;
657
+ if( defined('SUCURISCAN_LASTLOGINS_TABLENAME') ){
658
+ $table_name = SUCURISCAN_LASTLOGINS_TABLENAME;
659
+ $current_user = get_user_by('login', $user_login);
660
+
661
+ sucuriscan_set_flashdata('lastlogin', 'Last user login at '.date('Y/M/d H:i:s').' from '.$_SERVER['REMOTE_ADDR']);
662
+
663
+ $wpdb->insert($table_name, array(
664
+ 'user_id'=>$current_user->ID,
665
+ 'user_login'=>$current_user->user_login,
666
+ 'user_remoteaddr'=>isset($_SERVER['REMOTE_ADDR'])?$_SERVER['REMOTE_ADDR']:'127.0.0.1',
667
+ 'user_lastlogin'=>current_time('mysql')
668
+ ));
669
+ }
670
+ }
671
+ add_action('wp_login', 'sucuriscan_set_lastlogin', 50);
672
+
673
+ function sucuriscan_get_logins($limit=10, $user_id=0)
674
+ {
675
+ global $wpdb;
676
+ if( defined('SUCURISCAN_LASTLOGINS_TABLENAME') ){
677
+ $table_name = SUCURISCAN_LASTLOGINS_TABLENAME;
678
+
679
+ $sql = "SELECT * FROM {$table_name} RIGHT JOIN {$wpdb->prefix}users ON {$table_name}.user_id = {$wpdb->prefix}users.ID";
680
+ if( !is_admin() ){
681
+ $current_user = wp_get_current_user();
682
+ $sql .= chr(32)."WHERE {$wpdb->prefix}users.user_login = '{$current_user->user_login}'";
683
+ }
684
+ if( $user_id>0 ){
685
+ $where_append = strpos('WHERE ', $sql)===FALSE ? 'WHERE' : 'AND';
686
+ $sql .= chr(32)."{$where_append} {$table_name}.user_id = '{$user_id}'";
687
+ }
688
+ $sql .= chr(32)."ORDER BY {$table_name}.id DESC";
689
+ if( preg_match('/^([0-9]+)#x2F;', $limit) && $limit>0 ){
690
+ $sql .= chr(32)."LIMIT {$limit}";
691
+ }
692
+ return $wpdb->get_results($sql);
693
+ }
694
+
695
+ return FALSE;
696
+ }
697
+
698
?>
sucuriscan_core_integrity.php CHANGED
@@ -61,29 +61,29 @@ function sucuriscan_core_integrity_lib()
61
62
sucuriscan_core_integrity_function_wrapper(
63
'sucuriwp_core_integrity_check',
64
- 'Check wp-include, wp-admin, and top directory files against the latest WordPress version.'
65
);
66
sucuriscan_core_integrity_function_wrapper(
67
'sucuriwp_list_admins',
68
- 'Check Administrator Users.'
69
);
70
sucuriscan_core_integrity_function_wrapper(
71
'sucuriwp_content_check',
72
- 'Check wp-content files modified in the past 3 days.'
73
);
74
sucuriscan_core_integrity_function_wrapper(
75
'sucuriwp_check_plugins',
76
- 'Check outdated active plugins in there.'
77
);
78
sucuriscan_core_integrity_function_wrapper(
79
'sucuriwp_check_themes',
80
- 'Check outdated themes in there.'
81
);
82
?>
83
84
</div>
85
86
- <p align="center"><strong>If you have any questions about these checks or this plugin, contact us at support@sucuri.net or visit <a href="http://sucuri.net">Sucuri Security</a></strong></p>
87
88
<?php
89
}
61
62
sucuriscan_core_integrity_function_wrapper(
63
'sucuriwp_core_integrity_check',
64
+ '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.'
65
);
66
sucuriscan_core_integrity_function_wrapper(
67
'sucuriwp_list_admins',
68
+ 'List all administrator users and their latest login time.'
69
);
70
sucuriscan_core_integrity_function_wrapper(
71
'sucuriwp_content_check',
72
+ 'This test will list all files inside wp-content that have been modified in the past 3 days.'
73
);
74
sucuriscan_core_integrity_function_wrapper(
75
'sucuriwp_check_plugins',
76
+ 'This test will list any outdated (active) plugins.'
77
);
78
sucuriscan_core_integrity_function_wrapper(
79
'sucuriwp_check_themes',
80
+ 'This test will list any outdated theme.'
81
);
82
?>
83
84
</div>
85
86
+ <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>
87
88
<?php
89
}