panelSafe.py 7.56 KB
Newer Older
jose's avatar
jose committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
#!/usr/bin/env python
# encoding: utf-8
  
import os,sys,hashlib,time,re,threading,chardet,json
import public

class safe:
    danger = public.GetMsg("DANGER")
    high_risk = public.GetMsg("HIGH_RISK")
    one_word_th = public.GetMsg("ONE_WORD_TROJAN_HORSE")
    get_post_ev=public.GetMsg("GET_POST_EXPLOITABLE_VULNERABILITIES")
    get_post_cookie_ev = public.GetMsg("GET_POST_COOKIE_EXPLOITABLE_VULNERABILITIES")
    webshell = public.GetMsg("WEBSHELL")
    ev = public.GetMsg("EXPLOITABLE_VULNERABILITIES")
    dc = public.GetMsg("DANGEROUS_CITATION")
    rulelist = [
        {'msg':get_post_ev,'level':danger,'code':'(\$_(GET|POST|REQUEST)\[.{0,15}\]\s{0,10}\(\s{0,10}\$_(GET|POST|REQUEST)\[.{0,15}\]\))'},
        {'msg':one_word_th,'level':high_risk,'code':'((eval|assert)(\s|\n)*\((\s|\n)*\$_(POST|GET|REQUEST)\[.{0,15}\]\))'},
        {'msg':one_word_th,'level':high_risk,'code':'(eval(\s|\n)*\(base64_decode(\s|\n)*\((.|\n){1,200})'},
        {'msg':webshell,'level':danger,'code':'(function\_exists\s*\(\s*[\'|\"](shell\_exec|system|popen|exec|proc\_open|passthru)+[\'|\"]\s*\))'},
        {'msg':webshell,'level':danger,'code':'((exec|shell\_exec|passthru)+\s*\(\s*\$\_(\w+)\[(.*)\]\s*\))'},
        {'msg':ev,'level':danger,'code':'(\$(\w+)\s*\(\s.chr\(\d+\)\))'},
        {'msg':webshell,'level':danger,'code':'(\$(\w+)\s*\$\{(.*)\})'},
        {'msg':get_post_cookie_ev,'level':danger,'code':'(\$(\w+)\s*\(\s*\$\_(GET|POST|REQUEST|COOKIE|SERVER)+\[(.*)\]\s*\))'},
        {'msg':get_post_cookie_ev,'level':danger,'code':'(\$\_(GET|POST|REQUEST|COOKIE|SERVER)+\[(.*)\]\(\s*\$(.*)\))'},
        {'msg':webshell,'level':danger,'code':'(\$\_\=(.*)\$\_)'},
        {'msg':webshell,'level':danger,'code':'(\$(.*)\s*\((.*)\/e(.*)\,\s*\$\_(.*)\,(.*)\))'},
        {'msg':webshell,'level':danger,'code':'(new com\s*\(\s*[\'|\"]shell(.*)[\'|\"]\s*\))'},
        {'msg':webshell,'level':danger,'code':'(echo\s*curl\_exec\s*\(\s*\$(\w+)\s*\))'},
        {'msg':public.GetMsg("HAZARDOUS_FILE_OPERATION_VULNERABILITIES"),'level':high_risk,'code':'((fopen|fwrite|fputs|file\_put\_contents)+\s*\((.*)\$\_(GET|POST|REQUEST|COOKIE|SERVER)+\[(.*)\](.*)\))'},
        {'msg':public.GetMsg("DANGEROUS_UPLOAD_VULNERABILITIES"),'level':danger,'code':'(\(\s*\$\_FILES\[(.*)\]\[(.*)\]\s*\,\s*\$\_(GET|POST|REQUEST)+\[(.*)\]\[(.*)\]\s*\))'},
        {'msg':dc,'level':high_risk,'code':'(\$\_(\w+)(.*)(eval|assert|include|require|include\_once|require\_once)+\s*\(\s*\$(\w+)\s*\))'},
        {'msg':dc,'level':high_risk,'code':'((include|require|include\_once|require\_once)+\s*\(\s*[\'|\"](\w+)\.(jpg|gif|ico|bmp|png|txt|zip|rar|htm|css|js)+[\'|\"]\s*\))'},
        {'msg':ev,'level':danger,'code':'(eval\s*\(\s*\(\s*\$\$(\w+))'},
        {'msg':one_word_th,'level':high_risk,'code':'((eval|assert|include|require|include\_once|require\_once|array\_map|array\_walk)+\s*\(\s*\$\_(GET|POST|REQUEST|COOKIE|SERVER|SESSION)+\[(.*)\]\s*\))'},
        {'msg':one_word_th,'level':danger,'code':'(preg\_replace\s*\((.*)\(base64\_decode\(\$)'}
        ]
    
    ruleFile = '/www/server/panel/data/ruleList.conf';
    if not os.path.exists(ruleFile): public.writeFile(ruleFile,json.dumps(rulelist));
    rulelist = json.loads(public.readFile(ruleFile));
    
    result = {};
    result['data'] = []
    result['phpini'] = []
    result['userini'] = result['sshd'] = result['scan'] = True;
    result['outime'] = result['count'] = result['error'] = 0
    
    def scan(self,path):
        start = time.time();
        ce = ['.jsp','.asp','.html','.htm','.php','.tpl','.xml']
        for root,dirs,files in os.walk(path):
            for filespath in files:
                if not os.path.splitext(filespath)[1] in ce: continue;
                if os.path.getsize(os.path.join(root,filespath)) < 262144:
                    filename = os.path.join(root,filespath);
                    self.threadto(filename);
        end = time.time();
        self.result['outime'] = int(end - start)
    
    def threadto(self,filename):
        print 'scanning ' + filename,
        file= open(filename)
        filestr = file.read()
        char=chardet.detect(filestr)
        try:
            filestr = filestr.decode(char['encoding'])
        except:
            return;
        file.close()
        for rule in self.rulelist:
            tmps = re.compile(rule['code']).findall(filestr)
            if tmps:
                tmp = {}
                tmp['msg'] = rule['msg'];
                tmp['level'] = rule['level'];
                tmp['filename'] = filename;
                tmp['code'] = str(tmps[0][0:200])
                tmp['etime'] = time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(os.path.getmtime(filename)))
                self.result['data'].append(tmp);
                self.result['error'] += 1
                break
        print '  done'
        self.result['count'] += 1
        public.writeFile(self.result['path'] + '/scan.pl',json.dumps(self.result));
        del(filestr)
        
    def md5sum(self,md5_file):
        m = hashlib.md5()
        fp = open(md5_file)
        m.update(fp.read())
        return m.hexdigest()
        fp.close()
        
    
    def checkUserINI(self,path):
        self.result['userini'] =  os.path.exists(path+'/.user.ini');
        if not self.result['userini']: self.result['error'] += 1;
        public.writeFile(self.result['path'] + '/scan.pl',json.dumps(self.result));
    
    def checkPHPINI(self):
        setupPath = '/www/server';
        phps = ['52','53','54','55','56','70','71']
        rep = "disable_functions\s*=\s*(.+)\n"
        defs = ['passthru','exec','system','chroot','chgrp','chown','shell_exec','popen','ini_alter','ini_restore','dl','openlog','syslog','readlink','symlink','popepassthru']
        data = []
        for phpv in phps:
            phpini = setupPath + '/php/'+phpv+'/etc/php.ini';
            if not os.path.exists(phpini): continue;
            conf = public.readFile(phpini);
            tmp = re.search(rep,conf).groups();
            disables = tmp[0].split(',');
            for defstr in defs:
                if defstr in disables: continue;
                tmp = {}
                tmp['function'] = defstr;
                tmp['version'] = phpv;
                self.result['phpini'].append(tmp);
        self.result['error'] += len(self.result['phpini']);
        public.writeFile(self.result['path'] + '/scan.pl',json.dumps(self.result));
            
        
        
    def checkSSH(self):
        if self.md5sum('/etc/issue') == '3e3c7c4194b12af573ab11c16990c477':
            if self.md5sum('/usr/sbin/sshd') != 'abf7a90c36705ef679298a44af80b10b':  self.result['sshd'] = False
                
        if self.md5sum('/etc/issue') == '6c9222ee501323045d85545853ebea55':
            if self.md5sum('/usr/sbin/sshd') != '4bbf2b12d6b7f234fa01b23dc9822838': self.result['sshd'] = False
        self.result['sshd'] = True
        public.writeFile(self.result['path'] + '/scan.pl',json.dumps(self.result));
    
    
                
    def suspect(self,path):
        self.result['path'] = path;
        self.checkSSH();
        self.checkPHPINI();
        self.checkUserINI(path);
        public.writeFile(self.result['path'] + '/scan.pl',json.dumps(self.result));
        self.scan(path);
        self.result['scan'] = False
        public.writeFile(self.result['path'] + '/scan.pl',json.dumps(self.result));
        return self.result;

if __name__=='__main__':
  
    if len(sys.argv)!=2:
        print(public.GetMsg("INIT_ARGS_ERR"))
        exit();
    if os.path.lexists(sys.argv[1]) == False:
        print(public.GetMsg("DIR_NOT_EXISTS"))
        exit();
    if len(sys.argv) ==2:
        safe().suspect(sys.argv[1]);
    else:
        exit()