large 'scan' function broken up comment flag added

scan function has been broken up into a multiple functions which should make it more modular if future scan types are needed.
--comment, -a flag was added which prints the first comment to appear prior to the matched pattern in the pattern file.
This commit is contained in:
nichogenius
2017-08-19 17:46:09 -06:00
committed by GitHub
parent ea2da42f8e
commit dea08acd2e

129
scan.php
View File

@@ -27,7 +27,9 @@ class MalwareScanner
private $dir = ''; private $dir = '';
private $extension = '.php'; private $extension = '.php';
private $flagBase64 = false;
private $flagChecksum = false; private $flagChecksum = false;
private $flagComments = false;
private $flagHideOk = false; private $flagHideOk = false;
private $flagHideWhitelist = false; private $flagHideWhitelist = false;
private $flagTime = false; private $flagTime = false;
@@ -42,9 +44,11 @@ class MalwareScanner
); );
private $followSymlink = false; private $followSymlink = false;
private $patterns_raw = array(); private $patterns_raw = array();
private $patterns_iraw = array(); private $patterns_iraw = array();
private $patterns_re = array(); private $patterns_re = array();
private $patterns_b64functions = array();
private $patterns_b64keywords = array();
public function __construct() public function __construct()
{ {
@@ -77,9 +81,17 @@ class MalwareScanner
private function initializePatterns() private function initializePatterns()
{ {
$this->patterns_raw = $this->loadPatterns(dirname(__FILE__) . '/patterns_raw.txt'); if (!$this->flagBase64) {
$this->patterns_iraw = $this->loadPatterns(dirname(__FILE__) . '/patterns_iraw.txt'); $this->patterns_raw = $this->loadPatterns(dirname(__FILE__) . '/patterns_raw.txt');
$this->patterns_re = $this->loadPatterns(dirname(__FILE__) . '/patterns_re.txt'); $this->patterns_iraw = $this->loadPatterns(dirname(__FILE__) . '/patterns_iraw.txt');
$this->patterns_re = $this->loadPatterns(dirname(__FILE__) . '/patterns_re.txt');
}
if ($this->flagBase64) {
$this->patterns_b64functions = $this->loadPatterns(dirname(__FILE__). '/php_functions.txt');
$this->patterns_b64keywrds = $this->loadPatterns(dirname(__FILE__). '/php_keywords.txt');
}
if ($this->extraCheck) { if ($this->extraCheck) {
array_push($this->patterns_raw, "googleBot", "htaccess"); array_push($this->patterns_raw, "googleBot", "htaccess");
} }
@@ -103,6 +115,7 @@ class MalwareScanner
private function loadPatterns($file) private function loadPatterns($file)
{ {
$last_comment = '';
$list = array(); $list = array();
if (is_readable($file)) { if (is_readable($file)) {
foreach (file($file) as $pattern) { foreach (file($file) as $pattern) {
@@ -112,9 +125,10 @@ class MalwareScanner
} }
//Check if first char in pattern is a '#' which indicates a comment and skips. //Check if first char in pattern is a '#' which indicates a comment and skips.
if ($pattern[0] === '#') { if ($pattern[0] === '#') {
$last_comment = $pattern;
continue; continue;
} }
$list[] = trim($pattern); $list[trim($pattern)] = trim($last_comment);
} }
} }
return $list; return $list;
@@ -134,7 +148,7 @@ class MalwareScanner
private function parseArgs() private function parseArgs()
{ {
$options = getopt('d:e:i:cxlhkwntv', array('directory:', 'extension:', 'ignore:', 'checksum', 'extra-check', 'follow-link', 'help', 'hide-ok', 'hide-whitelist', 'no-color', 'time', 'verbose')); $options = getopt('d:e:i:bacxlhkwntv', array('directory:', 'extension:', 'ignore:', 'base', 'checksum', 'comment', 'extra-check', 'follow-link', 'help', 'hide-ok', 'hide-whitelist', 'no-color', 'time', 'verbose'));
//Help Option should be first //Help Option should be first
if (isset($options['help']) || isset($options['h'])) { if (isset($options['help']) || isset($options['h'])) {
@@ -159,9 +173,15 @@ class MalwareScanner
} }
//Simple Flag Options //Simple Flag Options
if (isset($options['base64']) || isset($options['b'])){
$this->flagBase64 = true;
}
if (isset($options['checksum']) || isset($options['c'])){ if (isset($options['checksum']) || isset($options['c'])){
$this->flagChecksum = true; $this->flagChecksum = true;
} }
if (isset($options['comment']) || isset($options['a'])){
$this->flagComments = true;
}
if (isset($options['extra-check']) || isset($options['x'])) { if (isset($options['extra-check']) || isset($options['x'])) {
$this->extraCheck = true; $this->extraCheck = true;
} }
@@ -211,7 +231,7 @@ class MalwareScanner
return (bool)preg_match($expr, $path); return (bool)preg_match($expr, $path);
} }
private function printPath($found, $path, $pattern, $hash) private function printPath(&$found, &$path, &$pattern, &$comment, &$hash)
{ {
$output_string = '# '; $output_string = '# ';
@@ -256,6 +276,9 @@ class MalwareScanner
if ($found) { if ($found) {
$opatt = "# $pattern"; $opatt = "# $pattern";
$output_string = $output_string . $state_color . $opatt . $this->ANSI_OFF; $output_string = $output_string . $state_color . $opatt . $this->ANSI_OFF;
if ($this->flagComments) {
$output_string = $output_string . ' ' . $comment;
}
} }
$output_string = $output_string . PHP_EOL; $output_string = $output_string . PHP_EOL;
@@ -331,52 +354,20 @@ class MalwareScanner
$found = false; $found = false;
$hash = ''; $hash = '';
$toSearch = ''; $toSearch = '';
$comment = '';
foreach ($this->patterns_raw as $toSearch) {
if (strpos($fileContent, $toSearch) !== FALSE){
$found = true;
if ($hash === ''){
$hash = md5($fileContent);
}
$this->printPath($found, $path, $toSearch, $hash);
if (!$this->verbose){
break;
}
}
}
if (!$found || $this->verbose) {
foreach ($this->patterns_iraw as $toSearch) {
if (stripos($fileContent, $toSearch) !== FALSE){
$found = true;
if ($hash === ''){
$hash = md5($fileContent);
}
$this->printPath($found, $path, $toSearch, $hash);
if (!$this->verbose){
break;
}
}
}
}
if (!$found || $this->verbose) { if (!$this->flagBase64) {
foreach ($this->patterns_re as $toSearch) { $this->scanLoop('scanFunc_STR', $fileContent, $this->patterns_raw, $path, $found, $hash);
if (preg_match('/' . $toSearch . '/im', $fileContent)) { $this->scanLoop('scanFunc_STRI', $fileContent, $this->patterns_iraw, $path, $found, $hash);
$found = true; $this->scanLoop('scanFunc_RE', $fileContent, $this->patterns_re, $path, $found, $hash);
if ($hash === ''){ }
$hash = md5($fileContent); if ($this->flagBase64) {
} $this->scanLoop('scanFunc_STR', $fileContent, $this->patterns_b64functions, $path, $found, $hash);
$this->printPath($found, $path, $toSearch, $hash); $this->scanLoop('scanFunc_STR', $fileContent, $this->patterns_b64keywords, $path, $found, $hash);
if (!$this->verbose){
break;
}
}
}
} }
if (!$found) { if (!$found) {
$this->printPath($found, $path, $toSearch, $hash); $this->printPath($found, $path, $toSearch, $comment, $hash);
return false; return false;
} }
@@ -388,6 +379,40 @@ class MalwareScanner
return true; return true;
} }
private function scanFunc_STR(&$pattern, &$content)
{
return (strpos($content, $pattern) !== false);
}
private function scanFunc_STRI(&$pattern, &$content)
{
return (stripos($content, $pattern) !== false);
}
private function scanFunc_RE(&$pattern, &$content)
{
return preg_match('/' . $pattern . '/im', $content);
}
private function scanLoop($scanFunction, &$fileContent, &$patterns, &$path, &$found, &$hash)
{
if (!$found || $this->verbose) {
foreach ($patterns as $pattern => $comment) {
if ($this->$scanFunction($pattern, $fileContent)) {
$found = true;
if ($hash === ''){
$hash = md5($fileContent);
}
$this->printPath($found, $path, $pattern, $comment, $hash);
if (!$this->verbose){
return;
}
}
}
}
}
private function showHelp() private function showHelp()
{ {
echo 'Usage: scan.php -d <directory>' . PHP_EOL; echo 'Usage: scan.php -d <directory>' . PHP_EOL;
@@ -395,7 +420,9 @@ class MalwareScanner
echo ' -d <directory> --directory Directory for searching' . PHP_EOL; echo ' -d <directory> --directory Directory for searching' . PHP_EOL;
echo ' -e <file extension> --extension File Extension to Scan' . PHP_EOL; echo ' -e <file extension> --extension File Extension to Scan' . PHP_EOL;
echo ' -i <directory|file> --ignore Directory of file to igonre' . PHP_EOL; echo ' -i <directory|file> --ignore Directory of file to igonre' . PHP_EOL;
echo ' -b --base64 Scan for base64 encoded PHP keywords' . PHP_EOL;
echo ' -c --checksum Display MD5 Checksum of file' . PHP_EOL; echo ' -c --checksum Display MD5 Checksum of file' . PHP_EOL;
echo ' -a --comment Display comments for matched patterns' . PHP_EOL;
echo ' -x --extra-check Adds GoogleBot and htaccess to Scan List' . PHP_EOL; echo ' -x --extra-check Adds GoogleBot and htaccess to Scan List' . PHP_EOL;
echo ' -l --follow-symlink Follow symlinked directories' . PHP_EOL; echo ' -l --follow-symlink Follow symlinked directories' . PHP_EOL;
echo ' -k --hide-ok Hide OK aka not infected messages' . PHP_EOL; echo ' -k --hide-ok Hide OK aka not infected messages' . PHP_EOL;