-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathSimpleFixScanner.php
More file actions
205 lines (179 loc) · 6.46 KB
/
SimpleFixScanner.php
File metadata and controls
205 lines (179 loc) · 6.46 KB
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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
<?php
/*
* Sample class usage
*/
$scanner = new SimpleFixScanner();
$scanner->scan();
/**
* Simple trojan scanner to fix some tedious trojans that
* corrupt some files on the server.
*
* You can modify this code as you need, to add a new trojan fix
* simply add a method that takes in input a filepath and return
* the appropriate exit status (see FixExitStatus class for details), and add the
* trojan name and the method name to the fixList[] array for the callback.
* See fix336988InjectionAndVariants() for an example.
*
* Currently supported fix:
* - 336988 Injection Trojan and variants [336988, 68c8c7, 8f4d8e, a59dc4] - @see fix336988InjectionAndVariants(),
* thanks to fatsouls32 for 336988 regex fix - http://www.freestuff.gr/forums/viewtopic.php?t=64419 and to Brett and Paul for the variants
*
* @author Franco D'Agostino franco.dgstn@gmail.com
*
*/
class SimpleFixScanner {
var $fileTypeToScan = array('php','html','htm','tpl', 'htaccess'); // Extensions of the files to scan
var $memoryLimit = "200M"; // Php memory limit, adjust if needed
var $maxExecutionTime = "300"; // Php max execution time, adjust if needed
var $docRoot = null; // Initial directory where start the scan process (null = server root; otherwise insert a custom path)
var $fixList = array( // Array for fix method callback ('Trojan name' => 'fixFunction')
'Injection Trojan 336988 or variant' => 'fix336988InjectionAndVariants',
//'Scanner Regex Check'=>'devCheckRegex', //Use to check wich files are scannd
);
// Don't modify
var $startTime;
var $filesToScan;
var $filesScannedCount = 0;
var $filesFixed = array();
/*
* Start Fix Functions
* Add your custom fix function here and then update the $fixList array.
* ========================================================================
*/
/**
* Check if the regex works.
* @param unknown $path
*/
function devCheckRegex($path) {
if(is_file($path))
return true;
else
return false;
}
/**
* Check and fix files for some code injection trojan:
* - 336988
* - 68c8c7 thanks to Brett
* - 8f4d8e thanks to Paul
* - a59dc4 thanks to Paul
*
* @param unknown $path
* @return FILE_FIXED if trojan foud and fixed; otherwise FILE_OK;
*/
function fix336988InjectionAndVariants( $path ) {
$fileFixed = false;
$regexPaterns = array(
'/#336988#(.*?)#\/336988#/ism', '/\<!--336988-->(.*?)\<!--\/336988-->/ism', '#(/\*336988\*/).*?(/\*/336988\*/)#ism', //Trojan 336988 (php, html and js versions)
'/#68c8c7#(.*?)#\/68c8c7#/ism', '/\<!--68c8c7-->(.*?)\<!--\/68c8c7-->/ism', '#(/\*68c8c7\*/).*?(/\*/68c8c7\*/)#ism', //Trojan 68c8c7 (php, html and js versions)
'/#8f4d8e#(.*?)#\/8f4d8e#/ism', '/\<!--8f4d8e-->(.*?)\<!--\/8f4d8e-->/ism', '#(/\*8f4d8e\*/).*?(/\*/8f4d8e\*/)#ism', //Trojan 8f4d8e (php, html and js versions)
'/#a59dc4#(.*?)#\/a59dc4#/ism', '/\<!--a59dc4-->(.*?)\<!--\/a59dc4-->/ism', '#(/\*a59dc4\*/).*?(/\*/a59dc4\*/)#ism', //Trojan a59dc4 (php, html and js versions)
'@(/\*aef9d\*/).*?(/\*aef9d\*/)@ism' //Trojan aef9d (js versions)
);
$data = file_get_contents($path);
foreach ($regexPaterns as $regex) {
if (preg_match($regex,$data)){
// If foud, replace malicious code with empty string
$data = preg_replace($regex,"",$data);
$fileFixed = FixExitStatus::FILE_FIXED;
}
}
if ($fileFixed != FixExitStatus::FILE_OK)
file_put_contents( $path, $data);
return $fileFixed;
}
/*
* End Fix Functions
* ========================================================================
*/
/**
* Wrapper for the scan process
* @see $this->doScan()
*/
function scan(){
echo "<h3>Simple Fix Scanner</h3>";
echo "<hr />";
echo "<p>Prepare the scanner... ";
$this->prepareScanner();
echo "<i>done</i>";
echo "<br><small>(Directory: " . $this->docRoot . ")</small></p>";
// Do the scann process
echo "<p>Do scan... ";
$this->doScan();
echo "<i>done</i></p>";
// Echo scan results
$fileFixedCount = count($this->filesFixed);
if ( $fileFixedCount > 0 ){
echo "<h4>Matches:</h4>";
echo "<p>Fixed " . $fileFixedCount . " of " . $this->filesScannedCount . " files scanned</p>";
echo "<ul>";
foreach($this->filesFixed as $item) {
$exitStatus = FixExitStatus::translateExitStatus($item['exitStatus']);
echo sprintf("<li>{$exitStatus} - <strong>{$item['fix']}</strong> was found in file {$item['file']}</li>"); ;
}
echo "</ul>";
} else {
echo "<h4>No match found.</h4>";
echo "<p>{$this->filesScannedCount} file scanned.</p>";
}
$endtime = microtime(true);
$totaltime = ($endtime - $this->startTime);
echo "<p><small>Time elpased: ".$totaltime." seconds</small></p>";
}
/**
* Prepare the scanner
*/
function prepareScanner(){
ini_set('memory_limit', $this->memoryLimit);
ini_set('max_execution_time', $this->maxExecutionTime);
$this->startTime = microtime(true);
if (!$this->docRoot)
$this->docRoot = $_SERVER['DOCUMENT_ROOT'];
$this->filesToScan = $this->getFilesToScan($this->docRoot);
}
/**
* Execute the scan process
*/
function doScan() {
foreach ($this->filesToScan as $search) {
$this->filesScannedCount++;
foreach ($this->fixList as $name => $method){
$chekFile = call_user_func( array($this, $method), $search[0] );
if ( $chekFile != FixExitStatus::FILE_OK )
$this->filesFixed[] = array('fix' => $name, 'file' => $search[0], 'exitStatus' => $chekFile);
}
}
}
/**
* Helper to get the list of files to scan
* @param unknown $rootDir Root directory to scan
* @return RegexIterator
*/
function getFilesToScan($rootDir){
$directoryIterator = new RecursiveDirectoryIterator($rootDir);
$iterator = new RecursiveIteratorIterator($directoryIterator);
$regex ='/^.+\.(' .implode("|", $this->fileTypeToScan ) . ')$/i';
$files = new RegexIterator($iterator, $regex, RecursiveRegexIterator::GET_MATCH);
return $files;
}
}
final class FixExitStatus {
private function __constructor() {}
// fix exit status
const FILE_OK = 0;
const FILE_FIXED = 1;
const CANT_FIX = 2;
public static function translateExitStatus($status) {
switch ($status) {
case FixExitStatus::FILE_OK:
return "File is safe";
break;
case FixExitStatus::FILE_FIXED:
return "File fixed";
break;
case FixExitStatus::CANT_FIX:
return "Can't fix file";
break;
}
}
}
?>