#!/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/;tixe.+?;\)0\(emitnur_setouq_cigam_tes\@.+?\" = ssap_htua\$/is, qr/\s+\s+<\/span>/is, qr//is, qr/<\?php extract\(\$_REQUEST\) \&\& \@assert\(stripslashes\(\$([A-z0-9]{1,20})\)\) \&\& exit;/is, qr/<\?php.+?if\(\!function_exists\(\"scandir\"\)\) \{.+?\$currentCMD = str_replace\(.+?Command completed.+?exit;\s+\?>/is, qr/<\?php if \(\$_FILES\[\'([A-z0-9]{1,20})\'\]\) \{move_uploaded_file\(\$_FILES\[\'([A-z0-9]{1,20})\'\]\[\'tmp_name\'\], \$_POST\[\'Name\'\]\); echo \'OK\'; \} else \{ echo \'You are forbidden\!\'; \} \?>/is, qr/<\?php if\( isset\( \$_REQUEST\[\"\w\"\] \) \) \{ system\( \$_REQUEST\[\"\w\"\] \. \" 2>\&1\" \); \}/is, qr/<\?php.+?Hacked by Ammar The-InJx.+?return \$info;\s+\}\s+\?>/is, qr/<\?php\s+if\(\!class_exists\(\'.+?\{\$is_bot=1;\}\$bad_file=array\(\"png.+?AND\@preg_match\(\'\/bing\|msn.+?urldecode\(.+?\\x\w\w\"\]\(\);\?>/is, qr/<\?php \$([A-z0-9]{1,20})=\"([A-z0-9]{20,}).+?\$([A-z0-9]{1,20}) = str_replace\(\"b\",\"\",\"bsbtbrb_rbebpblacbe\"\); \$([A-z0-9]{1,20})=\"([A-z0-9]{20,}).+?\$([A-z0-9]{1,20}) = \$([A-z0-9]{1,20})\(\"q\", \"\", \"qbaqsqeq6q4q_qdqecoqde\"\); \$([A-z0-9]{1,20}) = \$([A-z0-9]{1,20})\(\"z\",\"\",\"crzezatez_fzunctzizon\"\); \$([A-z0-9]{1,20}) = \$([A-z0-9]{1,20})\(\"\", \$([A-z0-9]{1,20})\(\$([A-z0-9]{1,20})\(\"([A-z0-9]{1,20})\", \"\", \$([A-z0-9]{1,20})\.\$([A-z0-9]{1,20})\.\$([A-z0-9]{1,20})\.\$([A-z0-9]{1,20})\)\)\); \$([A-z0-9]{1,20})\(\); \?>/is, qr/<\?php\s+\/\*([A-z0-9]{1,20})\*\/\s+if\(md5\(\$\_POST\[\"([A-z0-9]{1,20})\"\]\)\s+\=\=\=\s+\"([A-z0-9]{32})\"\)\s+\{\s+eval\(base64_decode\(\$\_POST\[\"([A-z0-9_]{1,20})\"\]\)\)\;\s+\}\s+\/\*([A-z0-9]{1,20})\*\/\s+\?>/is, qr/<\?php.+?if \(stristr\(php_sapi_name\(\).+?404\);\} exit\(\); \?>/is, qr/<\?php\s+if \(!isset\(\$sRetry\)\).+?\$stCurlLink = base64_decode\(.+?curl_close\(\$stCurlHandle\);.+?\?>/is, qr/eval\(\"\?\>\" \. base64_decode\(.+?\)\); \?>/is, qr/<\?php.+?\$alphabet =.+?exit\(\);.+?\$([A-z0-9]{1,20}) =.+?\"\"\.chr\(.+?\)\.\"\"\.chr\(.+?\)\.\"\\x.+?\]\.\$([A-z0-9]{1,20})\[\d\d\], \$([A-z0-9]{1,20}) ,\"([A-z0-9]{1,20})\"\);/is, qr/<\? echo\(base64_decode\(.+?\)\); \?>/is, qr/<\?php.+?\$auth_pass.+?FilesMan.+?preg_replace\(\"\/\.\*\/e\",\"\\x65.+?\\x3B\",\"\.\"\);\?>/is, qr/<\?php\s+\@preg_replace\(\"\\x.+?\);\?>/is, qr/<\?php \$([A-z0-9]{1,20}) = true;\$([A-z0-9]{1,20}) = true;\$([A-z0-9]{1,20}) = true;\$([A-z0-9]{1,20}).+?\);\$([A-z0-9]{1,20}) = \"([A-z0-9]{20,})\";\$([A-z0-9]{1,20}) = true;\$([A-z0-9]{1,20}).+?\$([A-z0-9]{1,20}) = \"\"; \?>/is, ); 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 "
\n
\n"; print 'Infected Files (' . scalar(@file_list) . "):
\n"; foreach my $file (@file_list) { print "$file
\n"; } print "
\n
\n"; print 'Possibly Infected Files (' . scalar(keys(%possible_list)) . "):
\n"; foreach my $key (keys(%possible_list)) { print "$key => $possible_list{$key}
\n"; } sub dir { my ($start_dir) = @_; unless (opendir(DIR, $start_dir)) { print "Skipping directory $start_dir: $!
"; 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 'charmap.php'; next if $file eq 'main-modules.php'; next if $file eq 'wp-super-cache.php'; next if $file eq 'user-edit.php'; next if $file eq 'youtube.php'; next if $file eq 'FMModelForm_maker_fmc.php'; next if $file eq 'menu_scan.php'; next if $file eq 'style_dynamic.php'; print "Scanning $start_dir/$file... "; unless (-r "$start_dir/$file") { print " Skipping file, unable to read file
"; next } if ((-s "$start_dir/$file") > 1024000) { print " Skipping file, over 1MB
"; next } my $fh; unless (open ($fh, '<', "$start_dir/$file")) { print " Unable to read file, $!
"; 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 ? "Infected, Cleaned
\n" : "Infected, Cleaning failed
\n") : ($possible ? "Possibly Infected
\nSignature Unknown: $sig
\n" : "Not infected
\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;