| Current Path : /home/krobertfnz/www/wp-content/plugins/wp-defender/src/behavior/scan/ |
| Current File : /home/krobertfnz/www/wp-content/plugins/wp-defender/src/behavior/scan/malware-quick-scan.php |
<?php
namespace WP_Defender\Behavior\Scan;
use Calotes\Component\Behavior;
use WP_Defender\Traits\IO;
/**
* This will fast travel all yara rules to quickly get files seem suspicious, this is catchy.
*
* Class Malware_Quick_Scan
* @package WP_Defender\Behavior\Scan
*/
class Malware_Quick_Scan extends Behavior {
use IO;
private $content;
/**
* @param string $file
* @param array $rules
*
* @return array
*/
public function do_quick_scan( string $file, array $rules ): array {
$total_issues = 0;
$qs_detail = [];
if ( file_exists( $file ) ) {
$content = file_get_contents( $file );
$this->content = $content;
foreach ( $rules as $rule ) {
$strings = $rule['strings'];
$local_issues = [
'identifier' => $rule['identifier'],
'catches' => [],
];
foreach ( $strings as $string ) {
$offset = false;
if ( $string['type'] === 0 ) {
$offset = strpos( $content, $string['text'] );
$text = $string['text'];
} else {
$pattern = "/{$string['text']}/";
$is_match = preg_match_all( $pattern, $content, $matches,
PREG_PATTERN_ORDER | PREG_OFFSET_CAPTURE );
if ( $is_match ) {
$offset = $matches[0][0][1];
$text = $matches[0][0][0];
}
}
if ( false === $offset ) {
continue;
}
$local_issues['catches'] [] = [
'id' => $string['id'],
'text' => $text,
'offset' => $offset,
];
}
if ( empty( $local_issues['catches'] ) ) {
continue;
}
if ( $this->condition_valid( $local_issues['catches'], $rule ) ) {
$total_issues ++;
$qs_detail[] = $local_issues;
}
}
}
return [ $total_issues, $qs_detail ];
}
/**
* Parse the condition to see if this is an issue or not.
*
* @param $found
* @param $rule
*
* @return bool
*/
private function condition_valid( $found, $rule ): bool {
$condition = explode( 'and', $rule['condition'] );
$count = 0;
foreach ( $condition as $item ) {
$patterns = [
'x_of_them' => '/([a-z0-9]+)\s*of\s*(.*)/',
'id_at_pos' => '/(\$[a-zA-Z0-9]+)\s*at\s*(\d+)/',
];
foreach ( $patterns as $func => $pattern ) {
if ( preg_match( $pattern, $item, $match ) ) {
$count ++;
$ret = $this->$func( $found, $match, $rule );
if ( false === $ret ) {
return false;
}
}
}
}
if ( $count === 0 ) {
$this->log( $rule['identifier'], 'malware_scan.log' );
$this->log( var_export( $found, true ), 'malware_scan.log' );
return false;
}
return true;
}
/**
* This will parse the condition x of y.
*
* @param $found
* @param $match
* @param $rule
*
* @return bool
*/
private function x_of_them( $found, $match, $rule ): bool {
$num = $match[1];
$num = 'all' === $num ? count( $rule['strings'] ) : $num;
$num = 'any' === $num ? 1 : $num;
if ( '(s*)' == $match[2] ) {
// Hard code in this situation.
$num -= 1;
}
//$this->log( sprintf( 'num %s', $num ), 'malware_scan.log' );
//$this->log( sprintf( 'count %s', count( $found ) ), 'malware_scan.log' );
return ( is_array($found) || $found instanceof \Countable ? count( $found ) : 0 ) >= $num;
}
/**
* @param $found
* @param $match
* @param $rule
*
* @return bool
*/
private function id_at_pos( $found, $match, $rule ): bool {
// Get the text to check.
foreach ( $found as $item ) {
if ( $item['id'] === $match[1] ) {
return strpos( $this->content, $item['text'] ) == $match[2];
}
}
return false;
}
}