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

Version Description

This version adds an option to refresh the malware scan results on demand, as well as several small bug fixes and improvements.

=

Download this release

Release Info

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

Code changes from version 1.8.18 to 1.8.19

inc/tpl/dashboard.html.tpl CHANGED
@@ -28,6 +28,7 @@ jQuery(document).ready(function ($) {
28
  $.post('%%SUCURI.AjaxURL.Dashboard%%', {
29
  action: 'sucuriscan_ajax',
30
  sucuriscan_page_nonce: '%%SUCURI.PageNonce%%',
 
31
  form_action: 'malware_scan',
32
  }, function (data) {
33
  $('#sucuriscan-title-iframes').html(data.iframes.title);
28
  $.post('%%SUCURI.AjaxURL.Dashboard%%', {
29
  action: 'sucuriscan_ajax',
30
  sucuriscan_page_nonce: '%%SUCURI.PageNonce%%',
31
+ sucuriscan_sitecheck_refresh: '%%SUCURI.SiteCheck.Refresh%%',
32
  form_action: 'malware_scan',
33
  }, function (data) {
34
  $('#sucuriscan-title-iframes').html(data.iframes.title);
inc/tpl/integrity.html.tpl CHANGED
@@ -6,6 +6,7 @@ jQuery(document).ready(function ($) {
6
  $.post('%%SUCURI.AjaxURL.Dashboard%%', {
7
  action: 'sucuriscan_ajax',
8
  sucuriscan_page_nonce: '%%SUCURI.PageNonce%%',
 
9
  form_action: 'check_wordpress_integrity',
10
  }, function (data) {
11
  $('#sucuriscan-integrity-response').html(data);
6
  $.post('%%SUCURI.AjaxURL.Dashboard%%', {
7
  action: 'sucuriscan_ajax',
8
  sucuriscan_page_nonce: '%%SUCURI.PageNonce%%',
9
+ sucuriscan_sitecheck_refresh: '%%SUCURI.SiteCheck.Refresh%%',
10
  form_action: 'check_wordpress_integrity',
11
  }, function (data) {
12
  $('#sucuriscan-integrity-response').html(data);
inc/tpl/sitecheck-details.html.tpl CHANGED
@@ -4,3 +4,10 @@
4
  %%%SUCURI.SiteCheck.Metadata%%%
5
  </ul>
6
  </div>
 
 
 
 
 
 
 
4
  %%%SUCURI.SiteCheck.Metadata%%%
5
  </ul>
6
  </div>
7
+
8
+ <div class="sucuriscan-cache-expiration">
9
+ <small>
10
+ This information will be updated %%SUCURI.SiteCheck.Lifetime%%
11
+ &mdash; <a href="%%SUCURI.URL.Dashboard%%&sucuriscan_sitecheck_refresh=true">Refresh Malware Scan</a>
12
+ </small>
13
+ </div>
inc/tpl/sitecheck-recommendations.html.tpl CHANGED
@@ -1,6 +1,6 @@
1
 
2
- <div class="sucuriscan-panel sucuriscan-sitecheck-list sucuriscan-sitecheck-recommendations sucuriscan-%%SUCURI.Recommendations.Visibility%%">
3
- <h3 class="sucuriscan-tag-title sucuriscan-tag-blue">Recomendations</h3>
4
 
5
  <ul>
6
  %%%SUCURI.Recommendations.Content%%%
1
 
2
+ <div class="sucuriscan-panel sucuriscan-sitecheck-list sucuriscan-sitecheck-recommendations">
3
+ <h3 class="sucuriscan-tag-title sucuriscan-tag-%%SUCURI.Recommendations.Color%%">Recomendations</h3>
4
 
5
  <ul>
6
  %%%SUCURI.Recommendations.Content%%%
readme.txt CHANGED
@@ -3,8 +3,8 @@ Contributors: dd@sucuri.net
3
  Donate Link: https://sucuri.net/
4
  Tags: malware, security, firewall, scan, spam, virus, sucuri, protection, blacklist, detection, hardening, file integrity
5
  Requires at least: 3.6
6
- Tested up to: 4.9.4
7
- Stable tag: 1.8.18
8
 
9
  The Sucuri WordPress Security plugin is a security toolset for security integrity monitoring, malware detection and security hardening.
10
 
@@ -185,11 +185,16 @@ We take your privacy seriously. For free plugin users without an API key, no inf
185
 
186
  == Upgrade Notice ==
187
 
188
- = 1.8.15 =
189
- This version adds support for the latest version of WordPress. Introduces new features and fixes some bugs reported by the WordPress community as well as bugs found by our automated testing system.
190
 
191
  == Changelog ==
192
 
 
 
 
 
 
193
  = 1.8.18 =
194
  * Keep settings when the plugin is deactivated, unless the plugin is uninstalled
195
 
3
  Donate Link: https://sucuri.net/
4
  Tags: malware, security, firewall, scan, spam, virus, sucuri, protection, blacklist, detection, hardening, file integrity
5
  Requires at least: 3.6
6
+ Tested up to: 5.0.3
7
+ Stable tag: 1.8.19
8
 
9
  The Sucuri WordPress Security plugin is a security toolset for security integrity monitoring, malware detection and security hardening.
10
 
185
 
186
  == Upgrade Notice ==
187
 
188
+ = 1.8.19 =
189
+ This version adds an option to refresh the malware scan results on demand, as well as several small bug fixes and improvements.
190
 
191
  == Changelog ==
192
 
193
+ = 1.8.19 =
194
+ * Add option to refresh the SiteCheck malware scan results
195
+ * Add support for a CLI command to ignore files in the core integrity check
196
+ * Fix text
197
+
198
  = 1.8.18 =
199
  * Keep settings when the plugin is deactivated, unless the plugin is uninstalled
200
 
src/base.lib.php CHANGED
@@ -877,6 +877,10 @@ class SucuriScan
877
  */
878
  public static function implode($separator = '', $list = array())
879
  {
 
 
 
 
880
  if (self::isMultiList($list)) {
881
  $pieces = array();
882
 
877
  */
878
  public static function implode($separator = '', $list = array())
879
  {
880
+ if (!is_array($list)) {
881
+ return 'INVALID_ARGS';
882
+ }
883
+
884
  if (self::isMultiList($list)) {
885
  $pieces = array();
886
 
src/cache.lib.php CHANGED
@@ -288,9 +288,39 @@ class SucuriScanCache extends SucuriScan
288
 
289
  $finfo['info']['fpath'] = $this->datastore_path;
290
 
 
 
 
 
 
 
 
 
291
  return $finfo['info'];
292
  }
293
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
294
  /**
295
  * Get the total number of unique entries in the datastore file.
296
  *
288
 
289
  $finfo['info']['fpath'] = $this->datastore_path;
290
 
291
+ if (!isset($finfo['info']['created_on'])) {
292
+ $finfo['info']['created_on'] = time();
293
+ }
294
+
295
+ if (!isset($finfo['info']['updated_on'])) {
296
+ $finfo['info']['updated_on'] = time();
297
+ }
298
+
299
  return $finfo['info'];
300
  }
301
 
302
+ /**
303
+ * Returns the Unix timestamp when the cache was created.
304
+ *
305
+ * @return int Unix timestamp when the cache was created.
306
+ */
307
+ public function createdAt()
308
+ {
309
+ $info = $this->getDatastoreInfo();
310
+ return (int) $info['created_on'];
311
+ }
312
+
313
+ /**
314
+ * Returns the Unix timestamp when the cache was updated.
315
+ *
316
+ * @return int Unix timestamp when the cache was updated.
317
+ */
318
+ public function updatedAt()
319
+ {
320
+ $info = $this->getDatastoreInfo();
321
+ return (int) $info['updated_on'];
322
+ }
323
+
324
  /**
325
  * Get the total number of unique entries in the datastore file.
326
  *
src/cli.lib.php CHANGED
@@ -88,6 +88,81 @@ class SucuriScanCLI extends WP_CLI_Command
88
 
89
  WP_CLI::success($message);
90
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
  }
92
 
93
  WP_CLI::add_command('sucuri', 'SucuriScanCLI');
88
 
89
  WP_CLI::success($message);
90
  }
91
+
92
+ /**
93
+ * Manage which files are included in Sucuri integrity checks.
94
+ *
95
+ * ## OPTIONS
96
+ *
97
+ * <action>
98
+ * : The action to be taken (ignore or unignore).
99
+ *
100
+ * <file_path>
101
+ * : Relative path to a file.
102
+ *
103
+ * [--reason=<reason>]
104
+ * : Why the file should be ignored from integrity checks.
105
+ * ---
106
+ * default: added
107
+ * options:
108
+ * - added
109
+ * - modified
110
+ * - removed
111
+ * ---
112
+ *
113
+ * ## EXAMPLES
114
+ *
115
+ * # Ignore a file
116
+ * wp sucuri integrity ignore wp-admin/install.php --reason=removed
117
+ * Success: 'wp-admin/install.php' file successfully ignored.
118
+ *
119
+ * # Unignore a file
120
+ * wp sucuri integrity unignore foo.php
121
+ * Success: 'foo.php' file successfully unignored.
122
+ *
123
+ * @param array $args Arguments from the command line interface.
124
+ * @param array $assoc_args Associative arguments from the command line interface.
125
+ * @return void
126
+ */
127
+ public function integrity($args, $assoc_args)
128
+ {
129
+ list($action, $file_path) = $args;
130
+
131
+ $allowed_actions = array('ignore', 'unignore');
132
+
133
+ if (! in_array($action, $allowed_actions, true)) {
134
+ WP_CLI::error("Requested action '{$action}' is not supported.");
135
+ }
136
+
137
+ $allowed_reasons = array('added', 'modified', 'removed');
138
+
139
+ $file_status = WP_CLI\Utils\get_flag_value( $assoc_args, 'reason', $default = 'added' );
140
+
141
+ if (! in_array($file_status, $allowed_reasons, true)) {
142
+ WP_CLI::error("Specified reason '{$file_status}' is not supported.");
143
+ }
144
+
145
+ $cache = new SucuriScanCache('integrity');
146
+
147
+ $cache_key = md5($file_path);
148
+
149
+ if ('ignore' === $action) {
150
+ $cache->add(
151
+ $cache_key,
152
+ array(
153
+ 'file_path' => $file_path,
154
+ 'file_status' => $file_status,
155
+ 'ignored_at' => time(),
156
+ )
157
+ );
158
+ WP_CLI::success("'{$file_path}' file successfully ignored.");
159
+ }
160
+
161
+ if ('unignore' === $action) {
162
+ $cache->delete($cache_key);
163
+ WP_CLI::success("'{$file_path}' file successfully unignored.");
164
+ }
165
+ }
166
  }
167
 
168
  WP_CLI::add_command('sucuri', 'SucuriScanCLI');
src/pagehandler.php CHANGED
@@ -40,6 +40,7 @@ function sucuriscan_page()
40
  $params['AuditLogs'] = SucuriScanAuditLogs::pageAuditLogs();
41
 
42
  /* load data for the SiteCheck section */
 
43
  $params['SiteCheck.iFramesTitle'] = 'iFrames';
44
  $params['SiteCheck.LinksTitle'] = 'Links';
45
  $params['SiteCheck.ScriptsTitle'] = 'Scripts';
@@ -50,6 +51,10 @@ function sucuriscan_page()
50
  $params['SiteCheck.Blacklist'] = '<div id="sucuriscan-blacklist"></div>';
51
  $params['SiteCheck.Recommendations'] = '<div id="sucuriscan-recommendations"></div>';
52
 
 
 
 
 
53
  echo SucuriScanTemplate::getTemplate('dashboard', $params);
54
  }
55
 
40
  $params['AuditLogs'] = SucuriScanAuditLogs::pageAuditLogs();
41
 
42
  /* load data for the SiteCheck section */
43
+ $params['SiteCheck.Refresh'] = 'false';
44
  $params['SiteCheck.iFramesTitle'] = 'iFrames';
45
  $params['SiteCheck.LinksTitle'] = 'Links';
46
  $params['SiteCheck.ScriptsTitle'] = 'Scripts';
51
  $params['SiteCheck.Blacklist'] = '<div id="sucuriscan-blacklist"></div>';
52
  $params['SiteCheck.Recommendations'] = '<div id="sucuriscan-recommendations"></div>';
53
 
54
+ if (SucuriScanRequest::get(':sitecheck_refresh') !== false) {
55
+ $params['SiteCheck.Refresh'] = 'true';
56
+ }
57
+
58
  echo SucuriScanTemplate::getTemplate('dashboard', $params);
59
  }
60
 
src/settings-hardening.php CHANGED
@@ -144,7 +144,7 @@ class SucuriScanHardeningPage extends SucuriScan
144
 
145
  $params['URL.Settings'] = admin_url('update-core.php');
146
  $params['Hardening.Status'] = 0;
147
- $params['Hardening.FieldText'] = 'Apply Hardening';
148
  $params['Hardening.Title'] = 'Verify WordPress Version';
149
  $params['Hardening.Description'] = 'Why keep your site updated? WordPr'
150
  . 'ess is an open-source project which means that with every update th'
@@ -154,7 +154,7 @@ class SucuriScanHardeningPage extends SucuriScan
154
 
155
  if (isset($updates[0]) && $updates[0] instanceof stdClass) {
156
  if ($updates[0]->response == 'latest' || $updates[0]->response == 'development') {
157
- $params['Hardening.FieldText'] = 'Revert Hardening';
158
  $params['Hardening.FieldAttrs'] = 'disabled';
159
  $params['Hardening.Status'] = 1;
160
  }
144
 
145
  $params['URL.Settings'] = admin_url('update-core.php');
146
  $params['Hardening.Status'] = 0;
147
+ $params['Hardening.FieldText'] = 'Check Updates Now';
148
  $params['Hardening.Title'] = 'Verify WordPress Version';
149
  $params['Hardening.Description'] = 'Why keep your site updated? WordPr'
150
  . 'ess is an open-source project which means that with every update th'
154
 
155
  if (isset($updates[0]) && $updates[0] instanceof stdClass) {
156
  if ($updates[0]->response == 'latest' || $updates[0]->response == 'development') {
157
+ $params['Hardening.FieldText'] = 'WordPress Update Available';
158
  $params['Hardening.FieldAttrs'] = 'disabled';
159
  $params['Hardening.Status'] = 1;
160
  }
src/sitecheck.lib.php CHANGED
@@ -112,6 +112,12 @@ class SucuriScanSiteCheck extends SucuriScanAPI
112
  public static function scanAndCollectData()
113
  {
114
  $cache = new SucuriScanCache('sitecheck');
 
 
 
 
 
 
115
  $results = $cache->get('scan_results', SUCURISCAN_SITECHECK_LIFETIME, 'array');
116
 
117
  /* return cached malware scan results. */
@@ -140,6 +146,21 @@ class SucuriScanSiteCheck extends SucuriScanAPI
140
  return $results;
141
  }
142
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
143
  /**
144
  * Generates the HTML section for the SiteCheck details.
145
  *
@@ -152,6 +173,8 @@ class SucuriScanSiteCheck extends SucuriScanAPI
152
  $data['details'] = array();
153
 
154
  $params['SiteCheck.Metadata'] = '';
 
 
155
  $data['details'][] = 'PHP Version: ' . phpversion();
156
  $data['details'][] = 'Version: ' . SucuriScan::siteVersion();
157
 
@@ -332,9 +355,14 @@ class SucuriScanSiteCheck extends SucuriScanAPI
332
  {
333
  $params = array();
334
  $data = self::scanAndCollectData();
 
 
 
 
 
335
 
336
  $params['Recommendations.Content'] = '';
337
- $params['Recommendations.Visibility'] = 'hidden';
338
 
339
  if (isset($data['RECOMMENDATIONS'])) {
340
  foreach ($data['RECOMMENDATIONS'] as $recommendation) {
@@ -342,7 +370,19 @@ class SucuriScanSiteCheck extends SucuriScanAPI
342
  continue;
343
  }
344
 
345
- $params['Recommendations.Visibility'] = 'visible';
 
 
 
 
 
 
 
 
 
 
 
 
346
  $params['Recommendations.Content'] .= SucuriScanTemplate::getSnippet(
347
  'sitecheck-recommendations',
348
  array(
@@ -354,6 +394,12 @@ class SucuriScanSiteCheck extends SucuriScanAPI
354
  }
355
  }
356
 
 
 
 
 
 
 
357
  return SucuriScanTemplate::getSection('sitecheck-recommendations', $params);
358
  }
359
 
@@ -474,7 +520,7 @@ class SucuriScanSiteCheck extends SucuriScanAPI
474
  }
475
 
476
  // Extract the information from the malware message.
477
- $malware_parts = explode("\n", $malware[1]);
478
 
479
  if (isset($malware_parts[1])) {
480
  $pattern = ".\x20Details:\x20";
112
  public static function scanAndCollectData()
113
  {
114
  $cache = new SucuriScanCache('sitecheck');
115
+
116
+ if (SucuriScanRequest::post(':sitecheck_refresh') === 'true') {
117
+ /* user requested to reset the sitecheck cache */
118
+ $cache->delete('scan_results');
119
+ }
120
+
121
  $results = $cache->get('scan_results', SUCURISCAN_SITECHECK_LIFETIME, 'array');
122
 
123
  /* return cached malware scan results. */
146
  return $results;
147
  }
148
 
149
+ /**
150
+ * Returns the amount of time left before the SiteCheck cache expires.
151
+ *
152
+ * @return string Time left before the SiteCheck cache expires.
153
+ */
154
+ private static function cacheLifetime()
155
+ {
156
+ $current = time();
157
+ $cache = new SucuriScanCache('sitecheck');
158
+ $timeDiff = $current - $cache->updatedAt();
159
+ $timeLeft = SUCURISCAN_SITECHECK_LIFETIME - $timeDiff;
160
+
161
+ return self::humanTime($current + $timeLeft);
162
+ }
163
+
164
  /**
165
  * Generates the HTML section for the SiteCheck details.
166
  *
173
  $data['details'] = array();
174
 
175
  $params['SiteCheck.Metadata'] = '';
176
+ $params['SiteCheck.Lifetime'] = self::cacheLifetime();
177
+
178
  $data['details'][] = 'PHP Version: ' . phpversion();
179
  $data['details'][] = 'Version: ' . SucuriScan::siteVersion();
180
 
355
  {
356
  $params = array();
357
  $data = self::scanAndCollectData();
358
+ $sechead = array(
359
+ 'x-content-type-options' => 'X-Content-Type-Options Header',
360
+ 'x-frame-options' => 'X-Frame-Options Security Header',
361
+ 'x-xss-protection' => 'X-XSS-Protection Security Header',
362
+ );
363
 
364
  $params['Recommendations.Content'] = '';
365
+ $params['Recommendations.Color'] = 'green';
366
 
367
  if (isset($data['RECOMMENDATIONS'])) {
368
  foreach ($data['RECOMMENDATIONS'] as $recommendation) {
370
  continue;
371
  }
372
 
373
+ if (stripos($recommendation[0], 'x-content-type')) {
374
+ unset($sechead['x-content-type-options']);
375
+ }
376
+
377
+ if (stripos($recommendation[0], 'x-frame-options')) {
378
+ unset($sechead['x-frame-options']);
379
+ }
380
+
381
+ if (stripos($recommendation[0], 'x-xss-protection')) {
382
+ unset($sechead['x-xss-protection']);
383
+ }
384
+
385
+ $params['Recommendations.Color'] = 'blue';
386
  $params['Recommendations.Content'] .= SucuriScanTemplate::getSnippet(
387
  'sitecheck-recommendations',
388
  array(
394
  }
395
  }
396
 
397
+ foreach ($sechead as $header => $message) {
398
+ $params['Recommendations.Content'] .=
399
+ '<li class="sucuriscan-sitecheck-list-INFO">'
400
+ . $message . '</li>';
401
+ }
402
+
403
  return SucuriScanTemplate::getSection('sitecheck-recommendations', $params);
404
  }
405
 
520
  }
521
 
522
  // Extract the information from the malware message.
523
+ $malware_parts = explode("\n", $malware[1], 2);
524
 
525
  if (isset($malware_parts[1])) {
526
  $pattern = ".\x20Details:\x20";
sucuri.php CHANGED
@@ -6,7 +6,7 @@
6
  * Plugin URI: https://wordpress.sucuri.net/
7
  * Author URI: https://sucuri.net/
8
  * Author: Sucuri Inc.
9
- * Version: 1.8.18
10
  *
11
  * PHP version 5
12
  *
@@ -83,7 +83,7 @@ define('SUCURISCAN', 'sucuriscan');
83
  /**
84
  * Current version of the plugin's code.
85
  */
86
- define('SUCURISCAN_VERSION', '1.8.18');
87
 
88
  /**
89
  * Defines the human readable name of the plugin.
@@ -252,6 +252,7 @@ function sucuriscanResetAndDeactivate()
252
  {
253
  /* Delete scheduled task from the system */
254
  wp_clear_scheduled_hook('sucuriscan_scheduled_scan');
 
255
  }
256
 
257
  /**
@@ -303,6 +304,8 @@ function sucuriscanUninstall()
303
  $fifo->run_recursively = false;
304
  $directory = SucuriScan::dataStorePath();
305
  $fifo->removeDirectoryTree($directory);
 
 
306
  }
307
 
308
  register_deactivation_hook(__FILE__, 'sucuriscanResetAndDeactivate');
6
  * Plugin URI: https://wordpress.sucuri.net/
7
  * Author URI: https://sucuri.net/
8
  * Author: Sucuri Inc.
9
+ * Version: 1.8.19
10
  *
11
  * PHP version 5
12
  *
83
  /**
84
  * Current version of the plugin's code.
85
  */
86
+ define('SUCURISCAN_VERSION', '1.8.19');
87
 
88
  /**
89
  * Defines the human readable name of the plugin.
252
  {
253
  /* Delete scheduled task from the system */
254
  wp_clear_scheduled_hook('sucuriscan_scheduled_scan');
255
+ SucuriScanEvent::reportDebugEvent('Sucuri plugin has been deactivated');
256
  }
257
 
258
  /**
304
  $fifo->run_recursively = false;
305
  $directory = SucuriScan::dataStorePath();
306
  $fifo->removeDirectoryTree($directory);
307
+
308
+ SucuriScanEvent::reportDebugEvent('Sucuri plugin has been uninstalled');
309
  }
310
 
311
  register_deactivation_hook(__FILE__, 'sucuriscanResetAndDeactivate');