PluginProbe
Patchstack – WordPress & Plugins Security / 2.1.20
Patchstack – WordPress & Plugins Security v2.1.20
2.3.7 trunk 2.1.0 2.1.1 2.1.10 2.1.11 2.1.12 2.1.13 2.1.14 2.1.15 2.1.16 2.1.17 2.1.18 2.1.19 2.1.2 2.1.20 2.1.21 2.1.22 2.1.23 2.1.24 2.1.25 2.1.3 2.1.4 2.1.5 2.1.6 All 49 releases
patchstack / includes / upload.php

upload.php in Patchstack – WordPress & Plugins Security 2.1.20, at includes/upload.php

268 lines 9.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 // Do not allow the file to be called directly.
4 if ( ! defined( 'ABSPATH' ) ) {
5 exit;
6 }
7
8 /**
9 * This class is used to upload the local logs to our API so it can
10 * be shown on the app.
11 */
12 class P_Upload extends P_Core {
13
14 /**
15 * Add the actions required to upload logs to our API.
16 *
17 * @param Patchstack $core
18 * @return void
19 */
20 public function __construct( $core ) {
21 parent::__construct( $core );
22
23 // In case the software has never been synchronized, force it.
24 if ( ! get_option( 'patchstack_software_data_hash', false ) ) {
25 $this->upload_software();
26 }
27
28 // Register the actions.
29 add_action( 'patchstack_send_software_data', array( $this, 'upload_software' ) );
30 add_action( 'patchstack_send_hacker_logs', array( $this, 'upload_firewall_logs' ) );
31 add_action( 'patchstack_send_event_logs', array( $this, 'upload_activity_logs' ) );
32
33 // In case a plugin or upgrade has been performed, re-synchronize with the app.
34 add_action( 'activated_plugin', array( $this, 'upload_software' ) );
35 add_action( 'deactivated_plugin', array( $this, 'upload_software' ) );
36 add_action( 'deleted_plugin', array( $this, 'upload_software' ) );
37 add_action( 'upgrader_process_complete', array( $this, 'upload_software' ) );
38 add_action( '_core_updated_successfully', array( &$this, 'upload_software' ) );
39 }
40
41 /**
42 * Synchronize the software data with our API.
43 * This includes plugins, themes, WordPress and PHP version.
44 *
45 * @return void|array
46 */
47 public function upload_software() {
48 // Get the software data and hash.
49 $data = $this->get_software_data();
50 $hash = sha1( json_encode( $data ) );
51 if ( ! defined( 'DOING_CRON' ) && ! isset( $_POST['webarx_secret'] ) && get_option( 'patchstack_software_data_hash', false ) === $hash && ! is_admin() ) {
52 return;
53 }
54
55 // Synchronize the software list with the API.
56 $results = $this->plugin->api->upload_software( array( 'software' => json_encode( $data ) ) );
57 if ( isset( $results['success'] ) ) {
58 update_option( 'patchstack_software_data_hash', $hash );
59
60 // The result will also contain a list of all vulnerable plugins on the site that is returned by the API.
61 // If the auto update setting is enabled for vulnerable plugins, perform the update once the 15 minute
62 // scheduled task "patchstack_update_plugins" is executed.
63 $update = get_site_option( 'patchstack_auto_update', array() );
64 if ( isset( $results['vulnerable'] ) && is_array( $update ) && in_array( 'vulnerable', $update ) ) {
65 update_site_option( 'patchstack_vulnerable_plugins', $results['vulnerable'] );
66 }
67
68 return $results;
69 }
70
71 return;
72 }
73
74 /**
75 * Synchronize the firewall logs with our API.
76 *
77 * @return void
78 */
79 public function upload_firewall_logs() {
80 global $wpdb;
81 $lastid = get_option( 'patchstack_firewall_log_lastid', 0 );
82 $items = $wpdb->get_results( $wpdb->prepare( 'SELECT ip, log_date, request_uri, user_agent, fid, method, post_data FROM ' . $wpdb->prefix . 'patchstack_firewall_log WHERE id > %d ORDER BY id', $lastid ) );
83
84 // No need to synchronize if there are no new logs present.
85 if ( $wpdb->num_rows == 0 ) {
86 return;
87 }
88
89 // Construct the array to be uploaded to our API.
90 $logs = array();
91 foreach ( $items as $item ) {
92
93 // Entries that we don't want to store on the API side.
94 if ( stripos( $item->request_uri, 'wp-comments-post' ) !== false ) {
95 continue;
96 }
97
98 // Push to entries to be uploaded.
99 $logs[] = array(
100 'ip' => $item->ip,
101 'fid' => $item->fid,
102 'request_uri' => $item->request_uri,
103 'user_agent' => $item->user_agent,
104 'method' => $item->method,
105 'log_date' => $item->log_date,
106 'post_data' => $item->post_data,
107 );
108 }
109
110 // JSON encode the logs and upload.
111 $logs = json_encode( $logs );
112 $results = $this->plugin->api->upload_firewall_logs(
113 array(
114 'logs' => $logs,
115 'type' => 'firewall',
116 )
117 );
118 if ( isset( $results['errors'] ) ) {
119 return;
120 }
121
122 // Get the most recent id of the logs.
123 $lastid = $wpdb->get_var( 'SELECT id FROM ' . $wpdb->prefix . 'patchstack_firewall_log ORDER BY id DESC LIMIT 0, 1' );
124 update_option( 'patchstack_firewall_log_lastid', $lastid );
125
126 // Delete logs that are older than 2 weeks.
127 $wpdb->query( 'DELETE FROM ' . $wpdb->prefix . 'patchstack_firewall_log WHERE log_date < DATE_SUB(NOW(), INTERVAL 14 DAY)' );
128 }
129
130 /**
131 * Synchronize the activity logs with our API.
132 *
133 * @return void
134 */
135 public function upload_activity_logs() {
136 global $wpdb;
137
138 // Determine if we should upload failed logins to the app.
139 $where = " AND action != 'failed login' ";
140 if ( $this->get_option( 'patchstack_activity_log_failed_logins_db', 0 ) == 1 ) {
141 $where = ' ';
142 }
143
144 // Do we have data to upload?
145 $lastid = get_option( 'patchstack_eventlog_lastid', 0 );
146 $items = $wpdb->get_results( $wpdb->prepare( 'SELECT author, ip, object, object_id, object_name, action, date FROM ' . $wpdb->prefix . 'patchstack_event_log WHERE id > %d' . $where . 'ORDER BY id', array( $lastid ) ) );
147 if ( $wpdb->num_rows == 0 ) {
148 return;
149 }
150
151 // Send to the API.
152 $logs = json_encode( $items );
153 $results = $this->plugin->api->upload_activity_logs( array( 'logs' => $logs ) );
154 if ( isset( $results['errors'] ) ) {
155 return;
156 }
157
158 // Get the most recent id of the logs.
159 $lastid = $wpdb->get_var( 'SELECT id FROM ' . $wpdb->prefix . 'patchstack_event_log ORDER BY id DESC LIMIT 0, 1' );
160 update_option( 'patchstack_eventlog_lastid', $lastid );
161
162 // Delete logs that are older than 2 weeks.
163 $wpdb->query( 'DELETE FROM ' . $wpdb->prefix . 'patchstack_event_log WHERE date < DATE_SUB(NOW(), INTERVAL 14 DAY)' );
164 }
165
166 /**
167 * Obtain information about the software that the user has installed.
168 * This includes plugins, themes, WordPress and PHP version.
169 *
170 * @return array
171 */
172 public function get_software_data() {
173 if ( ! function_exists( 'get_plugins' ) ) {
174 require_once ABSPATH . 'wp-admin/includes/plugin.php';
175 }
176 if ( ! function_exists( 'get_plugin_updates' ) ) {
177 require_once ABSPATH . 'wp-admin/includes/update.php';
178 }
179
180 // Refetch updates data if we are performing a plugin listener related action.
181 if ( isset( $_POST['webarx_secret'] ) ) {
182 @require_once ABSPATH . 'wp-includes/update.php';
183 @wp_update_themes();
184 @wp_update_plugins();
185 }
186
187 // Fetch list of plugins.
188 $all_plugin = get_plugins();
189 $installed_plugins = array_keys( $all_plugin );
190 $updatable_plugins = get_plugin_updates();
191 $software_list = array();
192
193 foreach ( $installed_plugins as $plugin ) {
194 if ( ! file_exists( WP_PLUGIN_DIR . '/' . $plugin ) ) {
195 continue;
196 }
197
198 $plugin_data = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin );
199 $new_version = empty( $updatable_plugins[ $plugin ]->update->new_version ) ? '' : $updatable_plugins[ $plugin ]->update->new_version;
200 $plugin_name = empty( $plugin_data['Name'] ) ? '' : $plugin_data['Name'];
201 $plugin_version = empty( $plugin_data['Version'] ) ? '' : $plugin_data['Version'];
202
203 if ( ! empty( $plugin_name ) && ! empty( $plugin_version ) ) {
204
205 // Determine the active state.
206 if ( isset( $_GET['action'], $_GET['plugin'] ) && $_GET['action'] == 'deactivate' && $_GET['plugin'] == $plugin) {
207 $active = 0;
208 } else {
209 $active = (int) is_plugin_active( $plugin );
210 }
211
212 $software_list[] = array(
213 'sw_type' => 'plugin',
214 'sw_name' => $plugin_name,
215 'sw_cur_ver' => $plugin_version,
216 'sw_new_ver' => $new_version,
217 'sw_key' => $plugin,
218 'sw_active' => $active
219 );
220 }
221 }
222
223 // Fetch list of themes.
224 $themes = wp_get_themes();
225 $themes_keys = array_keys( $themes );
226 $updatable_themes = get_theme_updates();
227
228 foreach ( $themes_keys as $theme_key ) {
229 $themes_data = $themes[ $theme_key ];
230 $theme_temporary = empty( $updatable_themes[ $theme_key ] ) ? '' : $updatable_themes[ $theme_key ];
231 $theme_new_version = empty( $updatable_themes[ $theme_key ] ) || ! isset( $theme_temporary->update, $theme_temporary->update['new_version'] ) ? '' : $theme_temporary->update['new_version'];
232 $theme_name = $themes_data->get( 'Name' );
233 $theme_version = $themes_data->get( 'Version' );
234
235 if ( ! empty( $theme_name ) && ! empty( $theme_version ) ) {
236 $software_list[] = array(
237 'sw_type' => 'theme',
238 'sw_name' => $theme_name,
239 'sw_cur_ver' => $theme_version,
240 'sw_new_ver' => $theme_new_version,
241 'sw_key' => $theme_key,
242 );
243 }
244 }
245
246 // Fetch WordPress version.
247 global $wp_version;
248 $core_updates = get_core_updates();
249 $new_wp_version = ( ! empty( $core_updates ) && $core_updates[0]->response == 'upgrade' ) ? $core_updates[0]->version : '';
250 $software_list[] = array(
251 'sw_type' => 'wordpress',
252 'sw_name' => 'WordPress',
253 'sw_cur_ver' => $wp_version,
254 'sw_new_ver' => $new_wp_version,
255 );
256
257 // Fetch PHP version.
258 $software_list[] = array(
259 'sw_type' => 'php',
260 'sw_name' => 'PHP',
261 'sw_cur_ver' => substr( phpversion(), 0, 5 ),
262 'sw_new_ver' => '',
263 );
264
265 return $software_list;
266 }
267 }
268