-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathController.php
143 lines (123 loc) · 5.34 KB
/
Controller.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
<?php
namespace CleantalkSP\Common\Scanner\SignaturesAnalyser;
use CleantalkSP\Common\Helpers\Arr;
use CleantalkSP\Common\Helpers\Helper;
use CleantalkSP\Common\Scanner\SignaturesAnalyser\Structures\FileInfo;
use CleantalkSP\Common\Scanner\SignaturesAnalyser\Structures\Verdict;
use CleantalkSP\Common\Scanner\SignaturesAnalyser\Exceptions\SignaturesScannerException;
class Controller
{
const SIGNATURES_SCAN_MAX_FILE_SIZE = 1048576; // 1 MB
public function __construct()
{
}
public function scanFile(FileInfo $file_info, $root_path, &$signatures)
{
$output = new Verdict();
$output->status = 'ERROR';
try {
$output = $this->scanFileForSignatures($file_info, $root_path, $signatures);
} catch (SignaturesScannerException $e) {
$output->error_msg = $e->getMessage();
} catch (\Exception $e) {
$output->error_msg = 'UNKNOWN_INTERNAL_ERROR';
}
return $output;
}
/**
* @param int|string $file_size_or_path
*
* @return void
* @throws SignaturesScannerException
*/
private static function checkFileSize($file_size_or_path)
{
$file_size = ! is_int($file_size_or_path) ? filesize($file_size_or_path) : $file_size_or_path;
if ( ! (int)$file_size ) {
throw new SignaturesScannerException('FILE_SIZE_ZERO');
}
if ( (int)$file_size > self::SIGNATURES_SCAN_MAX_FILE_SIZE ) {
throw new SignaturesScannerException('FILE_SIZE_TOO_LARGE');
}
}
/**
* Scan file against malware signatures
*
* @param FileInfo $file_info Array with files data (path, real_full_hash, source_type, source, version), other is optional
* @param string $root_path Path to CMS's root folder
* @param array $signatures Set of signatures
*
* @return Verdict Verdict or Error Array
* @throws SignaturesScannerException
*/
private function scanFileForSignatures(FileInfo $file_info, $root_path, &$signatures)
{
$output = new Verdict();
if ( file_exists($root_path . $file_info->path) ) {
if ( is_readable($root_path . $file_info->path) ) {
self::checkFileSize($root_path . $file_info->path);
$verdict = array();
$file_content = file_get_contents($root_path . $file_info->path);
// Check if md5 is persisting and collectable
if ( (empty($file_info->full_hash) || $file_info->full_hash === 'full_hash') &&
function_exists('md5') &&
!empty($file_content)
) {
$file_info->full_hash = md5($file_content);
}
foreach ( (array)$signatures as $signature ) {
if ( $signature['type'] === 'FILE' ) {
if ( $file_info->full_hash === $signature['body'] ) {
$verdict['SIGNATURES'][1][] = $signature['id'];
}
}
if ( in_array($signature['type'], array('CODE_PHP', 'CODE_JS', 'CODE_HTML')) ) {
$is_regexp = Helper::isRegexp($signature['body']);
if (
( $is_regexp && preg_match($signature['body'], $file_content) ) ||
( ! $is_regexp &&
(
strripos($file_content, stripslashes($signature['body'])) !== false ||
strripos($file_content, $signature['body']) !== false
)
)
) {
$line_numbers = Helper::getNeedleStringsNumberFromFile(
$root_path . $file_info->path,
$signature['body'],
$is_regexp
);
foreach ($line_numbers as $line_number) {
$verdict['SIGNATURES'][$line_number][] = $signature['id'];
}
}
}
}
// Removing signatures from the previous result
$file_info->weak_spots = ! empty($file_info->weak_spots) ? json_decode(
$file_info->weak_spots,
true
) : array();
if ( isset($file_info->weak_spots['SIGNATURES']) ) {
unset($file_info->weak_spots['SIGNATURES']);
}
$verdict = Arr::mergeWithSavingNumericKeysRecursive($file_info->weak_spots, $verdict);
// Processing results
if ( ! empty($verdict) ) {
$output->weak_spots = $verdict;
$output->severity = 'CRITICAL';
$output->status = 'INFECTED';
} else {
$output->weak_spots = 'NULL';
$output->severity = 'NULL';
$output->status = 'OK';
}
} else {
throw new SignaturesScannerException('NOT_READABLE');
}
} else {
throw new SignaturesScannerException('NOT_EXISTS');
}
return $output;
}
}