Skip to content

Commit

Permalink
Mod. Heuristic always returns SUSPICIOUS severity.
Browse files Browse the repository at this point in the history
Mod. Heuristic always returns SUSPICIOUS severity.
  • Loading branch information
Glomberg authored Mar 5, 2024
2 parents 0d68ea1 + 6b03107 commit 825b339
Show file tree
Hide file tree
Showing 11 changed files with 624 additions and 26 deletions.
14 changes: 3 additions & 11 deletions Controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,21 +76,13 @@ private function scanFileForHeuristic(FileInfo $file_info, $root_path)
// Processing results
if ( !empty($verdict) ) {
$output->weak_spots = $verdict;
$output->severity = (
array_key_exists('CRITICAL', $verdict) ||
array_key_exists('SIGNATURES', $verdict)
)
$output->severity = array_key_exists('SIGNATURES', $verdict)
? 'CRITICAL'
: (
array_key_exists('DANGER', $verdict)
? 'DANGER'
: 'SUSPICIOUS'
);
: 'SUSPICIOUS';
$output->status = (
array_key_exists('CRITICAL', $verdict) ||
array_key_exists('SIGNATURES', $verdict) ||
array_key_exists('SUSPICIOUS', $verdict) ||
array_key_exists('DANGER', $verdict)
array_key_exists('SUSPICIOUS', $verdict)
)
? 'INFECTED'
: 'OK';
Expand Down
31 changes: 16 additions & 15 deletions HeuristicAnalyser.php
Original file line number Diff line number Diff line change
Expand Up @@ -85,25 +85,21 @@ class HeuristicAnalyser
public $looks_safe = false;

private $bad_constructs = array(
'CRITICAL' => array(
'SUSPICIOUS' => array(
'str_rot13',
'syslog',
'eval',
'assert',
'create_function',
'shell_exec',
// 'unserialize',
),
'DANGER' => array(
'system',
'passthru',
'proc_open',
'exec',
'pcntl_exec',
'popen',
'`',
),
'SUSPICIOUS' => array(
'str_rot13',
'syslog',
// 'unserialize',
),
);

Expand Down Expand Up @@ -298,6 +294,11 @@ private function checkFileSize($file_size)
*/
public function processContent()
{
// Skip files does not contain PHP code
if ( $this->extension !== 'php' && ! $this->code_style->hasPHPOpenTags() ) {
return;
}

// Analysing code style
// Do this, only for initial code
if ( ! $this->evaluations->evaluations ) {
Expand Down Expand Up @@ -447,14 +448,14 @@ public function makeVerdict()

// If common bad structures found, then check containment for superglobals
if ($found_malware_key !== false && $this->checkingSuperGlobalsInTheSystemCommands($this->tokens->current)) {
$this->verdict['CRITICAL'][$this->tokens->current->line][] = 'global variables in a sys command';
$this->verdict['SUSPICIOUS'][$this->tokens->current->line][] = 'global variables in a sys command';
break;
}

// If the current token is backtick, so we have to check shell command existing inside the backticks.
if ( $current_token_value === '`' ) {
if ( $this->checkingShellCommand($this->tokens->current) ) {
$this->verdict['CRITICAL'][$this->tokens->current->line][] = 'shell command inside the backticks';
$this->verdict['SUSPICIOUS'][$this->tokens->current->line][] = 'shell command inside the backticks';
}
break;
}
Expand All @@ -471,17 +472,17 @@ public function makeVerdict()
$this->dangerous_decoded_values,
true
);
$this->verdict['CRITICAL'][$this->tokens->current->line][] = $this->dangerous_decoded_values[$found_malware_key];
$this->verdict['SUSPICIOUS'][$this->tokens->current->line][] = $this->dangerous_decoded_values[$found_malware_key];
} elseif ($this->checkingDecryptedToken($this->tokens->current)) {
$this->verdict['CRITICAL'][$this->tokens->current->line][] = 'the function contains suspicious arguments';
$this->verdict['SUSPICIOUS'][$this->tokens->current->line][] = 'the function contains suspicious arguments';
}
}

// Adding bad includes to $verdict['SEVERITY']['string_num'] = 'whole string with include'
foreach ( $this->includes->includes as $include ) {
if ( $include['status'] === false ) {
if ( $include['not_url'] === false && $include['ext_good'] === false ) {
$this->verdict['CRITICAL'][$include['string']][] = substr(
$this->verdict['SUSPICIOUS'][$include['string']][] = substr(
$this->tokens->glueTokens(ExtendedSplFixedArray::createFromArray($include['include'])),
0,
255
Expand Down Expand Up @@ -589,8 +590,8 @@ private function checkingSpecialDecryptedToken(DataStructures\Token $token)
}

return $token->type === 'T_CONSTANT_ENCAPSED_STRING' &&
is_callable(trim((string)$token->value, '\'')) &&
in_array(trim((string)$token->value, '\''), $this->dangerous_decoded_values, true);
is_callable(trim((string)$token->value, '\'')) &&
in_array(trim((string)$token->value, '\''), $this->dangerous_decoded_values, true);
}

private function checkingDecryptedToken(DataStructures\Token $token)
Expand Down
26 changes: 26 additions & 0 deletions Modules/CodeStyle.php
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,32 @@ public function detectBadLines()
return $result;
}

/**
* Check if file contains PHP open tags ("<\?php" or `<\?`).
* @return bool
*/
public function hasPHPOpenTags()
{
foreach ( $this->tokens as $_token => $content ) {
if ( isset($content[0]) && isset($this->tokens->next1[0]) ) {
if ( $content[0] === 'T_OPEN_TAG' ) {
//check if open tag is short
$is_short = isset($content[1]) && $content[1] === '<?';
if (
// should be whitespaces after tag
$is_short && $this->tokens->next1[0] === 'T_WHITESPACE' ||
// should be whitespaces or variable after tag
!$is_short && in_array($this->tokens->next1[0], array('T_WHITESPACE', 'T_VARIABLE'))
) {
return true;
}
}
}
}

return false;
}

private function proportionOfSpecialSymbols()
{
$content = '';
Expand Down
100 changes: 100 additions & 0 deletions tests/Cases/Common/NoPHPCodeTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
<?php

use CleantalkSP\Common\Scanner\HeuristicAnalyser\Controller;
use CleantalkSP\Common\Scanner\HeuristicAnalyser\Structures\FileInfo;
use PHPUnit\Framework\TestCase;

class NoPHPCodeTest extends TestCase
{
private $current_dir;
private $heuristic_scanner;

private $files_list;

public function setUp()
{
$this->current_dir = __DIR__ . DIRECTORY_SEPARATOR . 'files' . DIRECTORY_SEPARATOR;
$this->heuristic_scanner = new Controller();
$this->files_list = array(
'testNoPHPCodeFile' => new FileInfo(
'has_no_php.otf',
file_get_contents($this->current_dir . 'has_no_php.otf')
),
'testNoPHPCodeFileWithShortOpenTag' => new FileInfo(
'has_no_php_but_has_short_open_tag.otf',
file_get_contents($this->current_dir . 'has_no_php_but_has_short_open_tag.otf')
),
'testHasPHPCodeBadFile' => new FileInfo(
'has_bad_php.otf',
file_get_contents($this->current_dir . 'has_bad_php.otf')
),
'testHasPHPCodeBadFileShortOpenTag' => new FileInfo(
'has_bad_php_short_tag.otf',
file_get_contents($this->current_dir . 'has_bad_php_short_tag.otf')
),
'testHasPHPCodeBadFileNoClosingTag' => new FileInfo(
'has_bad_php_no_closing_tag.otf',
file_get_contents($this->current_dir . 'has_bad_php_no_closing_tag.otf')
),
'testHasPHPCodeBadFileOpenSomewhere' => new FileInfo(
'has_bad_php_open_somewhere.otf',
file_get_contents($this->current_dir . 'has_bad_php_open_somewhere.otf')
),
'testHasPHPCodeGoodFile' => new FileInfo(
'has_good_php.otf',
file_get_contents($this->current_dir . 'has_good_php.otf')
),
);
parent::setUp(); // TODO: Change the autogenerated stub
}

public function testNoPHPCodeFile()
{
$verdict = $this->heuristic_scanner->scanFile($this->files_list[__FUNCTION__], $this->current_dir);
$this->assertEquals('OK', $verdict->status);
$this->assertEquals(null, $verdict->severity);
}

public function testNoPHPCodeFileWithShortOpenTag()
{
$verdict = $this->heuristic_scanner->scanFile($this->files_list[__FUNCTION__], $this->current_dir);
$this->assertEquals('OK', $verdict->status);
$this->assertEquals(null, $verdict->severity);
}
public function testHasPHPCodeBadFile()
{
$verdict = $this->heuristic_scanner->scanFile($this->files_list[__FUNCTION__], $this->current_dir);
$this->assertEquals('INFECTED', $verdict->status);
$this->assertEquals('SUSPICIOUS', $verdict->severity);
}

public function testHasPHPCodeBadFileNoClosingTag()
{
$verdict = $this->heuristic_scanner->scanFile($this->files_list[__FUNCTION__], $this->current_dir);
$this->assertEquals('INFECTED', $verdict->status);
$this->assertEquals('SUSPICIOUS', $verdict->severity);
}

public function testHasPHPCodeBadFileOpenSomewhere()
{
$verdict = $this->heuristic_scanner->scanFile($this->files_list[__FUNCTION__], $this->current_dir);
$this->assertEquals('INFECTED', $verdict->status);
$this->assertEquals('SUSPICIOUS', $verdict->severity);
}

public function testHasPHPCodeBadFileShortOpenTag()
{
if ( ini_get('short_open_tag') ) {
$verdict = $this->heuristic_scanner->scanFile($this->files_list[__FUNCTION__], $this->current_dir);
$this->assertEquals('INFECTED', $verdict->status);
$this->assertEquals('SUSPICIOUS', $verdict->severity);
}
}

public function testHasPHPCodeGoodFile()
{
$verdict = $this->heuristic_scanner->scanFile($this->files_list[__FUNCTION__], $this->current_dir);
$this->assertEquals('OK', $verdict->status);
$this->assertEquals(null, $verdict->severity);
}
}
96 changes: 96 additions & 0 deletions tests/Cases/Common/files/has_bad_php.otf
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<?php
$code = eval('$a=$b;');
?>
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malwaresome text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware

some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware
some text not contains malware


Loading

0 comments on commit 825b339

Please sign in to comment.