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$/', $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_]+)$/', $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_]+)=(.*);$/', $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)$/', $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$',
@@ -6391,14 +6572,30 @@ function sucuriscan_ignore_integrity_filepath( $filepath='' ){
6391
  '^(503|404)\.php$',
6392
  '^500\.(shtml|php)$',
6393
  '^40[0-9]\.shtml$',
6394
- '^([^\/]*)\.(pdf|css)$',
6395
  '^google[0-9a-z]{16}\.html$',
6396
  '^pinterest-[0-9a-z]{5}\.html$',
6397
  '(^|\/)error_log$',
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$/', $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_]+)$/';
1367
+ }
1368
+
1369
+ if( $action == 'content' ){
1370
+ return '/^([0-9a-zA-Z_]+):(.+)/';
1371
+ }
1372
 
1373
+ if( $action == 'header' ){
1374
+ return '/^\/\/ ([a-z_]+)=(.*);$/';
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)$/', $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$',
6572
  '^(503|404)\.php$',
6573
  '^500\.(shtml|php)$',
6574
  '^40[0-9]\.shtml$',
6575
+ '^([^\/]*)\.(pdf|css|txt)$',
6576
  '^google[0-9a-z]{16}\.html$',
6577
  '^pinterest-[0-9a-z]{5}\.html$',
6578
  '(^|\/)error_log$',
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;