From dea08acd2e48fd3a59d8ed6ab34164b4b07c715f Mon Sep 17 00:00:00 2001 From: nichogenius Date: Sat, 19 Aug 2017 17:46:09 -0600 Subject: [PATCH] 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. --- scan.php | 129 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 78 insertions(+), 51 deletions(-) diff --git a/scan.php b/scan.php index acbb5bc..eefe45c 100644 --- a/scan.php +++ b/scan.php @@ -27,7 +27,9 @@ class MalwareScanner private $dir = ''; private $extension = '.php'; + private $flagBase64 = false; private $flagChecksum = false; + private $flagComments = false; private $flagHideOk = false; private $flagHideWhitelist = false; private $flagTime = false; @@ -42,9 +44,11 @@ class MalwareScanner ); private $followSymlink = false; - private $patterns_raw = array(); - private $patterns_iraw = array(); - private $patterns_re = array(); + private $patterns_raw = array(); + private $patterns_iraw = array(); + private $patterns_re = array(); + private $patterns_b64functions = array(); + private $patterns_b64keywords = array(); public function __construct() { @@ -77,9 +81,17 @@ class MalwareScanner private function initializePatterns() { - $this->patterns_raw = $this->loadPatterns(dirname(__FILE__) . '/patterns_raw.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_raw = $this->loadPatterns(dirname(__FILE__) . '/patterns_raw.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) { array_push($this->patterns_raw, "googleBot", "htaccess"); } @@ -103,6 +115,7 @@ class MalwareScanner private function loadPatterns($file) { + $last_comment = ''; $list = array(); if (is_readable($file)) { 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. if ($pattern[0] === '#') { + $last_comment = $pattern; continue; } - $list[] = trim($pattern); + $list[trim($pattern)] = trim($last_comment); } } return $list; @@ -134,7 +148,7 @@ class MalwareScanner 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 if (isset($options['help']) || isset($options['h'])) { @@ -159,9 +173,15 @@ class MalwareScanner } //Simple Flag Options + if (isset($options['base64']) || isset($options['b'])){ + $this->flagBase64 = true; + } if (isset($options['checksum']) || isset($options['c'])){ $this->flagChecksum = true; } + if (isset($options['comment']) || isset($options['a'])){ + $this->flagComments = true; + } if (isset($options['extra-check']) || isset($options['x'])) { $this->extraCheck = true; } @@ -211,7 +231,7 @@ class MalwareScanner return (bool)preg_match($expr, $path); } - private function printPath($found, $path, $pattern, $hash) + private function printPath(&$found, &$path, &$pattern, &$comment, &$hash) { $output_string = '# '; @@ -256,6 +276,9 @@ class MalwareScanner if ($found) { $opatt = "# $pattern"; $output_string = $output_string . $state_color . $opatt . $this->ANSI_OFF; + if ($this->flagComments) { + $output_string = $output_string . ' ' . $comment; + } } $output_string = $output_string . PHP_EOL; @@ -331,52 +354,20 @@ class MalwareScanner $found = false; $hash = ''; $toSearch = ''; - - 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; - } - } - } - } + $comment = ''; - if (!$found || $this->verbose) { - foreach ($this->patterns_re as $toSearch) { - if (preg_match('/' . $toSearch . '/im', $fileContent)) { - $found = true; - if ($hash === ''){ - $hash = md5($fileContent); - } - $this->printPath($found, $path, $toSearch, $hash); - if (!$this->verbose){ - break; - } - } - } + if (!$this->flagBase64) { + $this->scanLoop('scanFunc_STR', $fileContent, $this->patterns_raw, $path, $found, $hash); + $this->scanLoop('scanFunc_STRI', $fileContent, $this->patterns_iraw, $path, $found, $hash); + $this->scanLoop('scanFunc_RE', $fileContent, $this->patterns_re, $path, $found, $hash); + } + if ($this->flagBase64) { + $this->scanLoop('scanFunc_STR', $fileContent, $this->patterns_b64functions, $path, $found, $hash); + $this->scanLoop('scanFunc_STR', $fileContent, $this->patterns_b64keywords, $path, $found, $hash); } if (!$found) { - $this->printPath($found, $path, $toSearch, $hash); + $this->printPath($found, $path, $toSearch, $comment, $hash); return false; } @@ -388,6 +379,40 @@ class MalwareScanner 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() { echo 'Usage: scan.php -d ' . PHP_EOL; @@ -395,7 +420,9 @@ class MalwareScanner echo ' -d --directory Directory for searching' . PHP_EOL; echo ' -e --extension File Extension to Scan' . PHP_EOL; echo ' -i --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 ' -a --comment Display comments for matched patterns' . 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 ' -k --hide-ok Hide OK aka not infected messages' . PHP_EOL;