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/behavior/scan-item/class-core-integrity.php +84 -10 5.5.0 → 6.3.0 View file →
@@ -15,8 +15,10 @@
15 15 use WP_Defender\Traits\Formats;
16 16 use WP_Defender\Model\Scan_Item;
17 17 use WP_Defender\Traits\File_Operations;
18 18 use WP_Defender\Controller\Scan as Scan_Controller;
19 +use WP_Defender\Behavior\Scan\Core_Integrity as Core_Integrity_Scan;
20 +use WP_Filesystem_Base;
19 21
20 22 /**
21 23 * This class represents a behavior related to core integrity in the WP_Defender plugin.
22 24 */
@@ -57,9 +59,9 @@
57 59 */
58 60 private function get_origin_code() {
59 61 global $wp_filesystem;
60 62 // Initialize the WP filesystem, no more using 'file-put-contents' function.
61 - if ( empty( $wp_filesystem ) ) {
63 + if ( ! $wp_filesystem instanceof WP_Filesystem_Base ) {
62 64 require_once ABSPATH . '/wp-admin/includes/file.php';
63 65 WP_Filesystem();
64 66 }
65 67 global $wp_version;
@@ -65,9 +67,9 @@
65 67 global $wp_version;
66 68 $data = $this->owner->raw_data;
67 69 $file = wp_normalize_path( $data['file'] );
68 70 $relative_path = str_replace( wp_normalize_path( ABSPATH ), '', $file );
69 - $source_file_url = "http://core.svn.wordpress.org/tags/$wp_version/" . $relative_path;
71 + $source_file_url = "https://core.svn.wordpress.org/tags/$wp_version/" . $relative_path;
70 72 $ds = DIRECTORY_SEPARATOR;
71 73 if ( ! function_exists( 'download_url' ) ) {
72 74 require_once ABSPATH . 'wp-admin' . $ds . 'includes' . $ds . 'file.php';
73 75 }
@@ -76,13 +78,65 @@
76 78 return $tmp;
77 79 }
78 80 $content = $wp_filesystem->get_contents( $tmp );
79 81 wp_delete_file( $tmp );
82 + $trusted_checksum = $this->get_trusted_checksum( $relative_path );
80 83
84 + if ( ! is_string( $content ) || ! is_string( $trusted_checksum ) ) {
85 + return new WP_Error(
86 + 'defender_core_checksum_unavailable',
87 + esc_html__( 'The trusted WordPress core checksum is unavailable.', 'defender-security' )
88 + );
89 + }
90 +
91 + if ( ! hash_equals( strtolower( $trusted_checksum ), md5( $content ) ) ) {
92 + return new WP_Error(
93 + 'defender_core_checksum_mismatch',
94 + esc_html__( 'The downloaded WordPress core file failed checksum verification.', 'defender-security' )
95 + );
96 + }
97 +
81 98 return $content;
82 99 }
83 100
84 101 /**
102 + * Get the trusted WordPress checksum for a core file.
103 + *
104 + * New scan items persist the checksum used to identify the modification.
105 + * The temporary scan cache and the WordPress checksum API are fallbacks for
106 + * scan items created before that checksum was stored with the issue.
107 + *
108 + * @param string $relative_path Core file path relative to ABSPATH.
109 + * @return string|null
110 + */
111 + private function get_trusted_checksum( $relative_path ) {
112 + $data = $this->owner->raw_data;
113 + if ( isset( $data['checksum'] ) && is_string( $data['checksum'] ) ) {
114 + return $data['checksum'];
115 + }
116 +
117 + $checksums = get_site_option( Core_Integrity_Scan::CACHE_CHECKSUMS, array() );
118 + if ( is_array( $checksums ) && isset( $checksums[ $relative_path ] ) && is_string( $checksums[ $relative_path ] ) ) {
119 + return $checksums[ $relative_path ];
120 + }
121 +
122 + if ( ! function_exists( 'get_core_checksums' ) ) {
123 + require_once ABSPATH . 'wp-admin/includes/update.php';
124 + }
125 +
126 + global $wp_version, $wp_local_package;
127 + $locale = isset( $wp_local_package ) && '' !== $wp_local_package ? $wp_local_package : 'en_US';
128 + $checksums = get_core_checksums( $wp_version, $locale );
129 + if ( isset( $checksums[ $wp_version ] ) && is_array( $checksums[ $wp_version ] ) ) {
130 + $checksums = $checksums[ $wp_version ];
131 + }
132 +
133 + return is_array( $checksums ) && isset( $checksums[ $relative_path ] ) && is_string( $checksums[ $relative_path ] )
134 + ? $checksums[ $relative_path ]
135 + : null;
136 + }
137 +
138 + /**
85 139 * Restore the file with its origin content.
86 140 *
87 141 * @return void|array|WP_Error
88 142 */
@@ -88,12 +142,13 @@
88 142 */
89 143 public function resolve() {
90 144 global $wp_filesystem;
91 145 // Initialize the WP filesystem, no more using 'file-put-contents' function.
92 - if ( empty( $wp_filesystem ) ) {
93 - include_once ABSPATH . '/wp-admin/includes/file.php';
146 + if ( ! $wp_filesystem instanceof WP_Filesystem_Base ) {
147 + require_once ABSPATH . '/wp-admin/includes/file.php';
94 148 WP_Filesystem();
95 149 }
150 +
96 151 $data = $this->owner->raw_data;
97 152 if ( 'modified' !== $data['type'] ) {
98 153 // Should not be here unless case changed.
99 154 return;
@@ -130,12 +185,26 @@
130 185 *
131 186 * @return array
132 187 */
133 188 public function ignore(): array {
134 - $scan = Scan::get_last();
135 - $scan->ignore_issue( $this->owner->id );
189 + $scan = Scan::get_last();
190 + $data = $this->owner->raw_data;
191 + $issue_name = '<b>' . pathinfo( $data['file'], PATHINFO_BASENAME ) . '</b>';
192 + $res = $scan->ignore_issue( $this->owner->id );
193 + if ( ! $res ) {
194 + return array(
195 + 'type_notice' => 'error',
196 + 'message' => $this->get_failed_ignore_result( $issue_name ),
197 + );
198 + }
136 199
137 - return array( 'message' => esc_html__( 'The suspicious file has been successfully ignored.', 'defender-security' ) );
200 + return array(
201 + 'message' => sprintf(
202 + /* translators: %s: Scan issue name. */
203 + esc_html__( 'You’ve successfully ignored the security issue related to %s.', 'defender-security' ),
204 + $issue_name
205 + ),
206 + );
138 207 }
139 208
140 209 /**
141 210 * Restore the ignored suspicious file.
@@ -187,12 +256,13 @@
187 256 */
188 257 public function pull_src(): array {
189 258 global $wp_filesystem;
190 259 // Initialize the WP filesystem, no more using 'file-put-contents' function.
191 - if ( empty( $wp_filesystem ) ) {
192 - include_once ABSPATH . '/wp-admin/includes/file.php';
260 + if ( ! $wp_filesystem instanceof WP_Filesystem_Base ) {
261 + require_once ABSPATH . '/wp-admin/includes/file.php';
193 262 WP_Filesystem();
194 263 }
264 +
195 265 $data = $this->owner->raw_data;
196 266 if ( ! file_exists( $data['file'] ) && ! is_dir( $data['file'] ) ) {
197 267 return array(
198 268 'code' => '',
@@ -207,11 +277,13 @@
207 277
208 278 return array( 'code' => implode( PHP_EOL, $dir_tree->get_dir_tree() ) );
209 279 case 'modified':
210 280 default:
281 + $origin = $this->get_origin_code();
282 +
211 283 return array(
212 284 'code' => $wp_filesystem->get_contents( $data['file'] ),
213 - 'origin' => $this->get_origin_code(),
285 + 'origin' => is_string( $origin ) ? $origin : '',
214 286 );
215 287 }
216 288 }
217 289
@@ -228,6 +300,8 @@
228 300 return esc_html__( 'This directory does not belong to WordPress core', 'defender-security' );
229 301 } elseif ( 'modified' === $data['type'] ) {
230 302 return esc_html__( 'This WordPress core file appears modified', 'defender-security' );
231 303 }
304 +
305 + return '';
232 306 }
233 307 }