FileTypeFunnellingAnalyzer   A
last analyzed

Complexity

Total Complexity 21

Size/Duplication

Total Lines 102
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 51
c 2
b 0
f 0
dl 0
loc 102
rs 10
wmc 21

2 Methods

Rating   Name   Duplication   Size   Complexity  
D analyze() 0 74 19
A countKnownFileExtensions() 0 4 2
1
<?php
2
3
/**
4
 * @copyright Copyright (c) 2018 Matthias Held <[email protected]>
5
 * @author Matthias Held <[email protected]>
6
 * @license GNU AGPL version 3 or any later version
7
 *
8
 * This program is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU Affero General Public License as
10
 * published by the Free Software Foundation, either version 3 of the
11
 * License, or (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU Affero General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Affero General Public License
19
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
20
 */
21
22
namespace OCA\RansomwareDetection\Analyzer;
23
24
use OCA\RansomwareDetection\Classifier;
25
use OCA\RansomwareDetection\Monitor;
26
27
class FileTypeFunnellingAnalyzer
28
{
29
    /**
30
     * Analyzes if the written files fulfill the property of
31
     * file type funneling.
32
     *
33
     * Therefor classifies the sequence in three funneling classes:
34
     *
35
     * Class 1: All file extensions are unknown and the same.
36
     * Class 2: All file extensions are unknown and every extensions is distinct.
37
     * Class 3: All file extensions are unknown.
38
     * Class 4: All file extensions are known, but all files are corrupted.
39
     *
40
     * @param array $sequence
41
     *
42
     * @return int Class of file type funneling
43
     */
44
    public function analyze($sequence)
45
    {
46
        $writtenExtensions = [];
47
        $deletedExtensions = [];
48
        $corruptedFiles = [];
49
        $writtenFiles = [];
50
        $numberOfKnownFileExtensions = 0;
51
        $numberOfInfoFiles = 0;
52
53
        foreach ($sequence as $file) {
54
            if ($file->getType() === 'file') {
55
                switch ($file->getCommand()) {
56
                    case Monitor::WRITE:
57
                        if ($file->getSuspicionClass() === Classifier::NOT_SUSPICIOUS) {
58
                            if ($numberOfInfoFiles < SequenceAnalyzer::NUMBER_OF_INFO_FILES) {
59
                                $numberOfInfoFiles++;
60
                                break;
61
                            }
62
                        }
63
                        $numberOfKnownFileExtensions += $this->countKnownFileExtensions($file);
64
                        $pathInfo = pathinfo($file->getOriginalName());
65
                        if (isset($pathInfo['extension'])) {
66
                            $writtenExtensions[$pathInfo['extension']] = 1;
67
                            $writtenFiles[] = $file;
68
                        }
69
                        if ($file->getCorrupted()) {
70
                            $corruptedFiles[] = $file;
71
                        }
72
                        break;
73
                    case Monitor::READ:
74
                        break;
75
                    case Monitor::RENAME:
76
                        break;
77
                    case Monitor::DELETE:
78
                        $pathInfo = pathinfo($file->getOriginalName());
79
                        if (isset($pathInfo['extension'])) {
80
                            $deletedExtensions[] = $pathInfo['extension'];
81
                        }
82
                        break;
83
                    case Monitor::CREATE:
84
                        break;
85
                    default:
86
                        break;
87
                }
88
            }
89
        }
90
91
        // File type funneling must be at least 2 files
92
        if (sizeof($writtenFiles) > 2) {
93
            // Some files were written
94
            if ($numberOfKnownFileExtensions === 0) {
0 ignored issues
show
introduced by
The condition $numberOfKnownFileExtensions === 0 is always true.
Loading history...
95
                if (sizeof($writtenExtensions) === sizeof($writtenFiles)) {
96
                    // All files have distinct unknown extensions
97
                    return 2;
98
                }
99
                if (sizeof($writtenExtensions) === 1) {
100
                    // All files have the same extension
101
                    return 2;
102
                }
103
                // All file extensions are unknown
104
                return 1;
105
            } elseif ($numberOfKnownFileExtensions === sizeof($writtenFiles)) {
106
                if ($numberOfKnownFileExtensions === sizeof($corruptedFiles)) {
107
                    // All files are corrupted
108
                    return 2;
109
                }
110
                // All written files have known extensions
111
                return 0;
112
            }
113
            // Some files are known
114
            return 0;
115
        }
116
117
        return 0;
118
    }
119
120
    /**
121
     * Count the known file extensions.
122
     *
123
     * @param Entity $file
0 ignored issues
show
Bug introduced by
The type OCA\RansomwareDetection\Analyzer\Entity was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
124
     */
125
    private function countKnownFileExtensions($file)
126
    {
127
        if (intval($file->getFileExtensionClass()) === FileExtensionResult::NOT_SUSPICIOUS) {
128
            return 1;
129
        }
130
    }
131
}
132