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

Version Description

  • Fixing interface.
Download this release

Release Info

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

Code changes from version 1.6.6 to 1.6.8

inc/css/sucuriscan-default-css.css CHANGED
@@ -146,7 +146,7 @@ div.sucuriscan-alert > a.close{position:absolute;top:10px;right:10px;font-size:1
146
.sucuriscan-scanner-results .sucuriscan-scanner-links tr:nth-child(even){background:#f5f5f5}
147
.sucuriscan-scanner-results td.sucuriscan-border-bad{border-left-width:4px;border-left-style:solid}
148
/* Integrity Styles */
149
- .sucuriscan-status-type{width:20px;background:#ddd;text-align:center;text-transform:uppercase;margin-right:10px;padding:0 3px;border:1px solid transparent;border-radius:3px}
150
.sucuriscan-status-added{background:#dff0d8;color:#3c763d;border-color:#d6e9c6}
151
.sucuriscan-status-modified{background:#fcf8e3;color:#8a6d3b;border-color:#faebcc}
152
.sucuriscan-status-removed, td.sucuriscan-corefiles-warning > div{background:#f2dede;color:#a94442;border-color:#ebccd1}
@@ -154,13 +154,17 @@ div.sucuriscan-alert > a.close{position:absolute;top:10px;right:10px;font-size:1
154
.sucuriscan-maincontent .sucuriscan-integrity-message,
155
.sucuriscan-maincontent .sucuriscan-wordpress-outdated,
156
.sucuriscan-maincontent .sucuriscan-auditlogs{margin-top:0;margin-bottom:20px}
157
- .sucuriscan-maincontent .sucuriscan-corefiles td{padding:4px 10px}
158
- .sucuriscan-corefiles-abbrs .sucuriscan-status-type{display:inline-block;width:initial;font-size:12px;text-transform:capitalize;float:left;margin-top:4px;margin-right:5px}
159
.sucuriscan-maincontent td.sucuriscan-corefiles-warning, .sucuriscan-maincontent td.sucuriscan-corefiles-warning p{margin:0;padding:0}
160
.sucuriscan-maincontent td.sucuriscan-corefiles-warning div{padding:10px;border-width:1px;border-style:solid}
161
.sucuriscan-maincontent td.sucuriscan-corefiles-warning code{font-size:12px;padding:0 5px}
162
.sucuriscan-maincontent .sucuriscan-integrity-message{position:relative}
163
.sucuriscan-maincontent .sucuriscan-integrity-message .sucuriscan-integrity-mark{position:absolute;top:1px;right:1px;background:#7ad03a;font-weight:bold;color:#fff;line-height:35px;padding:0 10px;border-left:1px solid #ddd}
164
/* Monitoring Styles */
165
.sucuriscan-monitoring-settings{margin-bottom:20px}
166
.sucuriscan-monitoring-settings td.td-with-button{text-align:left}
@@ -212,11 +216,7 @@ div.sucuriscan-alert > a.close{position:absolute;top:10px;right:10px;font-size:1
212
.sucuriscan_wpconfig_keys_updated textarea{width:100%;height:250px;background:#f5f5f5;font-family:monospace;font-size:12px;resize:vertical;margin:20px 0 0 0}
213
.sucuriscan-maincontent .sucuriscan-last-logins{margin-top:0}
214
.sucuriscan-maincontent .sucuriscan-last-logins .sucuriscan-ellipsis{width:150px;line-height:inherit}
215
- .sucuriscan-maincontent .sucuriscan-modifiedfiles .sucuriscan-ellipsis{width:100px}
216
.sucuriscan-maincontent .sucuriscan-full-textarea{width:100%;height:400px;line-height:normal;resize:vertical;padding:10px}
217
- .sucuriscan-maincontent .sucuriscan-auditlogs{margin-bottom:0}
218
- .sucuriscan-maincontent .sucuriscan-auditlogs td small{font-style:italic}
219
- .sucuriscan-maincontent .sucuriscan-auditlogs .sucuriscan-maxper-page{text-align:right}
220
.sucuriscan-maincontent .sucuriscan-settings{margin-top:0}
221
.sucuriscan-maincontent .sucuriscan-settings form{display:inline-block}
222
.sucuriscan-maincontent .sucuriscan-settings select, .sucuriscan-maincontent .sucuriscan-settings .input-text{min-width:220px}
146
.sucuriscan-scanner-results .sucuriscan-scanner-links tr:nth-child(even){background:#f5f5f5}
147
.sucuriscan-scanner-results td.sucuriscan-border-bad{border-left-width:4px;border-left-style:solid}
148
/* Integrity Styles */
149
+ .sucuriscan-status-type{display:inline-block;width:20px;background:#ddd;text-align:center;text-transform:uppercase;margin-right:10px;padding:0 3px;border:1px solid transparent;border-radius:3px}
150
.sucuriscan-status-added{background:#dff0d8;color:#3c763d;border-color:#d6e9c6}
151
.sucuriscan-status-modified{background:#fcf8e3;color:#8a6d3b;border-color:#faebcc}
152
.sucuriscan-status-removed, td.sucuriscan-corefiles-warning > div{background:#f2dede;color:#a94442;border-color:#ebccd1}
154
.sucuriscan-maincontent .sucuriscan-integrity-message,
155
.sucuriscan-maincontent .sucuriscan-wordpress-outdated,
156
.sucuriscan-maincontent .sucuriscan-auditlogs{margin-top:0;margin-bottom:20px}
157
+ .sucuriscan-corefiles-abbrs .sucuriscan-status-type{width:initial;font-size:12px;text-transform:capitalize;float:left;margin-top:4px;margin-right:5px}
158
.sucuriscan-maincontent td.sucuriscan-corefiles-warning, .sucuriscan-maincontent td.sucuriscan-corefiles-warning p{margin:0;padding:0}
159
.sucuriscan-maincontent td.sucuriscan-corefiles-warning div{padding:10px;border-width:1px;border-style:solid}
160
.sucuriscan-maincontent td.sucuriscan-corefiles-warning code{font-size:12px;padding:0 5px}
161
.sucuriscan-maincontent .sucuriscan-integrity-message{position:relative}
162
.sucuriscan-maincontent .sucuriscan-integrity-message .sucuriscan-integrity-mark{position:absolute;top:1px;right:1px;background:#7ad03a;font-weight:bold;color:#fff;line-height:35px;padding:0 10px;border-left:1px solid #ddd}
163
+ .sucuriscan-maincontent .sucuriscan-auditlogs{margin-bottom:0}
164
+ .sucuriscan-maincontent .sucuriscan-auditlogs td small{font-style:italic}
165
+ .sucuriscan-maincontent .sucuriscan-auditlogs .sucuriscan-maxper-page{text-align:right}
166
+ .sucuriscan-maincontent .sucuriscan-ignoredfiles{margin-top:0}
167
+ .sucuriscan-maincontent .sucuriscan-modifiedfiles .sucuriscan-ellipsis{width:100px}
168
/* Monitoring Styles */
169
.sucuriscan-monitoring-settings{margin-bottom:20px}
170
.sucuriscan-monitoring-settings td.td-with-button{text-align:left}
216
.sucuriscan_wpconfig_keys_updated textarea{width:100%;height:250px;background:#f5f5f5;font-family:monospace;font-size:12px;resize:vertical;margin:20px 0 0 0}
217
.sucuriscan-maincontent .sucuriscan-last-logins{margin-top:0}
218
.sucuriscan-maincontent .sucuriscan-last-logins .sucuriscan-ellipsis{width:150px;line-height:inherit}
219
.sucuriscan-maincontent .sucuriscan-full-textarea{width:100%;height:400px;line-height:normal;resize:vertical;padding:10px}
220
.sucuriscan-maincontent .sucuriscan-settings{margin-top:0}
221
.sucuriscan-maincontent .sucuriscan-settings form{display:inline-block}
222
.sucuriscan-maincontent .sucuriscan-settings select, .sucuriscan-maincontent .sucuriscan-settings .input-text{min-width:220px}
inc/js/sucuriscan-scripts.js CHANGED
@@ -50,10 +50,10 @@ jQuery(document).ready(function($){
50
var action = this_button.data('action');
51
52
if( action == 'show' ){
53
- $('.sucuriscan-corefiles tbody > tr').removeClass('sucuriscan-hidden');
54
this_button.html('Hide files').data('action', 'hide');
55
} else {
56
- $('.sucuriscan-corefiles tbody > tr').addClass('sucuriscan-hidden');
57
this_button.html('Show files').data('action', 'show');
58
}
59
});
50
var action = this_button.data('action');
51
52
if( action == 'show' ){
53
+ $('.sucuriscan-corefiles thead tr:last-child, .sucuriscan-corefiles tbody > tr').removeClass('sucuriscan-hidden');
54
this_button.html('Hide files').data('action', 'hide');
55
} else {
56
+ $('.sucuriscan-corefiles thead tr:last-child, .sucuriscan-corefiles tbody > tr').addClass('sucuriscan-hidden');
57
this_button.html('Show files').data('action', 'show');
58
}
59
});
inc/tpl/integrity-corefiles.html.tpl CHANGED
@@ -1,42 +1,82 @@
1
2
<div class="postbox sucuriscan-border sucuriscan-border-good sucuriscan-integrity-message sucuriscan-%%SUCURI.CoreFiles.GoodVisibility%%">
3
<span class="sucuriscan-integrity-mark">OK</span>
4
- <h3>WordPress core integrity</h3>
5
6
<div class="inside">
7
<p>Your WordPress core files are clean and were not modified.</p>
8
</div>
9
</div>
10
11
- <table class="wp-list-table widefat sucuriscan-table sucuriscan-corefiles sucuriscan-%%SUCURI.CoreFiles.BadVisibility%%">
12
- <thead>
13
- <tr>
14
- <th class="sucuriscan-clearfix thead-with-button">
15
- <span>WordPress core integrity (%%SUCURI.CoreFiles.ListCount%% files)</span>
16
- <div class="sucuriscan-pull-right sucuriscan-corefiles-abbrs">
17
- <span class="sucuriscan-status-type sucuriscan-status-added">Added</span>
18
- <span class="sucuriscan-status-type sucuriscan-status-modified">Modified</span>
19
- <span class="sucuriscan-status-type sucuriscan-status-removed">Removed</span>
20
- <button id="sucuriscan-corefiles-show" class="button button-primary thead-topright-action" data-action="show">Show files</button>
21
- </div>
22
- </th>
23
- </tr>
24
-
25
- <tr>
26
- <td class="sucuriscan-corefiles-warning">
27
- <div>
28
<p>
29
- We detected changes in the integrity of your WordPress core files. There are files that
30
- were added, modified, and/or removed in the core directories <code>/&lt;root&gt;</code>,
31
- <code>/wp-admin</code> and/or <code>/wp-includes</code>.
32
</p>
33
- </div>
34
- </td>
35
- </tr>
36
- </thead>
37
38
- <tbody>
39
40
- %%SUCURI.CoreFiles.List%%
41
- </tbody>
42
- </table>
1
2
<div class="postbox sucuriscan-border sucuriscan-border-good sucuriscan-integrity-message sucuriscan-%%SUCURI.CoreFiles.GoodVisibility%%">
3
<span class="sucuriscan-integrity-mark">OK</span>
4
+ <h3>Core integrity</h3>
5
6
<div class="inside">
7
<p>Your WordPress core files are clean and were not modified.</p>
8
</div>
9
</div>
10
11
+ <form action="%%SUCURI.URL.Home%%" method="post">
12
+ <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
13
+
14
+ <table class="wp-list-table widefat sucuriscan-table sucuriscan-corefiles sucuriscan-%%SUCURI.CoreFiles.BadVisibility%%">
15
+ <thead>
16
+ <tr>
17
+ <th colspan="3" class="sucuriscan-clearfix thead-with-button">
18
+ <span>Core integrity (%%SUCURI.CoreFiles.ListCount%% files)</span>
19
+ <div class="sucuriscan-pull-right sucuriscan-corefiles-abbrs">
20
+ <span class="sucuriscan-status-type sucuriscan-status-added">Added</span>
21
+ <span class="sucuriscan-status-type sucuriscan-status-modified">Modified</span>
22
+ <span class="sucuriscan-status-type sucuriscan-status-removed">Removed</span>
23
+ <button id="sucuriscan-corefiles-show" class="button button-primary thead-topright-action" data-action="show">Show files</button>
24
+ </div>
25
+ </th>
26
+ </tr>
27
+
28
+ <tr>
29
+ <td colspan="3" class="sucuriscan-corefiles-warning">
30
+ <div>
31
+ <p>
32
+ Changes in the integrity of your core files were detected. There are files that
33
+ were added, modified, and/or removed in the core directories
34
+ <code>/&lt;root&gt;</code>, <code>/wp-admin</code> and/or <code>/wp-
35
+ includes</code>. You may want to check each file to determine if they were
36
+ infected with malicious code.
37
+ </p>
38
+ </div>
39
+ </td>
40
+ </tr>
41
+
42
+ <tr class="sucuriscan-hidden">
43
+ <th class="manage-column column-cb check-column">
44
+ <label class="screen-reader-text" for="cb-select-all-1">Select All</label>
45
+ <input id="cb-select-all-1" type="checkbox">
46
+ </th>
47
+ <th width="70" class="manage-column">Status</th>
48
+ <th class="manage-column">Filepath</th>
49
+ </tr>
50
+ </thead>
51
+
52
+ <tbody>
53
+ %%SUCURI.CoreFiles.List%%
54
+ </tbody>
55
+
56
+ <tfoot>
57
+ <tr>
58
+ <td colspan="3">
59
<p>
60
+ The action to restore the content of a file will only work with files that were
61
+ <b>modified</b> or <b>removed</b>, for files that were <b>added</b> you must
62
+ either remove or mark as fixed. Files marked as <b>fixed</b> will always be
63
+ ignored from the integrity checks, an attacker can use this option to hide a
64
+ malicious file, so always check what files are being ignored.
65
</p>
66
67
+ <label>
68
+ <select name="sucuriscan_integrity_action">
69
+ <option value="">Choose action</option>
70
+ <option value="restore">Restore file(s) content</option>
71
+ <option value="remove">Remove file(s)</option>
72
+ <option value="fixed">Mark as fixed</option>
73
+ </select>
74
+ </label>
75
+
76
+ <button type="submit" class="button button-primary">Send action</button>
77
+ </td>
78
+ </tr>
79
+ </tfoot>
80
+ </table>
81
82
+ </form>
inc/tpl/integrity-corefiles.snippet.tpl CHANGED
@@ -1,9 +1,9 @@
1
2
<tr class="%%SUCURI.CoreFiles.CssClass%% sucuriscan-hidden">
3
- <td>
4
- <div class="sucuriscan-clearfix">
5
- <div class="sucuriscan-pull-left sucuriscan-status-type sucuriscan-status-%%SUCURI.CoreFiles.StatusType%%">%%SUCURI.CoreFiles.StatusAbbr%%</div>
6
- <div class="sucuriscan-pull-left sucuriscan-monospace">%%SUCURI.CoreFiles.FilePath%%</div>
7
- </div>
8
</td>
9
</tr>
1
2
<tr class="%%SUCURI.CoreFiles.CssClass%% sucuriscan-hidden">
3
+ <td class="check-column">
4
+ <input type="checkbox" name="sucuriscan_integrity_files[]" value="%%SUCURI.CoreFiles.FilePath%%" />
5
+ <input type="hidden" name="sucuriscan_integrity_types[]" value="%%SUCURI.CoreFiles.StatusType%%" />
6
</td>
7
+ <td><span class="sucuriscan-status-type sucuriscan-status-%%SUCURI.CoreFiles.StatusType%%">%%SUCURI.CoreFiles.StatusAbbr%%</span></td>
8
+ <td><span class="sucuriscan-monospace sucuriscan-wraptext">%%SUCURI.CoreFiles.FilePath%%</span></td>
9
</tr>
inc/tpl/integrity.html.tpl CHANGED
@@ -1,10 +1,8 @@
1
2
<div id="poststuff">
3
-
4
%%SUCURI.WordpressVersion%%
5
6
%%SUCURI.CoreFiles%%
7
8
%%SUCURI.AuditLogs%%
9
-
10
</div>
1
2
<div id="poststuff">
3
%%SUCURI.WordpressVersion%%
4
5
%%SUCURI.CoreFiles%%
6
7
%%SUCURI.AuditLogs%%
8
</div>
inc/tpl/malwarescan.html.tpl CHANGED
@@ -4,7 +4,7 @@
4
5
<p class="description">Visit our <a href="http://sucuri.net/signup?fromloader" target="_blank">coverage &amp; pricing</a> page for details on how sucuri can help you.</p>
6
7
- <form action="%%SUCURI.URL.Scanner%%" method="post" name="sucuriscan_sitecheck_form">
8
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
9
<input type="hidden" name="sucuriscan_malware_scan" value="1" />
10
<button type="submit" class="button button-hero button-primary">Scan Website</button>
4
5
<p class="description">Visit our <a href="http://sucuri.net/signup?fromloader" target="_blank">coverage &amp; pricing</a> page for details on how sucuri can help you.</p>
6
7
+ <form action="%%SUCURI.URL.Scanner%%" method="post" class="sucuriscan-sitecheck-form">
8
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
9
<input type="hidden" name="sucuriscan_malware_scan" value="1" />
10
<button type="submit" class="button button-hero button-primary">Scan Website</button>
inc/tpl/setup-notice.html.tpl CHANGED
@@ -6,8 +6,8 @@
6
7
<div class="sucuriscan-pull-left">
8
<p>
9
- Plugin not fully activated yet. Please generate the free API<br>
10
- to enable audit logging, integrity checking and email alerts.
11
</p>
12
</div>
13
6
7
<div class="sucuriscan-pull-left">
8
<p>
9
+ Plugin not fully activated yet. Please generate the free API key to<br>
10
+ enable audit logging, integrity checking, email alerts and other tools.
11
</p>
12
</div>
13
readme.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: dd@sucuri.net
3
Donate Link: http://sitecheck.sucuri.net
4
Tags: malware, security, firewall, scan, spam, virus, sucuri, protection
5
Requires at least:3.2
6
- Stable tag:1.6.6
7
Tested up to: 3.9.2
8
9
The Sucuri Security - Auditing, SiteCheck Malware Scanner and Hardening is a security plugin enables you to scan your WordPress site using Sucuri SiteCheck for security and malware issues, and also verifies the security integrity of your core files right in your dashboard. It includes audit trails and post-hack security ions to help you reset passwords and secret keys in case it has been already hacked, or infected with malware.
@@ -66,6 +66,13 @@ the compromise on your site).
66
67
== Changelog ==
68
69
= 1.6.6 =
70
* Internal code cleanup and re-organization.
71
* More white lists for the integrity checks.
3
Donate Link: http://sitecheck.sucuri.net
4
Tags: malware, security, firewall, scan, spam, virus, sucuri, protection
5
Requires at least:3.2
6
+ Stable tag:1.6.8
7
Tested up to: 3.9.2
8
9
The Sucuri Security - Auditing, SiteCheck Malware Scanner and Hardening is a security plugin enables you to scan your WordPress site using Sucuri SiteCheck for security and malware issues, and also verifies the security integrity of your core files right in your dashboard. It includes audit trails and post-hack security ions to help you reset passwords and secret keys in case it has been already hacked, or infected with malware.
66
67
== Changelog ==
68
69
+ = 1.6.8 =
70
+ * Fixing interface.
71
+
72
+ = 1.6.7 =
73
+ * Added Support for integrity checks on i18n installations.
74
+ * Fixed the setting change bug.
75
+
76
= 1.6.6 =
77
* Internal code cleanup and re-organization.
78
* More white lists for the integrity checks.
sucuri.php CHANGED
@@ -4,7 +4,7 @@ Plugin Name: Sucuri Security - Auditing, Malware Scanner and Hardening
4
Plugin URI: http://wordpress.sucuri.net/
5
Description: The <a href="http://sucuri.net/" target="_blank">Sucuri Security</a> <em>(Auditing, Malware Scanner and Hardening)</em> plugin enables you to scan your WordPress site using <a href="http://sitecheck.sucuri.net/" target="_blank">Sucuri SiteCheck</a> right in your dashboard. SiteCheck will check for malware, spam, blacklisting and other security issues like .htaccess redirects, hidden eval code, etc. The best thing about it is it's completely free.
6
Author: Sucuri, INC
7
- Version: 1.6.6
8
Author URI: http://sucuri.net
9
*/
10
@@ -66,7 +66,7 @@ define('SUCURISCAN', 'sucuriscan');
66
/**
67
* Current version of the plugin's code.
68
*/
69
- define('SUCURISCAN_VERSION', '1.6.6');
70
71
/**
72
* The name of the Sucuri plugin main file.
@@ -522,25 +522,35 @@ class SucuriScan {
522
* @return string The real ip address of the user in the current request.
523
*/
524
public static function get_remote_addr(){
525
- $alternatives = array(
526
- 'HTTP_X_REAL_IP',
527
- 'HTTP_CLIENT_IP',
528
- 'HTTP_X_FORWARDED_FOR',
529
- 'HTTP_X_FORWARDED',
530
- 'HTTP_FORWARDED_FOR',
531
- 'HTTP_FORWARDED',
532
- 'REMOTE_ADDR',
533
- 'SUCURI_RIP',
534
- );
535
-
536
- foreach( $alternatives as $alternative ){
537
- if( isset($_SERVER[$alternative]) ){
538
- $remote_addr = preg_replace('/[^0-9a-z.,: ]/', '', $_SERVER[$alternative]);
539
540
- if( $remote_addr ){ break; }
541
}
542
}
543
544
if( $remote_addr == '::1' ){
545
$remote_addr = '127.0.0.1';
546
}
@@ -564,19 +574,30 @@ class SucuriScan {
564
/**
565
* Check whether the site is behing the Sucuri CloudProxy network.
566
*
567
- * @return boolean Either TRUE or FALSE if the site is behind CloudProxy.
568
*/
569
- public static function is_behind_cloudproxy(){
570
- if( isset($_SERVER['HTTP_HOST']) ){
571
- $http_host = preg_replace('/^(.*):[0-9]+/', '$1', $_SERVER['HTTP_HOST']);
572
} else {
573
$http_host = 'localhost';
574
}
575
576
$host_by_name = gethostbyname($http_host);
577
$host_by_addr = gethostbyaddr($host_by_name);
578
579
- return (bool) preg_match('/^cloudproxy[0-9]+\.sucuri\.net#x2F;', $host_by_addr);
580
}
581
582
/**
@@ -1333,21 +1354,39 @@ class SucuriScanCache extends SucuriScan {
1333
}
1334
1335
/**
1336
- * Check whether a key has a valid name or not.
1337
*
1338
- * @param string $key Unique name to identify the data in the datastore file.
1339
- * @return boolean TRUE if the format of the key name is valid, FALSE otherwise.
1340
*/
1341
- private function valid_key_name( $key='' ){
1342
- $key = trim($key);
1343
1344
- if( !empty($key) ){
1345
- return (bool) preg_match('/^([a-zA-Z_]+)#x2F;', $key);
1346
}
1347
1348
return FALSE;
1349
}
1350
1351
/**
1352
* Update the content of the datastore file with the new entries.
1353
*
@@ -1391,11 +1430,11 @@ class SucuriScanCache extends SucuriScan {
1391
1392
if( !empty($data_lines) ){
1393
foreach( $data_lines as $line ){
1394
- if( preg_match('/^\/\/ ([a-z_]+)=(.*);#x2F;', $line, $match) ){
1395
$data_object['info'][$match[1]] = $match[2];
1396
}
1397
1398
- elseif( preg_match('/^([a-z_]+):(.+)/', $line, $match) ){
1399
if(
1400
$this->valid_key_name($match[1])
1401
&& !array_key_exists($match[1], $data_object)
@@ -1483,8 +1522,11 @@ class SucuriScanCache extends SucuriScan {
1483
* @return boolean TRUE if the operation finished successfully, FALSE otherwise.
1484
*/
1485
private function handle_key_data( $key='', $data=NULL, $action='', $lifetime=0, $assoc=FALSE ){
1486
- if( preg_match('/^(add|set|get|delete)#x2F;', $action) ){
1487
- if( $this->valid_key_name($key) && $this->usable_datastore ){
1488
$finfo = $this->get_datastore_content($assoc);
1489
1490
switch( $action ){
@@ -1501,6 +1543,18 @@ class SucuriScanCache extends SucuriScan {
1501
return $finfo['entries'][$key];
1502
}
1503
break;
1504
case 'delete':
1505
unset($finfo['entries'][$key]);
1506
return $this->save_new_entries($finfo);
@@ -1551,6 +1605,29 @@ class SucuriScanCache extends SucuriScan {
1551
return $this->handle_key_data( $key, NULL, 'get', $lifetime, $assoc );
1552
}
1553
1554
/**
1555
* Delete any entry from the datastore file matching the key name specified.
1556
*
@@ -1616,10 +1693,11 @@ class SucuriScanOption extends SucuriScanRequest {
1616
* @param string $option_name Optional parameter with the name of the option that will be filtered.
1617
* @return array List of options retrieved from the query in the database.
1618
*/
1619
- public function get_options_from_db( $filter_by='', $option_name='' ){
1620
global $wpdb;
1621
1622
$output = FALSE;
1623
switch($filter_by){
1624
case 'all_plugin_options':
1625
$output = $wpdb->get_results("SELECT * FROM {$wpdb->options} WHERE option_name LIKE 'sucuriscan%' ORDER BY option_id ASC");
@@ -3642,8 +3720,8 @@ class SucuriScanAPI extends SucuriScanOption {
3642
$can_cache = class_exists('SucuriScanCache');
3643
3644
if( $can_cache ){
3645
- $sucuri_cache = new SucuriScanCache('plugindata');
3646
- $cached_data = $sucuri_cache->get( 'plugins', SUCURISCAN_GET_PLUGINS_LIFETIME, 'array' );
3647
3648
// Return the previously cached results of this function.
3649
if( $cached_data !== FALSE ){
@@ -3710,7 +3788,7 @@ class SucuriScanAPI extends SucuriScanOption {
3710
3711
if( $can_cache ){
3712
// Add the information of the plugins to the file-based cache.
3713
- $sucuri_cache->add( 'plugins', $plugins );
3714
}
3715
3716
return $plugins;
@@ -3748,6 +3826,42 @@ class SucuriScanAPI extends SucuriScanOption {
3748
return FALSE;
3749
}
3750
3751
}
3752
3753
/**
@@ -4520,8 +4634,8 @@ function sucuriscan_scanner_page(){
4520
SucuriScanInterface::check_permissions();
4521
4522
// Check if the information is already cached.
4523
- $sucuri_cache = new SucuriScanCache('sitecheck');
4524
- $scan_results = $sucuri_cache->get( 'scan_results', SUCURISCAN_SITECHECK_LIFETIME, 'array' );
4525
4526
if(
4527
(
@@ -4562,11 +4676,11 @@ function sucuriscan_sitecheck_info( $res=array() ){
4562
}
4563
4564
else {
4565
- $sucuri_cache = new SucuriScanCache('sitecheck');
4566
$display_results = TRUE;
4567
4568
// Cache the scanning results to reduce memory lose.
4569
- if( !$sucuri_cache->add( 'scan_results', $res ) ){
4570
SucuriScanInterface::error( 'Could not cache the results of the SiteCheck scanning.' );
4571
}
4572
}
@@ -4787,18 +4901,20 @@ function sucuriscan_sitecheck_info( $res=array() ){
4787
<tr>
4788
<th colspan="2">Web application details</th>
4789
</tr>
4790
- <?php foreach( $res['WEBAPP'] as $webapp_key=>$webapp_details ): ?>
4791
- <?php if( is_array($webapp_details) ): ?>
4792
- <?php foreach( $webapp_details as $i=>$details ): ?>
4793
- <?php if( is_array($details) ){ $details = isset($details[0]) ? $details[0] : ''; } ?>
4794
- <tr>
4795
- <td colspan="2">
4796
- <span class="sucuriscan-monospace"><?php _e($details) ?></span>
4797
- </td>
4798
- </tr>
4799
- <?php endforeach; ?>
4800
- <?php endif; ?>
4801
- <?php endforeach; ?>
4802
4803
<?php foreach( $res['SYSTEM']['NOTICE'] as $j=>$notice ): ?>
4804
<?php if( is_array($notice) ){ $notice = implode(', ', $notice); } ?>
@@ -5701,15 +5817,20 @@ function sucuriscan_harden_wpcontent(){
5701
}
5702
}
5703
5704
sucuriscan_harden_status(
5705
'Restrict wp-content access',
5706
$cp,
5707
'sucuriscan_harden_wpcontent',
5708
'WP-content directory properly hardened',
5709
'WP-content directory not hardened',
5710
- 'This option blocks direct PHP access to any file inside wp-content. If you experience any '
5711
- .'issue after this with a theme or plugin in your site, like for example images not displaying, '
5712
- .'remove the <code>.htaccess</code> file located at the <code>/wp-content/</code> directory.',
5713
$upmsg
5714
);
5715
}
@@ -5816,10 +5937,19 @@ function sucuriscan_harden_phpversion(){
5816
*/
5817
function sucuriscan_cloudproxy_enabled(){
5818
$btn_string = '';
5819
- $enabled = SucuriScan::is_behind_cloudproxy();
5820
$status = 1;
5821
5822
- if( $enabled !== TRUE ){
5823
$status = 0;
5824
$btn_string = '<a href="http://cloudproxy.sucuri.net/" target="_blank" class="button button-primary">Harden</a>';
5825
}
@@ -5830,9 +5960,7 @@ function sucuriscan_cloudproxy_enabled(){
5830
NULL,
5831
'Your website is protected by a Website Firewall (WAF)',
5832
$btn_string . 'Your website is not protected by a Website Firewall (WAF)',
5833
- 'A WAF is a protection layer for your web site, blocking all sort of attacks (brute force attempts, DDoS, '
5834
- .'SQL injections, etc) and helping it remain malware and blacklist free. This test checks if your site is '
5835
- .'using <a href="http://cloudproxy.sucuri.net/" target="_blank">Sucuri\'s CloudProxy WAF</a> to protect your site. ',
5836
NULL
5837
);
5838
}
@@ -6062,13 +6190,8 @@ function sucuriscan_harden_dbtables(){
6062
function sucuriscan_page(){
6063
SucuriScanInterface::check_permissions();
6064
6065
- if(
6066
- SucuriScanInterface::check_nonce()
6067
- && SucuriScanRequest::post(':force_scan')
6068
- ){
6069
- SucuriScanEvent::notify_event( 'plugin_change', 'Filesystem scan forced at: ' . date('r') );
6070
- SucuriScanEvent::filesystem_scan(TRUE);
6071
- }
6072
6073
$template_variables = array(
6074
'WordpressVersion' => sucuriscan_wordpress_outdated(),
@@ -6079,6 +6202,73 @@ function sucuriscan_page(){
6079
echo SucuriScanTemplate::get_template('integrity', $template_variables);
6080
}
6081
6082
/**
6083
* Retrieve a list of md5sum and last modification time of all the files in the
6084
* folder specified. This is a recursive function.
@@ -6247,9 +6437,12 @@ function sucuriscan_core_files(){
6247
);
6248
6249
if( $site_version && SucuriScanOption::get_option(':scan_checksums') == 'enabled' ){
6250
- $latest_hashes = sucuriscan_check_wp_integrity($site_version);
6251
6252
if( $latest_hashes ){
6253
$counter = 0;
6254
6255
foreach( $latest_hashes as $list_type => $file_list ){
@@ -6261,24 +6454,10 @@ function sucuriscan_core_files(){
6261
}
6262
6263
foreach( $file_list as $file_path ){
6264
- if( $file_path == '.htaccess' ){
6265
- $file_path = sprintf(
6266
- '%s <a href="%s" target="_blank">%s</a>',
6267
- $file_path,
6268
- '%%SUCURI.URL.Infosys%%#htaccess-integrity',
6269
- '<em>(Check HTAccess Integrity)</em>'
6270
- );
6271
- }
6272
-
6273
- elseif( $file_path == 'wp-config.php' ){
6274
- $file_path = sprintf(
6275
- '%s <a href="%s" target="_blank">%s</a>',
6276
- $file_path,
6277
- '%%SUCURI.URL.Infosys%%#wpconfig-rules',
6278
- '<em>(Check WP Config Variables)</em>'
6279
- );
6280
- }
6281
6282
$css_class = ( $counter % 2 == 0 ) ? '' : 'alternate';
6283
$template_variables['CoreFiles.List'] .= SucuriScanTemplate::get_snippet('integrity-corefiles', array(
6284
'CoreFiles.CssClass' => $css_class,
@@ -6318,7 +6497,7 @@ function sucuriscan_core_files(){
6318
* @param integer $version Valid version number of the WordPress project.
6319
* @return array Associative array with these keys: modified, stable, removed, added.
6320
*/
6321
- function sucuriscan_check_wp_integrity( $version=0 ){
6322
$latest_hashes = SucuriScanAPI::get_official_checksums($version);
6323
6324
if( !$latest_hashes ){ return FALSE; }
@@ -6337,32 +6516,32 @@ function sucuriscan_check_wp_integrity( $version=0 ){
6337
$wp_core_hashes = array_merge( $wp_top_hashes, $wp_admin_hashes, $wp_includes_hashes );
6338
6339
// Compare remote and local checksums and search removed files.
6340
- foreach( $latest_hashes as $filepath => $remote_checksum ){
6341
- if( sucuriscan_ignore_integrity_filepath($filepath) ){ continue; }
6342
6343
- $full_filepath = sprintf('%s/%s', ABSPATH, $filepath);
6344
6345
if( file_exists($full_filepath) ){
6346
$local_checksum = @md5_file($full_filepath);
6347
6348
if( $local_checksum && $local_checksum == $remote_checksum ){
6349
- $output['stable'][] = $filepath;
6350
} else {
6351
- $output['modified'][] = $filepath;
6352
}
6353
} else {
6354
- $output['removed'][] = $filepath;
6355
}
6356
}
6357
6358
// Search added files (files not common in a normal wordpress installation).
6359
- foreach( $wp_core_hashes as $filepath => $extra_info ){
6360
- $filepath = preg_replace('/^\.\/(.*)/', '$1', $filepath);
6361
6362
- if( sucuriscan_ignore_integrity_filepath($filepath) ){ continue; }
6363
6364
- if( !isset($latest_hashes[$filepath]) ){
6365
- $output['added'][] = $filepath;
6366
}
6367
}
6368
@@ -6372,10 +6551,12 @@ function sucuriscan_check_wp_integrity( $version=0 ){
6372
/**
6373
* Ignore irrelevant files and directories from the integrity checking.
6374
*
6375
- * @param string $filepath File path that will be compared.
6376
- * @return boolean TRUE if the file should be ignored, FALSE otherwise.
6377
*/
6378
- function sucuriscan_ignore_integrity_filepath( $filepath='' ){
6379
// List of files that will be ignored from the integrity checking.
6380
$ignore_files = array(
6381
'^sucuri-[0-9a-z]+\.php#x27;,
@@ -6391,14 +6572,30 @@ function sucuriscan_ignore_integrity_filepath( $filepath='' ){
6391
'^(503|404)\.php#x27;,
6392
'^500\.(shtml|php)#x27;,
6393
'^40[0-9]\.shtml#x27;,
6394
- '^([^\/]*)\.(pdf|css)#x27;,
6395
'^google[0-9a-z]{16}\.html#x27;,
6396
'^pinterest-[0-9a-z]{5}\.html#x27;,
6397
'(^|\/)error_log#x27;,
6398
);
6399
6400
foreach( $ignore_files as $ignore_pattern ){
6401
- if( preg_match('/'.$ignore_pattern.'/', $filepath) ){
6402
return TRUE;
6403
}
6404
}
@@ -7778,7 +7975,9 @@ function sucuriscan_settings_form_submissions( $page_nonce=NULL ){
7778
$options_updated_counter = 0;
7779
7780
foreach( $sucuriscan_notify_options as $alert_type => $alert_label ){
7781
- if( $option_value = SucuriScanRequest::post($alert_type, '(1|0)') ){
7782
$option_value = ( $option_value == '1' ) ? 'enabled' : 'disabled';
7783
SucuriScanOption::update_option( $alert_type, $option_value );
7784
$options_updated_counter += 1;
4
Plugin URI: http://wordpress.sucuri.net/
5
Description: The <a href="http://sucuri.net/" target="_blank">Sucuri Security</a> <em>(Auditing, Malware Scanner and Hardening)</em> plugin enables you to scan your WordPress site using <a href="http://sitecheck.sucuri.net/" target="_blank">Sucuri SiteCheck</a> right in your dashboard. SiteCheck will check for malware, spam, blacklisting and other security issues like .htaccess redirects, hidden eval code, etc. The best thing about it is it's completely free.
6
Author: Sucuri, INC
7
+ Version: 1.6.8
8
Author URI: http://sucuri.net
9
*/
10
66
/**
67
* Current version of the plugin's code.
68
*/
69
+ define('SUCURISCAN_VERSION', '1.6.8');
70
71
/**
72
* The name of the Sucuri plugin main file.
522
* @return string The real ip address of the user in the current request.
523
*/
524
public static function get_remote_addr(){
525
+ $remote_addr = '';
526
+
527
+ if( self::is_behind_cloudproxy() ){
528
+ $alternatives = array(
529
+ 'HTTP_X_REAL_IP',
530
+ 'HTTP_CLIENT_IP',
531
+ 'HTTP_X_FORWARDED_FOR',
532
+ 'HTTP_X_FORWARDED',
533
+ 'HTTP_FORWARDED_FOR',
534
+ 'HTTP_FORWARDED',
535
+ 'REMOTE_ADDR',
536
+ 'SUCURI_RIP',
537
+ );
538
539
+ foreach( $alternatives as $alternative ){
540
+ if(
541
+ isset($_SERVER[$alternative])
542
+ && self::is_valid_ip($_SERVER[$alternative])
543
+ ){
544
+ $remote_addr = $_SERVER[$alternative];
545
+ break;
546
+ }
547
}
548
}
549
550
+ elseif( isset($_SERVER['REMOTE_ADDR']) ) {
551
+ $remote_addr = $_SERVER['REMOTE_ADDR'];
552
+ }
553
+
554
if( $remote_addr == '::1' ){
555
$remote_addr = '127.0.0.1';
556
}
574
/**
575
* Check whether the site is behing the Sucuri CloudProxy network.
576
*
577
+ * @param boolean $verbose Return an array with the hostname, address, and status, or not.
578
+ * @return boolean Either TRUE or FALSE if the site is behind CloudProxy.
579
*/
580
+ public static function is_behind_cloudproxy( $verbose=FALSE ){
581
+ if( isset($_SERVER['SERVER_NAME']) ){
582
+ $http_host = preg_replace('/^(.*):[0-9]+/', '$1', $_SERVER['SERVER_NAME']);
583
} else {
584
$http_host = 'localhost';
585
}
586
587
$host_by_name = gethostbyname($http_host);
588
$host_by_addr = gethostbyaddr($host_by_name);
589
+ $status = (bool) preg_match('/^cloudproxy[0-9]+\.sucuri\.net#x2F;', $host_by_addr);
590
591
+ if( $verbose ){
592
+ return array(
593
+ 'http_host' => $http_host,
594
+ 'host_name' => $host_by_name,
595
+ 'host_addr' => $host_by_addr,
596
+ 'status' => $status,
597
+ );
598
+ }
599
+
600
+ return $status;
601
}
602
603
/**
1354
}
1355
1356
/**
1357
+ * Define the pattern for the regular expression that will check if a cache key
1358
+ * is valid or not, and also will help the function that parses the file to see
1359
+ * which characters of each line are the keys are which are the values.
1360
*
1361
+ * @param string $action Either "valid", "content", or "header".
1362
+ * @return string Cache key pattern.
1363
*/
1364
+ private function key_pattern( $action='valid' ){
1365
+ if( $action == 'valid' ){
1366
+ return '/^([0-9a-zA-Z_]+)#x2F;';
1367
+ }
1368
+
1369
+ if( $action == 'content' ){
1370
+ return '/^([0-9a-zA-Z_]+):(.+)/';
1371
+ }
1372
1373
+ if( $action == 'header' ){
1374
+ return '/^\/\/ ([a-z_]+)=(.*);#x2F;';
1375
}
1376
1377
return FALSE;
1378
}
1379
1380
+ /**
1381
+ * Check whether a key has a valid name or not.
1382
+ *
1383
+ * @param string $key Unique name to identify the data in the datastore file.
1384
+ * @return boolean TRUE if the format of the key name is valid, FALSE otherwise.
1385
+ */
1386
+ private function valid_key_name( $key='' ){
1387
+ return (bool) preg_match( $this->key_pattern('valid'), $key );
1388
+ }
1389
+
1390
/**
1391
* Update the content of the datastore file with the new entries.
1392
*
1430
1431
if( !empty($data_lines) ){
1432
foreach( $data_lines as $line ){
1433
+ if( preg_match( $this->key_pattern('header'), $line, $match ) ){
1434
$data_object['info'][$match[1]] = $match[2];
1435
}
1436
1437
+ elseif( preg_match( $this->key_pattern('content'), $line, $match ) ){
1438
if(
1439
$this->valid_key_name($match[1])
1440
&& !array_key_exists($match[1], $data_object)
1522
* @return boolean TRUE if the operation finished successfully, FALSE otherwise.
1523
*/
1524
private function handle_key_data( $key='', $data=NULL, $action='', $lifetime=0, $assoc=FALSE ){
1525
+ if( preg_match('/^(add|set|get|get_all|exists|delete)#x2F;', $action) ){
1526
+ if(
1527
+ $this->valid_key_name($key)
1528
+ && $this->usable_datastore
1529
+ ){
1530
$finfo = $this->get_datastore_content($assoc);
1531
1532
switch( $action ){
1543
return $finfo['entries'][$key];
1544
}
1545
break;
1546
+ case 'get_all': /* no_break */
1547
+ if( !$this->data_has_expired($lifetime, $finfo) ) {
1548
+ return $finfo['entries'];
1549
+ }
1550
+ case 'exists':
1551
+ if(
1552
+ !$this->data_has_expired($lifetime, $finfo)
1553
+ && array_key_exists($key, $finfo['entries'])
1554
+ ){
1555
+ return TRUE;
1556
+ }
1557
+ break;
1558
case 'delete':
1559
unset($finfo['entries'][$key]);
1560
return $this->save_new_entries($finfo);
1605
return $this->handle_key_data( $key, NULL, 'get', $lifetime, $assoc );
1606
}
1607
1608
+ /**
1609
+ * Retrieve all the entries found in the datastore file.
1610
+ *
1611
+ * @param integer $lifetime Life time of the key in the datastore file.
1612
+ * @param boolean $assoc When TRUE returned objects will be converted into associative arrays.
1613
+ * @return string Mixed data stored in the datastore file following the unique key name.
1614
+ */
1615
+ public function get_all( $lifetime=0, $assoc=FALSE ){
1616
+ $assoc = ( $assoc == 'array' ? TRUE : $assoc );
1617
+
1618
+ return $this->handle_key_data( 'temp', NULL, 'get_all', $lifetime, $assoc );
1619
+ }
1620
+
1621
+ /**
1622
+ * Check whether a specific key exists in the datastore file.
1623
+ *
1624
+ * @param string $key Unique name to identify the data in the datastore file.
1625
+ * @return boolean TRUE if the key exists in the datastore file, FALSE otherwise.
1626
+ */
1627
+ public function exists( $key='' ){
1628
+ return $this->handle_key_data( $key, NULL, 'exists' );
1629
+ }
1630
+
1631
/**
1632
* Delete any entry from the datastore file matching the key name specified.
1633
*
1693
* @param string $option_name Optional parameter with the name of the option that will be filtered.
1694
* @return array List of options retrieved from the query in the database.
1695
*/
1696
+ public static function get_options_from_db( $filter_by='', $option_name='' ){
1697
global $wpdb;
1698
1699
$output = FALSE;
1700
+
1701
switch($filter_by){
1702
case 'all_plugin_options':
1703
$output = $wpdb->get_results("SELECT * FROM {$wpdb->options} WHERE option_name LIKE 'sucuriscan%' ORDER BY option_id ASC");
3720
$can_cache = class_exists('SucuriScanCache');
3721
3722
if( $can_cache ){
3723
+ $cache = new SucuriScanCache('plugindata');
3724
+ $cached_data = $cache->get( 'plugins', SUCURISCAN_GET_PLUGINS_LIFETIME, 'array' );
3725
3726
// Return the previously cached results of this function.
3727
if( $cached_data !== FALSE ){
3788
3789
if( $can_cache ){
3790
// Add the information of the plugins to the file-based cache.
3791
+ $cache->add( 'plugins', $plugins );
3792
}
3793
3794
return $plugins;
3826
return FALSE;
3827
}
3828
3829
+ /**
3830
+ * Retrieve a specific file from the official WordPress subversion repository,
3831
+ * the content of the file is determined by the tags defined using the site
3832
+ * version specified. Only official core files are allowed to fetch.
3833
+ *
3834
+ * @see http://core.svn.wordpress.org/
3835
+ * @see http://i18n.svn.wordpress.org/
3836
+ * @see http://core.svn.wordpress.org/tags/VERSION_NUMBER/
3837
+ *
3838
+ * @param string $filepath Relative file path of a project core file.
3839
+ * @param string $version Optional site version, default will be the global version number.
3840
+ * @return string Full content of the official file retrieved, FALSE if the file was not found.
3841
+ */
3842
+ public static function get_original_core_file( $filepath='', $version=0 ){
3843
+ if( !empty($filepath) ){
3844
+ if( $version == 0 ){
3845
+ $version = self::site_version();
3846
+ }
3847
+
3848
+ $url = sprintf( 'http://core.svn.wordpress.org/tags/%s/%s', $version, $filepath );
3849
+ $response = self::api_call( $url, 'GET' );
3850
+
3851
+ if( $response ){
3852
+ if(
3853
+ isset($response['headers']['content-length'])
3854
+ && $response['headers']['content-length'] > 0
3855
+ && is_string($response['body'])
3856
+ ){
3857
+ return $response['body'];
3858
+ }
3859
+ }
3860
+ }
3861
+
3862
+ return FALSE;
3863
+ }
3864
+
3865
}
3866
3867
/**
4634
SucuriScanInterface::check_permissions();
4635
4636
// Check if the information is already cached.
4637
+ $cache = new SucuriScanCache('sitecheck');
4638
+ $scan_results = $cache->get( 'scan_results', SUCURISCAN_SITECHECK_LIFETIME, 'array' );
4639
4640
if(
4641
(
4676
}
4677
4678
else {
4679
+ $cache = new SucuriScanCache('sitecheck');
4680
$display_results = TRUE;
4681
4682
// Cache the scanning results to reduce memory lose.
4683
+ if( !$cache->add( 'scan_results', $res ) ){
4684
SucuriScanInterface::error( 'Could not cache the results of the SiteCheck scanning.' );
4685
}
4686
}
4901
<tr>
4902
<th colspan="2">Web application details</th>
4903
</tr>
4904
+ <?php if( isset($res['WEBAPP']) ): ?>
4905
+ <?php foreach( $res['WEBAPP'] as $webapp_key=>$webapp_details ): ?>
4906
+ <?php if( is_array($webapp_details) ): ?>
4907
+ <?php foreach( $webapp_details as $i=>$details ): ?>
4908
+ <?php if( is_array($details) ){ $details = isset($details[0]) ? $details[0] : ''; } ?>
4909
+ <tr>
4910
+ <td colspan="2">
4911
+ <span class="sucuriscan-monospace"><?php _e($details) ?></span>
4912
+ </td>
4913
+ </tr>
4914
+ <?php endforeach; ?>
4915
+ <?php endif; ?>
4916
+ <?php endforeach; ?>
4917
+ <?php endif; ?>
4918
4919
<?php foreach( $res['SYSTEM']['NOTICE'] as $j=>$notice ): ?>
4920
<?php if( is_array($notice) ){ $notice = implode(', ', $notice); } ?>
5817
}
5818
}
5819
5820
+ $description = 'This option blocks direct PHP access to any file inside wp-content. If you experience '
5821
+ . 'any issue after this with a theme or plugin in your site, like for example images not displaying, '
5822
+ . 'remove the <code>.htaccess</code> file located at the <code>/wp-content/</code> directory.'
5823
+ . '</p><p><b>Note:</b> Many <em>(insecure)</em> themes and plugins use a PHP file in this directory '
5824
+ . 'to generate images like thumbnails and captcha codes, this is intentional so it is recommended '
5825
+ . 'to check your site once this option is enabled.';
5826
+
5827
sucuriscan_harden_status(
5828
'Restrict wp-content access',
5829
$cp,
5830
'sucuriscan_harden_wpcontent',
5831
'WP-content directory properly hardened',
5832
'WP-content directory not hardened',
5833
+ $description,
5834
$upmsg
5835
);
5836
}
5937
*/
5938
function sucuriscan_cloudproxy_enabled(){
5939
$btn_string = '';
5940
+ $verbosity = TRUE;
5941
+ $proxy_info = SucuriScan::is_behind_cloudproxy($verbosity);
5942
$status = 1;
5943
5944
+ $description = 'A WAF is a protection layer for your web site, blocking all sort of attacks (brute force attempts, '
5945
+ . 'DDoS, SQL injections, etc) and helping it remain malware and blacklist free. This test checks if your site is '
5946
+ . 'using <a href="http://cloudproxy.sucuri.net/" target="_blank">Sucuri\'s CloudProxy WAF</a> to protect your site. '
5947
+ . '</p><p>'
5948
+ . '<b>HTTP Host:</b> <span class="sucuriscan-monospace">' . $proxy_info['http_host'] . '</span><br>'
5949
+ . '<b>Host Name:</b> <span class="sucuriscan-monospace">' . $proxy_info['host_name'] . '</span><br>'
5950
+ . '<b>Host Address:</b> <span class="sucuriscan-monospace">' . $proxy_info['host_addr'] . '</span>';
5951
+
5952
+ if( $proxy_info['status'] === FALSE ){
5953
$status = 0;
5954
$btn_string = '<a href="http://cloudproxy.sucuri.net/" target="_blank" class="button button-primary">Harden</a>';
5955
}
5960
NULL,
5961
'Your website is protected by a Website Firewall (WAF)',
5962
$btn_string . 'Your website is not protected by a Website Firewall (WAF)',
5963
+ $description,
5964
NULL
5965
);
5966
}
6190
function sucuriscan_page(){
6191
SucuriScanInterface::check_permissions();
6192
6193
+ // Process all form submissions.
6194
+ sucuriscan_integrity_form_submissions();
6195
6196
$template_variables = array(
6197
'WordpressVersion' => sucuriscan_wordpress_outdated(),
6202
echo SucuriScanTemplate::get_template('integrity', $template_variables);
6203
}
6204
6205
+ /**
6206
+ * Process the requests sent by the form submissions originated in the integrity
6207
+ * page, all forms must have a nonce field that will be checked against the one
6208
+ * generated in the template render function.
6209
+ *
6210
+ * @return void
6211
+ */
6212
+ function sucuriscan_integrity_form_submissions(){
6213
+ if( SucuriScanInterface::check_nonce() ){
6214
+
6215
+ // Force the execution of the filesystem scanner.
6216
+ if( SucuriScanRequest::post(':force_scan') ){
6217
+ SucuriScanEvent::notify_event( 'plugin_change', 'Filesystem scan forced at: ' . date('r') );
6218
+ SucuriScanEvent::filesystem_scan(TRUE);
6219
+ }
6220
+
6221
+ // Restore, Remove, Mark as fixed the core files.
6222
+ $allowed_actions = '(restore|remove|fixed)';
6223
+ $integrity_action = SucuriScanRequest::post(':integrity_action', $allowed_actions);
6224
+
6225
+ if( $integrity_action !== FALSE ){
6226
+ $cache = new SucuriScanCache('integrity');
6227
+ $integrity_files = SucuriScanRequest::post(':integrity_files', '_array');
6228
+ $integrity_types = SucuriScanRequest::post(':integrity_types', '_array');
6229
+ $files_selected = count($integrity_files);
6230
+ $files_processed = 0;
6231
+
6232
+ foreach( $integrity_files as $i => $file_path ){
6233
+ $full_path = ABSPATH . $file_path;
6234
+ $status_type = $integrity_types[$i];
6235
+
6236
+ switch( $integrity_action ){
6237
+ case 'restore':
6238
+ $file_content = SucuriScanAPI::get_original_core_file($file_path);
6239
+ if( $file_content ){
6240
+ $restored = @file_put_contents( $full_path, $file_content, LOCK_EX );
6241
+ $files_processed += ( $restored ? 1 : 0 );
6242
+ }
6243
+ break;
6244
+ case 'remove':
6245
+ if( @unlink($full_path) ){
6246
+ $files_processed += 1;
6247
+ }
6248
+ break;
6249
+ case 'fixed':
6250
+ $cache_key = md5($file_path);
6251
+ $cache_value = array(
6252
+ 'file_path' => $file_path,
6253
+ 'file_status' => $status_type,
6254
+ 'ignored_at' => time(),
6255
+ );
6256
+ $cached = $cache->add( $cache_key, $cache_value );
6257
+ $files_processed += ( $cached ? 1 : 0 );
6258
+ break;
6259
+ }
6260
+ }
6261
+
6262
+ SucuriScanInterface::info(sprintf(
6263
+ '<code>%d</code> out of <code>%d</code> files were successfully processed.',
6264
+ $files_selected,
6265
+ $files_processed
6266
+ ));
6267
+ }
6268
+
6269
+ }
6270
+ }
6271
+
6272
/**
6273
* Retrieve a list of md5sum and last modification time of all the files in the
6274
* folder specified. This is a recursive function.
6437
);
6438
6439
if( $site_version && SucuriScanOption::get_option(':scan_checksums') == 'enabled' ){
6440
+ // Check if there are added, removed, or modified files.
6441
+ $latest_hashes = sucuriscan_check_core_integrity($site_version);
6442
6443
if( $latest_hashes ){
6444
+ $cache = new SucuriScanCache('integrity');
6445
+ $ignored_files = $cache->get_all();
6446
$counter = 0;
6447
6448
foreach( $latest_hashes as $list_type => $file_list ){
6454
}
6455
6456
foreach( $file_list as $file_path ){
6457
+ // Skip files that were marked as fixed.
6458
+ if( array_key_exists(md5($file_path), $ignored_files) ){ continue; }
6459
6460
+ // Generate the HTML code from the snippet template for this file.
6461
$css_class = ( $counter % 2 == 0 ) ? '' : 'alternate';
6462
$template_variables['CoreFiles.List'] .= SucuriScanTemplate::get_snippet('integrity-corefiles', array(
6463
'CoreFiles.CssClass' => $css_class,
6497
* @param integer $version Valid version number of the WordPress project.
6498
* @return array Associative array with these keys: modified, stable, removed, added.
6499
*/
6500
+ function sucuriscan_check_core_integrity( $version=0 ){
6501
$latest_hashes = SucuriScanAPI::get_official_checksums($version);
6502
6503
if( !$latest_hashes ){ return FALSE; }
6516
$wp_core_hashes = array_merge( $wp_top_hashes, $wp_admin_hashes, $wp_includes_hashes );
6517
6518
// Compare remote and local checksums and search removed files.
6519
+ foreach( $latest_hashes as $file_path => $remote_checksum ){
6520
+ if( sucuriscan_ignore_integrity_filepath($file_path) ){ continue; }
6521
6522
+ $full_filepath = sprintf('%s/%s', ABSPATH, $file_path);
6523
6524
if( file_exists($full_filepath) ){
6525
$local_checksum = @md5_file($full_filepath);
6526
6527
if( $local_checksum && $local_checksum == $remote_checksum ){
6528
+ $output['stable'][] = $file_path;
6529
} else {
6530
+ $output['modified'][] = $file_path;
6531
}
6532
} else {
6533
+ $output['removed'][] = $file_path;
6534
}
6535
}
6536
6537
// Search added files (files not common in a normal wordpress installation).
6538
+ foreach( $wp_core_hashes as $file_path => $extra_info ){
6539
+ $file_path = preg_replace('/^\.\/(.*)/', '$1', $file_path);
6540
6541
+ if( sucuriscan_ignore_integrity_filepath($file_path) ){ continue; }
6542
6543
+ if( !isset($latest_hashes[$file_path]) ){
6544
+ $output['added'][] = $file_path;
6545
}
6546
}
6547
6551
/**
6552
* Ignore irrelevant files and directories from the integrity checking.
6553
*
6554
+ * @param string $file_path File path that will be compared.
6555
+ * @return boolean TRUE if the file should be ignored, FALSE otherwise.
6556
*/
6557
+ function sucuriscan_ignore_integrity_filepath( $file_path='' ){
6558
+ global $wp_local_package;
6559
+
6560
// List of files that will be ignored from the integrity checking.
6561
$ignore_files = array(
6562
'^sucuri-[0-9a-z]+\.php#x27;,
6572
'^(503|404)\.php#x27;,
6573
'^500\.(shtml|php)#x27;,
6574
'^40[0-9]\.shtml#x27;,
6575
+ '^([^\/]*)\.(pdf|css|txt)#x27;,
6576
'^google[0-9a-z]{16}\.html#x27;,
6577
'^pinterest-[0-9a-z]{5}\.html#x27;,
6578
'(^|\/)error_log#x27;,
6579
);
6580
6581
+ /**
6582
+ * Ignore i18n files.
6583
+ *
6584
+ * Sites with i18n have differences compared with the official English version
6585
+ * of the project, basically they have files with new variables specifying the
6586
+ * language that will be used in the admin panel, site options, and emails.
6587
+ */
6588
+ if(
6589
+ isset($wp_local_package)
6590
+ && $wp_local_package != 'en_US'
6591
+ ){
6592
+ $ignore_files[] = 'wp-includes\/version\.php';
6593
+ $ignore_files[] = 'wp-config-sample\.php';
6594
+ }
6595
+
6596
+ // Determine whether a file must be ignored from the integrity checks or not.
6597
foreach( $ignore_files as $ignore_pattern ){
6598
+ if( preg_match('/'.$ignore_pattern.'/', $file_path) ){
6599
return TRUE;
6600
}
6601
}
7975
$options_updated_counter = 0;
7976
7977
foreach( $sucuriscan_notify_options as $alert_type => $alert_label ){
7978
+ $option_value = SucuriScanRequest::post($alert_type, '(1|0)');
7979
+
7980
+ if( $option_value !== FALSE ){
7981
$option_value = ( $option_value == '1' ) ? 'enabled' : 'disabled';
7982
SucuriScanOption::update_option( $alert_type, $option_value );
7983
$options_updated_counter += 1;