PluginProbe
WebTotem Security / 2.4.31
WebTotem Security v2.4.31
3.0.1 3.0.0 trunk 1.0 1.1 1.2 1.3 1.3.1 1.3.2 1.3.3 2.0 2.1 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 2.2.1 2.2.2 2.2.3 2.2.4 All 109 releases
wt-security / lib / AgentManager.php

AgentManager.php in WebTotem Security 2.4.31, at lib/AgentManager.php

333 lines 10.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 if (!defined('WEBTOTEM_INIT') || WEBTOTEM_INIT !== true) {
4 if (!headers_sent()) {
5 header('HTTP/1.1 403 Forbidden');
6 }
7 die("Protected By WebTotem!");
8 }
9
10 /**
11 * Agent Manager library.
12 *
13 * Agent Manager is needed to create AM file,
14 * and to check whether am and other agents are installed.
15 * The AM file creates WAV and AV files,
16 * and transmits information to the Web Totem platform and back.
17 */
18 class WebTotemAgentManager extends WebTotem {
19
20 /**
21 * AM file install.
22 *
23 * Create AM file in the root of the site
24 * and save the data about it in the DB.
25 *
26 * @return bool
27 * TRUE if the AM file is successfully added.
28 */
29 public static function amInstall() {
30 try {
31 self::removeAgents();
32
33 $host = WebTotemAPI::siteInfo();
34
35 $files = self::getAgentsFiles( $host['id'] );
36
37 if ( $files['amFilename'] ) {
38
39 if (!is_writable(ABSPATH)) {
40 WebTotemOption::setNotification('error', __('There are no permissions to write to the root directory', 'wtotem'));
41 return FALSE;
42 }
43
44 // Download file.
45 $result = self::downloadFile(
46 $files['downloadLink'],
47 ABSPATH . $files['amFilename']
48 );
49
50 // If the file is downloaded, then we write the data to the DB.
51 if ( $result ) {
52 WebTotemOption::setOptions( [
53 'am_installed' => true,
54 'am_file' => $files['amFilename'],
55 'waf_file' => $files['wafFilename'],
56 'av_file' => $files['avFilename'],
57 ] );
58
59 self::generateMarkerFile();
60
61 $message = __( 'Agent manager have been successfully installed', 'wtotem');
62 WebTotemOption::setNotification( 'success', $message );
63 }
64 else {
65 $message = sprintf(__( 'Check %s folder\'s write permission.', 'wtotem' ), ABSPATH) . sprintf(__(' Read more <a href="%s" target="_blank">here</a>.', 'wtotem' ), 'https://docs.wtotem.com/agent-setup#it-additional-recommendations');
66 WebTotemOption::setNotification( 'error', $message );
67
68 return FALSE;
69 }
70 }
71
72 } catch ( \Exception $e ) {
73 WebTotemOption::setNotification( 'error', $e->getMessage() );
74
75 return FALSE;
76 }
77
78 return TRUE;
79 }
80
81 /**
82 * Get the AM file download link and agents (AV, WAF) files name.
83 *
84 * @param string $host_id
85 * Host id on WebTotem.
86 *
87 * @return array
88 * Agent Manager download link, names of agents
89 */
90 public static function getAgentsFiles( $host_id ) {
91 $result = WebTotemAPI::getAgentsFiles( $host_id );
92 if ( ! $result ) {
93 $file = [ 'amFilename' => NULL, 'downloadLink' => NULL ];
94
95 $message = __( 'Error generating the agent manager file.', 'wtotem' );
96 WebTotemOption::setNotification( 'error', $message );
97 } else {
98 $file = $result;
99 }
100
101 return $file;
102 }
103
104 /**
105 * Check the existence of the service file and the record in the DB.
106 *
107 * @param string $service
108 * Service short name (am, av, waf).
109 *
110 * @return array
111 * Service file data (installed status, file exist status, file name).
112 */
113 public static function checkInstalledService( $service ) {
114 $file = WebTotemOption::getOption( $service . "_file" );
115
116 return [
117 'option_status' => WebTotemOption::getOption( $service . "_installed" ),
118 'file_status' => ( (bool) $file ) && is_file( ABSPATH . $file ),
119 'file_name' => $file,
120 ];
121 }
122
123 /**
124 * Remove all agents files and folders. Clear agents options.
125 *
126 * @return bool
127 * Returns TRUE if agent files
128 * and folders have been successfully deleted.
129 */
130 public static function removeAgents() {
131 // Deleting all agent records from the database.
132 WebTotemOption::clearOptions( [
133 'am_installed',
134 'waf_installed',
135 'av_installed',
136 'am_file',
137 'waf_file',
138 'av_file',
139 ] );
140
141 self::postdelete();
142
143 if($wp_filesystem = self::wpFileSystem()){
144 $list = $wp_filesystem->dirlist( ABSPATH );
145
146 $uploads_list = $wp_filesystem->dirlist( ABSPATH .'wp-content/uploads' ) ?: [];
147 foreach ($uploads_list as $key => $item){
148 $uploads_list[$key]['name'] = 'wp-content/uploads/' . $item['name'];
149 }
150
151 $list = array_merge($list, $uploads_list);
152
153 foreach ( $list as $item ) {
154
155 $target_item = ABSPATH . $item['name'];
156
157 // Check whether the item is a directory.
158 $recursive = ( $item['type'] == 'd' ) ? true : false;
159
160 $pattern = '/([a-zA-Z0-9_]{64}.av.php)|([a-zA-Z0-9_]{64}.am.php)|([a-zA-Z0-9_]{64}.waf.php)|(\.wtotem_[a-zA-Z0-9_]{12,16})/';
161
162 if ( preg_match( $pattern, $target_item ) ) {
163 $wp_filesystem->delete( $target_item, $recursive, $item['type'] );
164 }
165 }
166 }
167
168 return TRUE;
169 }
170
171 /**
172 * This method clears the system file from the WAF connection strings.
173 *
174 * @return bool
175 */
176 public static function postdelete(): bool
177 {
178 $base_path = ABSPATH;
179 $targets = [
180 'default' => $base_path . 'index.php',
181 'wp' => $base_path . 'wp-load.php',
182 ];
183
184 foreach ($targets as $target_path) {
185 self::cut_inc($target_path);
186 }
187
188 return true;
189 }
190
191 /**
192 * This method clears the system file from the WAF connection strings.
193 *
194 * @return string
195 */
196 private static function cut_inc(string $target_path)
197 {
198 if (file_exists($target_path)) {
199 $reg = '/^([\r\n\t])*((<\?php\s)?if\s?\(function_exists\(\'current_user_can\'\)\)\s?{\s?if\s?\(\s?!current_user_can\(\'publish_posts\'\)\s?\)\s?{\s)?(<\?php\s?)?\$wtwaf\s?=\s?dirname\(__FILE__\).{76,77}\.waf\.php(\'|\")?;\s?if\s?\(file_exists\(\$wtwaf\)(\s&&\sis_readable\(\$wtwaf\))?\)\s?{(\s?if\s?\(function_exists\("is_admin"\)\)\s?{\s?if\s?\(!is_admin\(\)\)\s?{)?\s?@include_once\(\$wtwaf\);\s?}(\s?}\s?else\s?{\s?@include_once\(\$wtwaf\);\s?}\s?})?\s?unset\(\$wtwaf\);\s?(\?>|}\s})?([\r\n\t])*/im';
200 $reg2 = '/(\?>)?(\s*(<\?php)?\s+if\s?\(\s*PHP_VERSION_ID\s*>\s*70000\s*\)\s*{\s*\$wtwaf\s*=\s*__DIR__\s*\.\s*\'(\/\.\.\/\.\.)?\/_include_\w{64}\.waf\.php\'\s*;\s*if\s*\(\s*file_exists\s*\(\s*\$wtwaf\s*\)\s*\)\s*{\s*@\s*include_once\s*\(\s*\$wtwaf\s*\)\s*;\s*}\s*unset\s*\(\s*\$wtwaf\s*\)\s*;\s*}\s*(\?>)?\s*)(<\?php)?/im';
201 $target_content = file_get_contents($target_path);
202 $pos_inc = stripos($target_content, '@include_once($wtwaf);');
203 if ($pos_inc !== false) {
204 $cutted = preg_replace($reg, '', $target_content);
205 if (is_string($cutted) && $cutted !== '') {
206 if (preg_match($reg2, $cutted, $reg2_matches)) {
207 if (!empty($reg2_matches[1]) && !empty($reg2_matches[5])) {
208 $cutted = str_replace($reg2_matches[0], '', $cutted);
209 } else {
210 $cutted = str_replace($reg2_matches[2], '', $cutted);
211 }
212 }
213
214 if (is_string($cutted) && $cutted !== '') {
215 $wp_filesystem = self::wpFileSystem();
216 $res = $wp_filesystem->put_contents($target_path, $cutted, FS_CHMOD_FILE);
217 } else {
218 $res = 'preg_replace error 2';
219 }
220 } else {
221 $res = 'preg_replace error 1';
222 }
223 } else {
224 $res = 'inc not found';
225 }
226 } else {
227 $res = 'not found';
228 }
229 return $res;
230 }
231
232 /**
233 * Base WordPress Filesystem class which Filesystem implementations extend.
234 *
235 * @return object|bool
236 * Instance of Filesystem class.
237 */
238 private static function wpFileSystem() {
239 global $wp_filesystem;
240
241 if ( empty( $wp_filesystem ) ) {
242 require_once( ABSPATH . 'wp-admin/includes/file.php' );
243 WP_Filesystem();
244 }
245
246 if (empty($wp_filesystem)) {
247 WebTotemOption::setNotification('error', _('WP FileSystem path error'));
248 return FALSE;
249 }
250
251 return $wp_filesystem;
252 }
253
254 /**
255 * @param $url
256 * Link from where to download the file.
257 * @param $path
258 * Path where to save the file.
259 *
260 * @return bool
261 * If the file is saved successfully, it returns true.
262 */
263 private static function downloadFile($download_url, $path) {
264
265 $args = [
266 'timeout' => '30',
267 'sslverify' => FALSE,
268 ];
269
270 $response = wp_remote_get($download_url, $args);
271 $http_code = wp_remote_retrieve_response_code($response);
272
273 if ($http_code < 200) {
274 WebTotemOption::setNotification('error', __( 'Could not download file.', 'wtotem' ));
275 return FALSE;
276 }
277
278 $response_body = wp_remote_retrieve_body($response);
279
280 if($wp_filesystem = self::wpFileSystem()){
281 if(!empty($response_body)){
282 return $wp_filesystem->put_contents($path, $response_body, FS_CHMOD_FILE);
283 } else {
284 $message = __( 'API: Response body is empty.', 'wtotem' );
285 WebTotemOption::setNotification( 'error', $message );
286 }
287 }
288 return FALSE;
289
290 }
291
292 /**
293 * Generate the file that indicates that a WAF connection is being used through the plugin.
294 */
295 public static function generateMarkerFile() {
296 if($am_filename = WebTotemOption::getOption('am_file')) {
297 if ( $wp_filesystem = self::wpFileSystem() ) {
298 $content = '<?php exit(); ?>' . $am_filename;
299 $file_path = WEBTOTEM_PLUGIN_PATH . '/generate.php';
300 if ( ! file_exists($file_path) or $wp_filesystem->get_contents($file_path) != $content) {
301
302 if ( ! $wp_filesystem->put_contents( $file_path, $content, FS_CHMOD_FILE ) ) {
303 $message = sprintf( __( 'Check %s folder\'s write permission.', 'wtotem' ), WEBTOTEM_PLUGIN_PATH ) . sprintf( __( ' Read more <a href="%s" target="_blank">here</a>.', 'wtotem' ), 'https://docs.wtotem.com/agent-setup#it-additional-recommendations' );
304 WebTotemOption::setNotification( 'error', $message );
305 }
306
307 }
308 }
309 }
310 }
311
312 /**
313 * Check if the plugin version has changed.
314 */
315 public static function checkVersion(){
316 if(WebTotemOption::isActivated()){
317 // Get version of the plugin that was previously installed.
318 $version = WebTotemOption::getOption('plugin_version');
319
320 if ($version == WEBTOTEM_VERSION) {
321 return;
322 }
323
324 WebTotemOption::setOptions(['plugin_version' => WEBTOTEM_VERSION]);
325
326 // Generate the file that indicates that a WAF connection is being used through the plugin.
327 self::generateMarkerFile();
328 }
329
330 }
331
332 }
333