PluginProbe
WebTotem Security / 2.4.36
WebTotem Security v2.4.36
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.36, at lib/AgentManager.php

337 lines 10.1 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 if(WebTotemOption::getOption('api_environment') == 'M'){
271 $download_url = str_replace("wtotem.com", "wtotem.net", $download_url);
272 }
273
274 $response = wp_remote_get($download_url, $args);
275 $http_code = wp_remote_retrieve_response_code($response);
276
277 if ($http_code < 200) {
278 WebTotemOption::setNotification('error', __( 'Could not download file.', 'wtotem' ));
279 return FALSE;
280 }
281
282 $response_body = wp_remote_retrieve_body($response);
283
284 if($wp_filesystem = self::wpFileSystem()){
285 if(!empty($response_body)){
286 return $wp_filesystem->put_contents($path, $response_body, FS_CHMOD_FILE);
287 } else {
288 $message = __( 'API: Response body is empty.', 'wtotem' );
289 WebTotemOption::setNotification( 'error', $message );
290 }
291 }
292 return FALSE;
293
294 }
295
296 /**
297 * Generate the file that indicates that a WAF connection is being used through the plugin.
298 */
299 public static function generateMarkerFile() {
300 if($am_filename = WebTotemOption::getOption('am_file')) {
301 if ( $wp_filesystem = self::wpFileSystem() ) {
302 $content = '<?php exit(); ?>' . $am_filename;
303 $file_path = WEBTOTEM_PLUGIN_PATH . '/generate.php';
304 if ( ! file_exists($file_path) or $wp_filesystem->get_contents($file_path) != $content) {
305
306 if ( ! $wp_filesystem->put_contents( $file_path, $content, FS_CHMOD_FILE ) ) {
307 $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' );
308 WebTotemOption::setNotification( 'warning', $message );
309 }
310
311 }
312 }
313 }
314 }
315
316 /**
317 * Check if the plugin version has changed.
318 */
319 public static function checkVersion(){
320 if(WebTotemOption::isActivated()){
321 // Get version of the plugin that was previously installed.
322 $version = WebTotemOption::getOption('plugin_version');
323
324 if ($version == WEBTOTEM_VERSION) {
325 return;
326 }
327
328 WebTotemOption::setOptions(['plugin_version' => WEBTOTEM_VERSION]);
329
330 // Generate the file that indicates that a WAF connection is being used through the plugin.
331 self::generateMarkerFile();
332 }
333
334 }
335
336 }
337