51 Commits

Author SHA1 Message Date
Gabor Gyorvari
ba466dc1ff Sample update from #94 and some found in servers 2026-02-24 06:58:29 +01:00
Gabor Gyorvari
201ab77516 Sample update from #94 2025-06-09 20:28:26 +02:00
Gabor Gyorvari
46024eca5e Merge remote-tracking branch 'origin/master' 2025-05-15 17:55:32 +02:00
Gabor Gyorvari
a31cc18dc5 Sample update from #93 2025-05-15 17:55:25 +02:00
Győrvári Gábor
96806c69e9 Merge pull request #92 from edward-rafalovsky/feature/add-docker-support
Add Docker support with documentation
2024-12-05 06:44:14 +01:00
Edward Rafalovsky
42c2aad685 Add Docker support with documentation 2024-12-04 23:41:36 +01:00
Gabor Gyorvari
cad03dc3b4 Javascript sample update in #91 2024-07-08 17:55:38 +02:00
Gabor Gyorvari
c542a745e4 Sample update 2024-05-22 14:16:44 +02:00
Gabor Gyorvari
7ac65c0c8d Hide error arg fix 2024-05-22 14:04:07 +02:00
Gabor Gyorvari
5061e319e3 Sample update 2024-05-22 14:03:43 +02:00
Gabor Gyorvari
b2b2c4b081 Small typo, fix #88 2023-07-26 12:39:34 +02:00
Gabor Gyorvari
26458d20af Sample update 2023-05-14 08:59:43 +02:00
Gabor Gyorvari
70edc4210d Sample update 2023-05-14 08:45:20 +02:00
Gabor Gyorvari
aec0f56af5 Sample update 2023-02-25 07:47:30 +01:00
Gabor Gyorvari
2e8b9c604f Merge remote-tracking branch 'origin/master' 2022-11-18 14:10:57 +01:00
Gabor Gyorvari
802ead97cc Flag usage fix about wordpress version checksum 2022-11-18 14:10:45 +01:00
Győrvári Gábor
4666a101f9 Merge pull request #81 from Fot0n/patch-1
Make it compatible with php 8.1
2022-09-19 12:51:07 +02:00
Fot0n
e4755feeef Make it compatible with php 8.1
strftime was deprecated.
2022-09-19 13:49:05 +03:00
Gabor Gyorvari
920cf8a4c6 Backdoor script samples 2022-08-17 18:52:03 +02:00
Gabor Gyorvari
aa774f4330 Another obfuscated malware check 2022-08-09 09:18:07 +02:00
Győrvári Gábor
cd1164dbb5 Merge pull request #80 from elliotkendall/master
Cast $needle in calls to strpos/stripos to string to avoid automatic …
2022-07-25 19:15:19 +02:00
Elliot Kendall
77ebd8abd7 Cast $needle in calls to strpos/stripos to string to avoid automatic ordinal conversion of integer patterns 2022-07-25 09:52:27 -07:00
Gabor Gyorvari
29e6c73558 Webshell matching pattern update 2022-07-22 11:28:18 +02:00
Gabor Gyorvari
bf13288367 Nested function call pattern update 2022-07-17 08:17:20 +02:00
Gabor Gyorvari
088c0761b3 Pattern update about new infections found 2022-07-14 19:59:23 +02:00
Gabor Gyorvari
18b06fc48b Whitelist update and two little pattern fix, reported in #78 2022-07-11 20:03:53 +02:00
Gabor Gyorvari
f1b8b89ca5 Samples update, reported in #77 2022-07-07 14:42:37 +02:00
Gabor Gyorvari
c6a52dc67e Whitelist update, reported in #76 2022-06-30 20:55:37 +02:00
Gabor Gyorvari
3b76a7270e Backdoor reported in #72 2022-03-24 18:46:58 +01:00
Gabor Gyorvari
f0bdb1f1e1 Backdoor reported in #71 2021-12-13 18:09:02 +01:00
Gabor Gyorvari
43876b337b Pattern updates from new infections 2021-05-27 06:57:08 +02:00
Gabor Gyorvari
1fad164790 gzipped payload 2021-05-27 06:57:08 +02:00
Gabor Gyorvari
f4d53e89d8 Pattern updates from new infections 2021-05-27 06:57:08 +02:00
Gabor Gyorvari
34ea02323b New flag to specify custom white list file 2021-04-01 12:44:15 +02:00
Gabor Gyorvari
b74494a4f1 base64 sample for "file" too short and causes false positive 2021-02-26 13:27:58 +01:00
Gabor Gyorvari
9624ec4403 README update with new -r flag 2021-02-24 16:47:13 +01:00
Győrvári Gábor
335b13b7c4 Merge pull request #67 from mitchobrian/master
Feature flagHideErr #66
2021-02-24 16:45:34 +01:00
Michael Palmer
78bee49176 https://github.com/scr34m/php-malware-scanner/issues/66 2021-02-24 13:36:10 +01:00
Győrvári Gábor
cc0fdc7a9f Merge pull request #63 from aldavigdis/patch-1
Adding definitions based on recent code injection
2020-11-17 08:07:52 +01:00
Alda Vigdis Skarphedinsdottir
ec8f9920ba Adding definitions based on recent code injection 2020-11-17 04:06:03 +01:00
Gabor Gyorvari
5883c68f54 Small example how to use as library, fix #61 2020-10-05 13:34:16 +02:00
Gabor Gyorvari
22b51a1ee3 Change addWordpressChecksums to public, fix #58 2020-10-05 10:59:13 +02:00
Gabor Gyorvari
2b1a0c1266 Signature update from new infections 2020-10-01 11:26:02 +02:00
Gabor Gyorvari
c495cc822c Signature update for a pattern $_uU(101).$_uU(118).$_uU(97) 2020-09-30 17:02:33 +02:00
Gabor Gyorvari
e9a45d4bdc Allowing multiple use of -d option and braces in path syntax, closes #56 2020-08-18 15:36:52 +02:00
Gabor Gyorvari
21185202f3 Combined whitelist updated 2020-06-25 17:10:40 +02:00
Győrvári Gábor
195717d625 Merge pull request #55 from scr34m/libmode
Change function visibility to allow usage as library
2020-06-24 10:17:19 +02:00
Gabor Gyorvari
2973e55871 Change function visibility to allow usage as library 2020-06-23 19:37:29 +02:00
Gabor Gyorvari
8b1994956e Whitelist for sucuri-scanner wordpress plugin reported in #54 2020-03-08 17:13:29 +01:00
Győrvári Gábor
46faa31c74 Merge pull request #52 from cbotsikas/fix-php-support
Use array() instead of the short array syntax []
2019-07-24 16:32:18 +02:00
Christos Botsikas
d67a865bf0 Use array() instead of the short array syntax []
Short array syntax [] was added in PHP 5.4 but the scanner should be able to work with [PHP >=5.2.0](https://github.com/scr34m/php-malware-scanner/blob/master/composer.json#L9).
2019-07-24 12:32:59 +02:00
8 changed files with 442 additions and 126 deletions

15
Dockerfile Normal file
View File

@@ -0,0 +1,15 @@
FROM php:8.2-cli
# Install dependencies
RUN apt-get update && apt-get install -y \
git \
unzip \
libzip-dev \
&& docker-php-ext-install zip
WORKDIR /scanner
COPY . .
RUN chmod +x scan
ENTRYPOINT ["./scan"]
CMD ["/code"]

View File

@@ -26,6 +26,7 @@ Usage: php scan.php -d <directory>
-x --extra-check Adds GoogleBot and htaccess to Scan List
-l --follow-symlink Follow symlinked directories
-k --hide-ok Hide results with 'OK' status
-r --hide-err Hide results with 'ER' status
-w --hide-whitelist Hide results with 'WL' status
-n --no-color Disable color mode
-s --no-stop Continue scanning file after first hit
@@ -33,8 +34,9 @@ Usage: php scan.php -d <directory>
-t --time Show time of last file change
-L --line-number Display matching pattern line number in file
-o --output-format Custom defined output format
-j --wordpress-version Version of wordpress to get md5 signatures
-j <version> --wordpress-version Version of wordpress to get md5 signatures
--combined-whitelist Combined whitelist
--custom-whitelist Loads whitelist from specified file and merge with existing
--disable-stats Disable statistics output
```
@@ -113,6 +115,22 @@ It is guaranteed that IF 'base64_decode' was present in the plain text code, the
The presence of 'YmFzZTY0X2RlY29kZ' in a block of code may be because 'ase64_decod' was in the original code.
ote the missing edge characters which is due to bit misalignment and character bleed.
Using as library
----------------
The scan.php perform a check, that it's called by commandline or not, so to use as library use different directory than scan.php it self.
```php
<?php
require_once '../scan.php';
$scan = new MalwareScanner();
$scan->setFlagHideWhitelist(true);
$scan->setFlagHideOk(true);
$scan->run('../samples/test');
```
Resources
---------
@@ -128,3 +146,37 @@ Licensing
---------
PHP malware scanner is [licensed](https://github.com/scr34m/php-malware-scanner/blob/master/LICENSE.txt) under the GNU General Public License v3.
Docker Usage
-----------
You can also run the scanner using Docker:
1. Build the image:
```bash
docker build -t php-malware-scanner .
```
2. Scan a directory:
```bash
docker run -v /path/to/scan:/code php-malware-scanner -d /code
```
For example, to scan a WordPress installation:
```bash
docker run -v /var/www/html:/code php-malware-scanner -d /code -j 6.4.1
```
Common usage with flags:
```bash
# Show only infected files (hide OK status)
docker run -v /path/to/scan:/code php-malware-scanner -d /code -k
# Show comments for matched patterns
docker run -v /path/to/scan:/code php-malware-scanner -d /code -c
# Show MD5 hashes and continue after first match
docker run -v /path/to/scan:/code php-malware-scanner -d /code -m -s
```
The `/code` directory inside the container is where your files will be mounted for scanning.

View File

@@ -1,7 +1,7 @@
#This file contains raw strings that will be matched case-insensitive.
#Comments and whitespace are possible, but comments must have '#' at the first character of the line.
# This file contains raw strings that will be matched case-insensitive.
# Comments and whitespace are possible, but comments must have '#' at the first character of the line.
#List of security service providers that phishers often block.
# List of security service providers that phishers often block.
abovenet
avira
bitdefender
@@ -16,4 +16,48 @@ opendns
phishtank
sophos
surfright
symantec
# symantec - removed because already a TLD too so generate many false positives
# SEO poison, pharmacy redirect
dealonline.su
# functions escaped as hexadecimal string
7068705f756e616d65
70687076657273696f6e
6368646972
676574637764
707265675f73706c6974
636f7079
66696c655f6765745f636f6e74656e7473
6261736536345f6465636f6465
69735f646972
6f625f656e645f636c65616e28293b
756e6c696e6b
6d6b646972
63686d6f64
7363616e646972
7374725f7265706c616365
68746d6c7370656369616c6368617273
7661725f64756d70
666f70656e
667772697465
66636c6f7365
64617465
66696c656d74696d65
737562737472
737072696e7466
66696c657065726d73
746f756368
66696c655f657869737473
72656e616d65
69735f6172726179
69735f6f626a656374
737472706f73
69735f7772697461626c65
69735f7265616461626c65
737472746f74696d65
66696c6573697a65
726d646972
6f625f6765745f636c65616e
7265616466696c65
617373657274

View File

@@ -22,14 +22,23 @@ SHELL_PASSWORD
ConnectBackShell
ShellBOT
== "bindshell"
".\x00..\x20"
FM_SESSION_ID
HACKED BY
_Mybb
#Remote Code
curl_get_from_webpage
file_get_contents('http://codepad.org
#mailers
leafmailer.pw
#Base64 String Samples. Each plain text string should have 3 base64 equivalents
# https://
aHR0cHM6Ly
# "shell" in base64
c2hlbG
NoZWxs
@@ -108,11 +117,6 @@ SFRUUF9VU0VSX0FHRU5U
hUVFBfVVNFUl9BR0VOV
IVFRQX1VTRVJfQUdFTl
# "file" in base64
ZmlsZ
ZpbG
maWxl
# "gzinflate" in base64
Z3ppbmZsYXRl
d6aW5mbGF0Z
@@ -184,14 +188,23 @@ RlZmluZ
kZWZpbm
# Obfuscation related code
'.'6'.'4'.'_'.'
bas'.'e64_dec
file'.'_put_co
fil'.'e_ex
Pz4=
L3gvaQ==
eval("?>
eval('?>
@eval(
"base64_decode"
='base'.(32*2).'_de'.'code'
"p"."r"."e"."g"."_"
WSOstripslashes
\x73\x79\x73\x74\x65\x6d' /* case, dec/hex issue? */, // system
\x70\x72\x65\x67\x5f\x72\x65\x70\x6c\x61\x63\x65' /* case, dec/hex issue? */, // preg_replace
\x65\x78\x65\x63' /* dec/hex issue? */, // exec
\x5f\x43\x4f\x4f\x4b\x49\x45
\x73\x79\x73\x74\x65\x6d
\x70\x72\x65\x67\x5f\x72\x65\x70\x6c\x61\x63\x65
\x65\x78\x65\x63
ev\x61l
\x65\166\x61\154\x28' /* dec/hex issue? */,
\x65\x76\x61\x6C' /* case, dec/hex issue? */,
@@ -201,11 +214,24 @@ eval(base64_decode(
$data = base64_decode("
edoced_46esab
base=base64_encode
'b'.'ase6'.'4_e'.'ncode'
cr"."eat"."e_fun"."cti"."on
gz'.'inf'.'late
@eval("\
";eval(
eval(eval(
@eval(`
eVaL('?>
eval($_REQUEST
convert_uudecode(convert_uuencode
"64_decode"
'f' . 'il' . 'e' . '_'
'co' . 'nt' . 'e' . 'nt'
'h' . 'tm' . 'l' . 'sp'
'ha' . 'r' . 's'
# fopo.com.ar - free online php obfuscator. It conveniently leaves comments in the code.
http://www.fopo.com.ar/
@eval("\
#Malware/Attack specific strings/fingerprints/signatures
MagelangCyber
@@ -260,6 +286,16 @@ itsoknoproblembro
tmhapbzcerff
IndoXploit
FaisaL Ahmed aka rEd X
smisbot
smotherbot
Indonesian Hacker Rulez
pwetan.com
iNHUMaN
Heartzz
Bye Bye Litespeed
BunnyInvisible
SEMOGABERKAH
BUTERFLYCOUNTRY
# WP-VCD Malware https://www.getastra.com/blog/911/how-to-fix-wp-vcd-backdoor-hack-in-wordpress-functions-php/
wp-vcd
@@ -357,6 +393,7 @@ php_uname()
str_split(rawurldecode(str_rot13(
# generating PHP file name to put content
substr(md5(time()), 0, 8) . ".php"
'a:1:{s:13:\"administrator\";b:1;}'
# webshell
0byt3m1n1
@@ -371,3 +408,63 @@ ZeroByte
# JS escaped: String.fromCharCode(
83, 116, 114, 105, 110, 103, 46, 102, 114, 111, 109, 67, 104, 97, 114, 67, 111, 100, 101, 40
# SEO poisoning control site call
"http://$xxx
?useragent=$botbotbot
[#*#*#]
# php://input encoded in base64
cGhwOi8vaW5wdXQ=
# backdoor script
<font color="red">Upload Gagal..</font><br />
explode('?>',$shell
0.33333333333333+0.33333333333333+0.33333333333333
0.66666666666667+0.66666666666667+0.66666666666667
1.3333333333333+1.3333333333333+1.3333333333333
class _t{private static$_
'LQ'.'=='
# common mobile agent check in SEO poison scripts
Array("1207", "3gso", "4thp", "501i", "502i", "503i", "504i", "505i", "506i",
# eval url decoded string
eval(rawurldecode('
eval(htmlspecialchars_decode(
# simple obfuscated function
'gz'.'unc'.'ompress'
'create'.'_'.'function'
'gzinf', 'la', 'te'
'e_f', 'cti', 'un', 'on', 'cr', 'eat'
'base', '64_dec', 'ode'
'cook', 'set', 'ie'
'repl', 'str_', 'ace'
"base"."64_"
'base'.'64_'
"t"."m"."p"."_"."n"."a"."m"."e"
"f"."i"."l"."e"."_"."p"."u"."t"
"f"."i"."l"."e"."_"."g"."e"."t"
'ode', 'e64_', 'bas', 'dec'
'unct', 'ion', 'te_f', 'crea'
'te', 'g', 'nf', 'l', 'a', 'zi'
'tion', 'e_func', 'creat'
'64_d', 'se', 'eco', 'de', 'ba'
'co', 'ki', 'e', 'o', 'set'
'str', '_rep', 'lace'
# process data from request object directly
extract($_REQUEST) && @$
extract($_REQUEST)&&@$
xtract($_REQUEST)&&@$
# uncompress cafted content
gzuncompress(strrev(substr(
# disable error reporting
<?php error_reporting(0);?>
# infected file include attached on the top of a legit file
<?php if (file_exists(dirname(__FILE__) . '/class.theme-modules.php')) include_once(dirname(__FILE__) . '/class.theme-modules.php'); ?>
<?php if (file_exists(dirname(__FILE__) . '/class.plugin-modules.php')) include_once(dirname(__FILE__) . '/class.plugin-modules.php'); ?>

View File

@@ -4,10 +4,13 @@ eval\/\*[a-z0-9]+\*\/
#
eval\([a-z0-9]{4,}\(\$[a-z0-9]{4,}, \$[0-9a-z]{4,}\)\);
#
# chr(101).chr(118).chr(97)
(chr\(\d+\^\d+\)\.){4,}
#
# $_uU(101).$_uU(118).$_uU(97)
(\$\_[a-z0-9]{2,}\(\d+\)\.){4,}
# $uUx[101].$uUx[118].$uUx[97]
(\$[a-z0-9]{3,}\[\d+\]\.){4,}
#
@@ -37,6 +40,9 @@ Googlebot['"]{0,1}\s*\)\){echo\s+file_get_contents
#execute base64 code
eVaL\(\s*trim\(\s*baSe64_deCoDe\(
# execute escaped code
exec\("(\\[0-9a-fx]{2,3}){3,}
#
if\s*\(\s*mail\s*\(\s*\$mails\[\$i\]\s*,\s*\$tema\s*,\s*base64_encode\s*\(\s*\$text
@@ -54,7 +60,7 @@ chr\s*\(\s*101\s*\)\s*\.\s*chr\s*\(\s*118\s*\)\s*\.\s*chr\s*\(\s*97\s*\)\s*\.\s*
#Detects the '_' character encoded in a string like "\x5F". '_' is present in many functions that malware would want to hide.
# '_' as "\x5f"
\\[Xx](5[Ff])
# \\[Xx](5[Ff]) - removed because generate many false positives
#Detects the '_' character placed inside a call to the 'chr()' function
# '_' as 'chr(95)' or 'chr(0x5f)'
@@ -73,7 +79,7 @@ chr\s*\(\s*['"]?\s*((95)|(0[Xx]5[Ff]))\s*['"]?\s*\)
#Escaped path characters: \x2fho\x6de/\x69mp\x75ls\x69oq\x65/w\x77w. or \x2fhome\x2fimpu\x6csioq\x65/www\x2emusc
(\\x[0-9abcdef]{2}[a-z0-9.-\/]{1,4}){4,}
#Malware inffected files sometimes marked with comments like /*87cda*/ to avoid infect again
#Malware infected files sometimes marked with comments like /*87cda*/ to avoid infect again
\/\*[a-z0-9]{5}\*\/
# XOR-ed strings with custom math
@@ -89,7 +95,7 @@ eval\(\$[a-z0-9_]+\(\$_POST
("[a-z0-9]+"\.chr\(\d+\)\.){3,}
# nested function call used variables
\$[a-z]+\(\$[a-z0-9]+\(
\$[a-z0-9_]+\(\$[a-z0-9_]+\(
# GLOBALS inject with escaped content
\$GLOBALS;\$\{"\\x
@@ -107,4 +113,55 @@ function\s+_[0-9]{8,}\(
@include ".*?(\\x[0-9a-f]{2,}.*?){2,}.*?";
# create_function is dangerous as like eval() see http://php.net/manual/en/function.create-function.php
create_function\s*\(\s*['"]{2}
create_function\s*\(\s*['"]{2}
# control concated from cookie at the call
(\$[a-z]{2,}=urldecode\(\$_COOKIE\['[a-z]{2,}'\]\);){3,}
# ${$O{18}.$O{7}.$O{24}.$O{2}.$O{50}.$O{8}
(\$[A-Z]+\{\d+\}\.){3,}
# comment in variable name $_REQUEST /*YUsrqpbzvXTSa...QpDNTPYQvLSFPCqsSnWNVqPdSIAYaQj*/[
\$_REQUEST\s*\/\*[A-Za-z]+\*\/\[
# cookie payload if(isset($_COOKIE)){$p=$_COOKIE;(count($p)==55&&in_array(gettype($p).count($p),$p))?(($p[68]=$p[68].$p[22])&&($p[35]=$p[68]($p[35]))&&($p=$p[35]($p[13],$p[68]($p[45])))&&$p()):$p;}
\(count\(\$p\)==\d+&&in_array\(gettype\(\$p\)\.count\(\$p\),\$p\)\)
# gzipped payload post process
explode\('\|\x01\|\x03\|\x03', gzinflate\(
# backdoor reported #71
@header\(\w{3,5}::\w{1,2}\('_\w{1,3}' \. '\w{1,3}', '_\w{1,3}'\)\);
@header\(\w{3,5}::\w{1,2}\('_\w{1,3}', '_' \. '\w{1,3}' . '\w{1,3}'\)\);
# backdoor reported #72
@\$[a-z]{1}\[\d+\]\(\$[a-z]{1}\[\d+\]\);
# reported #77
\$[a-z]11 \^ [a-z]8\(\$[a-z]6, \$[a-z]14, \$[a-z]6\[13\]\(\$[a-z]11\)\)\)\);
# eval function return and concat
eval\([A-Za-z0-9]{5,}\(\) \. '
# eval function return, parameter is a hex string
eval\([A-Za-z0-9]{5,}\(\"[A-Z0-9]{16,}
eval\(\s+'\?>'
# gzip payload called by variable named function
\$[a-zA-Z0-9]{6,}\('\x78\x9C\xAD\x90\x41\x0E
# obfuscated code return with error suppression
return @\$[a-z]{2}\d+\[\d+\]\(\$[a-z]{2}\d+\[\d+\],
# htaccess alternating
[a-z]{1}\([a-z]{1}\(\$[a-z]{2}\.'\/\.htaccess'\)
# Javascript specific rules
# JS - escaped command
\.fromCharCode\([0-9,]{4,}\)
\+-parseInt\(\w\('0x[0-9a-z]+'\)\)\/
# concated hash value
('[a-z0-9]{2,}'\.){4,}

133
scan.php
View File

@@ -2,13 +2,13 @@
/*
* Copyright (c) 2016 Gabor Gyorvari
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -31,6 +31,7 @@ class MalwareScanner
private $flagChecksum = false;
private $flagComments = false;
private $flagHideOk = false;
private $flagHideErr = false;
private $flagHideWhitelist = false;
private $flagNoStop = false;
private $flagPattern = false;
@@ -41,6 +42,7 @@ class MalwareScanner
private $flagScanEverything = false;
private $flagCombinedWhitelist = false;
private $flagDisableStats = false;
private $customWhitelist = array();
private $outputFormat = '';
private $whitelist = array();
private $ignore = array();
@@ -69,16 +71,31 @@ class MalwareScanner
if ($cli === true) {
//Read Run Options
$this->parseArgs();
$this->dir = realpath($this->dir);
$dirs = array();
if (is_array($this->dir)) {
// allow multiple directory aka. array
foreach ($this->dir as $path) {
$dirs[] = realpath($path);
}
} elseif ($bpos = strpos($this->dir, '{')) {
// Check path has a "brace", expand it to subdirectories
foreach (glob($this->dir, GLOB_BRACE) as $path) {
$dirs[] = realpath($path);
}
} else {
// only one directory specified
$dirs = array (realpath($this->dir));
}
//Make sure a directory was specified.
if ($this->dir === '') {
if (empty($dirs)) {
$this->error('No directory specified or directory doesn\'t exist');
exit(-1);
}
//Initiate Scan
if (!$this->run($this->dir)) {
if (!$this->run($dirs)) {
exit(-1);
}
}
@@ -104,7 +121,7 @@ class MalwareScanner
}
//Handles pattern loading and saving to the class object
private function initializePatterns()
public function initializePatterns()
{
$dir = dirname(__FILE__);
//Loads either the primary scanning patterns or the base64 patterns depending on -b/--base64 flag
@@ -175,20 +192,25 @@ class MalwareScanner
return $list;
}
//Loads the whitelist file
private function loadWhitelist()
/**
* Loads the whitelist files
*/
public function loadWhitelists()
{
if (!is_file(__DIR__ . '/whitelist.txt')) {
return;
}
$fp = fopen(__DIR__ . '/whitelist.txt', 'r');
while (!feof($fp)) {
$line = fgets($fp);
$this->whitelist[] = substr($line, 0, 32);
$a = array_merge([__DIR__ . '/whitelist.txt'], $this->customWhitelist);
foreach ($a as $file) {
if (is_file($file)) {
$fp = fopen($file, 'r');
while (!feof($fp)) {
$line = fgets($fp);
$this->whitelist[] = substr($line, 0, 32);
}
fclose($fp);
}
}
}
private function addWordpressChecksums($wp_version)
public function addWordpressChecksums($wp_version)
{
$apiurl = 'https://api.wordpress.org/core/checksums/1.0/?version=' . $wp_version;
$json = json_decode(file_get_contents($apiurl));
@@ -209,7 +231,7 @@ class MalwareScanner
private function parseArgs()
{
$options = getopt(
'd:e:i:o:abmcxlhkwnsptLj:E',
'd:e:i:o:abmcxlhkrwnsptLj:E',
array(
'directory:',
'extension:',
@@ -222,6 +244,7 @@ class MalwareScanner
'follow-link',
'help',
'hide-ok',
'hide-err',
'hide-whitelist',
'no-color',
'no-stop',
@@ -232,6 +255,7 @@ class MalwareScanner
'wordpress-version:',
'scan-everything',
'combined-whitelist',
'custom-whitelist:',
'disable-stats'
)
);
@@ -283,6 +307,9 @@ class MalwareScanner
if (isset($options['hide-ok']) || isset($options['k'])) {
$this->setFlagHideOk(true);
}
if (isset($options['hide-err']) || isset($options['r'])) {
$this->setFlagHideErr(true);
}
if (isset($options['hide-whitelist']) || isset($options['w'])) {
$this->setFlagHideWhitelist(true);
}
@@ -315,6 +342,13 @@ class MalwareScanner
if (isset($options['combined-whitelist'])) {
$this->setFlagCombinedWhitelist(true);
}
if (isset($options['custom-whitelist'])) {
$a = $options['custom-whitelist'];
if (!is_array($a)) {
$a = array($a);
}
$this->setCustomWhitelist(array_unique($a));
}
if (isset($options['disable-stats'])) {
$this->setFlagDisableStats(true);
}
@@ -381,6 +415,11 @@ class MalwareScanner
$this->flagHideOk = $b;
}
public function setFlagHideErr($b)
{
$this->flagHideErr = $b;
}
public function setFlagHideWhitelist($b)
{
$this->flagHideWhitelist = $b;
@@ -411,6 +450,11 @@ class MalwareScanner
$this->flagDisableStats = $b;
}
public function setCustomWhitelist($a)
{
$this->customWhitelist = $a;
}
// @see http://stackoverflow.com/a/13914119
private function pathMatches($path, $pattern, $ignoreCase = false)
{
@@ -475,6 +519,9 @@ class MalwareScanner
$state = 'WL';
$state_color = $this->ANSI_YELLOW;
} else {
if ($this->flagHideErr) {
return;
}
$state = 'ER';
$state_color = $this->ANSI_RED;
}
@@ -511,7 +558,7 @@ class MalwareScanner
}
if ($this->outputFormat) {
$map = [
$map = array(
'%S' => $state,
'%T' => $ctime,
'%M' => $hash,
@@ -519,9 +566,9 @@ class MalwareScanner
'%P' => $pattern,
'%C' => $comment,
'%L' => $lineNumber,
];
);
} else {
$map = [
$map = array(
'%S' => $state_color . '# ' . $state . $this->ANSI_OFF,
'%T' => $this->ANSI_BLUE . $ctime . $this->ANSI_OFF,
'%M' => $this->ANSI_BLUE . $hash . $this->ANSI_OFF,
@@ -529,7 +576,7 @@ class MalwareScanner
'%P' => $state_color . '#' . $pattern . $this->ANSI_OFF,
'%C' => $this->ANSI_BLUE . $comment . $this->ANSI_OFF,
'%L' => $lineNumber,
];
);
}
if ($this->outputFormat) {
@@ -576,8 +623,8 @@ class MalwareScanner
private function report($start, $dir)
{
$end = time();
echo 'Start time: ' . strftime('%Y-%m-%d %H:%M:%S', $start) . PHP_EOL;
echo 'End time: ' . strftime('%Y-%m-%d %H:%M:%S', $end) . PHP_EOL;
echo 'Start time: ' . date('Y-m-d H:m:s', $start) . PHP_EOL;
echo 'End time: ' . date('Y-m-d H:m:s', $end) . PHP_EOL;
echo 'Total execution time: ' . ($end - $start) . PHP_EOL;
echo 'Base directory: ' . $dir . PHP_EOL;
echo 'Total directories scanned: ' . $this->stat['directories'] . PHP_EOL;
@@ -592,30 +639,37 @@ class MalwareScanner
* - Fetch and load combined whitelist
* - Calls the process and report functions.
*
* @param $dir
* @param string|array $dir A directory path or a list of paths in array
* @return bool
*/
public function run($dir)
{
// Make sure the input is a valid directory path.
$dir = rtrim($dir, '/');
if (!is_dir($dir)) {
$this->error('Specified path is not a directory: ' . $dir);
return false;
}
$this->initializePatterns();
$this->loadWhitelist();
$this->loadWhitelists();
if ($this->flagCombinedWhitelist && !$this->updateCombinedWhitelist()) {
return false;
}
$start = time();
$this->process($dir . '/');
if (!is_array($dir)) {
$dir = array ($dir);
}
foreach ($dir as $path) {
// Make sure the input is a valid directory path.
$path = rtrim($path, '/');
if (!is_dir($path)) {
$this->error('Specified path is not a directory: ' . $path);
return false;
}
$this->process($path . '/');
}
if (!$this->flagDisableStats) {
$this->report($start, $dir . '/');
$this->report($start, implode(', ', $dir));
}
return true;
}
@@ -656,14 +710,14 @@ class MalwareScanner
//Returns true if the raw string exists in the file contents.
private function scanFunc_STR(&$pattern, &$content)
{
return strpos($content, $pattern);
return strpos($content, (string)$pattern);
}
//Performs raw string, case insensitive matching.
//Returns true if the raw string exists in the file contents, ignoring case.
private function scanFunc_STRI(&$pattern, &$content)
{
return stripos($content, $pattern);
return stripos($content, (string)$pattern);
}
//Performs regular expression matching.
@@ -769,7 +823,7 @@ class MalwareScanner
}
$content = gzdecode(file_get_contents($file));
$this->combined_whitelist = [];
$this->combined_whitelist = array();
$this->combined_whitelist_count = 0;
foreach (explode("\n", $content) as $line) { // faster than strtok, but needs more memory
if ($line) {
@@ -798,6 +852,7 @@ class MalwareScanner
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 results with \'OK\' status' . PHP_EOL;
echo ' -r --hide-err Hide results with \'ER\' status' . PHP_EOL;
echo ' -w --hide-whitelist Hide results with \'WL\' status' . PHP_EOL;
echo ' -n --no-color Disable color mode' . PHP_EOL;
echo ' -s --no-stop Continue scanning file after first hit' . PHP_EOL;
@@ -805,7 +860,7 @@ class MalwareScanner
echo ' -t --time Show time of last file change' . PHP_EOL;
echo ' -L --line-number Display matching pattern line number in file' . PHP_EOL;
echo ' -o --output-format Custom defined output format' . PHP_EOL;
echo ' -j --wordpress-version Version of wordpress to get md5 signatures' . PHP_EOL;
echo ' -j <version> --wordpress-version Version of wordpress to get md5 signatures' . PHP_EOL;
echo ' --combined-whitelist Combined whitelist' . PHP_EOL;
echo ' --disable-stats Disable statistics output' . PHP_EOL;

View File

@@ -15,8 +15,8 @@ function fetch($url, $file = false)
$headers = array(
// drupal suxx
'Cookie: pxvid=44e1b040-4dde-11e8-b1dc-f15e898556c7; _ga=GA1.2.2042202377.1525247839; _gat=1; _gid=GA1.2.1601332121.1550831838; _px2=eyJ1IjoiZDM3OTk1MDAtMzY4ZC0xMWU5LWI3MDItYTdlMDI1ZWZhZmI2IiwidiI6IjQ0ZTFiMDQwLTRkZGUtMTFlOC1iMWRjLWYxNWU4OTg1NTZjNyIsInQiOjE1NTA4MzIxMzc5MjcsImgiOiJjMjBhNTQzNGIxYWQwNWFiOWUzNTI2OWRjNTM1MjgzNjkxNzg5OTIxNGM4YmIzZDBkZTg5ZTIxMzY0NTc5Zjk3In0=; has_js=1; _pxvid=44e1b040-4dde-11e8-b1dc-f15e898556c7',
'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0.3 Safari/605.1.15',
'Cookie: _px2=eyJ1IjoiZDZhNGM3MjAtYjZmNC0xMWVhLWI2MzMtNzk5YzRmZjM4ZmJkIiwidiI6IjQ0ZTFiMDQwLTRkZGUtMTFlOC1iMWRjLWYxNWU4OTg1NTZjNyIsInQiOjE1OTMwOTc2Mjg2NzAsImgiOiIzNzk5N2RkYTU3ZTI1NGY0ZDM5MmRiMWExNWZhZjhjNTZkMmM5NTZkZDJiZWVkZGVlZDc1MThiNTE5MTFjYzgwIn0=; _ga=GA1.2.2042202377.1525247839; _gat=1; _gid=GA1.2.1034461360.1593095881; has_js=1; _pxff_fp=1; _pxff_rf=1; pxvid=44e1b040-4dde-11e8-b1dc-f15e898556c7',
'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_5) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1.1 Safari/605.1.15',
);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
@@ -161,7 +161,7 @@ function fetch_typo3($fp)
continue;
}
$file = 'type3-' . $release->version . '.tar.gz';
fetch_archive($file, $release->url->tar, $release->checksums->tar->sha1, 'sha1');
fetch_archive($file, 'https://get.typo3.org' . $release->url->tar, $release->checksums->tar->sha1, 'sha1');
hash_archive($fp, $file);
}
}
@@ -185,38 +185,40 @@ function fetch_pagekit($fp)
}
// Ignored releases are: alpha, beta, rc, dev
function fetch_drupal($fp, $versions)
function fetch_drupal($fp)
{
foreach ($versions as $version => $id) {
echo 'Fetching Drupal ' . $version . PHP_EOL;
echo 'Fetching Drupal ' . PHP_EOL;
$page = 0;
$pages = false;
do {
$data = fetch('https://www.drupal.org/project/drupal/releases?api_version%5B%5D=' . $id . '&page=' .$page);
$page = 0;
$pages = false;
do {
$data = fetch('https://www.drupal.org/project/drupal/releases?page=' . $page);
// pagination init
if ($pages === false && preg_match('/&amp;page=(\d+)">last »<\/a>/', $data, $m)) {
$pages = $m[1];
// pagination init
if ($pages === false && preg_match('/\?page=(\d+)">last »<\/a>/', $data, $m)) {
$pages = $m[1];
}
preg_match_all(
'/<a href="(\/project\/drupal\/releases\/(\d\.\d\.\d))">drupal/i',
$data,
$m
);
foreach ($m[1] as $k => $ver_uri) {
$ver_data = fetch('https://www.drupal.org' . $ver_uri);
if (!preg_match('/<span class="field-content hash">([a-z0-9]+)<\/span>/i', $ver_data, $ver_m)) {
die('Missing hash info: ' . $m[2][$k]);
}
$file = 'drupal-' . $m[2][$k] . '.tar.gz';
fetch_archive($file, 'https://ftp.drupal.org/files/projects/' . $file, $ver_m[1], 'md5');
hash_archive($fp, $file);
}
preg_match_all(
'/data-th="Download">(.*?)<a href="(https:\/\/ftp\.drupal\.org\/files\/projects\/(drupal\-([0-9.]+)\.tar\.gz)).*?md5 hash">\s*([a-z0-9]{32})\s*<\/td>/is',
$data,
$m
);
foreach ($m[3] as $k => $file) {
fetch_archive($file, $m[2][$k], $m[5][$k], 'md5');
hash_archive($fp, $file);
}
if ($pages === false) {
break;
}
$page++;
}while($page <= $pages);
}
if ($pages === false) {
break;
}
$page++;
} while ($page <= $pages);
}
function fetch_joomla($fp, $versions)
@@ -272,24 +274,7 @@ fetch_jquery($fp);
fetch_wordpress($fp);
fetch_typo3($fp);
fetch_pagekit($fp);
fetch_drupal(
$fp,
[
'9.x' => 39794,
'8.x' => 7234,
'7.x' => 103,
'6.x' => 87,
'5.x' => 78,
'4.7.x' => 79,
'4.6.x' => 80,
'4.5.x' => 81,
'4.4.x' => 82,
'4.3.x' => 83,
'4.2.x' => 84,
'4.1.x' => 85,
'4.0.x' => 86
]
);
fetch_drupal($fp);
fetch_joomla($fp, ['3.0' => 3, '2.5' => 25, '1.5' => 15, '1.0' => 10]);
fclose($fp);

View File

@@ -256,22 +256,33 @@ e45b8afd0b65516c175ed23f7183bab1 /jquery-migrate-1.1.1.min.js
dc0102c151c491b8a0f65a520e26e083 /jquery-migrate-1.1.0.min.js
1f5980833a26b490296db71951e1024f /jquery-migrate-1.0.0.js
dd6f8586a1afae562493e9c7cd1ffeea /jquery-migrate-1.0.0.min.js
f2fc939d607b2e861af2701a15d14430 /ace/ace.min.js
2954b8d06fd846e81c12b0fd0b3d2d35 /ace/ace/ace.js
c333e22e892cd099e776e9384bbbaa63 /ace/ace/ext-beautify.js
b391899e17b7aea2cf2998656c40f2c6 /core/components/phpthumbof/model/aws/_compatibility_test/sdk_compatibility_test.php
6cfb5a3b2820fe378b73c901ee6fc031 /core/components/phpthumbof/model/aws/sdk.class.php
dd894a093463d38f9c9fdbcb7c88cc23 /core/model/aws/sdk.class.php
1ed9b9eea82c9f1ead337b67c188206b /core/model/phpthumb/phpthumb.class.php
ef55bdc338994e87b650e2cf0f87df45 /core/model/smarty/sysplugins/smarty_internal_template.php
f8f2e883e5323ed5935f42b17ceda6ba /core/model/smarty/sysplugins/smarty_template_compiled.php
3d84a338c9daaacc711834cb7797ac98 /core/model/smarty/sysplugins/smarty_cacheresource_custom.php
d6be1074d266aecb739352150798d97d /core/model/smarty/sysplugins/smarty_cacheresource_keyvaluestore.php
c363512229135b182006a97ba43d31e7 /core/model/smarty/sysplugins/smarty_resource_recompiled.php
fc8f1e9f0ff666af7beb3f61b055c0e8 /core/model/smarty/sysplugins/smarty_internal_cacheresource_file.php
092a5a658bf49a3c1549f9bd809218ea /core/xpdo/compression/pclzip.lib.php
761f1578928050a03f4aa4c789f1d136 /manager/assets/fileapi/FileAPI.js
3c9137d88a00b1ae0b41ff6a70571615 /assets/components/tinymcewrapper/frontend/imogen_theme/js/jquery.js
bb127b5ce56b45e8b4b91de2e60dd9eb /assets/components/googleanalytics/js/mgr/libs/highcharts.js
7d7958bb0a9438a8966807f9202d0bce /assets/components/tinymce/jscripts/tiny_mce/plugins/spellchecker/classes/PSpellShell.php
3ee0a4d8a06cedc0a56f29e8f351ef72 /pclzip-2-8-2/pclzip.lib.php
f2fc939d607b2e861af2701a15d14430 /ace/ace.min.js
2954b8d06fd846e81c12b0fd0b3d2d35 /ace/ace/ace.js
c333e22e892cd099e776e9384bbbaa63 /ace/ace/ext-beautify.js
b391899e17b7aea2cf2998656c40f2c6 /core/components/phpthumbof/model/aws/_compatibility_test/sdk_compatibility_test.php
6cfb5a3b2820fe378b73c901ee6fc031 /core/components/phpthumbof/model/aws/sdk.class.php
dd894a093463d38f9c9fdbcb7c88cc23 /core/model/aws/sdk.class.php
1ed9b9eea82c9f1ead337b67c188206b /core/model/phpthumb/phpthumb.class.php
ef55bdc338994e87b650e2cf0f87df45 /core/model/smarty/sysplugins/smarty_internal_template.php
f8f2e883e5323ed5935f42b17ceda6ba /core/model/smarty/sysplugins/smarty_template_compiled.php
3d84a338c9daaacc711834cb7797ac98 /core/model/smarty/sysplugins/smarty_cacheresource_custom.php
d6be1074d266aecb739352150798d97d /core/model/smarty/sysplugins/smarty_cacheresource_keyvaluestore.php
c363512229135b182006a97ba43d31e7 /core/model/smarty/sysplugins/smarty_resource_recompiled.php
fc8f1e9f0ff666af7beb3f61b055c0e8 /core/model/smarty/sysplugins/smarty_internal_cacheresource_file.php
092a5a658bf49a3c1549f9bd809218ea /core/xpdo/compression/pclzip.lib.php
761f1578928050a03f4aa4c789f1d136 /manager/assets/fileapi/FileAPI.js
3c9137d88a00b1ae0b41ff6a70571615 /assets/components/tinymcewrapper/frontend/imogen_theme/js/jquery.js
bb127b5ce56b45e8b4b91de2e60dd9eb /assets/components/googleanalytics/js/mgr/libs/highcharts.js
7d7958bb0a9438a8966807f9202d0bce /assets/components/tinymce/jscripts/tiny_mce/plugins/spellchecker/classes/PSpellShell.php
3ee0a4d8a06cedc0a56f29e8f351ef72 /pclzip-2-8-2/pclzip.lib.php
abfd2987afd1f66e3eed50bebbeb6750 /sucuri-scanner-1.8.24/src/base.lib.php
78477b67cb223e4504689fef33119884 /sucuri-scanner-1.8.24/src/sitecheck.lib.php
e48460f6ef0c911dc5ad558c57bfd52f /sucuri-scanner-1.8.24/src/integrity.lib.php
29f34168b7384cca58ba64885461e115 wp-admin/includes/class-pclzip.php -> Wordpress Core 6.0
a54895edc1402cf1b7b5ecd3f5d85e6b wp-includes/formatting.php -> Wordpress Core 6.0
178f2fbc6a48f605ed84b156103d5366 wp-content/plugins/wordpress-seo/vendor_prefixed/guzzlehttp/guzzle/src/Middleware.php -> Yoast SEO plugin 19.2
1e2d246c57d2123aa8938c8263cb1d3d wp-content/plugins/wordpress-seo/admin/tracking/class-tracking-server-data.php -> Yoast SEO plugin 19.2
cacb5670ebb2de31976a4b2eb06cac86 wp-content/plugins/worker/src/MWP/ServiceContainer/Abstract.php -> managewp plugin 4.9.14 from managewp.com
ffa76b9ff298702a733747521cfdee69 wp-content/plugins/worker/src/MWP/Action/GetState.php -> managewp plugin 4.9.14 from managewp.com
ccce5f45d1ac66bd2bebe75d666b5720 wp-content/plugins/redirection/models/regex.php
ae810d74d638c611d8bd958777c9ac6a wp-content/plugins/ssl-insecure-content-fixer/includes/nonces.php