Skip to content

Commit

Permalink
feat: add deobfuscate commands and functionality and fix backup path
Browse files Browse the repository at this point in the history
  • Loading branch information
marcocesarato committed Jan 10, 2021
1 parent 0c359ef commit 9238b6e
Show file tree
Hide file tree
Showing 2 changed files with 159 additions and 15 deletions.
11 changes: 8 additions & 3 deletions src/Actions.php
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,14 @@ public static function moveToQuarantine($file)
*/
public static function makeBackup($file)
{
$backup = Scanner::getPathBackups() . DIRECTORY_SEPARATOR . str_replace(realpath(Scanner::getPathScan()), '', realpath($file));
$backup = str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $backup);
if (!is_dir(dirname($backup)) && (!mkdir($concurrentDirectory = dirname($backup), 0755, true) && !is_dir($concurrentDirectory))) {
$scanPath = realpath(Scanner::getPathScan());
if (is_file($scanPath)) {
$scanPath = dirname($scanPath);
}
$backup = Scanner::getPathBackups() . DIRECTORY_SEPARATOR . str_replace($scanPath, '', realpath($file));
$backup = Scanner::replaceSlash($backup);
if (!is_dir(dirname($backup)) &&
(!mkdir($concurrentDirectory = dirname($backup), 0755, true) && !is_dir($concurrentDirectory))) {
throw new RuntimeException(sprintf('Directory "%s" was not created', $concurrentDirectory));
}
copy($file, $backup);
Expand Down
163 changes: 151 additions & 12 deletions src/Scanner.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
use Phar;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use RuntimeException;
use SplFileInfo;

/**
Expand Down Expand Up @@ -71,6 +72,13 @@ class Scanner
*/
public static $pathBackups = '/scanner-backups/';

/**
* Deobfuscate path.
*
* @var string
*/
public static $pathDeobfuscate = '/deobfuscated/';

/**
* Logs Path.
*
Expand Down Expand Up @@ -254,14 +262,12 @@ public function __construct()
self::$pathScan = self::currentDirectory();
}

$replaceSlash = function ($str) {
return str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $str);
};

self::$pathQuarantine = $replaceSlash(self::$root . self::$pathQuarantine);
self::$pathLogs = $replaceSlash(self::$root . self::$pathLogs);
self::$pathWhitelist = $replaceSlash(self::$root . self::$pathWhitelist);
self::$pathReport = $replaceSlash(self::$root . self::$pathReport);
self::$pathQuarantine = self::replaceSlash(self::$root . self::$pathQuarantine);
self::$pathLogs = self::replaceSlash(self::$root . self::$pathLogs);
self::$pathWhitelist = self::replaceSlash(self::$root . self::$pathWhitelist);
self::$pathReport = self::replaceSlash(self::$root . self::$pathReport);
self::$pathBackups = self::replaceSlash(self::$root . self::$pathBackups);
self::$pathDeobfuscate = self::replaceSlash(self::$root . self::$pathDeobfuscate);

if (!self::isCli()) {
self::setSilentMode(true);
Expand Down Expand Up @@ -388,13 +394,15 @@ private function arguments($args = null)
self::$argv->addFlag('auto-whitelist', ['default' => false, 'help' => 'Auto whitelist (if you sure that source isn\'t compromised)']);
self::$argv->addFlag('auto-prompt', ['default' => null, 'has_value' => true, 'value_name' => 'prompt', 'help' => "Set auto prompt command .\nex. --auto-prompt=\"delete\" or --auto-prompt=\"1\" (alias of auto-delete)"]);
self::$argv->addFlag('path-whitelist', ['default' => self::$pathWhitelist, 'has_value' => true, 'value_name' => 'path', 'help' => 'Set whitelist file']);
self::$argv->addFlag('path-deobfuscate', ['default' => self::$pathDeobfuscate, 'has_value' => true, 'value_name' => 'path', 'help' => "Set debofuscated files path directory.\nIs recommended put files outside the public document path"]);
self::$argv->addFlag('path-backups', ['default' => self::$pathBackups, 'has_value' => true, 'value_name' => 'path', 'help' => "Set backups path directory.\nIs recommended put files outside the public document path"]);
self::$argv->addFlag('path-quarantine', ['default' => self::$pathQuarantine, 'has_value' => true, 'value_name' => 'path', 'help' => "Set quarantine path directory.\nIs recommended put files outside the public document path"]);
self::$argv->addFlag('path-logs', ['default' => self::$pathLogs, 'has_value' => true, 'value_name' => 'path', 'help' => 'Set quarantine log file']);
self::$argv->addFlag('path-report', ['default' => self::$pathReport, 'has_value' => true, 'value_name' => 'path', 'help' => 'Set report log file']);
self::$argv->addFlag('disable-colors', ['alias' => ['--no-colors', '--no-color'], 'default' => false, 'help' => 'Disable CLI colors']);
self::$argv->addFlag('disable-cache', ['alias' => '--no-cache', 'default' => false, 'help' => 'Disable Cache']);
self::$argv->addFlag('disable-report', ['alias' => '--no-report', 'default' => false, 'help' => 'Disable Report']);
//self::$argv->addFlag('deobfuscate', ['default' => false, 'help' => 'Deobfuscate directory']);
self::$argv->addArgument('path', ['var_args' => true, 'default' => self::currentDirectory(), 'help' => 'Define the path of the file or directory to scan']);
self::$argv->parse($args);

Expand Down Expand Up @@ -445,14 +453,14 @@ private function arguments($args = null)
}

// Colors
if (isset(self::$argv['disable-colors']) && self::$argv['disable-colors']) {
if (!self::$argv['disable-colors']) {
self::setColors(false);
} elseif (function_exists('ncurses_has_colors')) {
self::setColors(ncurses_has_colors());
}

// Cache
self::setCache(!(isset(self::$argv['disable-cache']) && self::$argv['disable-cache']));
self::setCache(!self::$argv['disable-cache']);

// Max filesize
if (isset(self::$argv['max-filesize']) && is_numeric(self::$argv['max-filesize'])) {
Expand Down Expand Up @@ -485,7 +493,12 @@ private function arguments($args = null)

// Path backups
if (isset(self::$argv['path-backups']) && !empty(self::$argv['path-backups'])) {
self::setPathQuarantine(self::$argv['path-backups']);
self::setPathBackups(self::$argv['path-backups']);
}

// Path deobfuscate
if (isset(self::$argv['path-deobfuscate']) && !empty(self::$argv['path-deobfuscate'])) {
self::setPathDeobfuscate(self::$argv['path-deobfuscate']);
}

// Path Whitelist
Expand All @@ -494,11 +507,17 @@ private function arguments($args = null)
}

// Report
self::setReport(!(isset(self::$argv['disable-report']) && self::$argv['disable-report']));
self::setReport(!self::$argv['disable-report']);

// Report mode
self::setReportMode((isset(self::$argv['report']) && self::$argv['report']) || !self::isCli());

// Deobfuscate mode
if (isset(self::$argv['deobfuscate']) && self::$argv['deobfuscate']) {
self::enableDeobfuscateMode();
self::disableReport();
}

// Path report
if (isset(self::$argv['path-report']) && !empty(self::$argv['path-report'])) {
self::setPathReport(self::$argv['path-report']);
Expand Down Expand Up @@ -1063,6 +1082,47 @@ public function scanFile($info)
return $result;
}

/**
* Deobfuscate file.
*
* @param $info
*/
public function deobfuscateFile($info)
{
$filePath = $info->getPathname();

$mimeType = 'text/php';
if (function_exists('mime_content_type')) {
$mimeType = mime_content_type($filePath);
} elseif (function_exists('finfo_open')) {
$finfo = finfo_open(FILEINFO_MIME);
$mimeType = finfo_file($finfo, $filePath);
finfo_close($finfo);
}

if (0 === stripos($mimeType, 'text')) {
$deobfuscator = new Deobfuscator();
$content = php_strip_whitespace($filePath);
$content = $deobfuscator->deobfuscate($content);
$content = $deobfuscator->decode($content);

// TODO: format code

$scanPath = realpath(self::getPathScan());
if (is_file($scanPath)) {
$scanPath = dirname($scanPath);
}
$filePath = self::getPathDeobfuscate() . DIRECTORY_SEPARATOR . str_replace($scanPath, '', realpath($filePath));
$filePath = self::replaceSlash($filePath);
if (!is_dir(dirname($filePath)) &&
(!mkdir($concurrentDirectory = dirname($filePath), 0755, true) && !is_dir($concurrentDirectory))) {
throw new RuntimeException(sprintf('Directory "%s" was not created', $concurrentDirectory));
}

Actions::putContents($filePath, $content);
}
}

/**
* Run index.php.
*
Expand All @@ -1087,6 +1147,13 @@ private function scan($iterator)
$fileExtension = $info->getExtension();
$fileSize = filesize($filePath);

if (self::isDeobfuscateMode()) {
self::$report['scanned']++;
usleep(10);
$this->deobfuscateFile($info);
continue;
}

$isFavicon = self::isInfectedFavicon($info);

if ((
Expand Down Expand Up @@ -1651,6 +1718,45 @@ public static function isCacheEnabled()
return isset(self::$settings['cache']) ? self::$settings['cache'] : true;
}

/**
* @return self
*/
public static function setDeobfuscateMode($mode = true)
{
self::$settings['deobfuscate-mode'] = $mode;
self::enableReport();

return new static();
}

/**
* @return bool
*/
public static function isDeobfuscateMode()
{
return isset(self::$settings['deobfuscate-mode']) ? self::$settings['deobfuscate-mode'] : false;
}

/**
* @return self
*/
public static function enableDeobfuscateMode()
{
self::setDeobfuscateMode(true);

return new static();
}

/**
* @return self
*/
public static function disableDeobfuscateMode()
{
self::setDeobfuscateMode(false);

return new static();
}

/**
* @return self
*/
Expand Down Expand Up @@ -2019,6 +2125,24 @@ public static function setPathBackups($pathBackups)
return new static();
}

/**
* @return string
*/
public static function getPathDeobfuscate()
{
return self::$pathDeobfuscate;
}

/**
* @param string $pathDeobfuscate
*/
public static function setPathDeobfuscate($pathDeobfuscate)
{
self::$pathDeobfuscate = $pathDeobfuscate;

return new static();
}

/**
* @return string
*/
Expand Down Expand Up @@ -2381,4 +2505,19 @@ protected function setLastError($lastError)

return $this;
}

/**
* Replace slash.
*
* @param $path
*
* @return string
*/
public static function replaceSlash($path)
{
$path = str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $path);
$path = preg_replace('/' . preg_quote(DIRECTORY_SEPARATOR, '/') . '+/', DIRECTORY_SEPARATOR, $path);

return $path;
}
}

0 comments on commit 9238b6e

Please sign in to comment.