diff --git a/.php_cs b/.php_cs index 2f9bb26..aee7ec5 100644 --- a/.php_cs +++ b/.php_cs @@ -1,5 +1,6 @@ setUsingCache(true) ->setRiskyAllowed(true) diff --git a/bin/build b/bin/build index 379d2ce..723b2ab 100644 --- a/bin/build +++ b/bin/build @@ -13,43 +13,30 @@ define('ROOT', dirname(__DIR__)); require ROOT . '/vendor/autoload.php'; -$input = ROOT . '/src/scanner'; -$output = ROOT . '/dist/scanner'; - -$jc = new JuggleCode(); -$jc->masterfile = $input; -$jc->outfile = $output; -$jc->mergeScripts = true; -$jc->run(); - -if(empty($argv[1])) { - $version = "0.4.0"; -} else { - $version = $argv[1]; -} +$input = ROOT . '/src/'; +$output = ROOT . '/dist/scanner.phar'; +$finalOutput = ROOT . '/dist/scanner'; -$date = date("d-m-Y"); -$year = date("Y"); -$comment = << - * @copyright Copyright (c) $year - * @license http://opensource.org/licenses/gpl-3.0.html GNU Public License - * @link https://github.com/marcocesarato/PHP-Antimalware-Scanner - */ +// creating our library using whole directory +$p->buildFromDirectory($input); -EOD; +// pointing main file which requires all classes +$p->setDefaultStub('index.php', '/index.php'); +unset($p); +rename($output, $finalOutput); -$file = php_strip_whitespace($output); -$file = preg_replace('/namespace marcocesarato\\\\amwscan\;\s*/si', '', $file); -$file = preg_replace('/public\s*static\s*\$VERSION\s*=\s*(\"|\\\')0\.5\.0(\"|\\\')\s*\;/si', 'public static $VERSION = "'.$version.'";', $file); -$from = '/'.preg_quote("=5.3.0", - "ext-json": "*", - "ext-curl": "*" + "php": ">=5.4", + "ext-json": "*" }, "require-dev": { "brainmaestro/composer-git-hooks": "^2.8", diff --git a/composer.lock b/composer.lock index 1dfefec..68799fa 100644 --- a/composer.lock +++ b/composer.lock @@ -1,10 +1,10 @@ { "_readme": [ "This file locks the dependencies of your project to a known state", - "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "e21ee8c1a7e730f09082ae9eccc81d25", + "content-hash": "b4ec4b8fd2d495e455e72aebb1801669", "packages": [], "packages-dev": [ { @@ -252,30 +252,28 @@ }, { "name": "doctrine/lexer", - "version": "1.2.0", + "version": "1.0.2", "source": { "type": "git", "url": "https://github.com/doctrine/lexer.git", - "reference": "5242d66dbeb21a30dd8a3e66bf7a73b66e05e1f6" + "reference": "1febd6c3ef84253d7c815bed85fc622ad207a9f8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/lexer/zipball/5242d66dbeb21a30dd8a3e66bf7a73b66e05e1f6", - "reference": "5242d66dbeb21a30dd8a3e66bf7a73b66e05e1f6", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/1febd6c3ef84253d7c815bed85fc622ad207a9f8", + "reference": "1febd6c3ef84253d7c815bed85fc622ad207a9f8", "shasum": "" }, "require": { - "php": "^7.2" + "php": ">=5.3.2" }, "require-dev": { - "doctrine/coding-standard": "^6.0", - "phpstan/phpstan": "^0.11.8", - "phpunit/phpunit": "^8.2" + "phpunit/phpunit": "^4.5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2.x-dev" + "dev-master": "1.0.x-dev" } }, "autoload": { @@ -288,14 +286,14 @@ "MIT" ], "authors": [ - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, { "name": "Roman Borschel", "email": "roman@code-factory.org" }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, { "name": "Johannes Schmitt", "email": "schmittjoh@gmail.com" @@ -310,7 +308,7 @@ "parser", "php" ], - "time": "2019-10-30T14:39:59+00:00" + "time": "2019-06-08T11:03:04+00:00" }, { "name": "friendsofphp/php-cs-fixer", @@ -546,52 +544,6 @@ ], "time": "2017-02-14T16:28:37+00:00" }, - { - "name": "psr/event-dispatcher", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/event-dispatcher.git", - "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", - "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", - "shasum": "" - }, - "require": { - "php": ">=7.2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\EventDispatcher\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" - } - ], - "description": "Standard interfaces for event handling.", - "keywords": [ - "events", - "psr", - "psr-14" - ], - "time": "2019-01-08T18:20:26+00:00" - }, { "name": "psr/log", "version": "1.1.2", @@ -641,41 +593,41 @@ }, { "name": "symfony/console", - "version": "v5.0.1", + "version": "v4.4.1", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "dae5ef273d700771168ab889d9f8a19b2d206656" + "reference": "f0aea3df20d15635b3cb9730ca5eea1c65b7f201" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/dae5ef273d700771168ab889d9f8a19b2d206656", - "reference": "dae5ef273d700771168ab889d9f8a19b2d206656", + "url": "https://api.github.com/repos/symfony/console/zipball/f0aea3df20d15635b3cb9730ca5eea1c65b7f201", + "reference": "f0aea3df20d15635b3cb9730ca5eea1c65b7f201", "shasum": "" }, "require": { - "php": "^7.2.5", + "php": "^7.1.3", "symfony/polyfill-mbstring": "~1.0", "symfony/polyfill-php73": "^1.8", "symfony/service-contracts": "^1.1|^2" }, "conflict": { - "symfony/dependency-injection": "<4.4", - "symfony/event-dispatcher": "<4.4", + "symfony/dependency-injection": "<3.4", + "symfony/event-dispatcher": "<4.3|>=5", "symfony/lock": "<4.4", - "symfony/process": "<4.4" + "symfony/process": "<3.3" }, "provide": { "psr/log-implementation": "1.0" }, "require-dev": { "psr/log": "~1.0", - "symfony/config": "^4.4|^5.0", - "symfony/dependency-injection": "^4.4|^5.0", - "symfony/event-dispatcher": "^4.4|^5.0", + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/event-dispatcher": "^4.3", "symfony/lock": "^4.4|^5.0", - "symfony/process": "^4.4|^5.0", - "symfony/var-dumper": "^4.4|^5.0" + "symfony/process": "^3.4|^4.0|^5.0", + "symfony/var-dumper": "^4.3|^5.0" }, "suggest": { "psr/log": "For using the console logger", @@ -686,7 +638,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "5.0-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -713,41 +665,41 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2019-12-01T10:51:15+00:00" + "time": "2019-12-01T10:06:17+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v5.0.1", + "version": "v4.4.1", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "7b738a51645e10f864cc25c24d232fb03f37b475" + "reference": "b3c3068a72623287550fe20b84a2b01dcba2686f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/7b738a51645e10f864cc25c24d232fb03f37b475", - "reference": "7b738a51645e10f864cc25c24d232fb03f37b475", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/b3c3068a72623287550fe20b84a2b01dcba2686f", + "reference": "b3c3068a72623287550fe20b84a2b01dcba2686f", "shasum": "" }, "require": { - "php": "^7.2.5", - "symfony/event-dispatcher-contracts": "^2" + "php": "^7.1.3", + "symfony/event-dispatcher-contracts": "^1.1" }, "conflict": { - "symfony/dependency-injection": "<4.4" + "symfony/dependency-injection": "<3.4" }, "provide": { "psr/event-dispatcher-implementation": "1.0", - "symfony/event-dispatcher-implementation": "2.0" + "symfony/event-dispatcher-implementation": "1.1" }, "require-dev": { "psr/log": "~1.0", - "symfony/config": "^4.4|^5.0", - "symfony/dependency-injection": "^4.4|^5.0", - "symfony/expression-language": "^4.4|^5.0", - "symfony/http-foundation": "^4.4|^5.0", + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/http-foundation": "^3.4|^4.0|^5.0", "symfony/service-contracts": "^1.1|^2", - "symfony/stopwatch": "^4.4|^5.0" + "symfony/stopwatch": "^3.4|^4.0|^5.0" }, "suggest": { "symfony/dependency-injection": "", @@ -756,7 +708,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "5.0-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -783,33 +735,33 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "time": "2019-11-18T17:27:11+00:00" + "time": "2019-11-28T13:33:56+00:00" }, { "name": "symfony/event-dispatcher-contracts", - "version": "v2.0.1", + "version": "v1.1.7", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher-contracts.git", - "reference": "af23c2584d4577d54661c434446fb8fbed6025dd" + "reference": "c43ab685673fb6c8d84220c77897b1d6cdbe1d18" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/af23c2584d4577d54661c434446fb8fbed6025dd", - "reference": "af23c2584d4577d54661c434446fb8fbed6025dd", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/c43ab685673fb6c8d84220c77897b1d6cdbe1d18", + "reference": "c43ab685673fb6c8d84220c77897b1d6cdbe1d18", "shasum": "" }, "require": { - "php": "^7.2.5", - "psr/event-dispatcher": "^1" + "php": "^7.1.3" }, "suggest": { + "psr/event-dispatcher": "", "symfony/event-dispatcher-implementation": "" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "1.1-dev" } }, "autoload": { @@ -841,30 +793,30 @@ "interoperability", "standards" ], - "time": "2019-11-18T17:27:11+00:00" + "time": "2019-09-17T09:54:03+00:00" }, { "name": "symfony/filesystem", - "version": "v5.0.1", + "version": "v4.4.1", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "1d71f670bc5a07b9ccc97dc44f932177a322d4e6" + "reference": "40c2606131d56eff6f193b6e2ceb92414653b591" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/1d71f670bc5a07b9ccc97dc44f932177a322d4e6", - "reference": "1d71f670bc5a07b9ccc97dc44f932177a322d4e6", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/40c2606131d56eff6f193b6e2ceb92414653b591", + "reference": "40c2606131d56eff6f193b6e2ceb92414653b591", "shasum": "" }, "require": { - "php": "^7.2.5", + "php": "^7.1.3", "symfony/polyfill-ctype": "~1.8" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "5.0-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -891,29 +843,29 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2019-11-26T23:25:11+00:00" + "time": "2019-11-26T23:16:41+00:00" }, { "name": "symfony/finder", - "version": "v5.0.1", + "version": "v4.4.1", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "17874dd8ab9a19422028ad56172fb294287a701b" + "reference": "ce8743441da64c41e2a667b8eb66070444ed911e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/17874dd8ab9a19422028ad56172fb294287a701b", - "reference": "17874dd8ab9a19422028ad56172fb294287a701b", + "url": "https://api.github.com/repos/symfony/finder/zipball/ce8743441da64c41e2a667b8eb66070444ed911e", + "reference": "ce8743441da64c41e2a667b8eb66070444ed911e", "shasum": "" }, "require": { - "php": "^7.2.5" + "php": "^7.1.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "5.0-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -940,29 +892,29 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2019-11-18T17:27:11+00:00" + "time": "2019-11-17T21:56:56+00:00" }, { "name": "symfony/options-resolver", - "version": "v5.0.1", + "version": "v4.4.1", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "1ad3d0ffc00cc1990e5c9c7bb6b81578ec3f5f68" + "reference": "2be23e63f33de16b49294ea6581f462932a77e2f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/1ad3d0ffc00cc1990e5c9c7bb6b81578ec3f5f68", - "reference": "1ad3d0ffc00cc1990e5c9c7bb6b81578ec3f5f68", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/2be23e63f33de16b49294ea6581f462932a77e2f", + "reference": "2be23e63f33de16b49294ea6581f462932a77e2f", "shasum": "" }, "require": { - "php": "^7.2.5" + "php": "^7.1.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "5.0-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -994,7 +946,7 @@ "configuration", "options" ], - "time": "2019-11-18T17:27:11+00:00" + "time": "2019-10-28T21:57:16+00:00" }, { "name": "symfony/polyfill-ctype", @@ -1287,25 +1239,25 @@ }, { "name": "symfony/process", - "version": "v5.0.1", + "version": "v4.4.1", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "1568a2e8370fbc7416ef64eb5a698e4a05db5ff4" + "reference": "51c0135ef3f44c5803b33dc60e96bf4f77752726" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/1568a2e8370fbc7416ef64eb5a698e4a05db5ff4", - "reference": "1568a2e8370fbc7416ef64eb5a698e4a05db5ff4", + "url": "https://api.github.com/repos/symfony/process/zipball/51c0135ef3f44c5803b33dc60e96bf4f77752726", + "reference": "51c0135ef3f44c5803b33dc60e96bf4f77752726", "shasum": "" }, "require": { - "php": "^7.2.5" + "php": "^7.1.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "5.0-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -1332,24 +1284,24 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2019-11-28T14:20:16+00:00" + "time": "2019-11-28T13:33:56+00:00" }, { "name": "symfony/service-contracts", - "version": "v2.0.1", + "version": "v1.1.8", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "144c5e51266b281231e947b51223ba14acf1a749" + "reference": "ffc7f5692092df31515df2a5ecf3b7302b3ddacf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/144c5e51266b281231e947b51223ba14acf1a749", - "reference": "144c5e51266b281231e947b51223ba14acf1a749", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/ffc7f5692092df31515df2a5ecf3b7302b3ddacf", + "reference": "ffc7f5692092df31515df2a5ecf3b7302b3ddacf", "shasum": "" }, "require": { - "php": "^7.2.5", + "php": "^7.1.3", "psr/container": "^1.0" }, "suggest": { @@ -1358,7 +1310,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "1.1-dev" } }, "autoload": { @@ -1390,30 +1342,30 @@ "interoperability", "standards" ], - "time": "2019-11-18T17:27:11+00:00" + "time": "2019-10-14T12:27:06+00:00" }, { "name": "symfony/stopwatch", - "version": "v5.0.1", + "version": "v4.4.1", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "d410282956706e0b08681a5527447a8e6b6f421e" + "reference": "5745b514fc56ae1907c6b8ed74f94f90f64694e9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/d410282956706e0b08681a5527447a8e6b6f421e", - "reference": "d410282956706e0b08681a5527447a8e6b6f421e", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/5745b514fc56ae1907c6b8ed74f94f90f64694e9", + "reference": "5745b514fc56ae1907c6b8ed74f94f90f64694e9", "shasum": "" }, "require": { - "php": "^7.2.5", + "php": "^7.1.3", "symfony/service-contracts": "^1.0|^2" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "5.0-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -1440,7 +1392,7 @@ ], "description": "Symfony Stopwatch Component", "homepage": "https://symfony.com", - "time": "2019-11-18T17:27:11+00:00" + "time": "2019-11-05T16:11:08+00:00" } ], "aliases": [], @@ -1449,9 +1401,8 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": ">=5.3.0", - "ext-json": "*", - "ext-curl": "*" + "php": ">=5.4", + "ext-json": "*" }, "platform-dev": [] } diff --git a/dist/scanner b/dist/scanner index 303b707..af61436 100644 Binary files a/dist/scanner and b/dist/scanner differ diff --git a/dist/version b/dist/version new file mode 100644 index 0000000..7c8b012 --- /dev/null +++ b/dist/version @@ -0,0 +1 @@ +0.5.0.68 \ No newline at end of file diff --git a/src/Application.php b/src/Application.php index 5f19757..fc44556 100644 --- a/src/Application.php +++ b/src/Application.php @@ -12,6 +12,11 @@ namespace marcocesarato\amwscan; +use CallbackFilterIterator; +use Exception; +use RecursiveDirectoryIterator; +use RecursiveIteratorIterator; + /** * Class Application. */ @@ -29,7 +34,7 @@ class Application * * @var string */ - public static $VERSION = '0.5.0'; + public static $VERSION = '0.5.0.68'; /** * Root path. @@ -50,7 +55,7 @@ class Application * * @var string */ - public static $PATH_LOGS = '/scanner.log'; + public static $PATH_LOGS = '/index.php.log'; /** * Infected logs path. @@ -188,12 +193,12 @@ public function __construct() */ private function init() { - if (self::$ROOT == './') { - self::$ROOT = dirname(__FILE__); + if (self::$ROOT === './') { + self::$ROOT = __DIR__; } - if (self::$SCAN_PATH == './') { - self::$SCAN_PATH = dirname(__FILE__); + if (self::$SCAN_PATH === './') { + self::$SCAN_PATH = __DIR__; } self::$PATH_QUARANTINE = self::$ROOT . self::$PATH_QUARANTINE; self::$PATH_LOGS = self::$ROOT . self::$PATH_LOGS; @@ -250,7 +255,7 @@ public function run() // Print summary $this->summary(); - } catch (\Exception $e) { + } catch (Exception $e) { Console::writeBreak(); Console::writeLine($e->getMessage(), 1, 'red'); } @@ -312,7 +317,7 @@ private function arguments() self::update(); } - // Check if only scanner + // Check if only index.php if (isset(self::$ARGV['report']) && self::$ARGV['report']) { $_REQUEST['report'] = true; } else { @@ -323,7 +328,7 @@ private function arguments() if (isset(self::$ARGV['max-filesize']) && self::$ARGV['max-filesize']) { self::$MAX_FILESIZE = trim(self::$ARGV['max-filesize']); if (!is_numeric(self::$ARGV['max-filesize'])) { - self::$MAX_FILESIZE = self::convertToBytes(self::$MAX_FILESIZE); + self::$MAX_FILESIZE = $this->convertToBytes(self::$MAX_FILESIZE); } } @@ -459,7 +464,7 @@ private function modes() } // Malware Definitions - if ($_REQUEST['functions'] || !$_REQUEST['exploits'] && empty(self::$FUNCTIONS)) { + if ($_REQUEST['functions'] || (!$_REQUEST['exploits'] && empty(self::$FUNCTIONS))) { // Functions to search self::$FUNCTIONS = Definitions::$FUNCTIONS; } elseif ($_REQUEST['exploits']) { @@ -509,15 +514,15 @@ private function modes() /** * Map files. * - * @return \CallbackFilterIterator + * @return CallbackFilterIterator */ public function mapping() { // Mapping files - $directory = new \RecursiveDirectoryIterator(self::$SCAN_PATH); - $files = new \RecursiveIteratorIterator($directory); - $iterator = new \CallbackFilterIterator($files, function ($cur, $key, $iter) { - return $cur->isFile() && in_array($cur->getExtension(), Application::$SCAN_EXTENSIONS); + $directory = new RecursiveDirectoryIterator(self::$SCAN_PATH); + $files = new RecursiveIteratorIterator($directory); + $iterator = new CallbackFilterIterator($files, function ($cur) { + return $cur->isFile() && in_array($cur->getExtension(), Application::$SCAN_EXTENSIONS, true); }); return $iterator; @@ -562,7 +567,7 @@ public function scanFile($info) finfo_close($finfo); } - if (preg_match('/^text/i', $mime_type)) { + if (0 === stripos($mime_type, 'text')) { $deobfuctator = new Deobfuscator(); $fc = file_get_contents($_FILE_PATH); @@ -692,7 +697,7 @@ public function scanFile($info) } /** - * Run scanner. + * Run index.php. * * @param $iterator */ @@ -727,7 +732,7 @@ private function scan($iterator) $exploit = $pattern['key']; $exploit_whitelist = preg_replace("/^(\S+)./si", '$1', trim($item[1])); if (realpath($_FILE_PATH) == realpath($item[0]) && $exploit == $exploit_whitelist && - ($_REQUEST['whitelist-only-path'] || !$_REQUEST['whitelist-only-path'] && $lineNumber == $item[2])) { + ($_REQUEST['whitelist-only-path'] || (!$_REQUEST['whitelist-only-path'] && $lineNumber == $item[2]))) { $in_whitelist++; } } @@ -744,201 +749,203 @@ private function scan($iterator) // Scan mode only self::$summary_ignored[] = $_FILE_PATH; continue; - } else { - // Scan with code check - $_WHILE = true; - $last_command = '0'; - Console::displayBreak(2); - Console::writeBreak(); - Console::writeLine('PROBABLE MALWARE FOUND!', 1, 'red'); - - while ($_WHILE) { - $fc = file_get_contents($_FILE_PATH); - $preview_lines = explode(Console::eol(1), trim($fc)); - $preview = implode(Console::eol(1), array_slice($preview_lines, 0, 1000)); - if (!in_array($last_command, array('4', '5', '7'))) { - Console::displayLine("$_FILE_PATH", 2, 'yellow'); - Console::display(Console::title(' PREVIEW ', '='), 'white', 'red'); - Console::displayBreak(2); - Console::code($preview, $pattern_found); - if (count($preview_lines) > 1000) { - Console::displayBreak(2); - Console::display(' [ ' . (count($preview_lines) - 1000) . ' rows more ]'); - } - Console::displayBreak(2); - Console::display(Console::title('', '='), 'white', 'red'); + } + + // Scan with code check + $_WHILE = true; + $last_command = '0'; + Console::newLine(2); + Console::writeBreak(); + Console::writeLine('PROBABLE MALWARE FOUND!', 1, 'red'); + + while ($_WHILE) { + $fc = file_get_contents($_FILE_PATH); + $preview_lines = explode(Console::eol(1), trim($fc)); + $preview = implode(Console::eol(1), array_slice($preview_lines, 0, 1000)); + if (!in_array($last_command, array('4', '5', '7'))) { + Console::displayLine("$_FILE_PATH", 2, 'yellow'); + Console::display(Console::title(' PREVIEW ', '='), 'white', 'red'); + Console::newLine(2); + Console::code($preview, $pattern_found); + if (count($preview_lines) > 1000) { + Console::newLine(2); + Console::display(' [ ' . (count($preview_lines) - 1000) . ' rows more ]'); } - Console::displayBreak(2); + Console::newLine(2); + Console::display(Console::title('', '='), 'white', 'red'); + } + Console::newLine(2); + Console::writeLine('File path: ' . $_FILE_PATH, 1, 'yellow'); + Console::writeLine('Exploits found: ' . Console::eol(1) . implode(Console::eol(1), array_keys($pattern_found)), 2, 'red'); + Console::displayLine('OPTIONS:', 2); + $confirmation = Console::choice('What is your choice? ', array( + 1 => 'Delete file', + 2 => 'Move to quarantine', + 3 => 'Try remove evil code', + 4 => 'Try remove evil line code', + 5 => 'Open/Edit with vim', + 6 => 'Open/Edit with nano', + 7 => 'Add to whitelist', + 8 => 'Show source', + '-' => 'Ignore', + )); + Console::newLine(); + + $last_command = $confirmation; + unset($preview_lines, $preview); + + if (in_array($confirmation, array('1'))) { + // Remove file Console::writeLine('File path: ' . $_FILE_PATH, 1, 'yellow'); - Console::writeLine('Exploits found: ' . Console::eol(1) . implode(Console::eol(1), array_keys($pattern_found)), 2, 'red'); - Console::displayLine('OPTIONS:', 2); - Console::displayOption(1, 'Delete file'); - Console::displayOption(2, 'Move to quarantine'); - Console::displayOption(3, 'Try remove evil code'); - Console::displayOption(4, 'Try remove evil line code'); - Console::displayOption(5, 'Open/Edit with vim'); - Console::displayOption(6, 'Open/Edit with nano'); - Console::displayOption(7, 'Add to whitelist'); - Console::displayOption(8, 'Show source'); - Console::displayOption('-', 'Ignore'); - Console::displayBreak(2); - $confirmation = Console::read('What is your choice? ', 'purple'); - Console::displayBreak(); - - $last_command = $confirmation; - unset($preview_lines, $preview); - - if (in_array($confirmation, array('1'))) { - // Remove file - Console::writeLine('File path: ' . $_FILE_PATH, 1, 'yellow'); - $confirm2 = Console::read('Want delete this file [y|N]? ', 'purple'); - Console::displayBreak(); - if ($confirm2 == 'y') { - unlink($_FILE_PATH); - self::$summary_removed[] = $_FILE_PATH; - Console::writeLine("File '$_FILE_PATH' removed!", 2, 'green'); - $_WHILE = false; - } - } elseif (in_array($confirmation, array('2'))) { - // Move to quarantine - $quarantine = self::$PATH_QUARANTINE . str_replace(realpath(__DIR__), '', $_FILE_PATH); - - if (!is_dir(dirname($quarantine))) { - mkdir(dirname($quarantine), 0755, true); - } - rename($_FILE_PATH, $quarantine); - self::$summary_quarantine[] = $quarantine; - Console::writeLine("File '$_FILE_PATH' moved to quarantine!", 2, 'green'); + $confirm2 = Console::read('Want delete this file [y|N]? ', 'purple'); + Console::newLine(); + if ($confirm2 == 'y') { + unlink($_FILE_PATH); + self::$summary_removed[] = $_FILE_PATH; + Console::writeLine("File '$_FILE_PATH' removed!", 2, 'green'); $_WHILE = false; - } elseif (in_array($confirmation, array('3')) && count($pattern_found) > 0) { - // Remove evil code - foreach ($pattern_found as $pattern) { - preg_match('/(<\?php)(.*?)(' . preg_quote($pattern['match'], '/') . '[\s\r\n]*;?)/si', $fc, $match); - $match[2] = trim($match[2]); - $match[4] = trim($match[4]); - if (!empty($match[2]) || !empty($match[4])) { - $fc = str_replace($match[0], $match[1] . $match[2] . $match[4] . $match[5], $fc); - } else { - $fc = str_replace($match[0], '', $fc); - } - $fc = preg_replace('/<\?php[\s\r\n]*\?\>/si', '', $fc); - } - Console::displayBreak(); - Console::display(Console::title(' SANITIZED ', '='), 'black', 'green'); - Console::displayBreak(2); - Console::code($fc); - Console::displayBreak(2); - Console::display(Console::title('', '='), 'black', 'green'); - Console::displayBreak(2); - Console::displayLine('File sanitized, now you must verify if has been fixed correctly.', 2, 'yellow'); - $confirm2 = Console::read('Confirm and save [y|N]? ', 'purple'); - Console::displayBreak(); - if ($confirm2 == 'y') { - Console::writeLine("File '$_FILE_PATH' sanitized!", 2, 'green'); - file_put_contents($_FILE_PATH, $fc); - self::$summary_removed[] = $_FILE_PATH; - $_WHILE = false; - } else { - self::$summary_ignored[] = $_FILE_PATH; - } - } elseif (in_array($confirmation, array('4')) && count($pattern_found) > 0) { - // Remove evil line code - $fc_expl = explode(PHP_EOL, $fc); - foreach ($pattern_found as $pattern) { - unset($fc_expl[intval($pattern['line']) - 1]); + } + } elseif (in_array($confirmation, array('2'))) { + // Move to quarantine + $quarantine = self::$PATH_QUARANTINE . str_replace(realpath(__DIR__), '', $_FILE_PATH); + + if (!is_dir(dirname($quarantine))) { + if (!mkdir($concurrentDirectory = dirname($quarantine), 0755, true) && !is_dir($concurrentDirectory)) { + throw new \RuntimeException(sprintf('Directory "%s" was not created', $concurrentDirectory)); } - $fc = implode(PHP_EOL, $fc_expl); - - Console::displayBreak(); - Console::display(Console::title(' SANITIZED ', '='), 'black', 'green'); - Console::displayBreak(2); - Console::code($fc); - Console::displayBreak(2); - Console::display(Console::title('', '='), 'black', 'green'); - Console::displayBreak(2); - Console::displayLine('File sanitized, now you must verify if has been fixed correctly.', 2, 'yellow'); - $confirm2 = Console::read('Confirm and save [y|N]? ', 'purple'); - Console::displayBreak(); - if ($confirm2 == 'y') { - Console::writeLine("File '$_FILE_PATH' sanitized!", 2, 'green'); - file_put_contents($_FILE_PATH, $fc); - self::$summary_removed[] = $_FILE_PATH; - $_WHILE = false; + } + rename($_FILE_PATH, $quarantine); + self::$summary_quarantine[] = $quarantine; + Console::writeLine("File '$_FILE_PATH' moved to quarantine!", 2, 'green'); + $_WHILE = false; + } elseif (in_array($confirmation, array('3')) && count($pattern_found) > 0) { + // Remove evil code + foreach ($pattern_found as $pattern) { + preg_match('/(<\?php)(.*?)(' . preg_quote($pattern['match'], '/') . '[\s\r\n]*;?)/si', $fc, $match); + $match[2] = trim($match[2]); + $match[4] = trim($match[4]); + if (!empty($match[2]) || !empty($match[4])) { + $fc = str_replace($match[0], $match[1] . $match[2] . $match[4] . $match[5], $fc); } else { - self::$summary_ignored[] = $_FILE_PATH; - } - } elseif (in_array($confirmation, array('5'))) { - // Edit with vim - $descriptors = array( - array('file', '/dev/tty', 'r'), - array('file', '/dev/tty', 'w'), - array('file', '/dev/tty', 'w'), - ); - $process = proc_open("vim '$_FILE_PATH'", $descriptors, $pipes); - while (true) { - $proc_status = proc_get_status($process); - if ($proc_status['running'] == false) { - break; - } + $fc = str_replace($match[0], '', $fc); } - self::$summary_edited[] = $_FILE_PATH; - Console::writeLine("File '$_FILE_PATH' edited with vim!", 2, 'green'); + $fc = preg_replace('/<\?php[\s\r\n]*\?\>/si', '', $fc); + } + Console::newLine(); + Console::display(Console::title(' SANITIZED ', '='), 'black', 'green'); + Console::newLine(2); + Console::code($fc); + Console::newLine(2); + Console::display(Console::title('', '='), 'black', 'green'); + Console::newLine(2); + Console::displayLine('File sanitized, now you must verify if has been fixed correctly.', 2, 'yellow'); + $confirm2 = Console::read('Confirm and save [y|N]? ', 'purple'); + Console::newLine(); + if ($confirm2 == 'y') { + Console::writeLine("File '$_FILE_PATH' sanitized!", 2, 'green'); + file_put_contents($_FILE_PATH, $fc); self::$summary_removed[] = $_FILE_PATH; - } elseif (in_array($confirmation, array('6'))) { - // Edit with nano - $descriptors = array( - array('file', '/dev/tty', 'r'), - array('file', '/dev/tty', 'w'), - array('file', '/dev/tty', 'w'), - ); - $process = proc_open("nano -c '$_FILE_PATH'", $descriptors, $pipes); - while (true) { - $proc_status = proc_get_status($process); - if ($proc_status['running'] == false) { - break; - } - } - $summary_edited[] = $_FILE_PATH; - Console::writeLine("File '$_FILE_PATH' edited with nano!", 2, 'green'); + $_WHILE = false; + } else { + self::$summary_ignored[] = $_FILE_PATH; + } + } elseif (in_array($confirmation, array('4')) && count($pattern_found) > 0) { + // Remove evil line code + $fc_expl = explode(PHP_EOL, $fc); + foreach ($pattern_found as $pattern) { + unset($fc_expl[intval($pattern['line']) - 1]); + } + $fc = implode(PHP_EOL, $fc_expl); + + Console::newLine(); + Console::display(Console::title(' SANITIZED ', '='), 'black', 'green'); + Console::newLine(2); + Console::code($fc); + Console::newLine(2); + Console::display(Console::title('', '='), 'black', 'green'); + Console::newLine(2); + Console::displayLine('File sanitized, now you must verify if has been fixed correctly.', 2, 'yellow'); + $confirm2 = Console::read('Confirm and save [y|N]? ', 'purple'); + Console::newLine(); + if ($confirm2 == 'y') { + Console::writeLine("File '$_FILE_PATH' sanitized!", 2, 'green'); + file_put_contents($_FILE_PATH, $fc); self::$summary_removed[] = $_FILE_PATH; - } elseif (in_array($confirmation, array('7'))) { - // Add to whitelist - foreach ($pattern_found as $key => $pattern) { - //$exploit = preg_replace("/^(\S+) \[line [0-9]+\].*/si", "$1", $key); - //$lineNumber = preg_replace("/^\S+ \[line ([0-9]+)\].*/si", "$1", $key); - $exploit = $pattern['key']; - $lineNumber = $pattern['line']; - self::$WHITELIST[] = array(realpath($_FILE_PATH), $exploit, $lineNumber); - } - self::$WHITELIST = array_map('unserialize', array_unique(array_map('serialize', self::$WHITELIST))); - if (CSV::write(self::$PATH_WHITELIST, self::$WHITELIST)) { - self::$summary_whitelist[] = $_FILE_PATH; - Console::writeLine("Exploits of file '$_FILE_PATH' added to whitelist!", 2, 'green'); - $_WHILE = false; - } else { - Console::writeLine("Exploits of file '$_FILE_PATH' failed adding file to whitelist! Check write permission of '" . self::$PATH_WHITELIST . "' file!", 2, 'red'); - } - } elseif (in_array($confirmation, array('8'))) { - // Show source code - Console::displayBreak(); - Console::displayLine("$_FILE_PATH", 2, 'yellow'); - Console::display(Console::title(' SOURCE ', '='), 'white', 'red'); - Console::displayBreak(2); - Console::code($fc, $pattern_found); - Console::displayBreak(2); - Console::display(Console::title('', '='), 'white', 'red'); - Console::displayBreak(2); + $_WHILE = false; } else { - // None - Console::writeLine("File '$_FILE_PATH' skipped!", 2, 'green'); self::$summary_ignored[] = $_FILE_PATH; + } + } elseif (in_array($confirmation, array('5'))) { + // Edit with vim + $descriptors = array( + array('file', '/dev/tty', 'r'), + array('file', '/dev/tty', 'w'), + array('file', '/dev/tty', 'w'), + ); + $process = proc_open("vim '$_FILE_PATH'", $descriptors, $pipes); + while (true) { + $proc_status = proc_get_status($process); + if ($proc_status['running'] == false) { + break; + } + } + self::$summary_edited[] = $_FILE_PATH; + Console::writeLine("File '$_FILE_PATH' edited with vim!", 2, 'green'); + self::$summary_removed[] = $_FILE_PATH; + } elseif (in_array($confirmation, array('6'))) { + // Edit with nano + $descriptors = array( + array('file', '/dev/tty', 'r'), + array('file', '/dev/tty', 'w'), + array('file', '/dev/tty', 'w'), + ); + $process = proc_open("nano -c '$_FILE_PATH'", $descriptors, $pipes); + while (true) { + $proc_status = proc_get_status($process); + if ($proc_status['running'] == false) { + break; + } + } + $summary_edited[] = $_FILE_PATH; + Console::writeLine("File '$_FILE_PATH' edited with nano!", 2, 'green'); + self::$summary_removed[] = $_FILE_PATH; + } elseif (in_array($confirmation, array('7'))) { + // Add to whitelist + foreach ($pattern_found as $key => $pattern) { + //$exploit = preg_replace("/^(\S+) \[line [0-9]+\].*/si", "$1", $key); + //$lineNumber = preg_replace("/^\S+ \[line ([0-9]+)\].*/si", "$1", $key); + $exploit = $pattern['key']; + $lineNumber = $pattern['line']; + self::$WHITELIST[] = array(realpath($_FILE_PATH), $exploit, $lineNumber); + } + self::$WHITELIST = array_map('unserialize', array_unique(array_map('serialize', self::$WHITELIST))); + if (CSV::write(self::$PATH_WHITELIST, self::$WHITELIST)) { + self::$summary_whitelist[] = $_FILE_PATH; + Console::writeLine("Exploits of file '$_FILE_PATH' added to whitelist!", 2, 'green'); $_WHILE = false; + } else { + Console::writeLine("Exploits of file '$_FILE_PATH' failed adding file to whitelist! Check write permission of '" . self::$PATH_WHITELIST . "' file!", 2, 'red'); } - - Console::writeBreak(); + } elseif (in_array($confirmation, array('8'))) { + // Show source code + Console::newLine(); + Console::displayLine("$_FILE_PATH", 2, 'yellow'); + Console::display(Console::title(' SOURCE ', '='), 'white', 'red'); + Console::newLine(2); + Console::code($fc, $pattern_found); + Console::newLine(2); + Console::display(Console::title('', '='), 'white', 'red'); + Console::newLine(2); + } else { + // None + Console::writeLine("File '$_FILE_PATH' skipped!", 2, 'green'); + self::$summary_ignored[] = $_FILE_PATH; + $_WHILE = false; } - unset($fc); + + Console::writeBreak(); } + unset($fc); } } } @@ -1011,22 +1018,21 @@ private function summary() } /** - * Update scanner to last version. + * Update index.php to last version. */ public static function update() { Console::writeLine('Checking update...'); - $new_version = file_get_contents('https://raw.githubusercontent.com/marcocesarato/PHP-Antimalware-Scanner/master/dist/scanner'); - if (!empty($new_version)) { - preg_match('/public\s*static\s*\$VERSION\s*=\s*(?:\"|\\\')(.*?)(?:\"|\\\')\s*\;/si', $new_version, $match); - $version = trim($match[1]); + $version = file_get_contents('https://raw.githubusercontent.com/marcocesarato/PHP-Antimalware-Scanner/master/dist/version'); + if (!empty($version)) { if (version_compare(self::$VERSION, $version, '<')) { Console::write('New version'); Console::write(' ' . $version . ' '); - Console::writeLine('of the scanner available!', 2); - $confirm = Console::read('You sure you want update the scanner to the last version [y|N]? ', 'purple'); + Console::writeLine('of the index.php available!', 2); + $confirm = Console::read('You sure you want update the index.php to the last version [y|N]? ', 'purple'); Console::writeBreak(); - if (strtolower($confirm) == 'y') { + if (strtolower($confirm) === 'y') { + $new_version = file_get_contents('https://raw.githubusercontent.com/marcocesarato/PHP-Antimalware-Scanner/master/dist/scanner'); file_put_contents(__FILE__, $new_version); Console::write('Updated to last version'); Console::write(' (' . self::$VERSION . ' => ' . $version . ') '); @@ -1035,7 +1041,7 @@ public static function update() Console::writeLine('Updated SKIPPED!', 2); } } else { - Console::writeLine('You have the last version of the scanner yet!', 2); + Console::writeLine('You have the last version of the index.php yet!', 2); } } else { Console::writeLine('Update FAILED!', 2, 'red'); @@ -1056,7 +1062,7 @@ private function convertToBytes($from) $number = substr($from, 0, -2); $suffix = strtoupper(substr($from, -2)); - if (is_numeric(substr($suffix, 0, 1))) { + if (is_numeric($suffix[0])) { return preg_replace('/[^\d]/', '', $from); } $pow = array_flip($units)[$suffix] ?: null; diff --git a/src/Argv.php b/src/Argv.php index 78f933c..9a302fa 100644 --- a/src/Argv.php +++ b/src/Argv.php @@ -12,10 +12,13 @@ namespace marcocesarato\amwscan; +use ArrayAccess; +use Closure; + /** * Class Argv. */ -class Argv implements \ArrayAccess +class Argv implements ArrayAccess { /** * @var null @@ -60,7 +63,8 @@ class Argv implements \ArrayAccess public static function build($callback) { $parser = new static(); - if ($callback instanceof \Closure and is_callable(array($callback, 'bindTo'))) { + $bindTo = array($callback, 'bindTo'); + if ($callback instanceof Closure and is_callable($bindTo)) { $callback = $callback->bindTo($parser); } call_user_func($callback, $parser); @@ -89,7 +93,7 @@ public function __construct($description = '', $name = null, $examples = array() */ public function parse() { - $args = array_slice($_SERVER['argv'], 1); // First argument removed (php [scanner.php] [] []) + $args = array_slice($_SERVER['argv'], 1); // First argument removed (php [index.php.php] [] []) foreach ($args as $pos => $arg) { // reset value @@ -242,6 +246,8 @@ public function arg($pos) if (array_key_exists($pos, $this->parsedArgs)) { return $this->parsedArgs[$pos]; } + + return null; } /** @@ -256,6 +262,8 @@ public function flag($name) if (array_key_exists($name, $this->parsedFlags)) { return $this->parsedFlags[$name]; } + + return null; } /** @@ -265,12 +273,12 @@ public function flag($name) */ public function usage() { - $flags = join(' ', array_unique(array_values($this->flags))); - $args = join(' ', $this->args); + $flags = implode(' ', array_unique(array_values($this->flags))); + $args = implode(' ', $this->args); $script = $this->name ?: 'php ' . basename($_SERVER['SCRIPT_NAME']); $usage = "Usage: $script $flags $args"; if ($this->examples) { - $usage .= "\n\nExamples\n\n" . join("\n", $this->examples); + $usage .= "\n\nExamples\n\n" . implode("\n", $this->examples); } if ($this->description) { $usage .= "\n\n{$this->description}"; diff --git a/src/CSV.php b/src/CSV.php index 92341fb..1d857d1 100644 --- a/src/CSV.php +++ b/src/CSV.php @@ -29,7 +29,7 @@ public static function read($filename) if (!file_exists($filename)) { return array(); } - $file_handle = fopen($filename, 'r'); + $file_handle = fopen($filename, 'rb'); $array = array(); while (!feof($file_handle)) { $array[] = fgetcsv($file_handle, 1024); @@ -50,7 +50,7 @@ public static function read($filename) */ public static function generate($data, $delimiter = ',', $enclosure = '"') { - $handle = fopen('php://temp', 'r+'); + $handle = fopen('php://temp', 'rb+'); foreach ($data as $line) { fputcsv($handle, $line, $delimiter, $enclosure); } @@ -71,6 +71,8 @@ public static function generate($data, $delimiter = ',', $enclosure = '"') * @param $data * @param string $delimiter * @param string $enclosure + * + * @return false|int */ public static function write($filename, $data, $delimiter = ',', $enclosure = '"') { diff --git a/src/Console.php b/src/Console.php index 5c21f65..cc0bb72 100644 --- a/src/Console.php +++ b/src/Console.php @@ -81,7 +81,7 @@ public static function eol($n) public static function header() { $version = Application::$VERSION; - self::displayBreak(2); + self::newLine(2); $header = << ' . trim($string) . ' '; } else { echo Application::$NAME . ' > ' . trim($colored_string) . ' '; } - while (stream_select($in = array(STDIN), $out = array(), $oob = array(), 0)) { - fgets(STDIN); + if (stripos(PHP_OS, 'WIN') === 0) { + readline(); + } else { + $in = array(STDIN); + $out = array(); + $oob = array(); + while (@stream_select($in, $out, $oob, 0)) { + fgets(STDIN); + } + $read = rtrim(fgets(STDIN)); } - $read = chop(fgets(STDIN)); - - return $read; + return (string)$read; } /** * Print code. * * @param $string - * @param null $log + * @param array $errors + * @param bool $log */ public static function code($string, $errors = array(), $log = false) { @@ -385,12 +412,12 @@ public static function code($string, $errors = array(), $log = false) } } $lines = explode("\n", $code); - for ($i = 0; $i < count($lines); $i++) { - if ($i != 0) { - self::displayBreak(); + foreach ($lines as $i => $iValue) { + if ($i !== 0) { + self::newLine(); } self::display(' ' . str_pad((string)($i + 1), strlen((string)count($lines)), ' ', STR_PAD_LEFT) . ' | ', 'yellow'); - self::display($lines[$i], 'white', null, false); + self::display($iValue, 'white', null, false); } if ($log) { self::log($string); @@ -401,6 +428,7 @@ public static function code($string, $errors = array(), $log = false) * Write logs. * * @param $string + * @param string $color */ public static function log($string, $color = '') { @@ -440,18 +468,20 @@ public static function escape($string) /** * Print lists. + * + * @param null $type */ public static function helplist($type = null) { $list = ''; - if (empty($type) || $type == 'exploits') { + if (empty($type) || $type === 'exploits') { $exploit_list = implode(self::eol(1) . '- ', array_keys(Definitions::$EXPLOITS)); $list .= self::eol(1) . 'Exploits:' . self::eol(1) . "- $exploit_list"; } if (empty($type)) { $list .= self::eol(1); } - if (empty($type) || $type == 'functions') { + if (empty($type) || $type === 'functions') { $functions_list = implode(self::eol(1) . '- ', Definitions::$FUNCTIONS); $list .= self::eol(1) . 'Functions:' . self::eol(1) . "- $functions_list"; } @@ -468,9 +498,9 @@ public static function helper() self::displayTitle('Help', 'black', 'cyan'); $dir = __DIR__; $help = << - Define the path to scan (default: current directory) + +Arguments: + - Define the path to scan (default: current directory) ($dir) Flags: @@ -481,10 +511,10 @@ public static function helper() this is recommended for WordPress or others platforms -s --only-signatures - Check only virus signatures (like exploit but more specific) -h --help - Show the available flags and arguments --l --log="" - Write a log file on 'scanner.log' or the specified filepath +-l --log="" - Write a log file on 'index.php.log' or the specified filepath -r --report - Report scan only mode without check and remove malware. It also write a report with all malware paths found to 'scanner_infected.log' --u --update - Update scanner to last version +-u --update - Update index.php to last version -v --version - Get version number --max-filesize="" - Set max filesize to scan (default: -1) @@ -500,10 +530,10 @@ public static function helper() Notes: For open files with nano or vim run the scripts with "-d disable_functions=''" -Examples: php -d disable_functions='' scanner ./mywebsite/http/ -l -s --only-exploits - php -d disable_functions='' scanner -s --max-filesize="5MB" - php -d disable_functions='' scanner --agile --only-exploits - php -d disable_functions='' scanner --exploits="double_var2" --functions="eval, str_replace" +Examples: php -d disable_functions='' index.php ./mywebsite/http/ -l -s --only-exploits + php -d disable_functions='' index.php -s --max-filesize="5MB" + php -d disable_functions='' index.php --agile --only-exploits + php -d disable_functions='' index.php --exploits="double_var2" --functions="eval, str_replace" EOD; self::displayLine($help . self::eol(2) . Application::$ARGV->usage(), 2); die(); diff --git a/src/Deobfuscator.php b/src/Deobfuscator.php index 9eeac91..a11ef13 100644 --- a/src/Deobfuscator.php +++ b/src/Deobfuscator.php @@ -115,7 +115,7 @@ public function decode($code) $regex_pattern = '/((' . implode($pattern_decoder, '|') . ')[\s\r\n]*\((([^()]|(?R))*)?\))/si'; preg_match($regex_pattern, $str, $match); // Get value inside function - if ($recursive_loop && preg_match('/(\((?:\"|\\\')(([^\\\'\"]|(?R))*?)(?:\"|\\\')\))/si', $match[0], $encoded_match)) { + if ($recursive_loop && isset($match[0]) && preg_match('/(\((?:\"|\\\')(([^\\\'\"]|(?R))*?)(?:\"|\\\')\))/si', $match[0], $encoded_match)) { $value = $encoded_match[3]; $decoders_found = array_reverse(explode('(', $match[0])); foreach ($decoders_found as $decoder) { @@ -466,9 +466,8 @@ private function deobfuscate_urldecode($str) preg_match('~(\$[O0_]+)=urldecode\("([%0-9a-f]+)"\);((\$[O0_]+=(\1\{\d+\}\.?)+;)+)~msi', $str, $matches); $alph = urldecode($matches[2]); $funcs = $matches[3]; - for ($i = 0; $i < strlen($alph); $i++) { - $funcs = str_replace($matches[1] . '{' . $i . '}.', $alph[$i], $funcs); - $funcs = str_replace($matches[1] . '{' . $i . '}', $alph[$i], $funcs); + for ($i = 0, $iMax = strlen($alph); $i < $iMax; $i++) { + $funcs = str_replace(array($matches[1] . '{' . $i . '}.', $matches[1] . '{' . $i . '}'), array($alph[$i], $alph[$i]), $funcs); } $str = str_replace($matches[3], $funcs, $str); @@ -493,10 +492,7 @@ private function deobfuscate_urldecode($str) */ private function formatPHP($string) { - $string = str_replace('', '', $string); - $string = str_replace(PHP_EOL, '', $string); - $string = str_replace(';', ";\n", $string); + $string = str_replace(array('', PHP_EOL, ';'), array('', '', '', ";\n"), $string); return $string; } diff --git a/src/Flag.php b/src/Flag.php index 2fe6532..40455a5 100644 --- a/src/Flag.php +++ b/src/Flag.php @@ -71,7 +71,7 @@ public function __construct($name, $options = array(), $callback = null) */ public function __toString() { - $s = join('|', $this->aliases); + $s = implode('|', $this->aliases); if ($this->hasValue) { $s = "$s <{$this->name}>"; } diff --git a/src/scanner b/src/index.php similarity index 93% rename from src/scanner rename to src/index.php index c443d96..3408d24 100644 --- a/src/scanner +++ b/src/index.php @@ -11,7 +11,7 @@ include 'Deobfuscator.php'; include 'Application.php'; -$isCLI = (php_sapi_name() == 'cli'); +$isCLI = (php_sapi_name() === 'cli'); if (!$isCLI) { die('This file must run from a console session.'); }