LP-MSH-Scanner/malware4.pl

184 lines
7.9 KiB
Perl
Raw Normal View History

2017-01-02 09:13:21 +01:00
#!/usr/bin/perl
use strict;
use warnings;
use CGI;
BEGIN {
$SIG{__DIE__} = sub {
my $msg = shift;
print "status: 500\n";
print "content-type: text/html\n\n";
$msg =~ s/\n/\0/g;
print "error: $msg\n";
CORE::die $msg;
}
}
$| = 1;
our $q = CGI->new;
print "Content-type: text/html\n\n";
my @regexen = (
qr/<\?php\s+function\s+([A-z0-9]{1,10})\(\$([A-z0-9]{1,10})\,\s+\$([A-z0-9]{1,10})\)\{\$([A-z0-9]{1,10})\s+\=\s+\'\'\;\s+for\(\$([A-z]{1,2})\=0\;\s+\$([A-z]{1,2})\s+\<\s+strlen\(\$([A-z0-9]{1,10})\)\;\s+\$([A-z]{1,2})\+\+\)\{\$([A-z0-9]{1,10})\s+\.\=\s+isset\(\$([A-z0-9]{1,10})\[\$([A-z0-9]{1,10})\[\$([A-z]{1,2})\]\]\)\s+\?\s+\$([A-z0-9]{1,10})\[\$([A-z0-9]{1,10})\[\$([A-z]{1,2})\]\]\s+\:\s+\$([A-z0-9]{1,10})\[\$([A-z]{1,2})\]\;\}\s+\$([A-z0-9]{1,10})\=\"base64\_decode\"\;return\s+\$([A-z0-9]{1,10})\(\$([A-z0-9]{1,10})\)\;\}.+?\$([A-z]{1,2})\s+\=\s+\Array\(.+?eval\(([A-z0-9]{1,10})\(\$([A-z]{1,2})\,\s+\$([A-z]{1,2})\)\)\;\?>/is,
qr/<\?php\s+\$([A-z0-9]{1,10})\=\'aWYoaXNzZXQoJF9SRVFVRVNUWydjb2NvJ10pICYmICRfUkVRVUVTVFsnY29jbyddIT0nJyl7ZXZhbCgkX1JFUVVFU1RbJ2NvY28nXSk7ZXhpdCgpO30\=\'\;eval\(base64\_decode\(\$([A-z0-9]{1,10})\)\)\;exit\(\)\;\s+\?>/is,
2017-01-02 09:27:31 +01:00
qr/<\?php\s+chmod\(get\_root\_path\(\)\,\s+0755\)\;.+?function\s+get\_root\_path\(\).+?die\(\$reason\)\;\s+\}/is,
qr/<html>\s+<title>1962Cracker\s+\|\s+cPanel\s+Cracker\s+\&\s+Root\s+Server\.\.\.\|<\/title>.+?<\?php\s+eval\(base64\_decode\(.+?<\/Script>/is,
qr/<\?php.+?\$wp\_file\_descriptions\s+\=\s+array\(.+?\$wp\_template\s+\=\s+\@preg\_replace\(\"\/\(\[a\-z0\-9\-\%\]\+\)\.\(\[a\-z\-\@\]\+\)\.\(\[a\-z\]\+\)\/.+?\$2\(\$3\(urldecode\(\'\$1\'\)\)\)\"\,\s+\$search\.\"\.\@\"\.\$wp\_file\_descriptions\[\'rtl\.css\'\]\)\;\s+\?>/is,
qr/<\?php\s+if\s+\(isset\(\$\_REQUEST\[\"q\"\]\)\s+AND\s+\$\_REQUEST\[\"q\"\]\=\=\"1\"\)\{echo\s+\"200\"\;\s+exit\;\}\s+if\(isset\(\$\_POST\[\"key\"\]\)\s+\&\&\s+isset\(\$\_POST\[\"chk\"\]\)\s+\&\&\s+\$\_POST\[\"key\"\]\=\=\".+?\"\)eval\(gzuncompress\(base64\_decode\(\$\_POST\[\"chk\"\]\)\)\)\;\s+\?>/is,
qr/<\?php\s+if\s+\(\!defined\(\'ALREADY\_RUN\_.+?define\(\'ALREADY\_RUN\_.+?eval\/\*i\*\/\(([A-z0-9]{1,20})\(\$([A-z0-9]{1,10})\,\s+\$([A-z0-9]{1,10})\)\)\;\s+\}/is,
qr/<\?php\s+eval\(gzuncompress\(.+?\"\)\)\;/is,
qr/<\?php.+?class\s+JApplication.+?new\s+JApplication\(array\s+\(\'UID\'\s+\=>\s+\'([A-z0-9]{1,20})\'\)\)\;/is,
2017-01-06 13:21:08 +01:00
qr/<\?php\s+\/\*\s+\@package\s+WordPress\s+\*\/\s+eval\(base64\_decode\(\@\$\_POST\[\"([A-z0-9]{1,20})\"\]\)\)\;\?>/is,
2017-01-08 13:26:29 +01:00
qr/<\?php\s+\if\s+\(\!defined\(\'ALREADY\_RUN\_.+?\)\)\;\s+\}/is,
2017-01-13 21:22:54 +01:00
qr/<\?php\s+\$dom\s+\=\s+array\(.+?\$url\s+\=\s+\'http\:\/\/\'\.\$dom\[mt\_rand\(0\,sizeof\(\$dom\)\-1\)\]\.\'\/file\.php\'\;.+?header\(\'Location\:\s+\'\.\$url\)\;\s+\}\s+exit\;\s+\?>/is,
qr/<\?php\s+if\s+\(isset\(\$\_GET\[\"id\"\]\)\)\s+header\(.+?\.\$\_GET\[\"id\"\]\)\;\s+\?>/is,
2017-01-14 14:21:48 +01:00
qr/<\?php\s+eval\(base64\_decode\(.+?\)\)\;/is,
qr/<\?php\s+\$GLOBALS\[\'([A-z0-9]{1,20})\'\]\s+\=\s+\$\_SERVER\;\s+function\s+([A-z0-9]{1,20})\(\$([A-z0-9]{1,20})\).+?functions+([A-z0-9]{1,20})\(\$([A-z0-9]{1,20})\)\{return\s+([A-z0-9]{1,20})\(\$([A-z0-9]{1,20})\)\;\}\;.+?\}\(\$url\,\s+FALSE\,\s+\$\{([A-z0-9]{1,20})\(.+?return\s+\$\{.+?\)\}\;\s+\}/is,
qr/<\?php\s+eval\(base64\_decode\(.+?include.+?x70hp\"\;.+?include.+?x70hp\"\;/is,
qr/<\?php\s+\$([A-z0-9]{1,20})\=chr\(([0-9]{1,4})\).+?chr\(([0-9]{1,4})\).+?chr\(([0-9]{1,4})\).+?chr\(([0-9]{1,4})\).+?chr\(([0-9]{1,4})\).+?\)\;\s+\?>/is,
2017-01-15 13:14:54 +01:00
qr/\*\/\s+eval\(base64\_decode\(\"aWY.+?\=\"\)\)\;\s+\/\*/is,
qr/\*\/include\s+\/\*/is,
qr/\*\/\".+?\.co.+?php\"\;\/\*/is,
2017-01-15 13:22:45 +01:00
qr/<\?\s+\$([A-z0-9]{1,3})\[1\]\=\"([A-z0-9]{1,20})\.html\"\;\$([A-z0-9]{1,3})\[1\]\=.+?file\_put\_contents\(\$fileaddr\,gzuncompress\(base64\_decode\(\$([A-z0-9]{1,3})\[\$([A-z0-9]{1,3})\]\)\)\)\;\}\s+unlink\(\$scr\.\"\.php\"\)\;\s+\?>/is,
2017-01-18 21:23:45 +01:00
qr/<\?php\s+\$GLOBALS\[\'([A-z0-9]{1,20})\'\]\s+\=\s+\$\_SERVER\;\s+function\s+([A-z0-9]{1,20})\(\$([A-z0-9]{1,20})\).+?exit\(\$\{([A-z0-9]{1,20})\(\"lie\=\=\?\"\)\}\)\;\s+\}/is,
2017-01-19 21:30:18 +01:00
qr/eval\(base64\_decode\(\"aWY.+?include.+?eval\(base64\_decode\(\"aWY.+?include.+?ephp\"\;/is,
qr/<\?php\s+\/\*\s+ionCube24\s+encoder\s+\*\/\s+global.+?eval\(base64\_decode\(.+?\_\_halt\_compiler\(\)\;([A-z0-9]{250,})/is,
2017-01-20 10:43:33 +01:00
qr/<\?\s+eval\(gzuncompress\(base64\_decode\(.+?\)\)\)\;\s+\?>/is,
2017-01-18 21:31:26 +01:00
2017-01-18 21:23:45 +01:00
);
2017-01-02 09:13:21 +01:00
my @base64_decodes = (
);
my @file_list;
my %possible_list;
my $start_dir = $ENV{'SCRIPT_FILENAME'} || '../';
$start_dir =~ s/\/cgi-bin//;
$start_dir =~ s/\/lp-msh-scanner//;
$start_dir = substr($start_dir, 0, rindex($start_dir, '/'));
dir ($start_dir);
print "<br />\n<br />\n";
print 'Infected Files (' . scalar(@file_list) . "):<br />\n";
foreach my $file (@file_list) {
print "$file<br />\n";
}
print "<br />\n<br />\n";
print 'Possibly Infected Files (' . scalar(keys(%possible_list)) . "):<br />\n";
foreach my $key (keys(%possible_list)) {
print "$key => $possible_list{$key}<br />\n";
}
sub dir {
my ($start_dir) = @_;
unless (opendir(DIR, $start_dir)) {
print "Skipping directory $start_dir: $! <br />";
return;
}
opendir(DIR, $start_dir) || die "$start_dir: $!";
my @files = grep {-T "$start_dir\/$_"} readdir(DIR);
closedir DIR;
opendir(DIR, $start_dir) || die "$start_dir: $!";
my @folders = grep {-d "$start_dir\/$_"} readdir(DIR);
closedir DIR;
foreach my $file (sort @files) {
next if $file eq 'error_log';
next if $file eq 'tcpdf.php';
next if $file eq '*.xls';
next if $file eq '*.doc';
next if $file eq '*.pdf';
next if $file eq '*.sql';
next if $file eq '*.docx';
next if $file eq '*.eml';
next if $file eq '*.csv';
next if $file eq '*.zip';
next if $file eq '*.tar.gz';
next if $file eq '*.jpa';
next if $file eq '*.rar';
next if $file eq '*.tar';
next if $file eq '*.gz';
next if $file eq '*.mov';
next if $file eq '*.avi';
next if $file eq '*.mp3';
next if $file eq '*.mp4';
next if $file eq '*.webm';
next if $file eq '*.flv';
next if $file eq '*.fla';
next if $file eq '*.swf';
next if $file eq '*.ini';
next if $file eq '*.txt';
next if $file eq '*.po';
next if $file eq '*.mo';
print "Scanning $start_dir/$file... ";
unless (-r "$start_dir/$file") {
print " Skipping file, unable to read file<br />";
next
}
if ((-s "$start_dir/$file") > 1024000) {
print " Skipping file, over 1MB<br />";
next
}
my $fh;
unless (open ($fh, '<', "$start_dir/$file")) {
print " Unable to read file, $!<br />";
next
}
my $contents = do { local $/; <$fh> };
close $fh;
my ($infected, $cleaned, $possible, $known, $sig);
foreach my $pattern (@regexen) {
my $t;
if ($contents =~ /$pattern/) {
my ($d, $t) = ($1, $2);
$infected = 1;
($contents, $cleaned) = clean_file("$start_dir/$file", $contents, $pattern);
push (@file_list, "$start_dir/$file");
}
$t = undef;
}
print $infected ? ($cleaned ? "<font color='green'>Infected, Cleaned<br /></font>\n" : "Infected, Cleaning failed<br />\n") : ($possible ? "Possibly Infected<br />\nSignature Unknown: $sig<br />\n" : "Not infected<br />\n");
}
foreach my $folder (sort @folders) {
if ($folder !~ /^\.\.?$/) {
dir("$start_dir/$folder");
}
}
}
sub clean_file {
my ($file, $contents, $pattern) = @_;
my $cleaned;
if ($contents =~ /\n{4}/) {
$contents =~ s/\n\n/\n/g;
}
$contents =~ s/$pattern//g;
if ($contents =~ /$pattern/) {
$cleaned = 0;
}
else {
open (my $fh, '>', $file);
print $fh $contents;
close $fh;
$cleaned = 1;
}
return ($contents, $cleaned);
}
1;