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

Version Description

  • Fixed fatal error when PHPMailer failed
  • Fixed incorrect selected value in settings
  • Fixed kb links and content.
  • Added SiteCheck for arbitrary domain
  • Various code cleanup
Download this release

Release Info

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

Code changes from version 1.8.1 to 1.8.3

inc/tpl/bsidebar.html.tpl CHANGED
@@ -12,7 +12,7 @@
12
  </div>
13
  </div>
14
 
15
- <a href="https://goo.gl/9sD2sh" target="_blank" class="sucuriscan-ad-btn">Protect Your Website Today</a>
16
 
17
  <div class="sucuriscan-ad-footer">
18
  <ul>
@@ -32,7 +32,7 @@
32
  <h4>Blacklisted by Google?</h4>
33
  </div>
34
 
35
- <a href="https://goo.gl/vEwZq6" target="_blank" class="sucuriscan-ad-btn">Get Clean Today</a>
36
 
37
  <div class="sucuriscan-ad-footer sucuriscan-clearfix">
38
  <div class="sucuriscan-pull-left">
12
  </div>
13
  </div>
14
 
15
+ <a href="https://sucuri.net/lp/plugin/wp-pn-protect-wordpress" target="_blank" class="sucuriscan-ad-btn">Protect Your Website Today</a>
16
 
17
  <div class="sucuriscan-ad-footer">
18
  <ul>
32
  <h4>Blacklisted by Google?</h4>
33
  </div>
34
 
35
+ <a href="https://sucuri.net/lp/plugin/wp-pn-clean-wordpress-hack" target="_blank" class="sucuriscan-ad-btn">Get Clean Today</a>
36
 
37
  <div class="sucuriscan-ad-footer sucuriscan-clearfix">
38
  <div class="sucuriscan-pull-left">
inc/tpl/malwarescan.html.tpl CHANGED
@@ -2,7 +2,7 @@
2
  <div class="sucuriscan-loading">
3
  <h3 class="title">Website Security Scans by Sucuri Sitecheck</h3>
4
 
5
- <p class="description">Visit our <a href="https://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%%" />
2
  <div class="sucuriscan-loading">
3
  <h3 class="title">Website Security Scans by Sucuri Sitecheck</h3>
4
 
5
+ <p class="description">Visit our <a href="https://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%%" />
inc/tpl/settings-datastorage-files.snippet.tpl ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ <tr class="%%SUCURI.DataStorage.CssClass%%">
3
+ <td class="check-column">
4
+ <input type="checkbox" name="sucuriscan_fnames[]"
5
+ %%SUCURI.DataStorage.DisabledInput%%
6
+ value="%%SUCURI.DataStorage.Fname%%" />
7
+ </td>
8
+ <td><span class="sucuriscan-monospace">%%SUCURI.DataStorage.Fpath%%</span></td>
9
+ <td><span class="sucuriscan-monospace">%%SUCURI.DataStorage.Exists%%</span></td>
10
+ <td><span class="sucuriscan-monospace">%%SUCURI.DataStorage.IsWritable%%</span></td>
11
+ </tr>
inc/tpl/settings-general-datastorage.html.tpl CHANGED
@@ -14,49 +14,55 @@
14
 
15
  <div class="sucuriscan-inline-alert-warning">
16
  <p>
17
- Note that the virtual protection added by the plugin to these files is not bullet
18
- proof, it may be bypassed and depending on the configuration of the server it may
19
- leak information, but this is better than to store the data in the database and
20
- wait for a SQL injection to be used to attack the rest of the site.
 
 
21
  </p>
22
  </div>
23
 
24
- <div class="sucuriscan-inline-alert-info">
25
- <p>
26
- There are some entries in the options table that will be moved to a plain text
27
- file during the development of the next version of the plugin, this is part of
28
- a plan to include a way to import and export the settings of this extension to
29
- other sites in an easy way. This is necessary as importing data into a database
30
- may open security holes <em>(depending on how the code is written)</em> to reduce
31
- the risk we will use plain text files which makes things a bit safer.
32
- </p>
33
  </div>
34
 
 
 
 
 
 
 
 
 
 
 
35
  <div class="sucuriscan-inline-alert-info">
36
  <p>
37
- An alternative to this setting you can opt to set the directory path from the
38
- WordPress configuration file using a constant named <em>"SUCURI_DATA_STORAGE"</em>
39
- it must contain a valid and existing absolute directory path.
 
 
40
  </p>
41
  </div>
42
 
43
- <div class="sucuriscan-hstatus sucuriscan-hstatus-2">
44
- <span class="sucuriscan-monospace">%%SUCURI.DatastorePath%%</span>
45
- </div>
46
-
47
- <p>
48
- Some people may prefer to use a folder that is not in the document root of the
49
- website to add another layer of protection to the data, feel free to change this
50
- path if you want, make sure to use absolute paths.
51
- </p>
 
 
 
52
 
53
- <form action="%%SUCURI.URL.Settings%%" method="post">
54
- <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
55
- <span class="sucuriscan-input-group">
56
- <label>Data Storage Path:</label>
57
- <input type="text" name="sucuriscan_datastore_path" class="input-text" />
58
- </span>
59
- <button type="submit" class="button-primary">Proceed</button>
60
- </form>
61
  </div>
62
  </div>
14
 
15
  <div class="sucuriscan-inline-alert-warning">
16
  <p>
17
+ The plugin requires write permissions in this directory as well
18
+ as the files contained in it. If you prefer to keep these files
19
+ in a non-public directory <em>(one level up the document root)
20
+ </em> please define a constant in the <em>"wp-config.php"</em>
21
+ file named <em>"SUCURI_DATA_STORAGE"</em> with the absolute path
22
+ to the new directory.
23
  </p>
24
  </div>
25
 
26
+ <div class="sucuriscan-hstatus sucuriscan-hstatus-2">
27
+ <span class="sucuriscan-monospace">%%SUCURI.DatastorePath%%</span>
 
 
 
 
 
 
 
28
  </div>
29
 
30
+ <p>
31
+ As of version 1.7.18 the plugin started using a plain text file named
32
+ <em>"sucuri-settings.php"</em> to store its settings instead of the
33
+ database, this was both a security measure and a mechanism to simplify
34
+ the management of the settings for multisite installations. Options
35
+ created in the database by previous versions of the plugin will be
36
+ migrated to the settings file if it is writable, otherwise they will
37
+ remain in the database until the user grants write permissions.
38
+ </p>
39
+
40
  <div class="sucuriscan-inline-alert-info">
41
  <p>
42
+ Add this <code>define('SUCURI_SETTINGS_IN', 'database');</code>
43
+ in the configuration file if you want to keep using the database.
44
+ However, we encourage you to keep using the plain text files as
45
+ this guarantees that the automated tests will cover all the code
46
+ that powers the plugin.
47
  </p>
48
  </div>
49
 
50
+ <table class="wp-list-table widefat sucuriscan-table">
51
+ <thead>
52
+ <tr>
53
+ <th class="manage-column column-cb check-column">
54
+ <label class="screen-reader-text" for="cb-select-all-1">Select All</label>
55
+ <input id="cb-select-all-1" type="checkbox">
56
+ </th>
57
+ <th class="manage-column">File</th>
58
+ <th width="70" class="manage-column">Exists?</th>
59
+ <th width="90" class="manage-column">Writable?</th>
60
+ </tr>
61
+ </thead>
62
 
63
+ <tbody>
64
+ %%%SUCURI.DataStorage.Files%%%
65
+ </tbody>
66
+ </table>
 
 
 
 
67
  </div>
68
  </div>
readme.txt CHANGED
@@ -1,41 +1,39 @@
1
  === Sucuri Security - Auditing, Malware Scanner and Security Hardening ===
2
  Contributors: dd@sucuri.net
3
  Donate Link: https://sucuri.net/
4
- Tags: malware, security, firewall, scan, spam, virus, sucuri, protection,WordPress Security, Login Security,Security Auditing,File Integrity,htaccess,phishing,backdoors,SQL Injection, RFI, LFI, XSS, CSRF, website firewall, Website Security, Performance Optimization, Zero Day, Software Vulnerability, Exploits, Hacks, Attackers, Bad Actors, Reverse Proxy, Two Factor Security, Two Factor Authentication, Security Logs, HeatBleed Vulnerability, Website Protection, Bash Vulnerability, RevSlider Vulnerability, MailPoet Vulnerability, Malware Prevention, Website Firewall, Website AntiVirus, Security Response, Security Detection, Security Prevention
5
  Requires at least:3.2
6
- Stable tag: 1.8.1
7
- Tested up to: 4.5.3
8
 
9
- The Sucuri WordPress Security plugin is a security toolset for security integrity monitoring, malware detection and security hardening.
10
 
11
 
12
  == Description ==
13
 
14
 
15
- Sucuri Inc is a globally recognized authority in all matters related to
16
  website security, with specialization in WordPress Security.
17
 
18
  The Sucuri Security WordPress Security plugin is free to all WordPress users.
19
- It is a security suite meant to complement your existing security posture. It
20
- offers it’s users four key security features for their website, each designed
21
- to have a positive affect on their security posture:
22
 
23
  <ol>
24
- <li>Security Activity Auditing</li>
25
  <li>File Integrity Monitoring</li>
26
  <li>Remote Malware Scanning</li>
27
  <li>Blacklist Monitoring</li>
28
  <li>Effective Security Hardening</li>
29
  <li>Post-Hack Security Actions</li>
30
  <li>Security Notifications</li>
31
- <li>Website Firewall (add on)</li>
32
  </ol>
33
 
34
 
35
- = Security Activity Monitoring =
36
 
37
  This is perhaps the most underutilized security function. It’s the act of
38
- monitoring all security related events within your WordPress install. The
39
  challenge is, what makes up a security event. In the eyes of Sucuri, any
40
  change that occurs within the application could be categorized as a security
41
  event, as such we try to record it.
@@ -44,10 +42,6 @@ This is important because it allows you, the website owner, the ability keep a
44
  good eye on the various changes occurring within your environment. Who is
45
  logging in? What changes are being made?
46
 
47
- Here is a video of the Security Activity Monitoring feature:
48
-
49
- [youtube https://www.youtube.com/watch?v=RwEwJgL2-m8]
50
-
51
  This feature is logging all activity to the Sucuri cloud, for safe keeping.
52
  This ensures that an attacker is not able to wipe your forensic data and
53
  prevent further security analysis after a compromise. If an attacker is able
@@ -76,7 +70,7 @@ Here is a video of the Security File Integrity Monitoring feature:
76
  [youtube https://www.youtube.com/watch?v=JGbHq7OFs3Q]
77
 
78
 
79
- = Remote Security Malware Scanning =
80
 
81
  This feature is powered by our very powerful scanning engine, found on our
82
  free security scanner - <a href="https://sitecheck.sucuri.net">SiteCheck</a>. It’s
@@ -179,13 +173,10 @@ This is coupled with a number of features like:
179
 
180
  This is <strong>not included as a free</strong> option to the plugin, but is
181
  integrated so that if purchased you are able to activate. If you prefer to
182
- leverage the Sucuri Security Website Firewall (CloudProxy) product by itself,
183
  you have the option to operate the <a href="https://wordpress.org/plugins/sucuri-cloudproxy-waf/">
184
  Website Firewall WordPress Security</a> plugin in standalone mode.
185
 
186
- Here is a video of the Sucuri Security Website Firewall (Add On Security Service) feature:
187
-
188
- [youtube https://www.youtube.com/watch?v=fN-3DLObLF0]
189
 
190
  The Sucuri Security WordPress Security plugin is built by the team that is
191
  known for their proactive approach to security. It is built using intelligence
@@ -195,18 +186,18 @@ unique domain scans and 10’s of millions of website security attack blocks.
195
 
196
  == Installation ==
197
 
198
- The installation of the Sucuri Security WordPress Security plugin is very
199
  simple and straight forward. <a
200
  href="https://sucuri.net/wordpress-security-plugin-installation">A detailed
201
  breakdown of the process is available, including images,</a> below however we
202
  outline the bare minimum steps.
203
 
204
- Here is a quick video walking you through the installation and configuration of the Sucuri Security WordPress Security plugin:
205
 
206
  [youtube https://www.youtube.com/watch?v=KC3UC_Y27G0]
207
 
208
 
209
- To install Sucuri Security and complement your Security posture:
210
 
211
 
212
  1. You will want to log into your WordPress administration panel - (e.g.,
@@ -270,7 +261,7 @@ end-user. We've narrowed the key features we felt were most pertinent to any
270
  website owner and integrated them into this plugin.
271
 
272
 
273
- = If I install the Sucuri Security plugin do I get a Sucuri account? =
274
 
275
  No, this is a free plugin that we offer at no charge. It does not mean you get a free account.
276
 
@@ -354,6 +345,23 @@ service from the WordPress dashboard.
354
 
355
  == Changelog ==
356
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
357
  = 1.8.1 =
358
  * Modified default setting for the core integrity alerts
359
  * Added more files to the core integrity ignore list
1
  === Sucuri Security - Auditing, Malware Scanner and Security Hardening ===
2
  Contributors: dd@sucuri.net
3
  Donate Link: https://sucuri.net/
4
+ Tags: security, malware, firewall, scan, spam, virus, sucuri, protection, backdoors, protection, prevention, monitoring, integrity, auditlog
5
  Requires at least:3.2
6
+ Stable tag: 1.8.3
7
+ Tested up to: 4.6.1
8
 
9
+ The Sucuri WordPress Security plugin is a toolset for security integrity monitoring, malware detection, audit logging and security hardening.
10
 
11
 
12
  == Description ==
13
 
14
 
15
+ Sucuri is a globally recognized authority in all matters related to
16
  website security, with specialization in WordPress Security.
17
 
18
  The Sucuri Security WordPress Security plugin is free to all WordPress users.
19
+ It is a security suite meant to complement your existing security posture with
20
+ seven key security features:
 
21
 
22
  <ol>
23
+ <li>Security Activity Audit Logging</li>
24
  <li>File Integrity Monitoring</li>
25
  <li>Remote Malware Scanning</li>
26
  <li>Blacklist Monitoring</li>
27
  <li>Effective Security Hardening</li>
28
  <li>Post-Hack Security Actions</li>
29
  <li>Security Notifications</li>
 
30
  </ol>
31
 
32
 
33
+ = Security Activity Audit Logging =
34
 
35
  This is perhaps the most underutilized security function. It’s the act of
36
+ monitoring all security related events within your WordPress site. The
37
  challenge is, what makes up a security event. In the eyes of Sucuri, any
38
  change that occurs within the application could be categorized as a security
39
  event, as such we try to record it.
42
  good eye on the various changes occurring within your environment. Who is
43
  logging in? What changes are being made?
44
 
 
 
 
 
45
  This feature is logging all activity to the Sucuri cloud, for safe keeping.
46
  This ensures that an attacker is not able to wipe your forensic data and
47
  prevent further security analysis after a compromise. If an attacker is able
70
  [youtube https://www.youtube.com/watch?v=JGbHq7OFs3Q]
71
 
72
 
73
+ = Remote Malware Scanning =
74
 
75
  This feature is powered by our very powerful scanning engine, found on our
76
  free security scanner - <a href="https://sitecheck.sucuri.net">SiteCheck</a>. It’s
173
 
174
  This is <strong>not included as a free</strong> option to the plugin, but is
175
  integrated so that if purchased you are able to activate. If you prefer to
176
+ leverage the Sucuri Firewall (CloudProxy) product by itself,
177
  you have the option to operate the <a href="https://wordpress.org/plugins/sucuri-cloudproxy-waf/">
178
  Website Firewall WordPress Security</a> plugin in standalone mode.
179
 
 
 
 
180
 
181
  The Sucuri Security WordPress Security plugin is built by the team that is
182
  known for their proactive approach to security. It is built using intelligence
186
 
187
  == Installation ==
188
 
189
+ The installation of the Sucuri WordPress Security plugin is very
190
  simple and straight forward. <a
191
  href="https://sucuri.net/wordpress-security-plugin-installation">A detailed
192
  breakdown of the process is available, including images,</a> below however we
193
  outline the bare minimum steps.
194
 
195
+ Here is a quick video walking you through the installation and configuration of the Sucuri WordPress Security plugin:
196
 
197
  [youtube https://www.youtube.com/watch?v=KC3UC_Y27G0]
198
 
199
 
200
+ To install Sucuri and complement your Security posture:
201
 
202
 
203
  1. You will want to log into your WordPress administration panel - (e.g.,
261
  website owner and integrated them into this plugin.
262
 
263
 
264
+ = If I install the Sucuri plugin do I get a Sucuri account? =
265
 
266
  No, this is a free plugin that we offer at no charge. It does not mean you get a free account.
267
 
345
 
346
  == Changelog ==
347
 
348
+ = 1.8.3 =
349
+ * Fixed fatal error when PHPMailer failed
350
+ * Fixed incorrect selected value in settings
351
+ * Fixed kb links and content.
352
+ * Added SiteCheck for arbitrary domain
353
+ * Various code cleanup
354
+
355
+ = 1.8.2 =
356
+ * Modified logic of the settings in database checker
357
+ * Modified default value for the available updates alerts
358
+ * Fixed undefined array and object keys in audit logs
359
+ * Fixed incompatibilities with foreign API service responses
360
+ * Added development option to keep using the database
361
+ * Added panel with information about the plugin settings
362
+ * Added conditional to prevent redeclaration of class
363
+ * Fixed cache flush function used to delete datastore
364
+
365
  = 1.8.1 =
366
  * Modified default setting for the core integrity alerts
367
  * Added more files to the core integrity ignore list
sucuri.php CHANGED
@@ -1,10 +1,10 @@
1
  <?php
2
  /*
3
  Plugin Name: Sucuri Security - Auditing, Malware Scanner and Hardening
4
- Plugin URI: https://wordpress.sucuri.net/
5
- Description: The <a href="https://sucuri.net/" target="_blank">Sucuri</a> plugin provides the website owner the best Activity Auditing, SiteCheck Remote Malware Scanning, Effective Security Hardening and Post-Hack features. 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.8.1
8
  Author URI: https://sucuri.net
9
  */
10
 
@@ -14,9 +14,9 @@ Author URI: https://sucuri.net
14
  *
15
  * @package Sucuri Security
16
  * @author Daniel Cid <dcid@sucuri.net>
17
- * @copyright Since 2010-2015 Sucuri Inc.
18
  * @license Released under the GPL - see LICENSE file for details.
19
- * @link https://wordpress.sucuri.net/
20
  * @since File available since Release 0.1
21
  */
22
 
@@ -65,7 +65,7 @@ define('SUCURISCAN', 'sucuriscan');
65
  /**
66
  * Current version of the plugin's code.
67
  */
68
- define('SUCURISCAN_VERSION', '1.8.1');
69
 
70
  /**
71
  * The name of the Sucuri plugin main file.
@@ -438,6 +438,31 @@ class SucuriScan
438
  {
439
  }
440
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
441
  /**
442
  * Return name of a variable with the plugin's prefix (if needed).
443
  *
@@ -606,49 +631,9 @@ class SucuriScan
606
  */
607
  public static function datastore_folder_path($path = '')
608
  {
609
- $default_dir = 'sucuri';
610
- $abspath = self::fixPath(ABSPATH);
611
-
612
- if (defined('SUCURI_DATA_STORAGE')
613
- && file_exists(SUCURI_DATA_STORAGE)
614
- && is_dir(SUCURI_DATA_STORAGE)
615
- ) {
616
- $datastore = SUCURI_DATA_STORAGE;
617
- } else {
618
- $datastore = SucuriScanOption::get_option(':datastore_path');
619
- }
620
-
621
- // Use the uploads folder by default.
622
- if (empty($datastore)) {
623
- $uploads_path = false;
624
 
625
- // Multisite installations may have different paths.
626
- if (function_exists('wp_upload_dir')) {
627
- $upload_dir = wp_upload_dir();
628
-
629
- if (isset($upload_dir['basedir'])) {
630
- $uploads_path = rtrim($upload_dir['basedir'], DIRECTORY_SEPARATOR);
631
- }
632
- }
633
-
634
- if ($uploads_path === false) {
635
- if (defined('WP_CONTENT_DIR')) {
636
- $uploads_path = implode(DIRECTORY_SEPARATOR, array(WP_CONTENT_DIR, 'uploads'));
637
- } else {
638
- $uploads_path = implode(DIRECTORY_SEPARATOR, array($abspath, 'wp-content', 'uploads'));
639
- }
640
- }
641
-
642
- $datastore = $uploads_path . DIRECTORY_SEPARATOR . $default_dir;
643
- $datastore = self::fixPath($datastore);
644
- SucuriScanOption::update_option(':datastore_path', $datastore);
645
- }
646
-
647
- // Keep consistency with the directory separator.
648
- $final = $datastore . DIRECTORY_SEPARATOR . $path;
649
- $final = self::fixPath($final);
650
-
651
- return $final;
652
  }
653
 
654
  /**
@@ -691,9 +676,7 @@ class SucuriScan
691
  }
692
  }
693
 
694
- $wp_version = self::escape($wp_version);
695
-
696
- return $wp_version;
697
  }
698
 
699
  /**
@@ -766,6 +749,7 @@ class SucuriScan
766
  public static function run_scheduled_task()
767
  {
768
  SucuriScanEvent::filesystem_scan();
 
769
  sucuriscan_core_files_data(true);
770
  sucuriscan_posthack_updates_content(true);
771
  }
@@ -911,7 +895,7 @@ class SucuriScan
911
  if (function_exists('get_site_url')) {
912
  $site_url = get_site_url();
913
  $pattern = '/([fhtps]+:\/\/)?([^:\/]+)(:[0-9:]+)?(\/.*)?/';
914
- $replacement = ( $return_tld === true ) ? '$2' : '$2$3$4';
915
  $domain_name = @preg_replace($pattern, $replacement, $site_url);
916
 
917
  return $domain_name;
@@ -987,9 +971,7 @@ class SucuriScan
987
  * the site as protected by a firewall. A fake key can be used to bypass the DNS
988
  * checking, but that is not something that will affect us, only the client.
989
  */
990
- if ($status === false
991
- && SucuriScanAPI::getCloudproxyKey()
992
- ) {
993
  $status = true;
994
  }
995
 
@@ -1050,9 +1032,7 @@ class SucuriScan
1050
  public static function get_admin_users()
1051
  {
1052
  if (function_exists('get_users')) {
1053
- $args = array( 'role' => 'administrator' );
1054
-
1055
- return get_users($args);
1056
  }
1057
 
1058
  return false;
@@ -1076,7 +1056,7 @@ class SucuriScan
1076
  if ($users !== false) {
1077
  foreach ($users as $user) {
1078
  if ($user->user_status === '0') {
1079
- $valid_users[ $user->ID ] = sprintf(
1080
  '%s - %s',
1081
  $user->user_login,
1082
  $user->user_email
@@ -2687,6 +2667,8 @@ class SucuriScanCache extends SucuriScan
2687
  $finfo = $this->getDatastoreContent();
2688
 
2689
  if (!empty($finfo['info'])) {
 
 
2690
  return $finfo['info'];
2691
  }
2692
 
@@ -2869,6 +2851,10 @@ class SucuriScanCache extends SucuriScan
2869
  {
2870
  $finfo = $this->getDatastoreContent();
2871
 
 
 
 
 
2872
  return $this->saveNewEntries($finfo);
2873
  }
2874
  }
@@ -2917,7 +2903,7 @@ class SucuriScanOption extends SucuriScanRequest
2917
  'sucuriscan_cloudproxy_apikey' => '',
2918
  'sucuriscan_collect_wrong_passwords' => 'disabled',
2919
  'sucuriscan_comment_monitor' => 'disabled',
2920
- 'sucuriscan_datastore_path' => '',
2921
  'sucuriscan_dismiss_setup' => 'disabled',
2922
  'sucuriscan_dns_lookups' => 'enabled',
2923
  'sucuriscan_email_subject' => 'Sucuri Alert, :domain, :event',
@@ -2936,7 +2922,7 @@ class SucuriScanOption extends SucuriScanRequest
2936
  'sucuriscan_lastlogin_redirection' => 'enabled',
2937
  'sucuriscan_logs4report' => 500,
2938
  'sucuriscan_maximum_failed_logins' => 30,
2939
- 'sucuriscan_notify_available_updates' => 'enabled',
2940
  'sucuriscan_notify_bruteforce_attack' => 'disabled',
2941
  'sucuriscan_notify_failed_login' => 'enabled',
2942
  'sucuriscan_notify_plugin_activated' => 'disabled',
@@ -2979,9 +2965,6 @@ class SucuriScanOption extends SucuriScanRequest
2979
  'sucuriscan_xhr_monitor' => 'disabled',
2980
  );
2981
 
2982
- $fpath = self::optionsFilePath();
2983
- $defaults['sucuriscan_datastore_path'] = dirname($fpath);
2984
-
2985
  return $defaults;
2986
  }
2987
 
@@ -3048,6 +3031,41 @@ class SucuriScanOption extends SucuriScanRequest
3048
  return false;
3049
  }
3050
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3051
  /**
3052
  * Returns path of the options storage.
3053
  *
@@ -3061,7 +3079,10 @@ class SucuriScanOption extends SucuriScanRequest
3061
  */
3062
  public static function optionsFilePath()
3063
  {
3064
- $folder = WP_CONTENT_DIR . '/uploads/sucuri';
 
 
 
3065
 
3066
  if (defined('SUCURI_DATA_STORAGE')
3067
  && file_exists(SUCURI_DATA_STORAGE)
@@ -3070,7 +3091,7 @@ class SucuriScanOption extends SucuriScanRequest
3070
  $folder = SUCURI_DATA_STORAGE;
3071
  }
3072
 
3073
- return $folder . '/sucuri-settings.php';
3074
  }
3075
 
3076
  /**
@@ -3209,7 +3230,10 @@ class SucuriScanOption extends SucuriScanRequest
3209
  $option = self::variable_prefix($option);
3210
  $options[$option] = $value;
3211
 
3212
- return self::writeNewOptions($options);
 
 
 
3213
  }
3214
 
3215
  if (function_exists('update_option')) {
@@ -5355,16 +5379,19 @@ class SucuriScanAPI extends SucuriScanOption
5355
  }
5356
 
5357
  $output = curl_exec($curl);
5358
- $headers = curl_getinfo($curl);
 
5359
 
5360
  curl_close($curl);
5361
 
5362
- if (array_key_exists('http_code', $headers)
5363
- && $headers['http_code'] === 200
5364
  && !empty($output)
5365
  ) {
5366
  return $output;
5367
  }
 
 
5368
  }
5369
 
5370
  return false;
@@ -6578,7 +6605,6 @@ class SucuriScanAPI extends SucuriScanOption
6578
  */
6579
  class SucuriScanMail extends SucuriScanOption
6580
  {
6581
-
6582
  /**
6583
  * Check whether the email notifications will be sent in HTML or Plain/Text.
6584
  *
@@ -6654,7 +6680,12 @@ class SucuriScanMail extends SucuriScanOption
6654
  * @var boolean
6655
  */
6656
  if (SucuriScanOption::is_enabled(':use_wpmail')) {
6657
- $mail_sent = wp_mail($email, $subject, $message, $headers);
 
 
 
 
 
6658
  } else {
6659
  $headers = implode("\r\n", $headers);
6660
  $mail_sent = @mail($email, $subject, $message, $headers);
@@ -6662,6 +6693,7 @@ class SucuriScanMail extends SucuriScanOption
6662
 
6663
  if ($mail_sent) {
6664
  $emails_sent_num = (int) self::get_option(':emails_sent');
 
6665
  self::update_option(':emails_sent', $emails_sent_num + 1);
6666
  self::update_option(':last_email_at', time());
6667
 
@@ -7196,7 +7228,7 @@ class SucuriScanTemplate extends SucuriScanRequest
7196
  foreach ($allowed_values as $option_name => $option_label) {
7197
  $options .= sprintf(
7198
  "<option %s value='%s'>%s</option>\n",
7199
- ($option_name === $selected_val ? 'selected="selected"' : ''),
7200
  SucuriScan::escape($option_name),
7201
  SucuriScan::escape($option_label)
7202
  );
@@ -7823,19 +7855,14 @@ class SucuriScanInterface
7823
  @mkdir($directory, 0755, true);
7824
  }
7825
 
7826
- if (@preg_match(';/uploads/$;', $directory)) {
7827
- SucuriScanOption::delete_option(':datastore_path');
7828
- SucuriScanInterface::error('Uploads directory must not be used as the data store path.');
7829
- } elseif (file_exists($directory)) {
7830
  // Create last-logins datastore file.
7831
  sucuriscan_lastlogins_datastore_exists();
7832
 
7833
  // Create a htaccess file to deny access from all.
7834
- @file_put_contents(
7835
- $directory . '/.htaccess',
7836
- "Order Deny,Allow\nDeny from all\n",
7837
- LOCK_EX
7838
- );
7839
 
7840
  // Create an index.html to avoid directory listing.
7841
  @file_put_contents(
@@ -7843,16 +7870,6 @@ class SucuriScanInterface
7843
  '<!-- Prevent the directory listing. -->',
7844
  LOCK_EX
7845
  );
7846
- } else {
7847
- SucuriScanOption::delete_option(':datastore_path');
7848
- SucuriScanInterface::error(
7849
- 'Data folder does not exists and could not be created. Try to <a href="' .
7850
- SucuriScanTemplate::getUrl('settings') . '">click this link</a> to see
7851
- if the plugin is able to fix this error automatically, if this message
7852
- reappears you will need to either change the location of the directory from
7853
- the plugin general settings page or create this directory manually and give
7854
- it write permissions: <code>' . $directory . '</code>'
7855
- );
7856
  }
7857
  }
7858
 
@@ -7962,19 +7979,7 @@ class SucuriScanInterface
7962
 
7963
  // Display the HTML notice to the current user.
7964
  if ($display_notice === true && !empty($message)) {
7965
- if (defined('SUCURISCAN_THROW_EXCEPTIONS')
7966
- && SUCURISCAN_THROW_EXCEPTIONS === true
7967
- ) {
7968
- $number = (string) crc32($type);
7969
- $code = (int) substr($number, 0, 3);
7970
- $message = str_replace(
7971
- '<b>Sucuri:</b>',
7972
- ($type === 'error' ? 'Error:' : 'Info:'),
7973
- $message
7974
- );
7975
-
7976
- throw new Exception($message, $code);
7977
- }
7978
 
7979
  echo SucuriScanTemplate::getSection(
7980
  'notification-admin',
@@ -8035,7 +8040,10 @@ class SucuriScanInterface
8035
  '/wp-admin/plugins.php',
8036
  );
8037
 
8038
- if ($page && array_key_exists($page, $sucuriscan_pages)) {
 
 
 
8039
  return true;
8040
  }
8041
 
@@ -8209,11 +8217,30 @@ function sucuriscan_scanner_page()
8209
  $cache = new SucuriScanCache('sitecheck');
8210
  $scan_results = $cache->get('scan_results', SUCURISCAN_SITECHECK_LIFETIME, 'array');
8211
  $report_results = (bool) ($scan_results && !empty($scan_results));
 
8212
 
8213
- if (SucuriScanInterface::check_nonce()
8214
- && SucuriScanRequest::post(':malware_scan', '1')
8215
- ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8216
  $report_results = true;
 
 
 
8217
  }
8218
 
8219
  if ($report_results === true) {
@@ -8254,9 +8281,14 @@ function sucuriscan_scanner_ajax()
8254
  */
8255
  function sucuriscan_sitecheck_info($scan_results = array())
8256
  {
8257
- $clean_domain = SucuriScan::get_domain();
 
 
 
 
 
8258
  $params = array(
8259
- 'ScannedDomainName' => $clean_domain,
8260
  'ScannerResults.CssClass' => '',
8261
  'ScannerResults.Content' => '',
8262
  'WebsiteDetails.CssClass' => '',
@@ -8272,13 +8304,13 @@ function sucuriscan_sitecheck_info($scan_results = array())
8272
 
8273
  // If the results are not cached, then request a new scan and store in cache.
8274
  if ($scan_results === false) {
8275
- $scan_results = SucuriScanAPI::getSitecheckResults($clean_domain);
8276
 
8277
  // Check for error messages in the request's response.
8278
  if (is_string($scan_results)) {
8279
  if (@preg_match('/^ERROR:(.*)/', $scan_results, $error_m)) {
8280
  SucuriScanInterface::error(
8281
- 'The site <code>' . SucuriScan::escape($clean_domain) . '</code>'
8282
  . ' was not scanned: ' . SucuriScan::escape($error_m[1])
8283
  );
8284
  } else {
@@ -8432,6 +8464,7 @@ function sucuriscan_sitecheck_website_details($scan_results = false, $params = a
8432
  function sucuriscan_sitecheck_general_information($scan_results = false, $secvars = array())
8433
  {
8434
  $possible_keys = array(
 
8435
  'DOMAIN' => 'Domain Scanned',
8436
  'IP' => 'Site IP Address',
8437
  'HOSTING' => 'Hosting Company',
@@ -9241,8 +9274,9 @@ class SucuriScanHardening extends SucuriScan
9241
  $rules_str = implode("\n", $deny_rules);
9242
  $content = str_replace($rules_str, '', $content);
9243
  $written = @file_put_contents($fpath, $content);
 
9244
 
9245
- if (filesize($fpath) === 0) {
9246
  @unlink($fpath);
9247
  }
9248
 
@@ -9337,7 +9371,7 @@ class SucuriScanHardening extends SucuriScan
9337
 
9338
  if (file_exists($htaccess)) {
9339
  if (is_writable($htaccess)) {
9340
- $rules = self::whitelist_rule($file);
9341
  @file_put_contents($htaccess, $rules, FILE_APPEND);
9342
  } else {
9343
  throw new Exception('Access control file is not writable');
@@ -9358,6 +9392,8 @@ class SucuriScanHardening extends SucuriScan
9358
  $content = file_get_contents($htaccess);
9359
  $rules = self::whitelist_rule($file);
9360
  $content = str_replace($rules, '', $content);
 
 
9361
  @file_put_contents($htaccess, $content);
9362
  }
9363
  }
@@ -9366,9 +9402,7 @@ class SucuriScanHardening extends SucuriScan
9366
  {
9367
  $htaccess = self::htaccess($folder);
9368
 
9369
- if (file_exists($htaccess)
9370
- && is_readable($htaccess)
9371
- ) {
9372
  $content = file_get_contents($htaccess);
9373
 
9374
  if (@preg_match_all('/<Files (\S+)>/', $content, $matches)) {
@@ -10267,6 +10301,7 @@ function sucuriscan_audit_logs_ajax()
10267
  if (SucuriScanRequest::post('form_action') == 'get_audit_logs') {
10268
  $response = array();
10269
  $response['count'] = 0;
 
10270
  $response['enable_report'] = false;
10271
 
10272
  // Initialize the values for the pagination.
@@ -10339,7 +10374,7 @@ function sucuriscan_audit_logs_ajax()
10339
  $response['count'] = $counter_i;
10340
 
10341
  if ($total_items > 1) {
10342
- $max_pages = ceil($audit_logs->total_entries / $max_per_page);
10343
 
10344
  if ($max_pages > SUCURISCAN_MAX_PAGINATION_BUTTONS) {
10345
  $max_pages = SUCURISCAN_MAX_PAGINATION_BUTTONS;
@@ -11299,19 +11334,34 @@ function sucuriscan_posthack_updates_content($send_email = false)
11299
 
11300
  foreach ($updates as $data) {
11301
  $css_class = ($counter % 2 == 0) ? '' : 'alternate';
11302
- $response .= SucuriScanTemplate::getSnippet(
11303
- 'posthack-updates',
11304
- array(
11305
- 'Update.CssClass' => $css_class,
11306
- 'Update.IconType' => 'plugins',
11307
- 'Update.Extension' => SucuriScan::excerpt($data->Name, 35),
11308
- 'Update.Version' => $data->Version,
11309
- 'Update.NewVersion' => $data->update->new_version,
11310
- 'Update.TestedWith' => "WordPress\x20" . $data->update->tested,
11311
- 'Update.ArchiveUrl' => $data->update->package,
11312
- 'Update.MarketUrl' => $data->update->url,
11313
- )
11314
  );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11315
  $counter++;
11316
  }
11317
  }
@@ -12934,7 +12984,7 @@ function sucuriscan_settings_general_apikey($nonce)
12934
  $display_manual_key_form = (bool) (SucuriScanRequest::post(':recover_key') !== false);
12935
 
12936
  if ($nonce) {
12937
- if (!empty($_POST)) {
12938
  $fpath = SucuriScanOption::optionsFilePath();
12939
 
12940
  if (!is_writable($fpath)) {
@@ -13022,48 +13072,54 @@ function sucuriscan_settings_general_apikey($nonce)
13022
  function sucuriscan_settings_general_datastorage($nonce)
13023
  {
13024
  $params = array();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13025
 
13026
- // Update the datastore path (if the new directory exists).
13027
- if ($nonce) {
13028
- $directory = SucuriScanRequest::post(':datastore_path');
13029
-
13030
- if ($directory) {
13031
- $current = SucuriScanOption::datastore_folder_path();
13032
-
13033
- // Try to create the new directory (if possible).
13034
- if (!file_exists($directory)) {
13035
- @mkdir($directory, 0755, true);
13036
- }
13037
 
13038
- // Check if the directory is writable and move all the logs.
13039
- if (file_exists($directory)) {
13040
- if (is_writable($directory)) {
13041
- $message = 'Datastore path set to <code>' . $directory . '</code>';
 
 
 
 
13042
 
13043
- SucuriScanOption::update_option(':datastore_path', $directory);
13044
- SucuriScanEvent::report_info_event($message);
13045
- SucuriScanEvent::notify_event('plugin_change', $message);
13046
- SucuriScanInterface::info($message);
13047
 
13048
- if (file_exists($current)) {
13049
- $newpath = SucuriScanOption::datastore_folder_path();
13050
 
13051
- // Some file systems do not work correctly with trailing separators.
13052
- $current = rtrim($current, '/');
13053
- $newpath = rtrim($newpath, '/');
13054
- @rename($current, $newpath);
13055
- }
13056
- } else {
13057
- SucuriScanInterface::error('The new directory path is not writable.');
13058
- }
13059
- } else {
13060
- SucuriScanInterface::error('The directory path specified does not exists.');
13061
- }
13062
- }
13063
  }
13064
 
13065
- $params['DatastorePath'] = SucuriScanOption::get_option(':datastore_path');
13066
-
13067
  return SucuriScanTemplate::getSection('settings-general-datastorage', $params);
13068
  }
13069
 
@@ -13551,6 +13607,7 @@ function sucuriscan_settings_corefiles_cache($nonce)
13551
  return SucuriScanTemplate::getSection('settings-corefiles-cache', $params);
13552
  }
13553
 
 
13554
  class SucuriScanSiteCheck extends SucuriScanSettings
13555
  {
13556
  public static function isEnabled()
@@ -13643,6 +13700,7 @@ class SucuriScanSiteCheck extends SucuriScanSettings
13643
  return SucuriScanTemplate::getSection('settings-sitecheck-timeout', $params);
13644
  }
13645
  }
 
13646
 
13647
  /**
13648
  * Read and parse the content of the SiteCheck settings template.
1
  <?php
2
  /*
3
  Plugin Name: Sucuri Security - Auditing, Malware Scanner and Hardening
4
+ Plugin URI: https://sucuri.net/
5
+ Description: The <a href="https://sucuri.net/" target="_blank">Sucuri</a> plugin provides the website owner the best Audit logging, SiteCheck Remote Malware Scanning, Effective Security Hardening and Post-Hack features. 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.8.3
8
  Author URI: https://sucuri.net
9
  */
10
 
14
  *
15
  * @package Sucuri Security
16
  * @author Daniel Cid <dcid@sucuri.net>
17
+ * @copyright Since 2010-2016 Sucuri Inc.
18
  * @license Released under the GPL - see LICENSE file for details.
19
+ * @link https://sucuri.net/
20
  * @since File available since Release 0.1
21
  */
22
 
65
  /**
66
  * Current version of the plugin's code.
67
  */
68
+ define('SUCURISCAN_VERSION', '1.8.3');
69
 
70
  /**
71
  * The name of the Sucuri plugin main file.
438
  {
439
  }
440
 
441
+ /**
442
+ * Throw generic exception instead of silent failure for unit-tests.
443
+ *
444
+ * @param string $message Error or information message.
445
+ * @param string $type Either info or error.
446
+ * @return void
447
+ */
448
+ public static function throwException($message, $type = 'error')
449
+ {
450
+ if (defined('SUCURISCAN_THROW_EXCEPTIONS')
451
+ && SUCURISCAN_THROW_EXCEPTIONS === true
452
+ && is_string($message)
453
+ && !empty($message)
454
+ ) {
455
+ $code = ($type === 'error' ? 157 : 333);
456
+ $message = str_replace(
457
+ '<b>Sucuri:</b>',
458
+ ($type === 'error' ? 'Error:' : 'Info:'),
459
+ $message
460
+ );
461
+
462
+ throw new Exception($message, $code);
463
+ }
464
+ }
465
+
466
  /**
467
  * Return name of a variable with the plugin's prefix (if needed).
468
  *
631
  */
632
  public static function datastore_folder_path($path = '')
633
  {
634
+ $datastore = SucuriScanOption::get_option(':datastore_path');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
635
 
636
+ return self::fixPath($datastore . '/' . $path);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
637
  }
638
 
639
  /**
676
  }
677
  }
678
 
679
+ return self::escape($wp_version);
 
 
680
  }
681
 
682
  /**
749
  public static function run_scheduled_task()
750
  {
751
  SucuriScanEvent::filesystem_scan();
752
+
753
  sucuriscan_core_files_data(true);
754
  sucuriscan_posthack_updates_content(true);
755
  }
895
  if (function_exists('get_site_url')) {
896
  $site_url = get_site_url();
897
  $pattern = '/([fhtps]+:\/\/)?([^:\/]+)(:[0-9:]+)?(\/.*)?/';
898
+ $replacement = ($return_tld === true) ? '$2' : '$2$3$4';
899
  $domain_name = @preg_replace($pattern, $replacement, $site_url);
900
 
901
  return $domain_name;
971
  * the site as protected by a firewall. A fake key can be used to bypass the DNS
972
  * checking, but that is not something that will affect us, only the client.
973
  */
974
+ if (!$status && SucuriScanAPI::getCloudproxyKey()) {
 
 
975
  $status = true;
976
  }
977
 
1032
  public static function get_admin_users()
1033
  {
1034
  if (function_exists('get_users')) {
1035
+ return get_users(array('role' => 'administrator'));
 
 
1036
  }
1037
 
1038
  return false;
1056
  if ($users !== false) {
1057
  foreach ($users as $user) {
1058
  if ($user->user_status === '0') {
1059
+ $valid_users[$user->ID] = sprintf(
1060
  '%s - %s',
1061
  $user->user_login,
1062
  $user->user_email
2667
  $finfo = $this->getDatastoreContent();
2668
 
2669
  if (!empty($finfo['info'])) {
2670
+ $finfo['info']['fpath'] = $this->datastore_path;
2671
+
2672
  return $finfo['info'];
2673
  }
2674
 
2851
  {
2852
  $finfo = $this->getDatastoreContent();
2853
 
2854
+ if (array_key_exists('entries', $finfo)) {
2855
+ $finfo['entries'] = array();
2856
+ }
2857
+
2858
  return $this->saveNewEntries($finfo);
2859
  }
2860
  }
2903
  'sucuriscan_cloudproxy_apikey' => '',
2904
  'sucuriscan_collect_wrong_passwords' => 'disabled',
2905
  'sucuriscan_comment_monitor' => 'disabled',
2906
+ 'sucuriscan_datastore_path' => dirname(self::optionsFilePath()),
2907
  'sucuriscan_dismiss_setup' => 'disabled',
2908
  'sucuriscan_dns_lookups' => 'enabled',
2909
  'sucuriscan_email_subject' => 'Sucuri Alert, :domain, :event',
2922
  'sucuriscan_lastlogin_redirection' => 'enabled',
2923
  'sucuriscan_logs4report' => 500,
2924
  'sucuriscan_maximum_failed_logins' => 30,
2925
+ 'sucuriscan_notify_available_updates' => 'disabled',
2926
  'sucuriscan_notify_bruteforce_attack' => 'disabled',
2927
  'sucuriscan_notify_failed_login' => 'enabled',
2928
  'sucuriscan_notify_plugin_activated' => 'disabled',
2965
  'sucuriscan_xhr_monitor' => 'disabled',
2966
  );
2967
 
 
 
 
2968
  return $defaults;
2969
  }
2970
 
3031
  return false;
3032
  }
3033
 
3034
+ /**
3035
+ * Check if the settings will be stored in the database.
3036
+ *
3037
+ * Since version 1.7.18 the plugin started using plain text files to store
3038
+ * its settings as a security measure to reduce the scope of the attacks
3039
+ * against the database and to simplify the management of the settings for
3040
+ * multisite installations. Some users complained about this and suggested
3041
+ * to create an option to allow them to keep using the database instead of
3042
+ * plain text files.
3043
+ *
3044
+ * We will not add an explicit option in the settings page, but users can go
3045
+ * around this defining a constant in the configuration file named
3046
+ * "SUCURI_SETTINGS_IN" with value "database" to force the plugin to store
3047
+ * its settings in the database instead of the plain text files.
3048
+ *
3049
+ * @return boolean True if the settings will be stored in the database.
3050
+ */
3051
+ public static function settingsInDatabase()
3052
+ {
3053
+ return (bool) (
3054
+ defined('SUCURI_SETTINGS_IN')
3055
+ && SUCURI_SETTINGS_IN === 'database'
3056
+ );
3057
+ }
3058
+
3059
+ /**
3060
+ * Check if the settings will be stored in a plain text file.
3061
+ *
3062
+ * @return boolean True if the settings will be stored in a file.
3063
+ */
3064
+ public static function settingsInTextFile()
3065
+ {
3066
+ return (bool) (self::settingsInDatabase() === false);
3067
+ }
3068
+
3069
  /**
3070
  * Returns path of the options storage.
3071
  *
3079
  */
3080
  public static function optionsFilePath()
3081
  {
3082
+ $content_dir = defined('WP_CONTENT_DIR')
3083
+ ? rtrim(WP_CONTENT_DIR, '/')
3084
+ : ABSPATH . '/wp-content';
3085
+ $folder = $content_dir . '/uploads/sucuri';
3086
 
3087
  if (defined('SUCURI_DATA_STORAGE')
3088
  && file_exists(SUCURI_DATA_STORAGE)
3091
  $folder = SUCURI_DATA_STORAGE;
3092
  }
3093
 
3094
+ return self::fixPath($folder . '/sucuri-settings.php');
3095
  }
3096
 
3097
  /**
3230
  $option = self::variable_prefix($option);
3231
  $options[$option] = $value;
3232
 
3233
+ // Skip if user wants to use the database.
3234
+ if (self::settingsInTextFile() && self::writeNewOptions($options)) {
3235
+ return true;
3236
+ }
3237
  }
3238
 
3239
  if (function_exists('update_option')) {
5379
  }
5380
 
5381
  $output = curl_exec($curl);
5382
+ $header = curl_getinfo($curl);
5383
+ $errors = curl_error($curl);
5384
 
5385
  curl_close($curl);
5386
 
5387
+ if (array_key_exists('http_code', $header)
5388
+ && $header['http_code'] === 200
5389
  && !empty($output)
5390
  ) {
5391
  return $output;
5392
  }
5393
+
5394
+ SucuriScan::throwException($errors);
5395
  }
5396
 
5397
  return false;
6605
  */
6606
  class SucuriScanMail extends SucuriScanOption
6607
  {
 
6608
  /**
6609
  * Check whether the email notifications will be sent in HTML or Plain/Text.
6610
  *
6680
  * @var boolean
6681
  */
6682
  if (SucuriScanOption::is_enabled(':use_wpmail')) {
6683
+ try {
6684
+ $mail_sent = wp_mail($email, $subject, $message, $headers);
6685
+ }
6686
+ catch (Exception $e) {
6687
+ $mail_sent = false;
6688
+ }
6689
  } else {
6690
  $headers = implode("\r\n", $headers);
6691
  $mail_sent = @mail($email, $subject, $message, $headers);
6693
 
6694
  if ($mail_sent) {
6695
  $emails_sent_num = (int) self::get_option(':emails_sent');
6696
+
6697
  self::update_option(':emails_sent', $emails_sent_num + 1);
6698
  self::update_option(':last_email_at', time());
6699
 
7228
  foreach ($allowed_values as $option_name => $option_label) {
7229
  $options .= sprintf(
7230
  "<option %s value='%s'>%s</option>\n",
7231
+ ("$option_name" === "$selected_val" ? 'selected="selected"' : ''),
7232
  SucuriScan::escape($option_name),
7233
  SucuriScan::escape($option_label)
7234
  );
7855
  @mkdir($directory, 0755, true);
7856
  }
7857
 
7858
+ if (file_exists($directory)) {
 
 
 
7859
  // Create last-logins datastore file.
7860
  sucuriscan_lastlogins_datastore_exists();
7861
 
7862
  // Create a htaccess file to deny access from all.
7863
+ if (!SucuriScanHardening::is_hardened($directory)) {
7864
+ SucuriScanHardening::harden_directory($directory);
7865
+ }
 
 
7866
 
7867
  // Create an index.html to avoid directory listing.
7868
  @file_put_contents(
7870
  '<!-- Prevent the directory listing. -->',
7871
  LOCK_EX
7872
  );
 
 
 
 
 
 
 
 
 
 
7873
  }
7874
  }
7875
 
7979
 
7980
  // Display the HTML notice to the current user.
7981
  if ($display_notice === true && !empty($message)) {
7982
+ SucuriScan::throwException($message, $type);
 
 
 
 
 
 
 
 
 
 
 
 
7983
 
7984
  echo SucuriScanTemplate::getSection(
7985
  'notification-admin',
8040
  '/wp-admin/plugins.php',
8041
  );
8042
 
8043
+ if ($page
8044
+ && is_array($sucuriscan_pages)
8045
+ && array_key_exists($page, $sucuriscan_pages)
8046
+ ) {
8047
  return true;
8048
  }
8049
 
8217
  $cache = new SucuriScanCache('sitecheck');
8218
  $scan_results = $cache->get('scan_results', SUCURISCAN_SITECHECK_LIFETIME, 'array');
8219
  $report_results = (bool) ($scan_results && !empty($scan_results));
8220
+ $nonce = SucuriScanInterface::check_nonce();
8221
 
8222
+ // Retrieve SiteCheck scan results if user submits the form.
8223
+ if ($nonce && SucuriScanRequest::post(':malware_scan')) {
8224
+ $report_results = true;
8225
+ }
8226
+
8227
+ /**
8228
+ * Retrieve SiteCheck results from custom domain.
8229
+ *
8230
+ * To facilitate the debugging of the code we will allow the existence of a
8231
+ * GET parameter that will force the plugin to scan a specific website
8232
+ * instead of the website where the plugin is running. Since this will be a
8233
+ * semi-hidden feature we can bypass some actions like the recycling of the
8234
+ * data returned by a previous scan.
8235
+ *
8236
+ * Usage: Add "&s=TLD" where TLD is a WordPress or non-WordPress website.
8237
+ */
8238
+ if ($nonce && SucuriScanRequest::get('s')) {
8239
+ $info = $cache->getDatastoreInfo();
8240
  $report_results = true;
8241
+ $scan_results = false;
8242
+
8243
+ @unlink($info['fpath']);
8244
  }
8245
 
8246
  if ($report_results === true) {
8281
  */
8282
  function sucuriscan_sitecheck_info($scan_results = array())
8283
  {
8284
+ $tld = SucuriScan::get_domain();
8285
+
8286
+ if ($custom = SucuriScanRequest::get('s')) {
8287
+ $tld = SucuriScan::escape($custom);
8288
+ }
8289
+
8290
  $params = array(
8291
+ 'ScannedDomainName' => $tld,
8292
  'ScannerResults.CssClass' => '',
8293
  'ScannerResults.Content' => '',
8294
  'WebsiteDetails.CssClass' => '',
8304
 
8305
  // If the results are not cached, then request a new scan and store in cache.
8306
  if ($scan_results === false) {
8307
+ $scan_results = SucuriScanAPI::getSitecheckResults($tld);
8308
 
8309
  // Check for error messages in the request's response.
8310
  if (is_string($scan_results)) {
8311
  if (@preg_match('/^ERROR:(.*)/', $scan_results, $error_m)) {
8312
  SucuriScanInterface::error(
8313
+ 'The site <code>' . SucuriScan::escape($tld) . '</code>'
8314
  . ' was not scanned: ' . SucuriScan::escape($error_m[1])
8315
  );
8316
  } else {
8464
  function sucuriscan_sitecheck_general_information($scan_results = false, $secvars = array())
8465
  {
8466
  $possible_keys = array(
8467
+ 'SITE' => 'Website',
8468
  'DOMAIN' => 'Domain Scanned',
8469
  'IP' => 'Site IP Address',
8470
  'HOSTING' => 'Hosting Company',
9274
  $rules_str = implode("\n", $deny_rules);
9275
  $content = str_replace($rules_str, '', $content);
9276
  $written = @file_put_contents($fpath, $content);
9277
+ $trimmed = trim($content);
9278
 
9279
+ if (!filesize($fpath) || empty($trimmed)) {
9280
  @unlink($fpath);
9281
  }
9282
 
9371
 
9372
  if (file_exists($htaccess)) {
9373
  if (is_writable($htaccess)) {
9374
+ $rules = "\n" . self::whitelist_rule($file);
9375
  @file_put_contents($htaccess, $rules, FILE_APPEND);
9376
  } else {
9377
  throw new Exception('Access control file is not writable');
9392
  $content = file_get_contents($htaccess);
9393
  $rules = self::whitelist_rule($file);
9394
  $content = str_replace($rules, '', $content);
9395
+ $content = rtrim($content) . "\n";
9396
+
9397
  @file_put_contents($htaccess, $content);
9398
  }
9399
  }
9402
  {
9403
  $htaccess = self::htaccess($folder);
9404
 
9405
+ if (file_exists($htaccess) && is_readable($htaccess)) {
 
 
9406
  $content = file_get_contents($htaccess);
9407
 
9408
  if (@preg_match_all('/<Files (\S+)>/', $content, $matches)) {
10301
  if (SucuriScanRequest::post('form_action') == 'get_audit_logs') {
10302
  $response = array();
10303
  $response['count'] = 0;
10304
+ $response['content'] = '';
10305
  $response['enable_report'] = false;
10306
 
10307
  // Initialize the values for the pagination.
10374
  $response['count'] = $counter_i;
10375
 
10376
  if ($total_items > 1) {
10377
+ $max_pages = ceil($audit_logs['total_entries'] / $max_per_page);
10378
 
10379
  if ($max_pages > SUCURISCAN_MAX_PAGINATION_BUTTONS) {
10380
  $max_pages = SUCURISCAN_MAX_PAGINATION_BUTTONS;
11334
 
11335
  foreach ($updates as $data) {
11336
  $css_class = ($counter % 2 == 0) ? '' : 'alternate';
11337
+ $params = array(
11338
+ 'Update.CssClass' => $css_class,
11339
+ 'Update.IconType' => 'plugins',
11340
+ 'Update.Extension' => SucuriScan::excerpt($data->Name, 35),
11341
+ 'Update.Version' => $data->Version,
11342
+ 'Update.NewVersion' => 'Unknown',
11343
+ 'Update.TestedWith' => 'Unknown',
11344
+ 'Update.ArchiveUrl' => 'Unknown',
11345
+ 'Update.MarketUrl' => 'Unknown',
 
 
 
11346
  );
11347
+
11348
+ if (property_exists($data->update, 'new_version')) {
11349
+ $params['Update.NewVersion'] = $data->update->new_version;
11350
+ }
11351
+
11352
+ if (property_exists($data->update, 'tested')) {
11353
+ $params['Update.TestedWith'] = "WordPress\x20" . $data->update->tested;
11354
+ }
11355
+
11356
+ if (property_exists($data->update, 'package')) {
11357
+ $params['Update.ArchiveUrl'] = $data->update->package;
11358
+ }
11359
+
11360
+ if (property_exists($data->update, 'url')) {
11361
+ $params['Update.MarketUrl'] = $data->update->url;
11362
+ }
11363
+
11364
+ $response .= SucuriScanTemplate::getSnippet('posthack-updates', $params);
11365
  $counter++;
11366
  }
11367
  }
12984
  $display_manual_key_form = (bool) (SucuriScanRequest::post(':recover_key') !== false);
12985
 
12986
  if ($nonce) {
12987
+ if (!empty($_POST) && SucuriScanOption::settingsInTextFile()) {
12988
  $fpath = SucuriScanOption::optionsFilePath();
12989
 
12990
  if (!is_writable($fpath)) {
13072
  function sucuriscan_settings_general_datastorage($nonce)
13073
  {
13074
  $params = array();
13075
+ $files = array(
13076
+ '', /* <root> */
13077
+ 'auditqueue',
13078
+ 'blockedusers',
13079
+ 'failedlogins',
13080
+ 'ignorescanning',
13081
+ 'integrity',
13082
+ 'lastlogins',
13083
+ 'oldfailedlogins',
13084
+ 'plugindata',
13085
+ 'settings',
13086
+ 'sitecheck',
13087
+ 'trustip',
13088
+ );
13089
 
13090
+ $counter = 0;
13091
+ $params['DataStorage.Files'] = '';
13092
+ $params['DatastorePath'] = SucuriScanOption::get_option(':datastore_path');
 
 
 
 
 
 
 
 
13093
 
13094
+ foreach ($files as $name) {
13095
+ $counter++;
13096
+ $fname = ($name ? sprintf('sucuri-%s.php', $name) : '');
13097
+ $fpath = SucuriScan::datastore_folder_path($fname);
13098
+ $exists = (file_exists($fpath) ? 'Yes' : 'No');
13099
+ $iswritable = (is_writable($fpath) ? 'Yes' : 'No');
13100
+ $css_class = ($counter % 2 === 0) ? 'alternate' : '';
13101
+ $disabled = 'disabled="disabled"';
13102
 
13103
+ if ($exists === 'Yes' && $iswritable === 'Yes') {
13104
+ $disabled = ''; /* Allow file deletion */
13105
+ }
 
13106
 
13107
+ // Remove unnecessary parts from the file path.
13108
+ $fpath = str_replace(ABSPATH, '/', $fpath);
13109
 
13110
+ $params['DataStorage.Files'] .= SucuriScanTemplate::getSnippet(
13111
+ 'settings-datastorage-files',
13112
+ array(
13113
+ 'DataStorage.CssClass' => $css_class,
13114
+ 'DataStorage.Fname' => $fname,
13115
+ 'DataStorage.Fpath' => $fpath,
13116
+ 'DataStorage.Exists' => $exists,
13117
+ 'DataStorage.IsWritable' => $iswritable,
13118
+ 'DataStorage.DisabledInput' => $disabled,
13119
+ )
13120
+ );
 
13121
  }
13122
 
 
 
13123
  return SucuriScanTemplate::getSection('settings-general-datastorage', $params);
13124
  }
13125
 
13607
  return SucuriScanTemplate::getSection('settings-corefiles-cache', $params);
13608
  }
13609
 
13610
+ if (!class_exists('SucuriScanSiteCheck')) {
13611
  class SucuriScanSiteCheck extends SucuriScanSettings
13612
  {
13613
  public static function isEnabled()
13700
  return SucuriScanTemplate::getSection('settings-sitecheck-timeout', $params);
13701
  }
13702
  }
13703
+ }
13704
 
13705
  /**
13706
  * Read and parse the content of the SiteCheck settings template.