PluginProbe
Patchstack – WordPress & Plugins Security / 2.3.7
Patchstack – WordPress & Plugins Security v2.3.7
2.3.7 trunk 2.1.0 2.1.1 2.1.10 2.1.11 2.1.12 2.1.13 2.1.14 2.1.15 2.1.16 2.1.17 2.1.18 2.1.19 2.1.2 2.1.20 2.1.21 2.1.22 2.1.23 2.1.24 2.1.25 2.1.3 2.1.4 2.1.5 2.1.6 All 49 releases
← All changes | includes/htaccess.php +41 -13 2.1.12.3.7 View file →
@@ -23,9 +23,9 @@
23 23 if ( $this->get_option( 'patchstack_license_free', 0 ) == 1 ) {
24 24 return;
25 25 }
26 26
27 - add_action( 'updated_option', array( $this, 'update_option_extras' ), 10, 3 );
27 + add_action( 'updated_option', [ $this, 'update_option_extras' ], 10, 3 );
28 28 }
29 29
30 30 /**
31 31 * If option is updated, write to .htaccess file.
@@ -35,11 +35,17 @@
35 35 * @param mixed $value
36 36 * @return void
37 37 */
38 38 public function update_option_extras( $option_name, $old_value, $value ) {
39 - if ( in_array( $option_name, array( 'patchstack_prevent_default_file_access', 'patchstack_basic_firewall', 'patchstack_pingback_protection', 'patchstack_block_debug_log_access', 'patchstack_block_fake_bots', 'patchstack_index_views', 'patchstack_trace_and_track', 'patchstack_proxy_comment_posting', 'patchstack_image_hotlinking', 'patchstack_firewall_custom_rules' ) ) ) {
40 - $this->plugin->rules->post_firewall_rules();
39 + if ( !in_array( $option_name, [ 'patchstack_prevent_default_file_access', 'patchstack_basic_firewall', 'patchstack_pingback_protection', 'patchstack_block_debug_log_access', 'patchstack_block_fake_bots', 'patchstack_index_views', 'patchstack_trace_and_track', 'patchstack_proxy_comment_posting', 'patchstack_image_hotlinking', 'patchstack_firewall_custom_rules' ] ) ) {
40 + return;
41 41 }
42 +
43 + if ( $old_value == $value ) {
44 + return;
45 + }
46 +
47 + $this->plugin->rules->post_firewall_rules();
42 48 }
43 49
44 50 /**
45 51 * Get the turned on .htaccess firewall settings.
@@ -46,10 +52,10 @@
46 52 *
47 53 * @return array
48 54 */
49 55 public function get_firewall_rule_settings() {
50 - $settings = array();
51 - $options = array( 'patchstack_prevent_default_file_access', 'patchstack_basic_firewall', 'patchstack_block_debug_log_access', 'patchstack_block_fake_bots', 'patchstack_index_views', 'patchstack_proxy_comment_posting', 'patchstack_image_hotlinking', 'patchstack_basicscanblock' );
56 + $settings = [];
57 + $options = [ 'patchstack_prevent_default_file_access', 'patchstack_basic_firewall', 'patchstack_block_debug_log_access', 'patchstack_block_fake_bots', 'patchstack_index_views', 'patchstack_proxy_comment_posting', 'patchstack_image_hotlinking', 'patchstack_basicscanblock' ];
52 58 foreach ( $options as $option ) {
53 59 if ( get_site_option( $option ) ) {
54 60 $settings[] = ( $option == 'patchstack_basicscanblock' ? 'webarx_wpscan_block' : str_replace( 'patchstack_', 'webarx_', $option ) );
55 61 }
@@ -65,9 +71,9 @@
65 71 */
66 72 public function firewall() {
67 73 // Get the firewall state.
68 74 $sum_of_firewall = 0;
69 - foreach ( array( 'patchstack_prevent_default_file_access', 'patchstack_basic_firewall', 'patchstack_pingback_protection', 'patchstack_block_debug_log_access', 'patchstack_block_fake_bots', 'patchstack_index_views', 'patchstack_trace_and_track', 'patchstack_proxy_comment_posting', 'patchstack_image_hotlinking' ) as $option ) {
75 + foreach ( [ 'patchstack_prevent_default_file_access', 'patchstack_basic_firewall', 'patchstack_pingback_protection', 'patchstack_block_debug_log_access', 'patchstack_block_fake_bots', 'patchstack_index_views', 'patchstack_trace_and_track', 'patchstack_proxy_comment_posting', 'patchstack_image_hotlinking' ] as $option ) {
70 76 $value = get_site_option( $option, 0 );
71 77 $sum_of_firewall += empty( $value ) ? 0 : 1;
72 78 }
73 79
@@ -72,9 +78,9 @@
72 78 }
73 79
74 80 // Update the options.
75 81 $onoff = $sum_of_firewall > 1 ? 0 : 1;
76 - foreach ( array( 'patchstack_prevent_default_file_access', 'patchstack_basic_firewall', 'patchstack_block_debug_log_access', 'patchstack_index_views', 'patchstack_proxy_comment_posting' ) as $option ) {
82 + foreach ( [ 'patchstack_prevent_default_file_access', 'patchstack_basic_firewall', 'patchstack_block_debug_log_access', 'patchstack_index_views', 'patchstack_proxy_comment_posting' ] as $option ) {
77 83 update_site_option( $option, $onoff );
78 84 }
79 85 update_site_option( 'patchstack_block_fake_bots', 0 );
80 86 update_site_option( 'patchstack_image_hotlinking', 0 );
@@ -95,9 +101,9 @@
95 101 * @param string $rules
96 102 * @return void
97 103 */
98 104 public function write_rules_to_htaccess( $rules = '' ) {
99 - if ( ! $this->is_server_supported() || get_site_option( 'patchstack_disable_htaccess', 0 ) ) {
105 + if ( ! $this->is_server_supported() || get_site_option( 'patchstack_disable_htaccess', 0 ) || ( defined( 'PS_DISABLE_HTACCESS' ) && PS_DISABLE_HTACCESS ) ) {
100 106 return false;
101 107 }
102 108
103 109 // Determine if the .htaccess file exists.
@@ -114,9 +120,9 @@
114 120 }
115 121
116 122 // Get the current rules.
117 123 $current = $old = $fs->get_contents( ABSPATH . '.htaccess' );
118 - $current = $this->delete_all_between( '# Patchstack Firewall Start', "# Patchstack Firewall End\r\n", $current );
124 + $current = $this->delete_all_between( '# Patchstack Firewall Start', '# Patchstack Firewall End', $current );
119 125
120 126 // If no rules, then we delete the old ones.
121 127 if ( $rules != '' ) {
122 128 $current = "# Patchstack Firewall Start\r\n<IfModule mod_rewrite.c>\r\nRewriteEngine On\r\n" . $rules . "\r\n</IfModule>\r\n# Patchstack Firewall End\r\n" . $current;
@@ -142,9 +148,9 @@
142 148 * @param string $rules
143 149 * @return boolean
144 150 */
145 151 public function write_to_htaccess( $rules = '' ) {
146 - if ( ! $this->is_server_supported() || get_site_option( 'patchstack_disable_htaccess', 0 ) ) {
152 + if ( ! $this->is_server_supported() || get_site_option( 'patchstack_disable_htaccess', 0 ) || ( defined( 'PS_DISABLE_HTACCESS' ) && PS_DISABLE_HTACCESS ) ) {
147 153 return false;
148 154 }
149 155
150 156 require_once ABSPATH . 'wp-admin/includes/class-wp-filesystem-base.php';
@@ -153,8 +159,22 @@
153 159 if ( ! $fs->exists( ABSPATH . '.htaccess' ) ) {
154 160 $fs->touch( ABSPATH . '.htaccess' );
155 161 }
156 162
163 + // Some rule adjustments.
164 + $rewrites = [
165 + 'RedirectMatch 409 .(htaccess|htpasswd|errordocs|logs)$' => 'RedirectMatch 403 \.(htaccess|htpasswd|errordocs|logs)$',
166 + "\n RewriteCond %{HTTP_COOKIE} !^.*wordpress_logged_in.*$ [NC]" => '',
167 + "\n RewriteCond %{REMOTE_ADDR} !=18.221.197.243" => '',
168 + '^wp-includes/[^/]+.php$' => '^wp-includes/.*\.php$',
169 + 'RewriteRule ^debug*.*log$ index.php?webarx_fpage=502 [L,QSA]' => 'RewriteRule debug\.log$ index.php?webarx_fpage=502 [L,QSA]',
170 + '*.*' => '\.'
171 + ];
172 +
173 + foreach ($rewrites as $find => $replace) {
174 + $rules = str_replace($find, $replace, $rules);
175 + }
176 +
157 177 return $this->plugin->htaccess->self_check( $rules );
158 178 }
159 179
160 180 /**
@@ -162,10 +182,10 @@
162 182 *
163 183 * @return boolean
164 184 */
165 185 public function is_server_supported() {
166 - $server = strtolower( filter_var( $_SERVER['SERVER_SOFTWARE'], FILTER_SANITIZE_STRING ) );
167 - foreach ( array( 'apache', 'nginx', 'litespeed' ) as $webserver ) {
186 + $server = strtolower( $_SERVER['SERVER_SOFTWARE'] );
187 + foreach ( [ 'apache', 'nginx', 'litespeed' ] as $webserver ) {
168 188 if ( strstr( $server, $webserver ) ) {
169 189 return true;
170 190 }
171 191 }
@@ -325,8 +345,16 @@
325 345 if ( $begin_pos === false || $end_pos === false ) {
326 346 return $string;
327 347 }
328 348
329 - $delete = substr( $string, $begin_pos, ( $end_pos + strlen( $end ) ) - $begin_pos );
349 + $end_pos += strlen( $end );
350 +
351 + // Consume any trailing newline characters so the block is removed cleanly
352 + // regardless of CRLF/LF line endings and repeated writes don't stack blank lines.
353 + while ( isset( $string[ $end_pos ] ) && ( $string[ $end_pos ] === "\r" || $string[ $end_pos ] === "\n" ) ) {
354 + $end_pos++;
355 + }
356 +
357 + $delete = substr( $string, $begin_pos, $end_pos - $begin_pos );
330 358 return str_replace( $delete, '', $string );
331 359 }
332 360 }