diff options
Diffstat (limited to 'modules/grep_count.py')
| -rw-r--r-- | modules/grep_count.py | 234 |
1 files changed, 234 insertions, 0 deletions
diff --git a/modules/grep_count.py b/modules/grep_count.py new file mode 100644 index 0000000..2431960 --- /dev/null +++ b/modules/grep_count.py | |||
| @@ -0,0 +1,234 @@ | |||
| 1 | ''' This module count the occurences of dodgy terms present in a file | ||
| 2 | ''' | ||
| 3 | import os | ||
| 4 | import logging | ||
| 5 | logging.basicConfig(level=logging.DEBUG) | ||
| 6 | |||
| 7 | import scanmodule | ||
| 8 | |||
| 9 | def main(): | ||
| 10 | return GrepCount() | ||
| 11 | |||
| 12 | class GrepCount(scanmodule.ScanModule): | ||
| 13 | name = 'grep count' | ||
| 14 | |||
| 15 | # ranked from 1 to 10, 10 being EVIL | ||
| 16 | # Also, 100 is awarded to MEGA-DUH-OBVIOUS things. | ||
| 17 | dodgy_terms = { | ||
| 18 | '$GLOBALS': 6, | ||
| 19 | 'WWW-Authenticate': 7, | ||
| 20 | 'ZipArchive': 6, | ||
| 21 | 'apache_get_modules': 8, | ||
| 22 | 'assert': 5, | ||
| 23 | 'base64_decode': 7, | ||
| 24 | 'bzdecompress': 7, | ||
| 25 | 'chmod': 8, | ||
| 26 | 'curl_init("file://': 100, # safe mode bypass exploit | ||
| 27 | #'dl': 10, | ||
| 28 | #'exec': 10, | ||
| 29 | 'eval(': 10, | ||
| 30 | 'eval(base64_decode': 100, | ||
| 31 | 'eval($_GET': 100, | ||
| 32 | 'eval($_POST': 100, | ||
| 33 | 'eval($_REQUEST': 100, | ||
| 34 | 'eval(base64_decode': 100, | ||
| 35 | 'eval(gzinflate': 100, | ||
| 36 | 'file_get_contents': 6, | ||
| 37 | 'fpassthru': 100, | ||
| 38 | 'fsockopen': 7, | ||
| 39 | 'ftp_connect': 7, | ||
| 40 | 'ftp_exec': 7, | ||
| 41 | 'ftp_login': 7, | ||
| 42 | 'function_exists': 4, | ||
| 43 | 'get_current_user': 10, | ||
| 44 | 'getcwd': 8, | ||
| 45 | 'getenv': 9, | ||
| 46 | 'getmxrr': 5, | ||
| 47 | 'getmygid': 10, | ||
| 48 | 'getmygid': 10, | ||
| 49 | 'getmyinode': 10, | ||
| 50 | 'getmypid': 10, | ||
| 51 | 'getmyuid': 10, | ||
| 52 | 'gzinflate': 7, | ||
| 53 | 'gzinflate(base64_decode(': 100, | ||
| 54 | 'gzuncompress': 7, | ||
| 55 | 'ini_get': 6, | ||
| 56 | 'ini_set': 6, | ||
| 57 | 'is_readable': 10, | ||
| 58 | 'mysql_get_client_info': 7, | ||
| 59 | 'open_basedir': 9, | ||
| 60 | 'passthru': 10, | ||
| 61 | 'passthru($_GET': 100, | ||
| 62 | 'passthru($_POST': 100, | ||
| 63 | 'passthru($_REQUEST': 100, | ||
| 64 | 'pclose': 9, | ||
| 65 | 'pcntl_fork': 10, | ||
| 66 | 'php_logo_guid': 10, | ||
| 67 | 'php_uname': 8, | ||
| 68 | 'phpcredits': 10, | ||
| 69 | 'phpinfo': 10, | ||
| 70 | 'phpversion': 5, | ||
| 71 | 'pnctl_exec': 10, | ||
| 72 | 'pnctl_fork': 10, | ||
| 73 | 'popen': 10, | ||
| 74 | 'posix_getegid': 10, | ||
| 75 | 'posix_geteuid': 10, | ||
| 76 | 'posix_getgetgruid': 10, | ||
| 77 | 'posix_getpwuid': 10, | ||
| 78 | 'posix_kill': 10, | ||
| 79 | 'posix_mkfifo': 10, | ||
| 80 | 'posix_setgid': 10, | ||
| 81 | 'posix_setpgid': 10, | ||
| 82 | 'posix_setsid': 10, | ||
| 83 | 'posix_setuid': 10, | ||
| 84 | 'posix_uname': 10, | ||
| 85 | 'php://input': 7, | ||
| 86 | 'proc_close': 10, | ||
| 87 | 'proc_get_status': 10, | ||
| 88 | 'proc_nice': 10, | ||
| 89 | 'proc_open': 10, | ||
| 90 | 'proc_terminate': 10, | ||
| 91 | 'putenv': 10, | ||
| 92 | 'putenv("PHP': 100, # Shellshock exploit | ||
| 93 | 'putenv(\'PHP': 100, # Shellshock exploit | ||
| 94 | 'safe_mode': 10, | ||
| 95 | 'shell_exec': 10, | ||
| 96 | 'show_source': 10, | ||
| 97 | 'socket_create(AF_INET, SOCK_STREAM, SOL_TCP)': 10, # Used for SYN flood | ||
| 98 | 'symlink': 8, | ||
| 99 | 'system(': 9, | ||
| 100 | 'system($_GET': 100, | ||
| 101 | 'system($_POST': 100, | ||
| 102 | 'system($_REQUEST': 100, | ||
| 103 | 'win_shell_execute': 10, | ||
| 104 | 'win_create_service': 100, | ||
| 105 | 'wscript': 8, | ||
| 106 | 'zend_logo_guid': 10, | ||
| 107 | 'zend_thread_id': 9, | ||
| 108 | 'zend_version': 9, | ||
| 109 | } | ||
| 110 | |||
| 111 | dodgy_terms.update({ | ||
| 112 | '/bin/bash ': 100, | ||
| 113 | '/bin/sh ': 100, | ||
| 114 | '/etc/hosts': 100, | ||
| 115 | '/etc/passwd': 100, | ||
| 116 | '/etc/resolv.conf ': 100, | ||
| 117 | '/etc/shadow': 100, | ||
| 118 | '/etc/syslog.conf': 100, | ||
| 119 | '/proc/cpuinfo': 10, | ||
| 120 | '/tmp': 8, | ||
| 121 | '/var/cpanel/accounting.log': 100, | ||
| 122 | 'IRC server': 100, | ||
| 123 | 'LD_PRELOAD': 100, | ||
| 124 | 'PRIVMSG': 100, | ||
| 125 | 'Safe Mod Bypass': 100, | ||
| 126 | 'Shell ': 9, | ||
| 127 | '\\x': 3, # Shellcodes | ||
| 128 | '\x00/../': 100, # safe mode bypass | ||
| 129 | 'backdoor': 10, | ||
| 130 | 'bypass': 8, | ||
| 131 | 'chkrootkit': 100, | ||
| 132 | 'chmod 777': 7, | ||
| 133 | 'cmd.exe': 100, | ||
| 134 | 'dir /OG /X': 100, | ||
| 135 | 'find . -type f': 100, | ||
| 136 | 'gcc ': 8, | ||
| 137 | 'id_rsa': 100, | ||
| 138 | 'ipconfig /all': 100, | ||
| 139 | 'jschl_vc': 100, # Cloudflare bypass | ||
| 140 | 'jschl_answer': 100, # Cloudflare bypass | ||
| 141 | 'kernel32.dll': 100, | ||
| 142 | 'ls -la': 100, | ||
| 143 | 'milw0rm': 100, | ||
| 144 | 'my.cnf': 100, | ||
| 145 | 'my.conf': 100, | ||
| 146 | 'nc -l': 100, | ||
| 147 | 'netstat ': 100, | ||
| 148 | 'file:file://': 100, # basedir bypass | ||
| 149 | 'portsentry': 100, | ||
| 150 | 'proftpd.conf': 100, | ||
| 151 | 'ps -aux': 100, | ||
| 152 | 'rkhunter': 100, | ||
| 153 | 'shellcode': 100, | ||
| 154 | 'slowloris': 100, | ||
| 155 | 'snort': 100, | ||
| 156 | 'system32': 9, | ||
| 157 | 'tripwire': 100, | ||
| 158 | 'uname -a': 100, | ||
| 159 | 'wget': 8, | ||
| 160 | 'WinExec': 10, | ||
| 161 | }) | ||
| 162 | |||
| 163 | dodgy_terms.update({ | ||
| 164 | '/cdn-cgi/l/chk_jschl': 100, # Cloudflare bypass for DDoS'ing | ||
| 165 | 'Antichat Shell': 100, | ||
| 166 | 'Cr@zy_King': 100, | ||
| 167 | 'KAdot@ngs.ru': 100, | ||
| 168 | 'Kacak': 100, | ||
| 169 | 'KingDefacer': 100, | ||
| 170 | 'SimAttacker': 100, | ||
| 171 | 'SoldiersOfAllah': 100, | ||
| 172 | 'ak74-team.net': 100, | ||
| 173 | 'alturks.com': 100, | ||
| 174 | 'egy_spider' : 100, | ||
| 175 | 'egyspider.eu' : 100, | ||
| 176 | 'exploit-db.com': 100, | ||
| 177 | 'forever5pi': 100, | ||
| 178 | 'grayhatz.org': 100, | ||
| 179 | 'kacaq.blogspot.com': 100, | ||
| 180 | 'locus7s.com': 100, | ||
| 181 | 'michaeldaw.org': 100, | ||
| 182 | 'milw0rm.com': 100, | ||
| 183 | 'pentestmonkey': 100, | ||
| 184 | 'r57.biz': 100, | ||
| 185 | 'r57shell.net': 100, | ||
| 186 | 'rootshell-team.info': 100, | ||
| 187 | 'simorgh': 100, | ||
| 188 | 'thecrowsrew.org': 100, | ||
| 189 | 'vnhacker.org': 100, | ||
| 190 | 'xdevil.org': 100, | ||
| 191 | 'zehirhacker': 100, | ||
| 192 | '~z0mbie': 100, | ||
| 193 | }) | ||
| 194 | |||
| 195 | def populate(self, path): | ||
| 196 | ''' Does nothing :< | ||
| 197 | ''' | ||
| 198 | pass | ||
| 199 | |||
| 200 | def evaluate(self, path): | ||
| 201 | ''' Check the given file against a list of know dodgy strings. | ||
| 202 | The calculation formulae is empirical. | ||
| 203 | @ret A sorted list of the form [name, match_in_percent_superior_to_zero] | ||
| 204 | ''' | ||
| 205 | fsize = os.path.getsize(path) | ||
| 206 | if not fsize: | ||
| 207 | return None | ||
| 208 | |||
| 209 | content = '' | ||
| 210 | with open(path, 'r') as f: | ||
| 211 | content = f.read() | ||
| 212 | |||
| 213 | score = 0 | ||
| 214 | for key,data in self.dodgy_terms.iteritems(): | ||
| 215 | nb = content.find(key) * data | ||
| 216 | if nb > 0: | ||
| 217 | score += nb | ||
| 218 | score /= fsize | ||
| 219 | |||
| 220 | logging.info('Grep score for ' + path + ' : ' + str(score)) | ||
| 221 | |||
| 222 | if score > 75: | ||
| 223 | return [['MALWARE', min(score, 100)],] | ||
| 224 | return None | ||
| 225 | |||
| 226 | def load(self, path): | ||
| 227 | pass | ||
| 228 | |||
| 229 | def save(self, path): | ||
| 230 | pass | ||
| 231 | |||
| 232 | def is_malware(self, path): | ||
| 233 | return self.evaluate(path) is not None | ||
| 234 | |||
