| Current Path : /home/k/r/o/krobertfnz/www/wp-content/plugins/wp-defender/src/behavior/scan/ |
| Current File : /home/k/r/o/krobertfnz/www/wp-content/plugins/wp-defender/src/behavior/scan/known-vulnerability.php |
<?php
namespace WP_Defender\Behavior\Scan;
use Calotes\Base\Component;
use WP_Defender\Behavior\WPMUDEV;
use WP_Defender\Model\Scan;
use WP_Defender\Model\Scan_Item;
use WP_Defender\Traits\IO;
use WP_Defender\Traits\Plugin;
use WP_Defender\Traits\Theme;
class Known_Vulnerability extends Component {
use IO, Plugin, Theme;
/**
* @var WPMUDEV
*/
private $wpmudev;
/**
* @var Scan
*/
private $scan;
public function __construct( WPMUDEV $wpmudev, Scan $scan ) {
$this->wpmudev = $wpmudev;
$this->scan = $scan;
}
public function vuln_check(): bool {
global $wp_version;
$info_cached = [];
$data = [
'plugins' => json_encode( $this->gather_fact_plugins( $info_cached ) ),
'themes' => json_encode( $this->gather_fact_themes( $info_cached ) ),
'wordpress' => $wp_version,
];
$ret = $this->make_check( $data );
if ( is_wp_error( $ret ) ) {
$this->log( $ret->get_error_message(), 'scan.log' );
$this->scan->status = Scan::STATUS_ERROR;
$this->scan->save();
return true;
}
// Get ignored issues.
$last = Scan::get_last();
if ( is_object( $last ) ) {
$ignored_issues = $last->get_issues( Scan_Item::TYPE_VULNERABILITY, Scan_Item::STATUS_IGNORE );
} else {
$ignored_issues = [];
}
$this->process_result( $ret['plugins'], $info_cached, 'plugin', $ignored_issues );
$this->process_result( $ret['themes'], $info_cached, 'theme', $ignored_issues );
$this->process_result( $ret['wordpress'], [], 'wp_core', $ignored_issues );
$this->scan->calculate_percent( 100, 5 );
if ( ! empty( $ignored_issues ) ) {
foreach ( $ignored_issues as $issue ) {
$this->scan->add_item( Scan_Item::TYPE_VULNERABILITY, $issue->raw_data, Scan_Item::STATUS_IGNORE );
}
}
return true;
}
/**
* @param $data
*
* @return mixed
*/
public function make_check( $data ) {
return $this->wpmudev->make_wpmu_request(
WPMUDEV::API_SCAN_KNOWN_VULN, $data, [
'method' => 'POST',
]
);
}
/**
* @param mixed $result
* @param array $info
* @param string $type
* @param array $ignored_issues
*/
private function process_result( $result, $info, $type, $ignored_issues ) {
if ( empty( $result ) ) {
return;
}
$this->log( sprintf( 'Checking %s:', $type ) );
$model = $this->scan;
foreach ( $result as $base_slug => $bugs ) {
// Case with WP Core.
if ( 'wp_core' === $type ) {
global $wp_version;
$is_exist = false;
if ( ! empty( $ignored_issues ) ) {
// Stop if we already have it in the ignored list.
foreach ( $ignored_issues as $issue ) {
if ( $wp_version === $issue->raw_data['version'] ) {
$is_exist = true;
}
}
}
// Prepare data for saving if it was not before.
if ( ! $is_exist ) {
$raw_data = [
'type' => $type,
'slug' => '',
'base_slug' => '',
'version' => $wp_version,
'name' => 'WordPress Core',
'bugs' => [
[
'vuln_type' => $bugs['vuln_type'],
'title' => $bugs['title'],
'ref' => $bugs['references'],
'fixed_in' => $bugs['fixed_in'],
'cvss_score' => $bugs['cvss']['score'] ?? '',
],
],
'new_structure' => '3.4.0',
];
// Save it.
$model->add_item( Scan_Item::TYPE_VULNERABILITY, $raw_data );
}
} elseif ( 'plugin' === $type || 'theme' === $type ) {
// Case with WP plugin or theme.
if ( empty( $info[ $base_slug ] ) ) {
continue;
}
[ $name, $current_version, $slug ] = $info[ $base_slug ];
$raw_data = [
'type' => $type,
'slug' => $slug,
'base_slug' => $base_slug,
'version' => $current_version,
'name' => $name,
'bugs' => [],
];
if ( isset( $bugs['confirmed'] ) &&
( is_array( $bugs['confirmed'] ) || $bugs['confirmed'] instanceof \Countable ? count( $bugs['confirmed'] ) : 0 )
) {
// Do not save if the current plugin is not from wp.org, and we have bugs for plugin from wp.org.
if (
! $this->is_likely_wporg_slug( $base_slug ) &&
isset( $is_wp_org_plugin['success'] ) &&
$is_wp_org_plugin['success']
) {
continue;
}
$confirmed_bugs = (array) $bugs['confirmed'];
// @since 3.4.0 Restructure the view in relation to the new CVSS Score field.
$raw_data['new_structure'] = '3.4.0';
$this->log( sprintf( '%s has %d known bugs', $slug, count( $confirmed_bugs ) ) );
foreach ( $confirmed_bugs as $bug ) {
$raw_data['bugs'][] = [
'vuln_type' => $bug['vuln_type'],
'title' => $bug['title'],
'ref' => $bug['references'],
'fixed_in' => $bug['fixed_in'],
'cvss_score' => $bug['cvss']['score'] ?? '',
];
}
$model->add_item( Scan_Item::TYPE_VULNERABILITY, $raw_data );
}
}
}
}
/**
* Get all the plugins install on this site, no matter the plugin status.
*
* @param $info_cached
*
* @return array
*/
private function gather_fact_plugins( &$info_cached ): array {
$plugins = [];
$model = Scan::get_last();
foreach ( $this->get_plugins() as $slug => $plugin ) {
if ( is_object( $model ) && $model->is_issue_ignored( $slug ) ) {
continue;
}
// DIRECTORY_SEPARATOR won't work on Windows OS.
$base_slug = explode( '/', $slug );
$base_slug = array_shift( $base_slug );
$plugins[ $base_slug ] = $plugin['Version'];
$info_cached[ $base_slug ] = [ $plugin['Name'], $plugin['Version'], $slug ];
}
return $plugins;
}
/**
* @param $info_cached
*
* @return array
*/
private function gather_fact_themes( &$info_cached ): array {
$themes = [];
$model = Scan::get_last();
foreach ( $this->get_themes() as $theme ) {
if ( is_object( $theme->parent() ) ) {
continue;
}
if ( is_object( $model ) && $model->is_issue_ignored( $theme->get_template() ) ) {
continue;
}
$themes[ $theme->get_template() ] = $theme->Version;
$info_cached[ $theme->get_template() ] = [ $theme->Name, $theme->Version, $theme->get_template() ];
}
return $themes;
}
}