PluginProbe
WebTotem Security / 3.0.1
WebTotem Security v3.0.1
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 3.0.1, at lib/AgentManager.php

360 lines 10.9 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 ( isset($files['am_filename']) and $files['am_filename'] ) {
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['download_link'],
47 ABSPATH . $files['am_filename']
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['am_filename'],
55 'waf_file' => $files['waf_filename'],
56 'av_file' => $files['av_filename'],
57 'am_created_at' => $files['created_at'],
58 ] );
59
60 self::generateMarkerFile();
61
62 $message = __( 'Agent manager have been successfully installed', 'wtotem');
63 WebTotemOption::setNotification( 'success', $message );
64 }
65 else {
66 $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');
67 WebTotemOption::setNotification( 'error', $message );
68
69 return FALSE;
70 }
71 }
72
73 // Update config_id.
74 WebTotemAPI::getHostID($host['name']);
75
76 } catch ( \Exception $e ) {
77 WebTotemOption::setNotification( 'error', $e->getMessage() );
78
79 return FALSE;
80 }
81
82 return TRUE;
83 }
84
85 /**
86 * Get the AM file download link and agents (AV, WAF) files name.
87 *
88 * @param string $host_id
89 * Host id on WebTotem.
90 *
91 * @return array
92 * Agent Manager download link, names of agents
93 */
94 public static function getAgentsFiles( $host_id ) {
95 $result = WebTotemAPI::getAgentsFiles( $host_id );
96 if ( ! $result ) {
97 $file = [ 'download_link' => NULL ];
98
99 $message = __( 'Error generating the agent manager file.', 'wtotem' );
100 WebTotemOption::setNotification( 'error', $message );
101 } else {
102 $file = $result;
103 }
104
105 return $file;
106 }
107
108 /**
109 * Check the existence of the service file and the record in the DB.
110 *
111 * @param string $service
112 * Service short name (am, av, waf).
113 *
114 * @return array
115 * Service file data (installed status, file exist status, file name).
116 */
117 public static function checkInstalledService( $service ) {
118 $file = WebTotemOption::getOption( $service . "_file" );
119
120 return [
121 'option_status' => WebTotemOption::getOption( $service . "_installed" ),
122 'file_status' => ( (bool) $file ) && is_file( ABSPATH . $file ),
123 'file_name' => $file,
124 ];
125 }
126
127 /**
128 * Remove all agents files and folders. Clear agents options.
129 *
130 * @return bool
131 * Returns TRUE if agent files
132 * and folders have been successfully deleted.
133 */
134 public static function removeAgents() {
135 // Deleting all agent records from the database.
136 WebTotemOption::clearOptions( [
137 'am_installed',
138 'waf_installed',
139 'av_installed',
140 'am_file',
141 'waf_file',
142 'av_file',
143 ] );
144
145 self::postdelete();
146
147 if($wp_filesystem = self::wpFileSystem()){
148 $list = $wp_filesystem->dirlist( ABSPATH );
149
150 $uploads_list = $wp_filesystem->dirlist( ABSPATH .'wp-content/uploads' ) ?: [];
151 foreach ($uploads_list as $key => $item){
152 $uploads_list[$key]['name'] = 'wp-content/uploads/' . $item['name'];
153 }
154
155 $list = array_merge($list, $uploads_list);
156
157 foreach ( $list as $item ) {
158
159 $target_item = ABSPATH . $item['name'];
160
161 // Check whether the item is a directory.
162 $recursive = ( $item['type'] == 'd' ) ? true : false;
163
164 $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})/';
165
166 if ( preg_match( $pattern, $target_item ) ) {
167 $wp_filesystem->delete( $target_item, $recursive, $item['type'] );
168 }
169 }
170 }
171
172 return TRUE;
173 }
174
175 /**
176 * This method clears the system file from the WAF connection strings.
177 *
178 * @return bool
179 */
180 public static function postdelete(): bool
181 {
182 $base_path = ABSPATH;
183 $targets = [
184 'default' => $base_path . 'index.php',
185 'wp' => $base_path . 'wp-load.php',
186 ];
187
188 foreach ($targets as $target_path) {
189 self::cut_inc($target_path);
190 }
191
192 return true;
193 }
194
195 /**
196 * This method clears the system file from the WAF connection strings.
197 *
198 * @return string
199 */
200 private static function cut_inc(string $target_path)
201 {
202 if (file_exists($target_path)) {
203 $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';
204 $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';
205 $target_content = file_get_contents($target_path);
206 $pos_inc = stripos($target_content, '@include_once($wtwaf);');
207 if ($pos_inc !== false) {
208 $cutted = preg_replace($reg, '', $target_content);
209 if (is_string($cutted) && $cutted !== '') {
210 if (preg_match($reg2, $cutted, $reg2_matches)) {
211 if (!empty($reg2_matches[1]) && !empty($reg2_matches[5])) {
212 $cutted = str_replace($reg2_matches[0], '', $cutted);
213 } else {
214 $cutted = str_replace($reg2_matches[2], '', $cutted);
215 }
216 }
217
218 if (is_string($cutted) && $cutted !== '') {
219 $wp_filesystem = self::wpFileSystem();
220 $res = $wp_filesystem->put_contents($target_path, $cutted, FS_CHMOD_FILE);
221 } else {
222 $res = 'preg_replace error 2';
223 }
224 } else {
225 $res = 'preg_replace error 1';
226 }
227 } else {
228 $res = 'inc not found';
229 }
230 } else {
231 $res = 'not found';
232 }
233 return $res;
234 }
235
236 /**
237 * Base WordPress Filesystem class which Filesystem implementations extend.
238 *
239 * @return object|bool
240 * Instance of Filesystem class.
241 */
242 private static function wpFileSystem() {
243 global $wp_filesystem;
244
245 if ( empty( $wp_filesystem ) ) {
246 require_once( ABSPATH . 'wp-admin/includes/file.php' );
247 WP_Filesystem();
248 }
249
250 if (empty($wp_filesystem)) {
251 WebTotemOption::setNotification('error', _('WP FileSystem path error'));
252 return FALSE;
253 }
254
255 return $wp_filesystem;
256 }
257
258 /**
259 * @param $download_url
260 * Link from where to download the file.
261 * @param $path
262 * Path where to save the file.
263 *
264 * @return bool
265 * If the file is saved successfully, it returns true.
266 */
267 private static function downloadFile($download_url, $path) {
268
269 $args = [
270 'timeout' => '30',
271 'sslverify' => FALSE,
272 ];
273
274 // if(WebTotemOption::getOption('api_environment') == 'M'){
275 // $download_url = str_replace("wtotem.com", "wtotem.net", $download_url);
276 // }
277
278 $response = wp_remote_get($download_url, $args);
279 $http_code = wp_remote_retrieve_response_code($response);
280
281 if ($http_code < 200) {
282 WebTotemOption::setNotification('error', __( 'Could not download file.', 'wtotem' ));
283 return FALSE;
284 }
285
286 $response_body = wp_remote_retrieve_body($response);
287
288 if($wp_filesystem = self::wpFileSystem()){
289 if(!empty($response_body)){
290 return $wp_filesystem->put_contents($path, $response_body, FS_CHMOD_FILE);
291 } else {
292 $message = __( 'API: Response body is empty.', 'wtotem' );
293 WebTotemOption::setNotification( 'error', $message );
294 }
295 }
296 return FALSE;
297
298 }
299
300 /**
301 * Generate the file that indicates that a WAF connection is being used through the plugin.
302 */
303 public static function generateMarkerFile() {
304 if($am_filename = WebTotemOption::getOption('am_file')) {
305 if ( $wp_filesystem = self::wpFileSystem() ) {
306 $content = '<?php exit(); ?>' . $am_filename;
307 $file_path = WEBTOTEM_PLUGIN_PATH . '/generate.php';
308 if ( ! file_exists($file_path) or $wp_filesystem->get_contents($file_path) != $content) {
309
310 if ( ! $wp_filesystem->put_contents( $file_path, $content, FS_CHMOD_FILE ) ) {
311 $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' );
312 WebTotemOption::setNotification( 'warning', $message );
313 }
314
315 }
316 }
317 }
318 }
319
320 /**
321 * WAF Include.
322 */
323 public static function wafInclude(){
324 if(WebTotemOption::isActivated()){
325 $sapi = @php_sapi_name();
326 if( $sapi != "cli" ) {
327 if ($waf = WebTotemOption::getOption("waf_file")) {
328 $include_waf_file = ABSPATH . '_include_' . $waf;
329
330 if (is_file($include_waf_file) && is_readable($include_waf_file)) {
331 include_once $include_waf_file;
332 }
333 }
334 }
335 }
336
337 }
338
339 /**
340 * Check if the plugin version has changed.
341 */
342 public static function checkVersion(){
343 if(WebTotemOption::isActivated()){
344 // Get version of the plugin that was previously installed.
345 $version = WebTotemOption::getOption('plugin_version');
346
347 if ($version == WEBTOTEM_VERSION) {
348 return;
349 }
350
351 WebTotemOption::setOptions(['plugin_version' => WEBTOTEM_VERSION]);
352
353 // Generate the file that indicates that a WAF connection is being used through the plugin.
354 self::generateMarkerFile();
355 }
356
357 }
358
359 }
360