PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 6.3.0
Defender Security – Malware Scanner, Login Security & Firewall v6.3.0
6.3.0 6.2.3 6.2.4 6.2.0 6.2.1 6.2.2 6.1.0 5.3.1 5.4.0 5.4.1 5.5.0 5.5.1 5.6.0 5.6.1 5.6.2 5.7.0 5.7.1 5.7.2 5.8.0 5.8.1 5.9.0 6.0.0 6.0.1 3.0.1 3.1.0 All 141 releases
← All changes | src/controller/class-malicious-bot.php +69 -39 5.8.1 → 6.3.0 View file →
@@ -21,16 +21,14 @@
21 21 */
22 22 class Malicious_Bot extends Controller {
23 23 use IP;
24 24
25 - const URL_QUERY = 'wpdef-malicious-bot-url';
26 -
27 25 /**
28 26 * Service for handling logic.
29 27 *
30 28 * @var Malicious_Bot_Component
31 29 */
32 - protected $service;
30 + public $service;
33 31
34 32 /**
35 33 * Constructor for the Malicious_Bot class.
36 34 * Initializes the service and sets up necessary hooks.
@@ -41,11 +39,10 @@
41 39 $this->service = $service;
42 40
43 41 if ( $this->service->is_enabled() ) {
44 42 add_action( 'init', array( $this, 'init' ) );
45 - add_action( 'wpdef_rotate_malicious_bot_secret_hash', array( $this, 'rotate_hash' ) );
43 + add_action( 'wpdef_rotate_malicious_bot_secret_hash', array( $this->service, 'rotate_hash' ) );
46 44 add_filter( 'query_vars', array( $this, 'add_query_var' ) );
47 - add_action( 'after_switch_theme', array( $this, 'flush_rewrite' ) );
48 45
49 46 $service = wd_di()->get( Blacklist_Lockout::class );
50 47 $ip = $this->get_user_ip();
51 48 if ( ! $service->are_ips_whitelisted( $ip ) ) {
@@ -64,11 +61,12 @@
64 61 $this->schedule_cron();
65 62
66 63 if ( ! $this->service->get_hash() ) {
67 64 $this->service->rotate_hash();
65 + } else {
66 + $this->service->register_rewrite_rule();
68 67 }
69 68
70 - $this->flush_rewrite();
71 69 $this->service->handle_robots_txt();
72 70 }
73 71
74 72 /**
@@ -89,25 +87,8 @@
89 87 );
90 88 }
91 89
92 90 /**
93 - * Registers a rewrite rule for the malicious bot URL.
94 - * The URL will be in the format: /{hash}/
95 - * where {hash} is a 16-character hexadecimal string.
96 - */
97 - public function register_rewrite_rule() {
98 - $hash = $this->service->get_hash();
99 - add_rewrite_rule( "^{$hash}/?$", 'index.php?' . self::URL_QUERY . '=' . $hash, 'top' );
100 - }
101 -
102 - /**
103 - * Rotates the malicious bot hash and flushes rewrite rules.
104 - */
105 - public function rotate_hash() {
106 - $this->service->rotate_hash();
107 - }
108 -
109 - /**
110 91 * Adds a query variable for the malicious bot URL.
111 92 * This allows us to capture the hash from the URL.
112 93 *
113 94 * @param array $vars Existing query variables.
@@ -113,9 +94,9 @@
113 94 * @param array $vars Existing query variables.
114 95 * @return array Modified query variables.
115 96 */
116 97 public function add_query_var( $vars ) {
117 - $vars[] = self::URL_QUERY;
98 + $vars[] = Malicious_Bot_Component::URL_QUERY;
118 99 return $vars;
119 100 }
120 101
121 102 /**
@@ -123,12 +104,16 @@
123 104 * If the hash in the URL matches the stored hash, block the IP.
124 105 * Otherwise, it will do nothing.
125 106 */
126 107 public function handle_hash_url() {
127 - $used_hash = get_query_var( self::URL_QUERY );
108 + $used_hash = get_query_var( Malicious_Bot_Component::URL_QUERY );
128 109 $valid_hash = $this->service->get_hash();
129 110
130 111 if ( $used_hash === $valid_hash ) {
112 + if ( $this->is_cross_site_request() ) {
113 + return;
114 + }
115 +
131 116 $known_bots = Known_Bots_Factory::create();
132 117 $bot_ips = $known_bots->get_all_bot_ips();
133 118
134 119 // Flatten 2D array into a single array.
@@ -184,8 +169,55 @@
184 169 }
185 170 }
186 171
187 172 /**
173 + * Checks if the current request is a cross-site or embedded request.
174 + *
175 + * @return bool True if cross-site or embedded, false otherwise.
176 + */
177 + public function is_cross_site_request(): bool {
178 + $sec_fetch_site = defender_get_data_from_request( 'HTTP_SEC_FETCH_SITE', 's' );
179 + if ( is_string( $sec_fetch_site ) && 'cross-site' === strtolower( $sec_fetch_site ) ) {
180 + return true;
181 + }
182 +
183 + $sec_fetch_dest = defender_get_data_from_request( 'HTTP_SEC_FETCH_DEST', 's' );
184 + if ( is_string( $sec_fetch_dest ) && in_array( strtolower( $sec_fetch_dest ), array( 'image', 'iframe', 'frame', 'embed', 'object', 'audio', 'video', 'track', 'style', 'script', 'font' ), true ) ) {
185 + return true;
186 + }
187 +
188 + $sec_fetch_mode = defender_get_data_from_request( 'HTTP_SEC_FETCH_MODE', 's' );
189 + if ( is_string( $sec_fetch_mode ) && 'no-cors' === strtolower( $sec_fetch_mode ) ) {
190 + return true;
191 + }
192 +
193 + $site_host = wp_parse_url( home_url(), PHP_URL_HOST );
194 + $site_host = is_string( $site_host ) ? strtolower( $site_host ) : '';
195 +
196 + $http_host = defender_get_data_from_request( 'HTTP_HOST', 's' );
197 + if ( is_string( $http_host ) && '' !== $http_host ) {
198 + $http_host = strtolower( explode( ':', $http_host )[0] );
199 + } else {
200 + $http_host = '';
201 + }
202 +
203 + foreach ( array( 'HTTP_REFERER', 'HTTP_ORIGIN' ) as $header ) {
204 + $header_val = defender_get_data_from_request( $header, 's' );
205 + if ( is_string( $header_val ) && '' !== $header_val ) {
206 + $header_host = wp_parse_url( $header_val, PHP_URL_HOST );
207 + if ( is_string( $header_host ) && '' !== $header_host ) {
208 + $header_host_lower = strtolower( $header_host );
209 + if ( $header_host_lower !== $site_host && ( '' === $http_host || $header_host_lower !== $http_host ) ) {
210 + return true;
211 + }
212 + }
213 + }
214 + }
215 +
216 + return false;
217 + }
218 +
219 + /**
188 220 * Injects the malicious bot URL into the footer of frontend pages.
189 221 * This URL is hidden.
190 222 */
191 223 public function inject_footer() {
@@ -197,16 +229,8 @@
197 229 echo '<div style="display:none;"><a href="' . esc_url( home_url( "/{$hash}" ) ) . '" rel="nofollow">Secret Link</a></div>';
198 230 }
199 231
200 232 /**
201 - * Flushes the rewrite rules to ensure the new malicious bot URL is recognized.
202 - */
203 - public function flush_rewrite() {
204 - $this->register_rewrite_rule();
205 - flush_rewrite_rules();
206 - }
207 -
208 - /**
209 233 * Checks if the current request is for the malicious bot hash URL.
210 234 *
211 235 * @return bool True if the request is for the hash URL, false otherwise.
212 236 */
@@ -215,22 +239,28 @@
215 239 if ( ! is_string( $hash ) || '' === trim( $hash ) ) {
216 240 return false;
217 241 }
218 242
219 - $uri = defender_get_data_from_request( 'REQUEST_URI', 's' );
220 - if ( ! is_string( $uri ) || '' === $uri ) {
243 + $uri = defender_get_data_from_request( 'REQUEST_URI', 's' );
244 + $path = is_string( $uri ) ? wp_parse_url( $uri, PHP_URL_PATH ) : null;
245 + if ( ! is_string( $path ) || '' === $path ) {
221 246 return false;
222 247 }
223 248
224 - // Get request path.
225 - $uri = wp_parse_url( $uri, PHP_URL_PATH );
226 - $uri = trim( $uri, '/' );
249 + $path = trim( $path, '/' );
227 250
228 251 // Always check last segment only.
229 - $segments = explode( '/', $uri );
252 + $segments = explode( '/', $path );
230 253 $last = end( $segments );
231 254
232 255 return $last === $hash;
256 + }
257 +
258 + /**
259 + * Rotate the malicious bot hash and refresh the related rules.
260 + */
261 + public function rotate_hash() {
262 + $this->service->rotate_hash();
233 263 }
234 264
235 265 /**
236 266 * Delete all the data & the cache.