Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Scanner crash when encountering certain kind of malware #72

Open
kdescoubes opened this issue Mar 13, 2023 · 11 comments
Open

Scanner crash when encountering certain kind of malware #72

kdescoubes opened this issue Mar 13, 2023 · 11 comments
Labels
bug Something isn't working

Comments

@kdescoubes
Copy link

Hi there,

I use your scanner on multiple websites, but some times, it crashes prematurely (like described in issue #46 for example).

So I tried to run the scanner on sub directory until I find THE one which makes the scanner crashed.

I found a malware (attached), I move it to quarantine, then ran the scanner again : it didn't crash !

What's really weird is that if I run the scanner on the quarantine, it doesn't crash ...

(the file was a dot php file of course, renamed it to txt to upload it)

2308ba68.txt

@kdescoubes
Copy link
Author

Same here on another wordpress website :

image

File responsible for the crash is here :

themes.php.txt

I move it to the quarantine, and now the scan is OK.

Again, triggering the scan on the quarantine does not crash the scanner ...

@Borcejn
Copy link

Borcejn commented Oct 11, 2023

Hi kdescoubes,

The problem is in the file: vendor/marcocesarato/amwscan/src/Deobfuscator.php
The following "calc" function is defined in mentioned file:

private function calc($expr)
    {
        if (is_array($expr)) {
            $expr = $expr[0];
        }
        preg_match('~(min|max)?\(([^\)]+)\)~mi', $expr, $exprArr);
        if (!empty($exprArr[1]) && ($exprArr[1] === 'min' || $exprArr[1] === 'max')) {
            return $exprArr[1](explode(',', $exprArr[2]));
        }

        preg_match_all('~([\d\.]+)([\*\/\-\+])?~', $expr, $exprArr);
        if (!empty($exprArr[1]) && !empty($exprArr[2])) {
            if (in_array('*', $exprArr[2], true)) {
                $pos = array_search('*', $exprArr[2], true);
                $res = @$exprArr[1][$pos] * @$exprArr[1][$pos + 1];
                $expr = str_replace(@$exprArr[1][$pos] . '*' . @$exprArr[1][$pos + 1], $res, $expr);
                $expr = $this->calc($expr);
            } elseif (in_array('/', $exprArr[2], true)) {
                $pos = array_search('/', $exprArr[2], true);
                $res = $exprArr[1][$pos] / $exprArr[1][$pos + 1];
                $expr = str_replace($exprArr[1][$pos] . '/' . $exprArr[1][$pos + 1], $res, $expr);
                $expr = $this->calc($expr);
            } elseif (in_array('-', $exprArr[2], true)) {
                $pos = array_search('-', $exprArr[2], true);
                $res = $exprArr[1][$pos] - $exprArr[1][$pos + 1];
                $expr = str_replace($exprArr[1][$pos] . '-' . $exprArr[1][$pos + 1], $res, $expr);
                $expr = $this->calc($expr);
            } elseif (in_array('+', $exprArr[2], true)) {
                $pos = array_search('+', $exprArr[2], true);
                $res = $exprArr[1][$pos] + $exprArr[1][$pos + 1];
                $expr = str_replace($exprArr[1][$pos] . '+' . $exprArr[1][$pos + 1], $res, $expr);
                $expr = $this->calc($expr);
            } else {
                return $expr;
            }
        }

        return $expr;

As you can see, this is a recursive function that - for some reason - has an erroneous stop condition for the file you indicated and goes into very, very deep levels of recursion (in my case, about ~281000 - until the memory on the stack is exhausted).

I haven't had time to disarm this function and analyze the stop condition, but it seems that a simple and sufficient workaround is to add an additional guard in the form:

if($level>100000) return "";

This will interrupt further nesting if it goes too far :)

So, all the correct function code will therefore look as follows:

    private function calc($expr, $level = 0)
    {
		if($level>100000) return "";
		
        if (is_array($expr)) {
            $expr = $expr[0];
        }
        preg_match('~(min|max)?\(([^\)]+)\)~mi', $expr, $exprArr);
        if (!empty($exprArr[1]) && ($exprArr[1] === 'min' || $exprArr[1] === 'max')) {
            return $exprArr[1](explode(',', $exprArr[2]));
        }

        preg_match_all('~([\d\.]+)([\*\/\-\+])?~', $expr, $exprArr);
        if (!empty($exprArr[1]) && !empty($exprArr[2])) {
            if (in_array('*', $exprArr[2], true)) {
                $pos = array_search('*', $exprArr[2], true);
                $res = @$exprArr[1][$pos] * @$exprArr[1][$pos + 1];
                $expr = str_replace(@$exprArr[1][$pos] . '*' . @$exprArr[1][$pos + 1], $res, $expr);
                $expr = $this->calc($expr, $level+1);
            } elseif (in_array('/', $exprArr[2], true)) {
                $pos = array_search('/', $exprArr[2], true);
                $res = $exprArr[1][$pos] / $exprArr[1][$pos + 1];
                $expr = str_replace($exprArr[1][$pos] . '/' . $exprArr[1][$pos + 1], $res, $expr);
                $expr = $this->calc($expr, $level+1);
            } elseif (in_array('-', $exprArr[2], true)) {
                $pos = array_search('-', $exprArr[2], true);
                $res = $exprArr[1][$pos] - $exprArr[1][$pos + 1];
                $expr = str_replace($exprArr[1][$pos] . '-' . $exprArr[1][$pos + 1], $res, $expr);
                $expr = $this->calc($expr,$level+1);
            } elseif (in_array('+', $exprArr[2], true)) {
                $pos = array_search('+', $exprArr[2], true);
                $res = $exprArr[1][$pos] + $exprArr[1][$pos + 1];
                $expr = str_replace($exprArr[1][$pos] . '+' . $exprArr[1][$pos + 1], $res, $expr);
                $expr = $this->calc($expr,$level+1);
            } else {
                return $expr;
            }
        }

        return $expr;
    }

This is completely sufficient (at least for my needs).

I sincerely greet you and warm hugs for the file that helped me to solve this problem,
~WB

@AldoTapiaInnova
Copy link

Hi, @Borcejn
What should I do after changing this piece of code to execute the scanner?

@Borcejn
Copy link

Borcejn commented Oct 19, 2023

@AldoTapiaInnova Just run index.php from src

@stovesy
Copy link

stovesy commented Jan 22, 2024

I too have the same experience. Malware is present, yet the scanner fails. I had to use strace -e trace=file to discover the offending php scan file.
It would be great if the scanner failed with a report, and maybe the file it was last scanning.
Thank you.

@58legend
Copy link

58legend commented Apr 1, 2024

I have the same problem. The scanner "takes off" when it encounters a file.
Change in code "if($level>100000) return "";" did not help
After that, the scanner stopped starting at all.
I changed the file name from PHP to TXT

osjtcnhr.txt

@Borcejn
Copy link

Borcejn commented Apr 7, 2024

@58legend my fix definitely helps (I checked it just now). If the scanner crashed, you did something wrong.
Note you need to replace the entire piece of code, not just add one line...

@58legend
Copy link

58legend commented May 1, 2024

@Borcejn Thank you for your reply. This is very important to me. I appreciate your help.
What I do and what my actions are:

  1. I download the scanner:
    wget https://raw.githubusercontent.com/marcocesarato/PHP-Antimalware-Scanner/master/dist/scanner --no-check-certificate
    (if I scan, the scanner "freezes" on the virus file)
  2. I change lines number 7110-7149 to the code of your function private function calc
  3. After that I started scan and I get an error:
root@ip-172-31-37-200:/home/ubuntu# php7.4 scanner ./virus -r --path-report ./virusscan_$(date +%d-%b-%y).html
PHP Fatal error:  Uncaught PharException: phar "/home/ubuntu/scanner" has a broken signature in /home/ubuntu/scanner:8
Stack trace:
#0 /home/ubuntu/scanner(8): Phar::webPhar()
#1 {main}
  thrown in /home/ubuntu/scanner on line 8

What am i doing wrong?

@Borcejn
Copy link

Borcejn commented May 4, 2024

@58legend oh no, you cannot edit .phar directly. It's like trying to edit a zip/tar archive in notepad :) Instead you need to download all files of this project and then edit mentioned script. After fix run awmscan/src/index.php (you can set "scanner" as an alias for this localization in your environment).

@58legend
Copy link

58legend commented May 9, 2024

I understand what you mean. Downloaded and edited Dist, after this build new phar file.
It works!!! @Borcejn Thank you)
Now I have fixed scanner here:
wget https://raw.githubusercontent.com/58legend/scanner/main/scanner --no-check-certificate
and here my favorite command to scan:
php scanner ./ -r --path-report ./virusscan_$(date +%d-%b-%y).htm

@marcocesarato marcocesarato added the bug Something isn't working label May 10, 2024
@Xolog
Copy link

Xolog commented Jul 4, 2024

@58legend in my case, the scan still crashes for reasons unknown to me ((

I downloaded your version, but the flight did not stop

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

7 participants