File manager - Edit - /home/xfekoga/grenier/wp-content/plugins/defender-security/src/behavior/scan/class-malware-scan.php
Back
<?php /** * Handles malware scan. * * @package WP_Defender\Behavior\Scan */ namespace WP_Defender\Behavior\Scan; use ArrayIterator; use WP_Defender\Traits\IO; use Calotes\Base\Component; use WP_Defender\Traits\Plugin; use WP_Defender\Component\Timer; use WP_Defender\Model\Scan_Item; use WP_Defender\Behavior\WPMUDEV; use WP_Defender\Model\Scan as Model_Scan; use WP_Defender\Model\Setting\Scan as Scan_Settings; use WP_Defender\Helper\Analytics\Scan as Scan_Analytics; use WP_Defender\Controller\Scan as Scan_Controller; /** * It is responsible for performing suspicious checks on files using a quick scan and a deep scan. */ class Malware_Scan extends Component { use IO; use Plugin; public const YARA_RULES = 'defender_yara_rules'; public const MALWARE_LOG = 'malware_scan.log'; /** * Backup memory. * * @var string */ private $memory; /** * Holds the WPMUDEV object or null if not set. * * @var WPMUDEV */ private $wpmudev; /** * Holds the Model_Scan model or null if not set. * * @var Model_Scan */ private $scan; /** * Constructor for the Malware_Scan class. * * @param WPMUDEV $wpmudev The WPMUDEV object. * @param Model_Scan $scan The Model_Scan model. */ public function __construct( WPMUDEV $wpmudev, Model_Scan $scan ) { $this->wpmudev = $wpmudev; $this->scan = $scan; } /** * Retrieves additional rules based on the provided scan settings. * * @param Scan_Settings $scan_settings The scan settings object. * * @return array Returns an array containing plugin-related rules. */ protected function get_additional_rules( Scan_Settings $scan_settings ): array { $plugin_cache = false; $plugin_slugs_changes = array(); $plugin_pro_slugs = array(); $plugin_all_slugs = array(); // Checked Plugin option. if ( $scan_settings->integrity_check && $scan_settings->check_plugins ) { $plugin_cache = true; $arr = get_site_option( Plugin_Integrity::PLUGIN_SLUGS, false ); if ( is_array( $arr ) && ! empty( $arr ) ) { $plugin_slugs_changes = $arr; } $plugin_slugs = get_site_option( Plugin_Integrity::PLUGIN_PREMIUM_SLUGS, false ); if ( is_array( $plugin_slugs ) && ! empty( $plugin_slugs ) ) { $plugin_pro_slugs = $plugin_slugs; } $plugin_all_slugs = $this->get_plugin_slugs(); } return array( 'plugin_change' => $plugin_cache, // List of plugins with modifications. 'plugin_slugs_changes' => $plugin_slugs_changes, // List of pro plugins. 'plugin_pro_slugs' => $plugin_pro_slugs, 'plugin_all_slugs' => $plugin_all_slugs, ); } /** * Check if a file has been modified based on the given rules. * * @param string $file_path The path of the file to check. * @param array $rules The rules to determine if a file has been modified. * * @return bool Returns true if the file has been modified, false otherwise. */ protected function was_modificated_file( $file_path, $rules ): bool { // Unchecked 'Plugin change file' option, so green light to display Suspicious checks. if ( ! $rules['plugin_change'] ) { return true; } $search_on_plugin = WP_PLUGIN_DIR . '/'; if ( false !== stripos( $file_path, $search_on_plugin ) ) { /** * Suspicious code in /plugins. * Empty list of plugin slugs because there are premium plugins, * not modifications on Free plugins, * or not plugins on site. * Should check separate custom files/dirs in the root too. */ $rev_file = str_replace( $search_on_plugin, '', $file_path ); $matches = explode( '/', $rev_file ); $base_slug = array_shift( $matches ); // Custom files/dirs. if ( ! in_array( $base_slug, $rules['plugin_all_slugs'], true ) ) { return true; } if ( empty( $rules['plugin_slugs_changes'] ) && empty( $rules['plugin_pro_slugs'] ) ) { // No modifications. return false; } // Is it on premium plugins? if ( in_array( $base_slug, $rules['plugin_pro_slugs'], true ) ) { return true; } if ( in_array( $base_slug, (array) $rules['plugin_slugs_changes'], true ) ) { // Modifications in this plugin. return true; } // Modifications are not here. return false; } // Other WP places. return true; } /** * Perform a suspicious check on files using a quick scan and a deep scan. * * @param Malware_Quick_Scan $quick_scan The quick scan object. * @param Malware_Deep_Scan $deep_scan The deep scan object. * * @return bool Returns true if the check is successful, false otherwise. */ public function suspicious_check( Malware_Quick_Scan $quick_scan, Malware_Deep_Scan $deep_scan ): bool { $files = get_site_option( Gather_Fact::CACHE_CONTENT, array() ); if ( empty( $files ) ) { return true; } set_time_limit( 0 ); $this->prepare_emergency_shutdown(); $timer = new Timer(); $rules = $this->fetch_yara_rules(); $model = $this->scan; $pos = (int) $model->task_checkpoint; $combinations = $this->get_additional_rules( new Scan_Settings() ); $files = new ArrayIterator( $files ); $files->seek( $pos ); while ( $files->valid() ) { if ( ! $timer->check() ) { $reason = 'Rage quit'; /** * Retrieves the Scan_Analytics class. * * @var Scan_Analytics $scan_analytics */ $scan_analytics = wd_di()->get( Scan_Analytics::class ); $scan_analytics->track_feature( $scan_analytics::EVENT_SCAN_FAILED, array( $scan_analytics::EVENT_SCAN_FAILED_PROP => $scan_analytics::EVENT_SCAN_FAILED_ERROR, 'Error_Reason' => $reason, ) ); $this->log( $reason, self::MALWARE_LOG ); $model->save(); break; } if ( $model->is_issue_ignored( $files->current() ) ) { $this->log( sprintf( 'skip %s because of file is ignored', $files->current() ), self::MALWARE_LOG ); $files->next(); continue; } [ $result, $qs_detail ] = $quick_scan->do_quick_scan( $files->current(), $rules ); if ( $result ) { $this->log( sprintf( 'file %s suspicious', $files->current() ), self::MALWARE_LOG ); $result = $deep_scan->do_deep_scan( $files->current(), $rules, $qs_detail ); /** * Add new item if Suspicious code is found and: * plugins are premium, * plugins are on wp.org but the code doesn't match from the WP repo (there are differences in checksums), * deactivated options of File change detection > Scan plugin file changes. */ if ( is_array( $result ) && $this->was_modificated_file( $files->current(), $combinations ) ) { $result['file'] = $files->current(); $model->add_item( Scan_Item::TYPE_SUSPICIOUS, $result ); } } $files->next(); $files_key = $files->key(); $model->task_checkpoint = ! is_null( $files_key ) ? $files_key : ''; $model->calculate_percent( $files_key * 100 / $files->count(), 6 ); if ( 0 === $files_key % 100 ) { // We should update the model percent each 100 files so we have some progress on the screen. $model->save(); } } if ( ! $files->valid() ) { $last = Model_Scan::get_last(); if ( is_object( $last ) ) { $ignored_issues = $last->get_issues( Scan_Item::TYPE_SUSPICIOUS, Scan_Item::STATUS_IGNORE ); foreach ( $ignored_issues as $issue ) { $this->scan->add_item( Scan_Item::TYPE_SUSPICIOUS, $issue->raw_data, Scan_Item::STATUS_IGNORE ); } } $model->task_checkpoint = ''; } $model->save(); return ! $files->valid(); } /** * We will use this for a safe switch when memory out happen. */ public function prepare_emergency_shutdown() { $this->memory = str_repeat( '*', 1024 * 1024 ); register_shutdown_function( function () { if ( Model_Scan::STATUS_FINISH === $this->scan->status ) { return; } $this->memory = null; $err = error_get_last(); if ( ( ! is_null( $err ) ) && ( ! in_array( $err['type'], array( E_NOTICE, E_WARNING, E_DEPRECATED ), true ) ) ) { $this->log( $err, Scan_Controller::SCAN_LOG ); $this->log( 'Something wrong happen, saving and quit.', Scan_Controller::SCAN_LOG ); $this->scan->status = Model_Scan::STATUS_ERROR; ++$this->scan->task_checkpoint; $this->scan->save(); } } ); } /** * Fetch yara rules from API. * * @return array */ private function fetch_yara_rules(): array { $rules = get_site_option( self::YARA_RULES, false ); if ( is_array( $rules ) ) { return $rules; } $rules = $this->wpmudev->make_wpmu_request( WPMUDEV::API_SCAN_SIGNATURE ); if ( is_array( $rules ) ) { update_site_option( self::YARA_RULES, $rules ); return $rules; } return array(); } }
| ver. 1.4 |
Github
|
.
| PHP 8.0.30 | Generation time: 0 |
proxy
|
phpinfo
|
Settings