PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 5.7.2
Defender Security – Malware Scanner, Login Security & Firewall v5.7.2
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
defender-security / src / behavior / scan-item / class-core-integrity.php

class-core-integrity.php in Defender Security – Malware Scanner, Login Security & Firewall 5.7.2, at src/behavior/scan-item/class-core-integrity.php

253 lines 7.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Handles core integrity scan.
4 *
5 * @package WP_Defender\Behavior\Scan_Item
6 */
7
8 namespace WP_Defender\Behavior\Scan_Item;
9
10 use WP_Error;
11 use Calotes\Base\File;
12 use WP_Defender\Traits\IO;
13 use WP_Defender\Model\Scan;
14 use Calotes\Component\Behavior;
15 use WP_Defender\Traits\Formats;
16 use WP_Defender\Model\Scan_Item;
17 use WP_Defender\Traits\File_Operations;
18 use WP_Defender\Controller\Scan as Scan_Controller;
19 use WP_Filesystem_Base;
20
21 /**
22 * This class represents a behavior related to core integrity in the WP_Defender plugin.
23 */
24 class Core_Integrity extends Behavior {
25
26 use Formats;
27 use IO;
28 use File_Operations;
29
30 /**
31 * Return general data so we can output on frontend.
32 *
33 * @return array
34 */
35 public function to_array(): array {
36 $data = $this->owner->raw_data;
37 $file = $data['file'];
38
39 list( $file_created_at, $file_size, $deleted ) = $this->get_file_meta( $file );
40
41 return array(
42 'id' => $this->owner->id,
43 'type' => Scan_Item::TYPE_INTEGRITY,
44 'file_name' => pathinfo( $file, PATHINFO_BASENAME ),
45 'full_path' => $file,
46 'date_added' => $file_created_at,
47 'size' => $file_size,
48 'scenario' => $data['type'],
49 'deleted' => $deleted,
50 'short_desc' => $this->get_short_description(),
51 );
52 }
53
54 /**
55 * We will get the origin code by looking into svn repo.
56 *
57 * @return false|string|WP_Error
58 */
59 private function get_origin_code() {
60 global $wp_filesystem;
61 // Initialize the WP filesystem, no more using 'file-put-contents' function.
62 if ( ! $wp_filesystem instanceof WP_Filesystem_Base ) {
63 require_once ABSPATH . '/wp-admin/includes/file.php';
64 WP_Filesystem();
65 }
66 global $wp_version;
67 $data = $this->owner->raw_data;
68 $file = wp_normalize_path( $data['file'] );
69 $relative_path = str_replace( wp_normalize_path( ABSPATH ), '', $file );
70 $source_file_url = "http://core.svn.wordpress.org/tags/$wp_version/" . $relative_path;
71 $ds = DIRECTORY_SEPARATOR;
72 if ( ! function_exists( 'download_url' ) ) {
73 require_once ABSPATH . 'wp-admin' . $ds . 'includes' . $ds . 'file.php';
74 }
75 $tmp = download_url( $source_file_url );
76 if ( is_wp_error( $tmp ) ) {
77 return $tmp;
78 }
79 $content = $wp_filesystem->get_contents( $tmp );
80 wp_delete_file( $tmp );
81
82 return $content;
83 }
84
85 /**
86 * Restore the file with its origin content.
87 *
88 * @return void|array|WP_Error
89 */
90 public function resolve() {
91 global $wp_filesystem;
92 // Initialize the WP filesystem, no more using 'file-put-contents' function.
93 if ( empty( $wp_filesystem ) ) {
94 include_once ABSPATH . '/wp-admin/includes/file.php';
95 WP_Filesystem();
96 }
97 $data = $this->owner->raw_data;
98 if ( 'modified' !== $data['type'] ) {
99 // Should not be here unless case changed.
100 return;
101 }
102
103 $origin = $this->get_origin_code();
104 if ( false === $origin || is_wp_error( $origin ) ) {
105 return;
106 }
107
108 $path = $data['file'];
109 $ret = $wp_filesystem->put_contents( $path, $origin );
110 if ( $ret ) {
111 $scan = Scan::get_last();
112 $scan->remove_issue( $this->owner->id );
113 $this->log( sprintf( '%s is deleted', $path ), Scan_Controller::SCAN_LOG );
114
115 do_action( 'wpdef_fixed_scan_issue', 'core_integrity', 'resolve' );
116
117 return array( 'message' => esc_html__( 'This item has been resolved.', 'defender-security' ) );
118 } else {
119 return new WP_Error(
120 'defender_permissions_denied',
121 esc_html__(
122 'Permissions Denied. Defender does not have the needed permissions to edit the file. Please change file permissions to 640 or contact your hosting provider so they could change them for you.',
123 'defender-security'
124 )
125 );
126 }
127 }
128
129 /**
130 * Ignore the suspicious file.
131 *
132 * @return array
133 */
134 public function ignore(): array {
135 $scan = Scan::get_last();
136 $data = $this->owner->raw_data;
137 $issue_name = '<b>' . pathinfo( $data['file'], PATHINFO_BASENAME ) . '</b>';
138 $res = $scan->ignore_issue( $this->owner->id );
139 if ( ! $res ) {
140 return array(
141 'type_notice' => 'error',
142 'message' => sprintf(
143 /* translators: %s: Scan issue name. */
144 esc_html__( '%s is already marked as Ignored. It can’t be added to the Ignored list again.', 'defender-security' ),
145 $issue_name
146 ),
147 );
148 }
149
150 return array(
151 'message' => sprintf(
152 /* translators: %s: Scan issue name. */
153 esc_html__( 'You’ve successfully ignored the security issue related to %s.', 'defender-security' ),
154 $issue_name
155 ),
156 );
157 }
158
159 /**
160 * Restore the ignored suspicious file.
161 *
162 * @return array
163 */
164 public function unignore(): array {
165 $scan = Scan::get_last();
166 $scan->unignore_issue( $this->owner->id );
167
168 return array( 'message' => esc_html__( 'The suspicious file has been successfully restored.', 'defender-security' ) );
169 }
170
171 /**
172 * Delete the file or whole folder.
173 *
174 * @return array|WP_Error
175 */
176 public function delete() {
177 $data = $this->owner->raw_data;
178 $scan = Scan::get_last();
179
180 // Check if the file exists and is readable. If not, remove it from the scan result and log the result.
181 $file = $data['file'];
182 if ( ! file_exists( $file ) || ! is_readable( $file ) ) {
183 $scan->remove_issue( $this->owner->id );
184 $this->log(
185 sprintf( '%s is not readable and will be removed from the scan result', $file ),
186 Scan_Controller::SCAN_LOG
187 );
188
189 return array( 'message' => esc_html__( 'This item has been deleted.', 'defender-security' ) );
190 } elseif ( 'unversion' === $data['type'] && $this->delete_infected_file( $file ) ) {
191 return $this->after_delete( $file, $scan, 'core_integrity' );
192 } elseif ( 'dir' === $data['type'] && $this->delete_dir( $file ) ) {
193 return $this->after_delete( $file, $scan, 'core_integrity' );
194 }
195
196 return $this->get_permission_error( $file );
197 }
198
199 /**
200 * Return the source code depending on the type of the issue:
201 * If it is unversion, return full source,
202 * if it is dir, we return a list of files,
203 * if it is modified, we will return the current code & origin.
204 *
205 * @return array
206 */
207 public function pull_src(): array {
208 global $wp_filesystem;
209 // Initialize the WP filesystem, no more using 'file-put-contents' function.
210 if ( empty( $wp_filesystem ) ) {
211 include_once ABSPATH . '/wp-admin/includes/file.php';
212 WP_Filesystem();
213 }
214 $data = $this->owner->raw_data;
215 if ( ! file_exists( $data['file'] ) && ! is_dir( $data['file'] ) ) {
216 return array(
217 'code' => '',
218 'origin' => '',
219 );
220 }
221 switch ( $data['type'] ) {
222 case 'unversion':
223 return array( 'code' => $wp_filesystem->get_contents( $data['file'] ) );
224 case 'dir':
225 $dir_tree = new File( $data['file'], true, true, array(), array(), false );
226
227 return array( 'code' => implode( PHP_EOL, $dir_tree->get_dir_tree() ) );
228 case 'modified':
229 default:
230 return array(
231 'code' => $wp_filesystem->get_contents( $data['file'] ),
232 'origin' => $this->get_origin_code(),
233 );
234 }
235 }
236
237 /**
238 * Retrieves a short description based on the type of data.
239 *
240 * @return string The short description.
241 */
242 private function get_short_description(): string {
243 $data = $this->owner->raw_data;
244 if ( 'unversion' === $data['type'] ) {
245 return esc_html__( 'Unknown file in WordPress core', 'defender-security' );
246 } elseif ( 'dir' === $data['type'] ) {
247 return esc_html__( 'This directory does not belong to WordPress core', 'defender-security' );
248 } elseif ( 'modified' === $data['type'] ) {
249 return esc_html__( 'This WordPress core file appears modified', 'defender-security' );
250 }
251 }
252 }
253