PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 5.4.0
Defender Security – Malware Scanner, Login Security & Firewall v5.4.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
defender-security / src / behavior / scan / class-malware-quick-scan.php

class-malware-quick-scan.php in Defender Security – Malware Scanner, Login Security & Firewall 5.4.0, at src/behavior/scan/class-malware-quick-scan.php

179 lines 5.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Handles malware quick scan.
4 *
5 * @package WP_Defender\Behavior\Scan
6 */
7
8 namespace WP_Defender\Behavior\Scan;
9
10 use Countable;
11 use WP_Defender\Traits\IO;
12 use Calotes\Component\Behavior;
13 use WP_Defender\Behavior\Scan\Malware_Scan;
14
15 /**
16 * This will fast travel all yara rules to quickly get files seem suspicious, this is catchy.
17 */
18 class Malware_Quick_Scan extends Behavior {
19
20 use IO;
21
22 /**
23 * Holds the content of the file being scanned.
24 *
25 * @var string
26 */
27 private $content;
28
29 /**
30 * Perform a quick scan on the specified file using the provided rules.
31 *
32 * @param string $file The file to scan.
33 * @param array $rules The rules to apply during the scan.
34 *
35 * @return array An array containing the total number of issues found and detailed information about each issue.
36 */
37 public function do_quick_scan( string $file, array $rules ): array {
38 global $wp_filesystem;
39 // Initialize the WP filesystem, no more using 'file-put-contents' function.
40 if ( empty( $wp_filesystem ) ) {
41 require_once ABSPATH . '/wp-admin/includes/file.php';
42 WP_Filesystem();
43 }
44 $total_issues = 0;
45 $qs_detail = array();
46 if ( file_exists( $file ) ) {
47 $content = $wp_filesystem->get_contents( $file );
48 $this->content = $content;
49 foreach ( $rules as $rule ) {
50 $strings = $rule['strings'];
51 $local_issues = array(
52 'identifier' => $rule['identifier'],
53 'catches' => array(),
54 );
55 foreach ( $strings as $string ) {
56 $offset = false;
57 if ( 0 === $string['type'] ) {
58 $offset = strpos( $content, $string['text'] );
59 $text = $string['text'];
60 } else {
61 $pattern = "/{$string['text']}/";
62 $is_match = preg_match_all(
63 $pattern,
64 $content,
65 $matches,
66 PREG_PATTERN_ORDER | PREG_OFFSET_CAPTURE
67 );
68 if ( $is_match ) {
69 $offset = $matches[0][0][1];
70 $text = $matches[0][0][0];
71 }
72 }
73 if ( false === $offset ) {
74 continue;
75 }
76 $local_issues['catches'][] = array(
77 'id' => $string['id'],
78 'text' => $text,
79 'offset' => $offset,
80 );
81 }
82 if ( empty( $local_issues['catches'] ) ) {
83 continue;
84 }
85
86 if ( $this->condition_valid( $local_issues['catches'], $rule ) ) {
87 ++$total_issues;
88 $qs_detail[] = $local_issues;
89 }
90 }
91 }
92
93 return array( $total_issues, $qs_detail );
94 }
95
96 /**
97 * Checks if the condition is valid based on the given rule.
98 *
99 * @param array $found The found items.
100 * @param array $rule The rule to check against.
101 *
102 * @return bool Returns true if the condition is valid, false otherwise.
103 */
104 private function condition_valid( $found, $rule ): bool {
105 $condition = explode( 'and', $rule['condition'] );
106 $count = 0;
107 foreach ( $condition as $item ) {
108 $patterns = array(
109 'x_of_them' => '/([a-z0-9]+)\s*of\s*(.*)/',
110 'id_at_pos' => '/(\$[a-zA-Z0-9]+)\s*at\s*(\d+)/',
111 );
112 foreach ( $patterns as $func => $pattern ) {
113 if ( preg_match( $pattern, $item, $match ) ) {
114 ++$count;
115 $ret = $this->$func( $found, $match, $rule );
116 if ( false === $ret ) {
117 return false;
118 }
119 }
120 }
121 }
122 if ( 0 === $count ) {
123 $this->log( $rule['identifier'], Malware_Scan::MALWARE_LOG );
124 $this->log( $found, Malware_Scan::MALWARE_LOG );
125
126 return false;
127 }
128
129 return true;
130 }
131
132 /**
133 * Determines if a certain number of items in an array meet a certain condition.
134 *
135 * @param array $found The array of items to check.
136 * @param array $check_info The match array containing the number of items to check and the condition.
137 * @param array $rule The rule array containing the strings to check against.
138 *
139 * @return bool Returns true if the number of items that meet the condition is greater than or equal to the
140 * specified number, false otherwise.
141 */
142 private function x_of_them( $found, $check_info, $rule ): bool {
143 $num = $check_info[1];
144 $num = 'all' === $num ? count( $rule['strings'] ) : $num;
145 $num = 'any' === $num ? 1 : $num;
146
147 if ( '(s*)' === $check_info[2] ) {
148 // Hard code in this situation.
149 --$num;
150 }
151 /**
152 * Todo: uncomment the following lines if you need to get log details.
153 * $this->log( sprintf( 'num %s', $num ), Malware_Scan::MALWARE_LOG );
154 * $this->log( sprintf( 'count %s', count( $found ) ), Malware_Scan::MALWARE_LOG );
155 */
156 return ( is_array( $found ) || $found instanceof Countable ? count( $found ) : 0 ) >= $num;
157 }
158
159 /**
160 * Checks if the given ID is at the specified position in the content.
161 *
162 * @param array $found The array of items to check.
163 * @param array $check_info The match array containing the ID and position to check.
164 * @param array $rule The rule array containing the strings to check against.
165 *
166 * @return bool Returns true if the ID is at the specified position in the content, false otherwise.
167 */
168 private function id_at_pos( $found, $check_info, $rule ): bool {
169 // Get the text to check.
170 foreach ( $found as $item ) {
171 if ( $item['id'] === $check_info[1] ) {
172 return strpos( $this->content, $item['text'] ) === $check_info[2];
173 }
174 }
175
176 return false;
177 }
178 }
179