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

Version Description

  • Added better checks for SSL issues
  • Fix for audit log timezones
  • Various bugfixes and improvements
Download this release

Release Info

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

Code changes from version 1.7.9 to 1.7.10

inc/css/sucuriscan-default-css.css CHANGED
@@ -269,6 +269,14 @@ td.sucuriscan-corefiles-warning > div{background:#f2dede;color:#a94442;border-co
269
.sucuriscan-admins-lastlogins .sucuriscan-ellipsis{width:170px}
270
.sucuriscan-admins-lastlogins td{padding:4px 8px}
271
.sucuriscan-lastlogins-failed{}
272
/* About Page */
273
.sucuriscan-about ul{margin-left:20px}
274
.sucuriscan-about ul li{list-style:initial}
269
.sucuriscan-admins-lastlogins .sucuriscan-ellipsis{width:170px}
270
.sucuriscan-admins-lastlogins td{padding:4px 8px}
271
.sucuriscan-lastlogins-failed{}
272
+ /* Pattern Search Styles */
273
+ .sucuriscan-pattern-search {}
274
+ .sucuriscan-pattern-search-inputbox {margin-top:12px}
275
+ .sucuriscan-pattern-search-inputbox .input-text {width:84.7777%;line-height:30px;margin:0;margin-right:6px}
276
+ .sucuriscan-pattern-search-inputbox .input-button {width:14%;height:initial;line-height:35px}
277
+ .sucuriscan-pattern-search .sucuriscan-cleanup-btn {margin-top:12px}
278
+ .sucuriscan-pattern-search table label {color:#999}
279
+ .sucuriscan-pattern-search .sucuriscan-grep-text em{color:#ea3838}
280
/* About Page */
281
.sucuriscan-about ul{margin-left:20px}
282
.sucuriscan-about ul li{list-style:initial}
inc/images/main-logo.png ADDED
Binary file
inc/tpl/lastlogins-all.html.tpl CHANGED
@@ -13,7 +13,7 @@
13
</th>
14
</tr>
15
<tr>
16
- <th class="manage-column">No.</th>
17
<th class="manage-column">User</th>
18
<th class="manage-column">IP Address</th>
19
<th class="manage-column">Hostname</th>
13
</th>
14
</tr>
15
<tr>
16
+ <th class="manage-column">&nbsp;</th>
17
<th class="manage-column">User</th>
18
<th class="manage-column">IP Address</th>
19
<th class="manage-column">Hostname</th>
inc/tpl/lastlogins-failedlogins.html.tpl CHANGED
@@ -44,16 +44,17 @@
44
<table class="wp-list-table widefat sucuriscan-table sucuriscan-lastlogins-failed sucuriscan-%%SUCURI.IgnoreRules.TableVisibility%%">
45
<thead>
46
<tr>
47
- <th width="20">No.</th>
48
- <th>User</th>
49
- <th>Password</th>
50
- <th>IP Address</th>
51
- <th>Date/Time</th>
52
- <th width="300">User-Agent</th>
53
</tr>
54
</thead>
55
56
<tbody>
57
%%SUCURI.FailedLogins.List%%
58
59
<tr class="sucuriscan-%%SUCURI.FailedLogins.NoItemsVisibility%%">
@@ -61,5 +62,14 @@
61
<em>No logs so far.</em>
62
</td>
63
</tr>
64
</tbody>
65
</table>
44
<table class="wp-list-table widefat sucuriscan-table sucuriscan-lastlogins-failed sucuriscan-%%SUCURI.IgnoreRules.TableVisibility%%">
45
<thead>
46
<tr>
47
+ <th class="manage-column">&nbsp;</th>
48
+ <th class="manage-column">User</th>
49
+ <th class="manage-column">Password</th>
50
+ <th class="manage-column">IP Address</th>
51
+ <th class="manage-column">Date/Time</th>
52
+ <th class="manage-column" width="300">User-Agent</th>
53
</tr>
54
</thead>
55
56
<tbody>
57
+
58
%%SUCURI.FailedLogins.List%%
59
60
<tr class="sucuriscan-%%SUCURI.FailedLogins.NoItemsVisibility%%">
62
<em>No logs so far.</em>
63
</td>
64
</tr>
65
+
66
+ <tr class="sucuriscan-%%SUCURI.FailedLogins.PaginationVisibility%%">
67
+ <td colspan="6">
68
+ <ul class="sucuriscan-pagination">
69
+ %%SUCURI.FailedLogins.PaginationLinks%%
70
+ </ul>
71
+ </td>
72
+ </tr>
73
+
74
</tbody>
75
</table>
inc/tpl/malwarescan.html.tpl CHANGED
@@ -7,9 +7,19 @@
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>
11
</form>
12
13
<div class="sucuriscan-sitelogo">&nbsp;</div>
14
15
<div class="sucuriscan-sitecheck-disclaimer">
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
+ <input type="submit" value="Scan Website" class="button button-hero button-primary input-button" />
11
</form>
12
13
+ <script type="text/javascript">
14
+ jQuery(function($){
15
+ $('.sucuriscan-sitecheck-form .input-button').click(function(){
16
+ $('.sucuriscan-sitecheck-form .input-button')
17
+ .val('Scanning Website...')
18
+ .addClass('disabled');
19
+ });
20
+ });
21
+ </script>
22
+
23
<div class="sucuriscan-sitelogo">&nbsp;</div>
24
25
<div class="sucuriscan-sitecheck-disclaimer">
inc/tpl/notification-pretty.html.tpl CHANGED
@@ -4,7 +4,7 @@
4
<tr style="background-color:#4b4b4b;background-image:-moz-linear-gradient(top, #555555, #3b3b3b);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#555555), to(#3b3b3b));background-image:-webkit-linear-gradient(top, #555555, #3b3b3b);background-image:-o-linear-gradient(top, #555555, #3b3b3b);background-image:linear-gradient(to bottom, #555555, #3b3b3b);background-repeat:repeat-x">
5
<td sytle="font-size:20px;font-weight:normal;color:#ffffff;padding:10px;border-right:1px solid #2f2f2f;border-left:1px solid #6f6f6f;-webkit-box-shadow:inset 0 1px 0 #888888;-moz-box-shadow:inset 0 1px 0 #888888;box-shadow:inset 0 1px 0 #888888;text-shadow:1px 1px 2px rgba(0, 0, 0, 0.5)">
6
<a href="http://sucuri.net/" style="text-decoration:none;display:inline-block;margin:8px 0 5px 20px">
7
- <img src="http://sucuri.net/wp-content/themes/sucuri-two/images/main-logo.png" alt="Sucuri, Inc." style="border:none" />
8
</a>
9
<span style="display:inline-block;line-height:46px;margin:0 20px 0 0;float:right;color:#ffffff">%%SUCURI.TemplateTitle%%</span>
10
</td>
4
<tr style="background-color:#4b4b4b;background-image:-moz-linear-gradient(top, #555555, #3b3b3b);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#555555), to(#3b3b3b));background-image:-webkit-linear-gradient(top, #555555, #3b3b3b);background-image:-o-linear-gradient(top, #555555, #3b3b3b);background-image:linear-gradient(to bottom, #555555, #3b3b3b);background-repeat:repeat-x">
5
<td sytle="font-size:20px;font-weight:normal;color:#ffffff;padding:10px;border-right:1px solid #2f2f2f;border-left:1px solid #6f6f6f;-webkit-box-shadow:inset 0 1px 0 #888888;-moz-box-shadow:inset 0 1px 0 #888888;box-shadow:inset 0 1px 0 #888888;text-shadow:1px 1px 2px rgba(0, 0, 0, 0.5)">
6
<a href="http://sucuri.net/" style="text-decoration:none;display:inline-block;margin:8px 0 5px 20px">
7
+ <img src="%%SUCURI.SucuriURL%%/inc/images/main-logo.png" alt="Sucuri, Inc." style="border:none" />
8
</a>
9
<span style="display:inline-block;line-height:46px;margin:0 20px 0 0;float:right;color:#ffffff">%%SUCURI.TemplateTitle%%</span>
10
</td>
inc/tpl/notification-resetpwd.html.tpl ADDED
@@ -0,0 +1,10 @@
1
+
2
+ Your password for <strong>%%SUCURI.ResetPassword.UserName%%</strong>
3
+ <em>(%%SUCURI.ResetPassword.DisplayName%%)</em> at <a target="_blank"
4
+ href="http://%%SUCURI.ResetPassword.Website%%">%%SUCURI.ResetPassword.Website%%</a>
5
+ has been reset for security reasons.<br>
6
+ You can use this temporary password to log in:
7
+ <span style="display:inline-block;background:#f5f5f5;padding:2px 6px;
8
+ font-family:Menlo, Monaco, monospace, serif;border:1px solid #ddd">
9
+ %%SUCURI.ResetPassword.Password%%</span><br>
10
+ Please change your password after you log in.
inc/tpl/posthack-resetplugins.html.tpl CHANGED
@@ -1,8 +1,12 @@
1
2
<div id="poststuff" class="sucuriscan-reset-plugins">
3
<div class="postbox">
4
<div class="inside">
5
<form action="%%SUCURI.URL.Posthack%%#reset-plugins" method="post">
6
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
7
<input type="hidden" name="sucuriscan_reset_plugins" value="1" />
8
@@ -24,7 +28,7 @@
24
</p>
25
</div>
26
27
- <table class="wp-list-table widefat sucuriscan-table">
28
<thead>
29
<tr>
30
<th class="manage-column column-cb check-column">
@@ -39,7 +43,11 @@
39
</thead>
40
41
<tbody>
42
- %%SUCURI.ResetPlugin.PluginList%%
43
</tbody>
44
</table>
45
@@ -52,7 +60,23 @@
52
</p>
53
54
<input type="submit" value="Process selected items" class="button button-primary" />
55
</form>
56
</div>
57
</div>
58
</div>
1
2
<div id="poststuff" class="sucuriscan-reset-plugins">
3
+
4
<div class="postbox">
5
+
6
<div class="inside">
7
+
8
<form action="%%SUCURI.URL.Posthack%%#reset-plugins" method="post">
9
+
10
<input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
11
<input type="hidden" name="sucuriscan_reset_plugins" value="1" />
12
28
</p>
29
</div>
30
31
+ <table class="wp-list-table widefat sucuriscan-table sucuriscan-reset-plugins-table">
32
<thead>
33
<tr>
34
<th class="manage-column column-cb check-column">
43
</thead>
44
45
<tbody>
46
+ <tr>
47
+ <td colspan="5">
48
+ <span>Loading <em>(may take several seconds)</em>...</span>
49
+ </td>
50
+ </tr>
51
</tbody>
52
</table>
53
60
</p>
61
62
<input type="submit" value="Process selected items" class="button button-primary" />
63
+
64
</form>
65
+
66
+ <script type="text/javascript">
67
+ jQuery(function($){
68
+ $.post( '%%SUCURI.AjaxURL.Posthack%%', {
69
+ action: 'sucuriscan_posthack_ajax',
70
+ sucuriscan_page_nonce: '%%SUCURI.PageNonce%%',
71
+ form_action: 'get_plugins_data',
72
+ }, function(data){
73
+ $('.sucuriscan-reset-plugins-table tbody').html( data );
74
+ });
75
+ });
76
+ </script>
77
+
78
</div>
79
+
80
</div>
81
+
82
</div>
inc/tpl/settings-general.html.tpl CHANGED
@@ -152,27 +152,34 @@
152
</tr>
153
154
<tr>
155
- <td>API proxy host:port</td>
156
<td><span class="sucuriscan-monospace">%%SUCURI.APIProxy.Host%%:%%SUCURI.APIProxy.Port%%</span></td>
157
<td>&nbsp;</td>
158
</tr>
159
160
<tr class="alternate">
161
- <td>API proxy username</td>
162
- <td><span class="sucuriscan-monospace">%%SUCURI.APIProxy.Username%%</span></td>
163
- <td>&nbsp;</td>
164
- </tr>
165
-
166
- <tr>
167
- <td>API proxy password</td>
168
<td>
169
<span class="sucuriscan-label-%%SUCURI.APIProxy.PasswordType%%">
170
- %%SUCURI.APIProxy.PasswordText%%
171
</span>
172
</td>
173
<td>&nbsp;</td>
174
</tr>
175
176
<tr class="alternate">
177
<td>Support reverse proxy</td>
178
<td>%%SUCURI.ReverseProxyStatus%%</td>
152
</tr>
153
154
<tr>
155
+ <td>API proxy <em>(host:port)</em></td>
156
<td><span class="sucuriscan-monospace">%%SUCURI.APIProxy.Host%%:%%SUCURI.APIProxy.Port%%</span></td>
157
<td>&nbsp;</td>
158
</tr>
159
160
<tr class="alternate">
161
+ <td>API proxy <em>(auth)</em></td>
162
<td>
163
+ <span class="sucuriscan-monospace">%%SUCURI.APIProxy.Username%%</span>
164
<span class="sucuriscan-label-%%SUCURI.APIProxy.PasswordType%%">
165
+ <em>password is %%SUCURI.APIProxy.PasswordText%%</em>
166
</span>
167
</td>
168
<td>&nbsp;</td>
169
</tr>
170
171
+ <tr>
172
+ <td>API test request</td>
173
+ <td><em>(Test ability to send HTTP requests)</em></td>
174
+ <td class="td-with-button">
175
+ <form action="%%SUCURI.URL.Settings%%" method="post">
176
+ <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
177
+ <input type="hidden" name="sucuriscan_debug_request" value="1" />
178
+ <button type="submit" class="button-primary">Proceed</button>
179
+ </form>
180
+ </td>
181
+ </tr>
182
+
183
<tr class="alternate">
184
<td>Support reverse proxy</td>
185
<td>%%SUCURI.ReverseProxyStatus%%</td>
readme.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: dd@sucuri.net
3
Donate Link: http://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.7.9
7
Tested up to: 4.2.2
8
9
The Sucuri WordPress Security plugin is a security toolset for security integrity monitoring, malware detection and security hardening.
@@ -352,6 +352,11 @@ service from the WordPress dashboard.
352
353
== Changelog ==
354
355
= 1.7.9 =
356
* Improved reinstallation process
357
* Updated sidebar banners
3
Donate Link: http://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.7.10
7
Tested up to: 4.2.2
8
9
The Sucuri WordPress Security plugin is a security toolset for security integrity monitoring, malware detection and security hardening.
352
353
== Changelog ==
354
355
+ = 1.7.10 =
356
+ * Added better checks for SSL issues
357
+ * Fix for audit log timezones
358
+ * Various bugfixes and improvements
359
+
360
= 1.7.9 =
361
* Improved reinstallation process
362
* Updated sidebar banners
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</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.7.9
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.7.9' );
70
71
/**
72
* The name of the Sucuri plugin main file.
@@ -197,17 +197,17 @@ if ( defined( 'SUCURISCAN' ) ) {
197
'sucuriscan_notify_website_updated' => 'Receive email alerts when the WordPress version is updated',
198
'sucuriscan_notify_settings_updated' => 'Receive email alerts when your website settings are updated',
199
'sucuriscan_notify_theme_editor' => 'Receive email alerts when a file is modified with theme/plugin editor',
200
- 'sucuriscan_notify_plugin_installed' => 'plugin:Receive email alerts when a plugin is installed',
201
- 'sucuriscan_notify_plugin_activated' => 'plugin:Receive email alerts when a plugin is activated',
202
- 'sucuriscan_notify_plugin_deactivated' => 'plugin:Receive email alerts when a plugin is deactivated',
203
- 'sucuriscan_notify_plugin_updated' => 'plugin:Receive email alerts when a plugin is updated',
204
- 'sucuriscan_notify_plugin_deleted' => 'plugin:Receive email alerts when a plugin is deleted',
205
- 'sucuriscan_notify_widget_added' => 'widget:Receive email alerts when a widget is added to a sidebar',
206
- 'sucuriscan_notify_widget_deleted' => 'widget:Receive email alerts when a widget is deleted from a sidebar',
207
- 'sucuriscan_notify_theme_installed' => 'theme:Receive email alerts when a theme is installed',
208
- 'sucuriscan_notify_theme_activated' => 'theme:Receive email alerts when a theme is activated',
209
- 'sucuriscan_notify_theme_updated' => 'theme:Receive email alerts when a theme is updated',
210
- 'sucuriscan_notify_theme_deleted' => 'theme:Receive email alerts when a theme is deleted',
211
);
212
213
$sucuriscan_schedule_allowed = array(
@@ -282,6 +282,17 @@ if ( defined( 'SUCURISCAN' ) ) {
282
add_action( 'admin_enqueue_scripts', 'SucuriScanInterface::enqueue_scripts', 1 );
283
add_action( 'admin_menu', 'SucuriScanInterface::add_interface_menu' );
284
285
/**
286
* Function call interceptors.
287
*
@@ -795,11 +806,16 @@ class SucuriScan {
795
*/
796
public static function datetime( $timestamp = 0 ){
797
if ( is_numeric( $timestamp ) && $timestamp > 0 ) {
798
$date_format = get_option( 'date_format' );
799
$time_format = get_option( 'time_format' );
800
- $timezone_format = sprintf( '%s %s', $date_format, $time_format );
801
802
- return date_i18n( $timezone_format, $timestamp );
803
}
804
805
return null;
@@ -1631,9 +1647,9 @@ class SucuriScanFileInfo extends SucuriScan {
1631
/**
1632
* Skip some specific directories and file paths from the filesystem scan.
1633
*
1634
- * @param string $directory Directory where the scanner is located at the moment.
1635
- * @param string $filename Name of the folder or file being scanned at the moment.
1636
- * @return boolean Either TRUE or FALSE representing that the scan should ignore this folder or not.
1637
*/
1638
private function ignore_folderpath( $directory = '', $filename = '' ){
1639
// Ignoring current and parent folders.
@@ -1682,6 +1698,15 @@ class SucuriScanFileInfo extends SucuriScan {
1682
return true;
1683
}
1684
1685
// Any file maching one of these rules WILL NOT be ignored.
1686
if (
1687
( strpos( $filename, '.php' ) !== false) ||
@@ -1725,6 +1750,53 @@ class SucuriScanFileInfo extends SucuriScan {
1725
return $dirs;
1726
}
1727
1728
/**
1729
* Remove a directory recursively.
1730
*
@@ -2424,7 +2496,7 @@ class SucuriScanOption extends SucuriScanRequest {
2424
'sucuriscan_site_version' => '0.0',
2425
'sucuriscan_sitecheck_counter' => 0,
2426
'sucuriscan_sitecheck_scanner' => 'enabled',
2427
- 'sucuriscan_verify_ssl_cert' => 'true',
2428
);
2429
2430
return $defaults;
@@ -2926,9 +2998,9 @@ class SucuriScanEvent extends SucuriScan {
2926
) {
2927
self::report_site_version();
2928
2929
- $sucuri_fileinfo = new SucuriScanFileInfo();
2930
- $sucuri_fileinfo->scan_interface = SucuriScanOption::get_option( ':scan_interface' );
2931
- $signatures = $sucuri_fileinfo->get_directory_tree_md5( ABSPATH );
2932
2933
if ( $signatures ) {
2934
$hashes_sent = SucuriScanAPI::send_hashes( $signatures );
@@ -3237,13 +3309,17 @@ class SucuriScanEvent extends SucuriScan {
3237
$user = get_userdata( $user_id );
3238
3239
if ( $user instanceof WP_User ) {
3240
$new_password = wp_generate_password( 15, true, false );
3241
3242
- $message = 'The password for your user account <strong>"'. $user->display_name .'"</strong> '
3243
- . 'in the website specified above was changed, this is the new password generated automatically '
3244
- . 'by the system, please update as soon as possible.<br><div style="display:inline-block;'
3245
- . 'background:#ddd;font-family:monaco,monospace,courier;font-size:30px;margin:0;padding:15px;'
3246
- . 'border:1px solid #999">'. $new_password .'</div>';
3247
3248
$data_set = array( 'Force' => true ); // Skip limit for emails per hour.
3249
SucuriScanMail::send_mail( $user->user_email, 'Password changed', $message, $data_set );
@@ -4150,7 +4226,7 @@ class SucuriScanAPI extends SucuriScanOption {
4150
* @param string $method HTTP method that will be used to send the request.
4151
* @param array $params Parameters for the request defined in an associative array of key-value.
4152
* @param array $args Request arguments like the timeout, redirections, headers, cookies, etc.
4153
- * @return array Array of results including HTTP headers or WP_Error if the request failed.
4154
*/
4155
private static function api_call( $url = '', $method = 'GET', $params = array(), $args = array() ){
4156
if ( ! $url ) {
@@ -4192,38 +4268,39 @@ class SucuriScanAPI extends SucuriScanOption {
4192
} elseif ( $method == 'POST' ) {
4193
$req_args['body'] = $params;
4194
$response = wp_remote_post( $url, $req_args );
4195
}
4196
4197
- if ( isset($response) ) {
4198
- if ( is_wp_error( $response ) ) {
4199
- SucuriScanInterface::error(sprintf(
4200
- 'Something went wrong with an API call (%s action): %s',
4201
- ( isset($params['a']) ? self::escape( $params['a'] ) : 'unknown' ),
4202
- $response->get_error_message()
4203
- ));
4204
- } else {
4205
- $response['body_raw'] = $response['body'];
4206
4207
- // Check if the response data is JSON-encoded, then decode it.
4208
- if (
4209
- isset($response['headers']['content-type'])
4210
- && $response['headers']['content-type'] == 'application/json'
4211
- ) {
4212
- $assoc = ( isset($args['assoc']) && $args['assoc'] === true ) ? true : false;
4213
- $response['body'] = @json_decode( $response['body_raw'], $assoc );
4214
- } elseif ( self::is_serialized( $response['body'] ) ) {
4215
- // Check if the response data is serialized (which we will consider as insecure).
4216
- $response['body_raw'] = null;
4217
- $response['body'] = 'ERROR:Serialized data is not supported.';
4218
- }
4219
4220
- return $response;
4221
- }
4222
- } else {
4223
- SucuriScanInterface::error( 'HTTP method not allowed: ' . $method );
4224
}
4225
4226
- return false;
4227
}
4228
4229
/**
@@ -4328,7 +4405,7 @@ class SucuriScanAPI extends SucuriScanOption {
4328
* @param array $params Parameters for the request defined in an associative array of key-value.
4329
* @param boolean $send_api_key Whether the API key should be added to the request parameters or not.
4330
* @param array $args Request arguments like the timeout, redirections, headers, cookies, etc.
4331
- * @return array Array of results including HTTP headers or WP_Error if the request failed.
4332
*/
4333
public static function api_call_wordpress( $method = 'GET', $params = array(), $send_api_key = true, $args = array() ){
4334
$url = SUCURISCAN_API;
@@ -4355,7 +4432,7 @@ class SucuriScanAPI extends SucuriScanOption {
4355
*
4356
* @param string $method HTTP method that will be used to send the request.
4357
* @param array $params Parameters for the request defined in an associative array of key-value.
4358
- * @return array Array of results including HTTP headers or WP_Error if the request failed.
4359
*/
4360
public static function api_call_cloudproxy( $method = 'GET', $params = array() ){
4361
$send_request = false;
@@ -4385,12 +4462,90 @@ class SucuriScanAPI extends SucuriScanOption {
4385
return false;
4386
}
4387
4388
/**
4389
* Determine whether an API response was successful or not checking the expected
4390
* generic variables and types, in case of an error a notification will appears
4391
* in the administrator panel explaining the result of the operation.
4392
*
4393
- * @param array $response Array of results including HTTP headers or WP_Error if the request failed.
4394
* @return boolean Either true or false in case of success or failure of the API response (respectively).
4395
*/
4396
private static function handle_response( $response = array() ){
@@ -4404,11 +4559,14 @@ class SucuriScanAPI extends SucuriScanOption {
4404
4405
// Check whether the message list is empty or not.
4406
if ( isset($response['body']->messages[0]) ) {
4407
- $action_message = $response['body']->messages[0];
4408
}
4409
4410
// Special response for invalid API keys.
4411
- if ( strpos( $action_message, 'Log file not found' ) !== false ) {
4412
SucuriScanOption::delete_option( ':api_key' );
4413
4414
$action_message .= ' This generally happens when you add an invalid API key, the'
@@ -4417,7 +4575,50 @@ class SucuriScanAPI extends SucuriScanOption {
4417
. ' key to your email address.';
4418
}
4419
4420
- SucuriScanInterface::error( ucwords( $response['body']->action ) . ': ' . $action_message );
4421
}
4422
} else {
4423
SucuriScanInterface::error( 'Could not determine the status of an API call.' );
@@ -4560,8 +4761,8 @@ class SucuriScanAPI extends SucuriScanOption {
4560
if ( preg_match( $log_pattern, $log, $log_match ) ) {
4561
$log_data = array(
4562
'event' => 'notice',
4563
- 'date' => $log_match[1],
4564
- 'time' => $log_match[2],
4565
'datetime' => '',
4566
'timestamp' => 0,
4567
'account' => $log_match[3],
@@ -4572,11 +4773,16 @@ class SucuriScanAPI extends SucuriScanOption {
4572
'file_list_count' => 0,
4573
);
4574
4575
- $log_data['datetime'] = sprintf( '%s %s', $log_match[1], $log_match[2] );
4576
- $log_data['timestamp'] = strtotime( $log_data['datetime'] );
4577
- $log_data['message'] = str_replace( '<br>', '; ', $log_data['message'] );
4578
4579
// Extract more information from the generic audit logs.
4580
if ( preg_match( $generic_pattern, $log_data['message'], $log_extra ) ) {
4581
$log_data['event'] = strtolower( $log_extra[1] );
4582
$log_data['message'] = trim( $log_extra[3] );
@@ -4615,6 +4821,7 @@ class SucuriScanAPI extends SucuriScanOption {
4615
if ( preg_match( $extra_pattern, $log_data['message'], $log_extra ) ) {
4616
$log_data['message'] = $log_extra[1];
4617
$log_extra[2] = str_replace( ', new size', '; new size', $log_extra[2] );
4618
$log_data['file_list'] = explode( ',', $log_extra[2] );
4619
$log_data['file_list_count'] = count( $log_data['file_list'] );
4620
}
@@ -5488,6 +5695,23 @@ class SucuriScanTemplate extends SucuriScanRequest {
5488
return $url_path;
5489
}
5490
5491
/**
5492
* Complement the list of pseudo-variables that will be used in the base
5493
* template files, this will also generate the navigation bar and detect which
@@ -5529,6 +5753,10 @@ class SucuriScanTemplate extends SucuriScanRequest {
5529
5530
$params[ $pseudo_var ] = self::get_url( $unique_name );
5531
5532
$navbar_item_css_class = 'nav-tab';
5533
5534
if ( $params['CurrentPageFunc'] == $sub_page_func ) {
@@ -5939,11 +6167,11 @@ class SucuriScanFSScanner extends SucuriScan {
5939
}
5940
5941
// Scan the project and file all directories.
5942
- $sucuri_fileinfo = new SucuriScanFileInfo();
5943
- $sucuri_fileinfo->ignore_files = true;
5944
- $sucuri_fileinfo->ignore_directories = true;
5945
- $sucuri_fileinfo->scan_interface = SucuriScanOption::get_option( ':scan_interface' );
5946
- $directory_list = $sucuri_fileinfo->get_diretories_only( ABSPATH );
5947
5948
if ( $directory_list ) {
5949
$response['is_not_ignored'] = $directory_list;
@@ -6205,7 +6433,7 @@ class SucuriScanInterface {
6205
* @return void
6206
*/
6207
public static function initialize(){
6208
- if ( SucuriScan::is_behind_cloudproxy() ) {
6209
$_SERVER['SUCURIREAL_REMOTE_ADDR'] = $_SERVER['REMOTE_ADDR'];
6210
$_SERVER['REMOTE_ADDR'] = SucuriScan::get_remote_addr();
6211
}
@@ -6248,6 +6476,8 @@ class SucuriScanInterface {
6248
if (
6249
function_exists( 'add_menu_page' )
6250
&& $sucuriscan_pages
6251
) {
6252
// Add main menu link.
6253
add_menu_page(
@@ -6259,9 +6489,7 @@ class SucuriScanInterface {
6259
SUCURISCAN_URL . '/inc/images/menu-icon.png'
6260
);
6261
6262
- $sub_pages = is_array( $sucuriscan_pages ) ? $sucuriscan_pages : array();
6263
-
6264
- foreach ( $sub_pages as $sub_page_func => $sub_page_title ) {
6265
if (
6266
$sub_page_func == 'sucuriscan_scanner'
6267
&& SucuriScanTemplate::is_sitecheck_disabled()
@@ -6293,9 +6521,9 @@ class SucuriScanInterface {
6293
*/
6294
public static function handle_old_plugins(){
6295
if ( class_exists( 'SucuriScanFileInfo' ) ) {
6296
- $sucuri_fileinfo = new SucuriScanFileInfo();
6297
- $sucuri_fileinfo->ignore_files = false;
6298
- $sucuri_fileinfo->ignore_directories = false;
6299
6300
$plugins = array(
6301
'sucuri-wp-plugin/sucuri.php',
@@ -6310,7 +6538,7 @@ class SucuriScanInterface {
6310
deactivate_plugins( $plugin );
6311
}
6312
6313
- $plugin_removed = $sucuri_fileinfo->remove_directory_tree( $plugin_directory );
6314
}
6315
}
6316
}
@@ -8144,10 +8372,10 @@ function sucuriscan_harden_errorlog(){
8144
8145
// Search error log files in the project.
8146
if ( $scan_errorlogs != 'disabled' ) {
8147
- $sucuri_fileinfo = new SucuriScanFileInfo();
8148
- $sucuri_fileinfo->ignore_files = false;
8149
- $sucuri_fileinfo->ignore_directories = false;
8150
- $error_logs = $sucuri_fileinfo->find_file( $log_filename );
8151
$total_log_files = count( $error_logs );
8152
} else {
8153
$hardened = 2;
@@ -8333,12 +8561,12 @@ function sucuriscan_integrity_form_submissions(){
8333
function sucuriscan_get_integrity_tree( $dir = './', $recursive = false ){
8334
$abs_path = rtrim( ABSPATH, '/' );
8335
8336
- $sucuri_fileinfo = new SucuriScanFileInfo();
8337
- $sucuri_fileinfo->ignore_files = false;
8338
- $sucuri_fileinfo->ignore_directories = false;
8339
- $sucuri_fileinfo->run_recursively = $recursive;
8340
- $sucuri_fileinfo->scan_interface = SucuriScanOption::get_option( ':scan_interface' );
8341
- $integrity_tree = $sucuri_fileinfo->get_directory_tree_md5( $dir, true );
8342
8343
if ( ! $integrity_tree ) {
8344
$integrity_tree = array();
@@ -8915,6 +9143,21 @@ function sucuriscan_posthack_page(){
8915
echo SucuriScanTemplate::get_template( 'posthack', $template_variables );
8916
}
8917
8918
/**
8919
* Check whether the "I understand this operation" checkbox was marked or not.
8920
*
@@ -9057,7 +9300,7 @@ function sucuriscan_posthack_users( $process_form = false ){
9057
$max_per_page
9058
);
9059
9060
- if ( $total_items > SUCURISCAN_MAX_PAGINATION_BUTTONS ) {
9061
$template_variables['ResetPassword.PaginationVisibility'] = 'visible';
9062
}
9063
}
@@ -9142,38 +9385,51 @@ function sucuriscan_posthack_plugins( $process_form = false ){
9142
'ResetPlugin.CacheLifeTime' => 'unknown',
9143
);
9144
9145
-
9146
if ( defined( 'SUCURISCAN_GET_PLUGINS_LIFETIME' ) ) {
9147
$template_variables['ResetPlugin.CacheLifeTime'] = SUCURISCAN_GET_PLUGINS_LIFETIME;
9148
}
9149
9150
sucuriscan_posthack_reinstall_plugins( $process_form );
9151
- $all_plugins = SucuriScanAPI::get_plugins();
9152
- $counter = 0;
9153
9154
- foreach ( $all_plugins as $plugin_path => $plugin_data ) {
9155
- $css_class = ( $counter % 2 == 0 ) ? '' : 'alternate';
9156
- $plugin_type_class = ( $plugin_data['PluginType'] == 'free' ) ? 'primary' : 'warning';
9157
- $input_disabled = ( $plugin_data['PluginType'] == 'free' ) ? '' : 'disabled="disabled"';
9158
- $plugin_status = $plugin_data['IsPluginActive'] ? 'active' : 'not active';
9159
- $plugin_status_class = $plugin_data['IsPluginActive'] ? 'success' : 'default';
9160
-
9161
- $template_variables['ResetPlugin.PluginList'] .= SucuriScanTemplate::get_snippet('posthack-resetplugins', array(
9162
- 'ResetPlugin.CssClass' => $css_class,
9163
- 'ResetPlugin.Disabled' => $input_disabled,
9164
- 'ResetPlugin.PluginPath' => SucuriScan::escape( $plugin_path ),
9165
- 'ResetPlugin.Plugin' => SucuriScan::excerpt( $plugin_data['Name'], 35 ),
9166
- 'ResetPlugin.Version' => $plugin_data['Version'],
9167
- 'ResetPlugin.Type' => $plugin_data['PluginType'],
9168
- 'ResetPlugin.TypeClass' => $plugin_type_class,
9169
- 'ResetPlugin.Status' => $plugin_status,
9170
- 'ResetPlugin.StatusClass' => $plugin_status_class,
9171
- ));
9172
9173
- $counter += 1;
9174
- }
9175
9176
- return SucuriScanTemplate::get_section( 'posthack-resetplugins', $template_variables );
9177
}
9178
9179
/**
@@ -9192,10 +9448,10 @@ function sucuriscan_posthack_reinstall_plugins( $process_form = false ){
9192
9193
if ( $plugin_list = SucuriScanRequest::post( 'plugin_path', '_array' ) ) {
9194
// Create an instance of the FileInfo interface.
9195
- $sucuri_fileinfo = new SucuriScanFileInfo();
9196
- $sucuri_fileinfo->ignore_files = false;
9197
- $sucuri_fileinfo->ignore_directories = false;
9198
- $sucuri_fileinfo->skip_directories = false;
9199
9200
// Get (possible) cached information from the installed plugins.
9201
$all_plugins = SucuriScanAPI::get_plugins();
@@ -9213,7 +9469,7 @@ function sucuriscan_posthack_reinstall_plugins( $process_form = false ){
9213
// First, remove all files/sub-folders from the plugin's directory.
9214
if ( substr_count( $plugin_path, '/' ) >= 1 ) {
9215
$plugin_directory = dirname( WP_PLUGIN_DIR . '/' . $plugin_path );
9216
- $sucuri_fileinfo->remove_directory_tree( $plugin_directory );
9217
}
9218
9219
// Install a fresh copy of the plugin's files.
@@ -9872,8 +10128,16 @@ function sucuriscan_failed_logins_panel(){
9872
'FailedLogins.NoItemsVisibility' => 'visible',
9873
'FailedLogins.WarningVisibility' => 'visible',
9874
'FailedLogins.CollectPasswordsVisibility' => 'visible',
9875
);
9876
9877
$max_failed_logins = SucuriScanOption::get_option( ':maximum_failed_logins' );
9878
$notify_bruteforce_attack = SucuriScanOption::get_option( ':notify_bruteforce_attack' );
9879
$failed_logins = sucuriscan_get_failed_logins();
@@ -9897,37 +10161,50 @@ function sucuriscan_failed_logins_panel(){
9897
if ( $failed_logins ) {
9898
$counter = 0;
9899
9900
- foreach ( $failed_logins['entries'] as $login_data ) {
9901
- $css_class = ( $counter % 2 == 0 ) ? '' : 'alternate';
9902
- $wrong_user_password = '<span class="sucuriscan-label-default">hidden</span>';
9903
9904
- if ( sucuriscan_collect_wrong_passwords() === true ) {
9905
- if (
9906
- isset($login_data['user_password'])
9907
- && ! empty($login_data['user_password'])
9908
- ) {
9909
- $wrong_user_password = SucuriScan::escape( $login_data['user_password'] );
9910
- } else {
9911
- $wrong_user_password = '<span class="sucuriscan-label-info">empty</span>';
9912
}
9913
- }
9914
9915
- $template_variables['FailedLogins.List'] .= SucuriScanTemplate::get_snippet('lastlogins-failedlogins', array(
9916
- 'FailedLogins.CssClass' => $css_class,
9917
- 'FailedLogins.Num' => ($counter + 1),
9918
- 'FailedLogins.Username' => SucuriScan::escape( $login_data['user_login'] ),
9919
- 'FailedLogins.Password' => $wrong_user_password,
9920
- 'FailedLogins.RemoteAddr' => SucuriScan::escape( $login_data['remote_addr'] ),
9921
- 'FailedLogins.Datetime' => SucuriScan::datetime( $login_data['attempt_time'] ),
9922
- 'FailedLogins.UserAgent' => SucuriScan::escape( $login_data['user_agent'] ),
9923
- ));
9924
9925
- $counter += 1;
9926
}
9927
9928
if ( $counter > 0 ) {
9929
$template_variables['FailedLogins.NoItemsVisibility'] = 'hidden';
9930
}
9931
}
9932
9933
$template_variables['FailedLogins.MaxFailedLogins'] = $max_failed_logins;
@@ -10025,10 +10302,15 @@ function sucuriscan_get_failed_logins( $get_old_logs = false ){
10025
);
10026
10027
// Read and parse all the entries found in the datastore file.
10028
- foreach ( $lines as $i => $line ) {
10029
- if ( $i >= $default_content_n ) {
10030
- $login_data = @json_decode( trim( $line ), true );
10031
$login_data['attempt_date'] = date( 'r', $login_data['attempt_time'] );
10032
10033
if ( ! $login_data['user_agent'] ) {
10034
$login_data['user_agent'] = 'Unknown';
@@ -10794,6 +11076,16 @@ function sucuriscan_settings_form_submissions( $page_nonce = null ){
10794
SucuriScanEvent::report_info_event( $message );
10795
SucuriScanInterface::info( $message );
10796
}
10797
}
10798
}
10799
@@ -10906,10 +11198,10 @@ function sucuriscan_settings_general(){
10906
'ReverseProxySwitchValue' => 'disable',
10907
'ReverseProxySwitchCssClass' => 'button-danger',
10908
/* API Proxy Settings */
10909
- 'APIProxy.Host' => 'n/a',
10910
- 'APIProxy.Port' => 'n/a',
10911
- 'APIProxy.Username' => 'n/a',
10912
- 'APIProxy.Password' => 'n/a',
10913
'APIProxy.PasswordType' => 'default',
10914
'APIProxy.PasswordText' => 'empty',
10915
);
4
Plugin URI: http://wordpress.sucuri.net/
5
Description: The <a href="http://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.7.10
8
Author URI: http://sucuri.net
9
*/
10
66
/**
67
* Current version of the plugin's code.
68
*/
69
+ define( 'SUCURISCAN_VERSION', '1.7.10' );
70
71
/**
72
* The name of the Sucuri plugin main file.
197
'sucuriscan_notify_website_updated' => 'Receive email alerts when the WordPress version is updated',
198
'sucuriscan_notify_settings_updated' => 'Receive email alerts when your website settings are updated',
199
'sucuriscan_notify_theme_editor' => 'Receive email alerts when a file is modified with theme/plugin editor',
200
+ 'sucuriscan_notify_plugin_installed' => 'plugin:Receive email alerts when a <strong>plugin is installed</strong>',
201
+ 'sucuriscan_notify_plugin_activated' => 'plugin:Receive email alerts when a <strong>plugin is activated</strong>',
202
+ 'sucuriscan_notify_plugin_deactivated' => 'plugin:Receive email alerts when a <strong>plugin is deactivated</strong>',
203
+ 'sucuriscan_notify_plugin_updated' => 'plugin:Receive email alerts when a <strong>plugin is updated</strong>',
204
+ 'sucuriscan_notify_plugin_deleted' => 'plugin:Receive email alerts when a <strong>plugin is deleted</strong>',
205
+ 'sucuriscan_notify_widget_added' => 'widget:Receive email alerts when a <strong>widget is added</strong> to a sidebar',
206
+ 'sucuriscan_notify_widget_deleted' => 'widget:Receive email alerts when a <strong>widget is deleted</strong> from a sidebar',
207
+ 'sucuriscan_notify_theme_installed' => 'theme:Receive email alerts when a <strong>theme is installed</strong>',
208
+ 'sucuriscan_notify_theme_activated' => 'theme:Receive email alerts when a <strong>theme is activated</strong>',
209
+ 'sucuriscan_notify_theme_updated' => 'theme:Receive email alerts when a <strong>theme is updated</strong>',
210
+ 'sucuriscan_notify_theme_deleted' => 'theme:Receive email alerts when a <strong>theme is deleted</strong>',
211
);
212
213
$sucuriscan_schedule_allowed = array(
282
add_action( 'admin_enqueue_scripts', 'SucuriScanInterface::enqueue_scripts', 1 );
283
add_action( 'admin_menu', 'SucuriScanInterface::add_interface_menu' );
284
285
+ /**
286
+ * Attach Ajax requests to a custom page handler.
287
+ */
288
+ foreach ( $sucuriscan_pages as $page_func => $page_title ) {
289
+ $ajax_func = $page_func . '_ajax';
290
+
291
+ if ( function_exists( $ajax_func ) ) {
292
+ add_action( 'wp_ajax_' . $ajax_func, $ajax_func );
293
+ }
294
+ }
295
+
296
/**
297
* Function call interceptors.
298
*
806
*/
807
public static function datetime( $timestamp = 0 ){
808
if ( is_numeric( $timestamp ) && $timestamp > 0 ) {
809
+ $gmt_offset = get_option( 'gmt_offset' );
810
$date_format = get_option( 'date_format' );
811
$time_format = get_option( 'time_format' );
812
+ $tz_format = sprintf( '%s %s', $date_format, $time_format );
813
814
+ if ( is_numeric( $gmt_offset ) ) {
815
+ $timestamp += ( $gmt_offset * 3600 );
816
+ }
817
+
818
+ return date_i18n( $tz_format, $timestamp );
819
}
820
821
return null;
1647
/**
1648
* Skip some specific directories and file paths from the filesystem scan.
1649
*
1650
+ * @param string $directory Directory where the scanner is located at the moment.
1651
+ * @param string $filename Name of the folder or file being scanned at the moment.
1652
+ * @return boolean Either TRUE or FALSE representing that the scan should ignore this folder or not.
1653
*/
1654
private function ignore_folderpath( $directory = '', $filename = '' ){
1655
// Ignoring current and parent folders.
1698
return true;
1699
}
1700
1701
+ // Ignore files specified by the administrator.
1702
+ if ( ! empty($this->ignored_directories) ) {
1703
+ foreach ( $this->ignored_directories['directories'] as $ignored_dir ) {
1704
+ if ( strpos( $ignored_dir, $filename ) !== false ) {
1705
+ return true;
1706
+ }
1707
+ }
1708
+ }
1709
+
1710
// Any file maching one of these rules WILL NOT be ignored.
1711
if (
1712
( strpos( $filename, '.php' ) !== false) ||
1750
return $dirs;
1751
}
1752
1753
+ /**
1754
+ * Returns a list of lines matching the specified pattern in all the files found
1755
+ * in the specified directory, each entry in the list contains the relative path
1756
+ * of the file and the number of the line where the pattern was found, as well
1757
+ * as the string around the pattern in that line.
1758
+ *
1759
+ * @param string $directory Directory where the scanner is located at the moment.
1760
+ * @param string $pattern Text that will be searched inside each file.
1761
+ * @return array Associative list with the file path and line number of the match.
1762
+ */
1763
+ public function grep_pattern( $directory = '', $pattern = '' ){
1764
+ $dir_tree = $this->get_directory_tree( $directory );
1765
+ $pattern = '/.*' . str_replace( '/', '\/', $pattern ) . '.*/';
1766
+ $results = array();
1767
+
1768
+ if (
1769
+ class_exists( 'SplFileObject' )
1770
+ && class_exists( 'RegexIterator' )
1771
+ && SucuriScan::is_valid_pattern( $pattern )
1772
+ ) {
1773
+ foreach ( $dir_tree as $file_path ) {
1774
+ try {
1775
+ $fobject = new SplFileObject( $file_path );
1776
+ $fstream = new RegexIterator( $fobject, $pattern, RegexIterator::MATCH );
1777
+
1778
+ foreach ( $fstream as $key => $ltext ) {
1779
+ $lnumber = ( $key + 1 );
1780
+ $ltext = str_replace( "\n", '', $ltext );
1781
+ $fpath = str_replace( $directory, '', $file_path );
1782
+ $loutput = sprintf( '%s:%d:%s', $fpath, $lnumber, $ltext );
1783
+ $results[] = array(
1784
+ 'file_path' => $file_path,
1785
+ 'relative_path' => $fpath,
1786
+ 'line_number' => $lnumber,
1787
+ 'line_text' => $ltext,
1788
+ 'output' => $loutput,
1789
+ );
1790
+ }
1791
+ } catch ( RuntimeException $exception ) {
1792
+ SucuriScanEvent::report_exception( $exception );
1793
+ }
1794
+ }
1795
+ }
1796
+
1797
+ return $results;
1798
+ }
1799
+
1800
/**
1801
* Remove a directory recursively.
1802
*
2496
'sucuriscan_site_version' => '0.0',
2497
'sucuriscan_sitecheck_counter' => 0,
2498
'sucuriscan_sitecheck_scanner' => 'enabled',
2499
+ 'sucuriscan_verify_ssl_cert' => 'false',
2500
);
2501
2502
return $defaults;
2998
) {
2999
self::report_site_version();
3000
3001
+ $file_info = new SucuriScanFileInfo();
3002
+ $file_info->scan_interface = SucuriScanOption::get_option( ':scan_interface' );
3003
+ $signatures = $file_info->get_directory_tree_md5( ABSPATH );
3004
3005
if ( $signatures ) {
3006
$hashes_sent = SucuriScanAPI::send_hashes( $signatures );
3309
$user = get_userdata( $user_id );
3310
3311
if ( $user instanceof WP_User ) {
3312
+ $website = SucuriScan::get_domain();
3313
+ $user_login = $user->user_login;
3314
+ $display_name = $user->display_name;
3315
$new_password = wp_generate_password( 15, true, false );
3316
3317
+ $message = SucuriScanTemplate::get_section( 'notification-resetpwd', array(
3318
+ 'ResetPassword.UserName' => $user_login,
3319
+ 'ResetPassword.DisplayName' => $display_name,
3320
+ 'ResetPassword.Password' => $new_password,
3321
+ 'ResetPassword.Website' => $website,
3322
+ ) );
3323
3324
$data_set = array( 'Force' => true ); // Skip limit for emails per hour.
3325
SucuriScanMail::send_mail( $user->user_email, 'Password changed', $message, $data_set );
4226
* @param string $method HTTP method that will be used to send the request.
4227
* @param array $params Parameters for the request defined in an associative array of key-value.
4228
* @param array $args Request arguments like the timeout, redirections, headers, cookies, etc.
4229
+ * @return array Response object after the HTTP request is executed.
4230
*/
4231
private static function api_call( $url = '', $method = 'GET', $params = array(), $args = array() ){
4232
if ( ! $url ) {
4268
} elseif ( $method == 'POST' ) {
4269
$req_args['body'] = $params;
4270
$response = wp_remote_post( $url, $req_args );
4271
+ } else {
4272
+ $response = false;
4273
+ SucuriScanInterface::error( 'HTTP method not allowed: ' . $method );
4274
}
4275
4276
+ return self::process_response( $response, $params, $args );
4277
+ }
4278
4279
+ /**
4280
+ * Test ability of the site to send HTTP requests.
4281
+ *
4282
+ * @return string Response data from the remote service.
4283
+ */
4284
+ public static function test_api_call(){
4285
+ $params = array();
4286
+ $params['first'] = microtime();
4287
+ $params['lorem'] = microtime();
4288
+ $params['middle'] = microtime();
4289
+ $params['foobar'] = microtime();
4290
+ $params['last'] = microtime();
4291
+ $response_data = '{invalid_data}';
4292
4293
+ $response = self::api_call( 'http://httpbin.org/post', 'POST', $params );
4294
+
4295
+ if (
4296
+ is_array( $response )
4297
+ && array_key_exists( 'body_raw', $response )
4298
+ && is_string( $response['body_raw'] )
4299
+ ) {
4300
+ $response_data = $response['body_raw'];
4301
}
4302
4303
+ return $response_data;
4304
}
4305
4306
/**
4405
* @param array $params Parameters for the request defined in an associative array of key-value.
4406
* @param boolean $send_api_key Whether the API key should be added to the request parameters or not.
4407
* @param array $args Request arguments like the timeout, redirections, headers, cookies, etc.
4408
+ * @return array Response object after the HTTP request is executed.
4409
*/
4410
public static function api_call_wordpress( $method = 'GET', $params = array(), $send_api_key = true, $args = array() ){
4411
$url = SUCURISCAN_API;
4432
*
4433
* @param string $method HTTP method that will be used to send the request.
4434
* @param array $params Parameters for the request defined in an associative array of key-value.
4435
+ * @return array Response object after the HTTP request is executed.
4436
*/
4437
public static function api_call_cloudproxy( $method = 'GET', $params = array() ){
4438
$send_request = false;
4462
return false;
4463
}
4464
4465
+ /**
4466
+ * Execute some actions according to the response message.
4467
+ *
4468
+ * @param array $response Response object after the HTTP request is executed.
4469
+ * @param array $params Parameters for the request defined in an associative array of key-value.
4470
+ * @param array $args Request arguments like the timeout, redirections, headers, cookies, etc.
4471
+ * @return array Response object with some modifications.
4472
+ */
4473
+ private static function process_response( $response = array(), $params = array(), $args = array() ){
4474
+ /**
4475
+ * Convert the error message generated by the code base functions after the HTTP
4476
+ * request is executed to a valid response object that will allow this code
4477
+ * process the data according to the specified standards.
4478
+ */
4479
+ if ( is_wp_error( $response ) ) {
4480
+ // Extract information from the error object.
4481
+ $error_message = $response->get_error_message();
4482
+ $request_action = isset( $params['a'] ) ? $params['a'] : 'unknown';
4483
+
4484
+ // Build a fake request response with custom data.
4485
+ $data_set = array(
4486
+ 'status' => 0,
4487
+ 'action' => $request_action,
4488
+ 'messages' => array( $error_message ),
4489
+ 'request_time' => SucuriScan::local_time(),
4490
+ 'output' => new stdClass(),
4491
+ 'verbose' => 0,
4492
+ );
4493
+
4494
+ // Build the response object and encode data.
4495
+ $response = array();
4496
+ $response['body'] = json_encode( $data_set );
4497
+ $response['headers']['date'] = date( 'r' );
4498
+ $response['headers']['connection'] = 'close';
4499
+ $response['headers']['content-type'] = 'application/json';
4500
+ $response['headers']['content-length'] = strlen( $response['body'] );
4501
+ $response['response']['code'] = 500;
4502
+ $response['response']['message'] = 'ERROR';
4503
+ }
4504
+
4505
+ /**
4506
+ * Process the response object.
4507
+ *
4508
+ * Some response messages and even errors require extra steps of processing to,
4509
+ * for example, try to fix automatically issues related with disconnections,
4510
+ * timeouts, SSL certificate verifications, etc. Some of these actions can not
4511
+ * be fixed if the server where the website is being hosted has a special
4512
+ * configuration, which then requires the human interaction of the admin user,
4513
+ * they will see extra information explaining the response and how to proceed
4514
+ * with it.
4515
+ */
4516
+ if (
4517
+ is_array( $response )
4518
+ && array_key_exists( 'body', $response )
4519
+ && array_key_exists( 'headers', $response )
4520
+ && array_key_exists( 'response', $response )
4521
+ ) {
4522
+ $response['body_raw'] = $response['body'];
4523
+
4524
+ // Check if the response data is JSON-encoded, then decode it.
4525
+ if (
4526
+ isset($response['headers']['content-type'])
4527
+ && $response['headers']['content-type'] == 'application/json'
4528
+ ) {
4529
+ $assoc = ( isset($args['assoc']) && $args['assoc'] === true ) ? true : false;
4530
+ $response['body'] = @json_decode( $response['body_raw'], $assoc );
4531
+ } elseif ( self::is_serialized( $response['body'] ) ) {
4532
+ // Check if the response data is serialized (which we will consider as insecure).
4533
+ $response['body_raw'] = null;
4534
+ $response['body'] = 'ERROR:Serialized data is not supported.';
4535
+ }
4536
+
4537
+ return $response;
4538
+ }
4539
+
4540
+ return false;
4541
+ }
4542
+
4543
/**
4544
* Determine whether an API response was successful or not checking the expected
4545
* generic variables and types, in case of an error a notification will appears
4546
* in the administrator panel explaining the result of the operation.
4547
*
4548
+ * @param array $response Response object after the HTTP request is executed.
4549
* @return boolean Either true or false in case of success or failure of the API response (respectively).
4550
*/
4551
private static function handle_response( $response = array() ){
4559
4560
// Check whether the message list is empty or not.
4561
if ( isset($response['body']->messages[0]) ) {
4562
+ $action_message = $response['body']->messages[0] . '.';
4563
}
4564
4565
+ // Keep a copy of the original API response message.
4566
+ $raw_message = $action_message;
4567
+
4568
// Special response for invalid API keys.
4569
+ if ( stripos( $raw_message, 'log file not found' ) !== false ) {
4570
SucuriScanOption::delete_option( ':api_key' );
4571
4572
$action_message .= ' This generally happens when you add an invalid API key, the'
4575
. ' key to your email address.';
4576
}
4577
4578
+ // Special response for invalid CloudProxy API keys.
4579
+ if ( stripos( $raw_message, 'wrong api key' ) !== false ) {
4580
+ SucuriScanOption::delete_option( ':cloudproxy_apikey' );
4581
+ SucuriScanOption::delete_option( ':revproxy' );
4582
+
4583
+ $action_message .= ' The CloudProxy API key does not seems to be valid.';
4584
+ }
4585
+
4586
+ // Special response for connection time outs.
4587
+ if ( stripos( $raw_message, 'timed out' ) !== false ) {
4588
+ $current_timeout = SucuriScanOption::get_option( ':request_timeout' );
4589
+
4590
+ if ( $current_timeout < 300 ) {
4591
+ SucuriScanOption::update_option( ':request_timeout', 300 );
4592
+ }
4593
+
4594
+ $action_message .= ' This generally happens when the API service fails to respond'
4595
+ . ' in time, you currently have configured the plugin to discard the network'
4596
+ . ' connection after ' . $current_timeout . ' seconds. Wait a few minutes until'
4597
+ . ' the issue is resolved by itself, or change the timeout limit from the general'
4598
+ . ' settings page of the plugin, the option is named "API request timeout".';
4599
+ }
4600
+
4601
+ // Stop SSL peer verification on connection failures.
4602
+ if (
4603
+ stripos( $raw_message, 'no alternative certificate' )
4604
+ || stripos( $raw_message, 'error setting certificate' )
4605
+ ) {
4606
+ SucuriScanOption::update_option( ':verify_ssl_cert', 'false' );
4607
+
4608
+ $action_message .= 'There were some issues with the SSL certificate either in this'
4609
+ . ' server or with the remote API service. The automatic verification of the'
4610
+ . ' certificates has been deactivated to reduce the noise during the execution'
4611
+ . ' of the HTTP requests.';
4612
+ }
4613
+
4614
+ SucuriScanInterface::error(
4615
+ sprintf(
4616
+ '(%d) %s: %s',
4617
+ SucuriScan::local_time(),
4618
+ ucwords( $response['body']->action ),
4619
+ $action_message
4620
+ )
4621
+ );
4622
}
4623
} else {
4624
SucuriScanInterface::error( 'Could not determine the status of an API call.' );
4761
if ( preg_match( $log_pattern, $log, $log_match ) ) {
4762
$log_data = array(
4763
'event' => 'notice',
4764
+ 'date' => '',
4765
+ 'time' => '',
4766
'datetime' => '',
4767
'timestamp' => 0,
4768
'account' => $log_match[3],
4773
'file_list_count' => 0,
4774
);
4775
4776
+ // Extract and fix the date and time using the Eastern time zone.
4777
+ $datetime = sprintf( '%s %s EDT', $log_match[1], $log_match[2] );
4778
+ $log_data['timestamp'] = strtotime( $datetime );
4779
+ $log_data['datetime'] = date( 'Y-m-d H:i:s', $log_data['timestamp'] );
4780
+ $log_data['date'] = date( 'Y-m-d', $log_data['timestamp'] );
4781
+ $log_data['time'] = date( 'H:i:s', $log_data['timestamp'] );
4782
4783
// Extract more information from the generic audit logs.
4784
+ $log_data['message'] = str_replace( '<br>', '; ', $log_data['message'] );
4785
+
4786
if ( preg_match( $generic_pattern, $log_data['message'], $log_extra ) ) {
4787
$log_data['event'] = strtolower( $log_extra[1] );
4788
$log_data['message'] = trim( $log_extra[3] );
4821
if ( preg_match( $extra_pattern, $log_data['message'], $log_extra ) ) {
4822
$log_data['message'] = $log_extra[1];
4823
$log_extra[2] = str_replace( ', new size', '; new size', $log_extra[2] );
4824
+ $log_extra[2] = str_replace( ",\x20", ";\x20", $log_extra[2] );
4825
$log_data['file_list'] = explode( ',', $log_extra[2] );
4826
$log_data['file_list_count'] = count( $log_data['file_list'] );
4827
}
5695
return $url_path;
5696
}
5697
5698
+ /**
5699
+ * Generate an URL pointing to the page indicated in the function and that must
5700
+ * be loaded through the Ajax handler of the administrator panel.
5701
+ *
5702
+ * @param string $page Short name of the page that will be generated.
5703
+ * @return string Full string containing the link of the page.
5704
+ */
5705
+ public static function get_ajax_url( $page = '' ){
5706
+ $url_path = admin_url( 'admin-ajax.php?page=sucuriscan' );
5707
+
5708
+ if ( ! empty($page) ) {
5709
+ $url_path .= '_' . strtolower( $page );
5710
+ }
5711
+
5712
+ return $url_path;
5713
+ }
5714
+
5715
/**
5716
* Complement the list of pseudo-variables that will be used in the base
5717
* template files, this will also generate the navigation bar and detect which
5753
5754
$params[ $pseudo_var ] = self::get_url( $unique_name );
5755
5756
+ // Copy URL variable and create an Ajax handler.
5757
+ $pseudo_var_ajax = 'Ajax' . $pseudo_var;
5758
+ $params[ $pseudo_var_ajax ] = self::get_ajax_url( $unique_name );
5759
+
5760
$navbar_item_css_class = 'nav-tab';
5761
5762
if ( $params['CurrentPageFunc'] == $sub_page_func ) {
6167
}
6168
6169
// Scan the project and file all directories.
6170
+ $file_info = new SucuriScanFileInfo();
6171
+ $file_info->ignore_files = true;
6172
+ $file_info->ignore_directories = true;
6173
+ $file_info->scan_interface = SucuriScanOption::get_option( ':scan_interface' );
6174
+ $directory_list = $file_info->get_diretories_only( ABSPATH );
6175
6176
if ( $directory_list ) {
6177
$response['is_not_ignored'] = $directory_list;
6433
* @return void
6434
*/
6435
public static function initialize(){
6436
+ if ( SucuriScan::support_reverse_proxy() ) {
6437
$_SERVER['SUCURIREAL_REMOTE_ADDR'] = $_SERVER['REMOTE_ADDR'];
6438
$_SERVER['REMOTE_ADDR'] = SucuriScan::get_remote_addr();
6439
}
6476
if (
6477
function_exists( 'add_menu_page' )
6478
&& $sucuriscan_pages
6479
+ && is_array( $sucuriscan_pages )
6480
+ && array_key_exists( 'sucuriscan', $sucuriscan_pages )
6481
) {
6482
// Add main menu link.
6483
add_menu_page(
6489
SUCURISCAN_URL . '/inc/images/menu-icon.png'
6490
);
6491
6492
+ foreach ( $sucuriscan_pages as $sub_page_func => $sub_page_title ) {
6493
if (
6494
$sub_page_func == 'sucuriscan_scanner'
6495
&& SucuriScanTemplate::is_sitecheck_disabled()
6521
*/
6522
public static function handle_old_plugins(){
6523
if ( class_exists( 'SucuriScanFileInfo' ) ) {
6524
+ $file_info = new SucuriScanFileInfo();
6525
+ $file_info->ignore_files = false;
6526
+ $file_info->ignore_directories = false;
6527
6528
$plugins = array(
6529
'sucuri-wp-plugin/sucuri.php',
6538
deactivate_plugins( $plugin );
6539
}
6540
6541
+ $plugin_removed = $file_info->remove_directory_tree( $plugin_directory );
6542
}
6543
}
6544
}
8372
8373
// Search error log files in the project.
8374
if ( $scan_errorlogs != 'disabled' ) {
8375
+ $file_info = new SucuriScanFileInfo();
8376
+ $file_info->ignore_files = false;
8377
+ $file_info->ignore_directories = false;
8378
+ $error_logs = $file_info->find_file( $log_filename );
8379
$total_log_files = count( $error_logs );
8380
} else {
8381
$hardened = 2;
8561
function sucuriscan_get_integrity_tree( $dir = './', $recursive = false ){
8562
$abs_path = rtrim( ABSPATH, '/' );
8563
8564
+ $file_info = new SucuriScanFileInfo();
8565
+ $file_info->ignore_files = false;
8566
+ $file_info->ignore_directories = false;
8567
+ $file_info->run_recursively = $recursive;
8568
+ $file_info->scan_interface = SucuriScanOption::get_option( ':scan_interface' );
8569
+ $integrity_tree = $file_info->get_directory_tree_md5( $dir, true );
8570
8571
if ( ! $integrity_tree ) {
8572
$integrity_tree = array();
9143
echo SucuriScanTemplate::get_template( 'posthack', $template_variables );
9144
}
9145
9146
+ /**
9147
+ * Handle an Ajax request for this specific page.
9148
+ *
9149
+ * @return mixed.
9150
+ */
9151
+ function sucuriscan_posthack_ajax(){
9152
+ SucuriScanInterface::check_permissions();
9153
+
9154
+ if ( SucuriScanInterface::check_nonce() ) {
9155
+ sucuriscan_posthack_plugins_ajax();
9156
+ }
9157
+
9158
+ wp_die();
9159
+ }
9160
+
9161
/**
9162
* Check whether the "I understand this operation" checkbox was marked or not.
9163
*
9300
$max_per_page
9301
);
9302
9303
+ if ( $total_items > $max_per_page ) {
9304
$template_variables['ResetPassword.PaginationVisibility'] = 'visible';
9305
}
9306
}
9385
'ResetPlugin.CacheLifeTime' => 'unknown',
9386
);
9387
9388
if ( defined( 'SUCURISCAN_GET_PLUGINS_LIFETIME' ) ) {
9389
$template_variables['ResetPlugin.CacheLifeTime'] = SUCURISCAN_GET_PLUGINS_LIFETIME;
9390
}
9391
9392
sucuriscan_posthack_reinstall_plugins( $process_form );
9393
9394
+ return SucuriScanTemplate::get_section( 'posthack-resetplugins', $template_variables );
9395
+ }
9396
9397
+ /**
9398
+ * Process the Ajax request to retrieve the plugins metadata.
9399
+ *
9400
+ * @return string HTML code for a table with the plugins metadata.
9401
+ */
9402
+ function sucuriscan_posthack_plugins_ajax(){
9403
+ if ( SucuriScanRequest::post( 'form_action' ) == 'get_plugins_data' ) {
9404
+ $all_plugins = SucuriScanAPI::get_plugins();
9405
+ $response = '';
9406
+ $counter = 0;
9407
9408
+ foreach ( $all_plugins as $plugin_path => $plugin_data ) {
9409
+ $css_class = ( $counter % 2 == 0 ) ? '' : 'alternate';
9410
+ $plugin_type_class = ( $plugin_data['PluginType'] == 'free' ) ? 'primary' : 'warning';
9411
+ $input_disabled = ( $plugin_data['PluginType'] == 'free' ) ? '' : 'disabled="disabled"';
9412
+ $plugin_status = $plugin_data['IsPluginActive'] ? 'active' : 'not active';
9413
+ $plugin_status_class = $plugin_data['IsPluginActive'] ? 'success' : 'default';
9414
+
9415
+ $response .= SucuriScanTemplate::get_snippet('posthack-resetplugins', array(
9416
+ 'ResetPlugin.CssClass' => $css_class,
9417
+ 'ResetPlugin.Disabled' => $input_disabled,
9418
+ 'ResetPlugin.PluginPath' => SucuriScan::escape( $plugin_path ),
9419
+ 'ResetPlugin.Plugin' => SucuriScan::excerpt( $plugin_data['Name'], 35 ),
9420
+ 'ResetPlugin.Version' => $plugin_data['Version'],
9421
+ 'ResetPlugin.Type' => $plugin_data['PluginType'],
9422
+ 'ResetPlugin.TypeClass' => $plugin_type_class,
9423
+ 'ResetPlugin.Status' => $plugin_status,
9424
+ 'ResetPlugin.StatusClass' => $plugin_status_class,
9425
+ ));
9426
+
9427
+ $counter += 1;
9428
+ }
9429
+
9430
+ print( $response );
9431
+ exit(0);
9432
+ }
9433
}
9434
9435
/**
9448
9449
if ( $plugin_list = SucuriScanRequest::post( 'plugin_path', '_array' ) ) {
9450
// Create an instance of the FileInfo interface.
9451
+ $file_info = new SucuriScanFileInfo();
9452
+ $file_info->ignore_files = false;
9453
+ $file_info->ignore_directories = false;
9454
+ $file_info->skip_directories = false;
9455
9456
// Get (possible) cached information from the installed plugins.
9457
$all_plugins = SucuriScanAPI::get_plugins();
9469
// First, remove all files/sub-folders from the plugin's directory.
9470
if ( substr_count( $plugin_path, '/' ) >= 1 ) {
9471
$plugin_directory = dirname( WP_PLUGIN_DIR . '/' . $plugin_path );
9472
+ $file_info->remove_directory_tree( $plugin_directory );
9473
}
9474
9475
// Install a fresh copy of the plugin's files.
10128
'FailedLogins.NoItemsVisibility' => 'visible',
10129
'FailedLogins.WarningVisibility' => 'visible',
10130
'FailedLogins.CollectPasswordsVisibility' => 'visible',
10131
+ 'FailedLogins.PaginationLinks' => '',
10132
+ 'FailedLogins.PaginationVisibility' => 'hidden',
10133
);
10134
10135
+ // Define variables for the pagination.
10136
+ $page_number = SucuriScanTemplate::get_page_number();
10137
+ $max_per_page = SUCURISCAN_MAX_PAGINATION_BUTTONS;
10138
+ $page_offset = ( $page_number - 1 ) * $max_per_page;
10139
+ $page_limit = ( $page_offset + $max_per_page );
10140
+
10141
$max_failed_logins = SucuriScanOption::get_option( ':maximum_failed_logins' );
10142
$notify_bruteforce_attack = SucuriScanOption::get_option( ':notify_bruteforce_attack' );
10143
$failed_logins = sucuriscan_get_failed_logins();
10161
if ( $failed_logins ) {
10162
$counter = 0;
10163
10164
+ for ( $key = $page_offset; $key < $page_limit; $key++ ) {
10165
+ if ( array_key_exists( $key, $failed_logins['entries'] ) ) {
10166
+ $login_data = $failed_logins['entries'][ $key ];
10167
+ $css_class = ( $counter % 2 == 0 ) ? '' : 'alternate';
10168
+ $wrong_user_password = '<span class="sucuriscan-label-default">hidden</span>';
10169
10170
+ if ( sucuriscan_collect_wrong_passwords() === true ) {
10171
+ if (
10172
+ isset($login_data['user_password'])
10173
+ && ! empty($login_data['user_password'])
10174
+ ) {
10175
+ $wrong_user_password = SucuriScan::escape( $login_data['user_password'] );
10176
+ } else {
10177
+ $wrong_user_password = '<span class="sucuriscan-label-info">empty</span>';
10178
+ }
10179
}
10180
10181
+ $template_variables['FailedLogins.List'] .= SucuriScanTemplate::get_snippet('lastlogins-failedlogins', array(
10182
+ 'FailedLogins.CssClass' => $css_class,
10183
+ 'FailedLogins.Num' => $login_data['attempt_count'],
10184
+ 'FailedLogins.Username' => SucuriScan::escape( $login_data['user_login'] ),
10185
+ 'FailedLogins.Password' => $wrong_user_password,
10186
+ 'FailedLogins.RemoteAddr' => SucuriScan::escape( $login_data['remote_addr'] ),
10187
+ 'FailedLogins.Datetime' => SucuriScan::datetime( $login_data['attempt_time'] ),
10188
+ 'FailedLogins.UserAgent' => SucuriScan::escape( $login_data['user_agent'] ),
10189
+ ));
10190
10191
+ $counter += 1;
10192
+ }
10193
}
10194
10195
if ( $counter > 0 ) {
10196
$template_variables['FailedLogins.NoItemsVisibility'] = 'hidden';
10197
}
10198
+
10199
+ $template_variables['FailedLogins.PaginationLinks'] = SucuriScanTemplate::get_pagination(
10200
+ '%%SUCURI.URL.Lastlogins%%#failed-logins',
10201
+ $failed_logins['count'],
10202
+ $max_per_page
10203
+ );
10204
+
10205
+ if ( $failed_logins['count'] > $max_per_page ) {
10206
+ $template_variables['FailedLogins.PaginationVisibility'] = 'visible';
10207
+ }
10208
}
10209
10210
$template_variables['FailedLogins.MaxFailedLogins'] = $max_failed_logins;
10302
);
10303
10304
// Read and parse all the entries found in the datastore file.
10305
+ $offset = count( $lines ) - 1;
10306
+
10307
+ for ( $key = $offset; $key >= 0; $key-- ) {
10308
+ $line = trim( $lines[ $key ] );
10309
+ $login_data = @json_decode( $line, true );
10310
+
10311
+ if ( is_array( $login_data ) ) {
10312
$login_data['attempt_date'] = date( 'r', $login_data['attempt_time'] );
10313
+ $login_data['attempt_count'] = ( $key + 1 );
10314
10315
if ( ! $login_data['user_agent'] ) {
10316
$login_data['user_agent'] = 'Unknown';
11076
SucuriScanEvent::report_info_event( $message );
11077
SucuriScanInterface::info( $message );
11078
}
11079
+
11080
+ // Debug ability of the plugin to send HTTP requests correctly.
11081
+ if ( $debug_request = SucuriScanRequest::post( ':debug_request' ) ) {
11082
+ SucuriScanInterface::info(
11083
+ sprintf(
11084
+ '<pre>%s</pre>',
11085
+ SucuriScanAPI::test_api_call()
11086
+ )
11087
+ );
11088
+ }
11089
}
11090
}
11091
11198
'ReverseProxySwitchValue' => 'disable',
11199
'ReverseProxySwitchCssClass' => 'button-danger',
11200
/* API Proxy Settings */
11201
+ 'APIProxy.Host' => 'no_proxy_host',
11202
+ 'APIProxy.Port' => 'no_proxy_port',
11203
+ 'APIProxy.Username' => 'no_proxy_username',
11204
+ 'APIProxy.Password' => 'no_proxy_password',
11205
'APIProxy.PasswordType' => 'default',
11206
'APIProxy.PasswordText' => 'empty',
11207
);