Beispiel #1
0
    def insert_strategies(self, strategy_id_set):
        if not strategy_id_set:
            return
        logger.info('开始插入策略【%s】', len(strategy_id_set))

        strategy_insert_sql = '''INSERT INTO strategy
            (strategy_id, strategy_name, author, `desc`, create_time, created_at, updated_at)
            VALUES(%s, %s, %s, %s, %s, %s, %s)'''

        now = datetime.datetime.now()

        count = 0
        successful_count = 0
        cursor = self.cnx.cursor()
        for info in [
                x for x in [self.strategy_ind[x] for x in strategy_id_set]
                if x is not None
        ]:
            progress(count, len(strategy_id_set),
                     '插入策略 {}'.format(info.get('strategy_id')))
            info['created_at'] = now
            info['updated_at'] = now
            try:
                cursor.execute(strategy_insert_sql, [
                    info.get(k) for k in [
                        'strategy_id', 'name', 'author', 'desc', 'create_date',
                        'created_at', 'updated_at'
                    ]
                ])
                successful_count += 1
            except Exception as err:
                logger.warning('策略插入失败:%s\n%s', info, err)
        self.cnx.commit()
        logger.info('成功插入策略【%s个】', successful_count)
Beispiel #2
0
def sort_pocs(poc_base_dir, ignore_dirs=['common']):
    '''将 POC 放置到其检查的 产品类型/产品名 目录下'''

    mod_count = 0
    if '.venv' not in ignore_dirs:
        ignore_dirs.append('.venv')
    for (mod, d, file_name) in iter_modules(poc_base_dir, ignore_dirs):
        mod_count += 1
        progress(mod_count, mod_count, '处理模块', os.path.join(d, file_name))
        (vuln, _) = load_poc_mod(mod)
        if vuln is None:
            continue
        prd = vuln.product
        component = Component.get_component(prd)
        typ = component.type
        should_be_in = os.path.join(poc_base_dir, typ.name,
                                    prd.replace(' ', '_'))

        if should_be_in != d:
            if not os.path.exists(should_be_in):
                os.makedirs(should_be_in)
            src_file = os.path.join(d, file_name)
            dst_file = os.path.join(should_be_in, file_name)
            logger.info('move from {} to {}'.format(src_file, dst_file))
            os.rename(src_file, dst_file)

    logger.info(
        '********* Clean up poc dir: {} ************'.format(poc_base_dir))
    _clean_up_poc_dirs(poc_base_dir)
Beispiel #3
0
 def update_strategies(self, strategy_id_set):
     if not strategy_id_set:
         return
     strategy_update_sql = '''UPDATE strategy
         SET strategy_name=%s, author=%s, `desc`=%s, create_time=%s, updated_at=%s
         WHERE strategy_id=%s'''
     count = 0
     successful_count = 0
     cursor = self.cnx.cursor()
     for info in [
             x for x in [self.strategy_ind[x] for x in strategy_id_set]
             if x is not None
     ]:
         progress(count, len(strategy_id_set),
                  '更新策略 {}'.format(info.get('strategy_id')))
         info['updated_at'] = datetime.datetime.now()
         try:
             cursor.execute(strategy_update_sql, [
                 info.get(k) for k in [
                     'name', 'author', 'desc', 'create_date', 'updated_at',
                     'strategy_id'
                 ]
             ])
             successful_count += 1
         except Exception as err:
             logger.warning('策略更新失败:%s\n%s', info, err)
     self.cnx.commit()
     logger.info('成功更新策略【%s个】', successful_count)
Beispiel #4
0
def indexing_strategies(strategy_dir, index_dir=None):
    strategy_ind_file = INDEX_CONFIG.get_strategy_index_file(index_dir)
    with open(strategy_ind_file, 'w') as strategy_ind:
        mod_count = 0
        successful_count = 0
        strategy_ids = {}
        for (mod, dirpath, filename) in iter_modules(strategy_dir):
            pth = os.path.join(dirpath, filename)
            mod_count += 1
            progress(mod_count, successful_count, '处理模块', pth)
            strategy = None
            try:
                strategy = load_strategy_mod(mod)
            except:
                logger.exception('模块加载出错: %s', pth)
                continue
            if strategy.strategy_id in strategy_ids:
                logger.warning('相同 id 的策略在 %s 已经出现: %s',
                               strategy_ids[strategy.strategy_id], pth)
                continue
            strategy_ids[strategy.strategy_id] = pth
            strategy_dict = dump_strategy_to_dict(strategy)
            strategy_dict['__file__'] = pth
            strategy_dict['__class__'] = strategy.__class__.__name__
            _write_obj(strategy_ind, strategy_dict)
            successful_count += 1
    logger.info('*********** 成功加载 %s 个模块【共计 %s 个】**********', successful_count,
                mod_count)
Beispiel #5
0
def indexing_pocs(poc_dir, index_dir=None):
    (vuln_ind_file,
     poc_ind_file) = (INDEX_CONFIG.get_vuln_index_file(index_dir),
                      INDEX_CONFIG.get_poc_index_file(index_dir))

    vuln_ids = set({})
    poc_ids = set({})

    logger.info('开始查找 %s 下的 POC 信息', poc_dir)
    with open(poc_ind_file, 'w') as poc_ind, \
            open(vuln_ind_file, 'w') as vuln_ind:
        mod_count = 0
        successful_count = 0
        for (mod, poc_dir, poc_file) in iter_modules(poc_dir):
            poc_path = os.path.join(poc_dir, poc_file)
            mod_count += 1
            progress(mod_count, successful_count, '处理POC模块', poc_path)
            (vuln, pocs) = (None, None)
            try:
                (vuln, pocs) = load_poc_mod(mod)
            except:
                logger.exception('模块加载出错: %s', poc_path)
            if vuln is not None and vuln.vuln_id not in vuln_ids:
                vuln_ids.add(vuln.vuln_id)
                _write_obj(vuln_ind, dump_vuln_to_dict(vuln))
            for poc in pocs:
                if poc.poc_id not in poc_ids:
                    poc_ids.add(poc.poc_id)
                    poc_dict = dump_poc_to_dict(poc)
                    poc_dict['__file__'] = os.path.join(poc_dir, poc_file)
                    poc_dict['__class__'] = poc.__class__.__name__
                    _write_obj(poc_ind, poc_dict)
            successful_count += 1
    logger.info('*********** 成功加载 %s 个模块【共计 %s 个】**********', successful_count,
                mod_count)
 def pocs(self):
     component_name = self.get_option('component')
     if component_name is None:
         return []
     logger.info('遍历查找组件 %s 的 POC', component_name)
     for poc in iter_pocs_of_component(component_name, self.index_dir):
         poc.output.strategy = self
         yield poc
Beispiel #7
0
    def sync_strategy(self):
        logger.info('同步策略数据')
        existed_strategy_ids = set(self.fetch_strategy_ids())
        all_strategy_ids = set(self.strategy_ind.keys())

        self.insert_strategies(
            all_strategy_ids.difference(existed_strategy_ids))

        if self.updating:
            self.update_strategies(
                all_strategy_ids.intersection(existed_strategy_ids))
Beispiel #8
0
    def sync_poc(self):
        logger.info('同步 POC 数据')
        existed_poc_vuln_ind = {}
        for item in self.fetch_poc_and_related_vuln_ids():
            existed_poc_vuln_ind[item[0]] = item[1]
        existed_poc_ids = set(existed_poc_vuln_ind.keys())
        all_poc_ids = set(self.poc_vuln_ind.keys())

        self.insert_pocs(all_poc_ids.difference(existed_poc_ids))

        if self.updating:
            self.update_pocs(all_poc_ids.intersection(existed_poc_ids))
        logger.info('完成 POC 数据同步')
Beispiel #9
0
    def pocs(self):
        if self.component_name is None:
            return []
        logger.info('遍历查找组件 %s 的 POC', self.component_name)

        all_http_name = ["Apache", "Nginx", "IIS", "uWSGI", "Tomcat", "Node.js"]
        if (not self.component_name.upper() == "http".upper()) and self.component_name.upper() in [tmp.upper() for tmp in all_http_name]:
            for poc in iter_pocs_of_component(self.component_name, self.index_dir):
                poc.output.strategy = self
                yield poc
        elif self.component_name.upper() == "http".upper():
            for component_name in all_http_name:
                for poc in iter_pocs_of_component(component_name, self.index_dir):
                    poc.output.strategy = self
                    yield poc
Beispiel #10
0
    def sync_vuln(self, vuln_id_set):
        logger.info('同步 Vuln 数据')
        all_vuln_ids = set(self.vuln_ind.keys())
        existed_vuln_ids = self.fetch_vuln_ids()

        self.sync_components()

        self.insert_vuln(all_vuln_ids.difference(existed_vuln_ids))

        if self.updating:
            self.update_vuln(all_vuln_ids.intersection(existed_vuln_ids))

        self.vuln_synced = True
        self.synced_vuln_ids_in_db = self.fetch_vuln_ids()
        logger.info('完成漏洞数据同步')
def main():
    args = None
    parser = create_cmd_parser()
    try:
        args = parser.parse_args()
    except:
        logger.exception('解析错误')
        raise
    setup_cscan_poc_logger(verbose=args.verbose,
                           very_verbose=args.very_verbose)

    logger.debug('解析组件属性')
    components_properties = {}
    parse_properties(args, components_properties=components_properties)

    logger.info('开始尝试推荐任务')
    recommend(components_properties)
Beispiel #12
0
def _clean_up_poc_dirs(path):
    '''移除所有无用目录(空或者只有 .pyc 的目录)'''
    if not os.path.isdir(path):
        return

    # remove empty subfolders
    files = os.listdir(path)
    if len(files) != 0:
        for f in files:
            fullpath = os.path.join(path, f)
            if os.path.isdir(fullpath):
                _clean_up_poc_dirs(fullpath)
            elif fullpath.endswith('.pyc'):
                os.remove(fullpath)
    # if folder empty, delete it
    if len(os.listdir(path)) == 0:
        logger.info('Remove empty dir: {}'.format(path))
        os.rmdir(path)
Beispiel #13
0
def main():
    (parser, args) = (None), None
    try:
        parser = create_parser()
        args = parser.parse_args()
    except:
        return
    setup_cscan_poc_logger(verbose=args.verbose,
                           very_verbose=args.very_verbose)

    if args.sort:
        if not args.doc_dir:
            logger.warning('未指定 --poc-dir')
            parser.print_usage()
            return
        sort_pocs(args.poc_dir)
        return

    if args.vuln_detail_dir:
        args.skip_indexing = True

    if not args.skip_indexing:
        if not args.skip_indexing_poc and args.poc_dir:
            logger.info('开始索引 POC ...')
            indexing_pocs(args.poc_dir, args.index_dir)
        if not args.skip_indexing_strategy and args.strategy_dir:
            logger.info('开始索引策略 ...')
            indexing_strategies(args.strategy_dir, args.index_dir)

    if args.vuln_detail_dir or not args.skip_syncing:
        cnx = mysql.connector.connect(user=args.user,
                                      password=args.passwd,
                                      host=args.host,
                                      database=args.db,
                                      port=args.port,
                                      charset='utf8')
        cscan_db = CScanDb(cnx, args.index_dir, args.update)
        if args.vuln_detail_dir:
            logger.info('同步漏洞详情...')
            cscan_db.sync_vuln_detail(args.vuln_detail_dir,
                                      args.vuln_detail_static_dir,
                                      args.vuln_ids)
        else:
            logger.info('开始同步数据...')
            cscan_db.sync_poc()
            cscan_db.sync_strategy()
Beispiel #14
0
 def sync_components(self):
     logger.info('同步组件数据')
     existed_c_names = set([x[1] for x in self.fetch_component_id_names()])
     all_product_names = set(
         [x['product'] for x in list(self.vuln_ind.values())])
     for common_component in Component.get_common_components():
         logger.info('通用组件:%s', common_component)
         all_product_names.add(common_component)
     self.insert_component(all_product_names.difference(existed_c_names))
     if self.updating:
         self.update_component(
             all_product_names.intersection(existed_c_names))
     self.component_synced = True
     logger.info('完成组件数据同步')
Beispiel #15
0
    def insert_pocs(self, poc_id_set):
        if not poc_id_set:
            return
        logger.info('开始插入 POC [count={}]'.format(len(poc_id_set)))

        self.sync_vuln(
            set([self.poc_vuln_ind[poc_id] for poc_id in poc_id_set]))

        poc_insert_sql = '''INSERT INTO poc
            (poc_id, poc_name, author, vuln_id, create_time, created_at, updated_at, args)
            VALUES(%s, %s, %s, %s, %s, %s, %s, %s)'''

        logger.info('准备要插入的 POC 数据')
        now = datetime.datetime.now()
        poc_infos = [
            x for x in [self.poc_ind[x] for x in poc_id_set] if x is not None
        ]
        count = 0
        cursor = self.cnx.cursor()

        for poc_info in poc_infos:
            progress(count, len(poc_infos), '插入 POC')
            count += 1
            vuln_id = self.poc_vuln_ind[poc_info['poc_id']]
            if vuln_id not in self.synced_vuln_ids_in_db:
                poc_info['vuln_id'] = None
            else:
                poc_info['vuln_id'] = vuln_id
            poc_info['created_at'] = now
            poc_info['updated_at'] = now
            poc_info['args'] = poc_info.get('option_schema', None)
            poc_info['create_date'] = poc_info.get('create_date', now)

            try:
                cursor.execute(poc_insert_sql, [
                    poc_info.get(k) for k in [
                        'poc_id', 'name', 'author', 'vuln_id', 'create_date',
                        'created_at', 'updated_at', 'args'
                    ]
                ])
            except Exception as err:
                logger.warning('POC 插入失败: {}\n{}'.format(poc_info, err))

        self.cnx.commit()
        logger.info('成功插入 POC [count={}]'.format(len(poc_id_set)))
Beispiel #16
0
    def update_pocs(self, poc_id_set):
        if (len(poc_id_set) == 0):
            return
        logger.info('开始更新 POC [count={}]'.format(len(poc_id_set)))

        self.sync_vuln(
            set([self.poc_vuln_ind[poc_id] for poc_id in poc_id_set]))

        poc_update_sql = '''UPDATE poc
            SET poc_name=%s, author=%s, vuln_id=%s,
                updated_at=%s, args=%s, create_time=%s
            WHERE poc_id=%s'''

        logger.info('准备要更新的 POC 数据 [count={}]'.format(len(poc_id_set)))
        now = datetime.datetime.now()
        poc_infos = [
            x for x in [self.poc_ind[x] for x in poc_id_set] if x is not None
        ]
        count = 0
        cursor = self.cnx.cursor()

        for poc_info in poc_infos:
            progress(count, len(poc_infos), '更新 POC')
            count += 1
            vuln_id = self.poc_vuln_ind[poc_info['poc_id']]
            if vuln_id not in self.synced_vuln_ids_in_db:
                poc_info['vuln_id'] = None
            else:
                poc_info['vuln_id'] = vuln_id
            poc_info['updated_at'] = now
            poc_info['args'] = poc_info.get('option_schema', None)
            poc_info['create_date'] = poc_info.get('create_date', now)
            try:
                cursor.execute(poc_update_sql, [
                    poc_info.get(k) for k in [
                        'name', 'author', 'vuln_id', 'updated_at', 'args',
                        'poc_id', 'create_date'
                    ]
                ])
            except Exception as e:
                logger.warn('POC 更新失败: {}\n{}\n{}'.format(
                    poc_info, e, poc_update_sql))

        self.cnx.commit()
        logger.info('成功更新 POC [count={}]'.format(len(poc_id_set)))
Beispiel #17
0
    def insert_vuln(self, vuln_id_set):
        if (len(vuln_id_set) == 0):
            return
        logger.info('开始插入 Vuln [count={}]'.format(len(vuln_id_set)))

        vuln_insert_sql = '''INSERT INTO vuln
            (vuln_id, vuln_name, vuln_type, c_id, c_version, cve_id, disclosure_date,
             submit_time, level, source, detail, created_at, updated_at)
            VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)'''

        logger.info('准备要插入的 Vuln 数据')
        vuln_infos = [
            info
            for info in [self.vuln_ind[vuln_id] for vuln_id in vuln_id_set]
            if info is not None
        ]
        now = datetime.datetime.now()
        cursor = self.cnx.cursor()
        count = 0

        for vuln_info in vuln_infos:
            progress(count, len(vuln_infos), '插入漏洞')
            count += 1
            c_id = self.get_component_id(vuln_info['product'])
            if c_id is None:
                continue
            vuln_info['c_id'] = c_id
            vuln_info['submit_time'] = now
            vuln_info['created_at'] = now
            vuln_info['updated_at'] = now
            try:
                cursor.execute(vuln_insert_sql, [
                    vuln_info.get(k) for k in [
                        'vuln_id', 'name', 'type', 'c_id', 'product_version',
                        'cve_id', 'disclosure_date', 'submit_time', 'level',
                        'ref', 'desc', 'created_at', 'updated_at'
                    ]
                ])
            except Exception as e:
                logger.warn('Vuln 插入失败: {}\n{}'.format(vuln_info, e))
        self.cnx.commit()
        logger.info('成功插入 Vuln [count={}]'.format(len(vuln_id_set)))
Beispiel #18
0
    def update_component(self, component_name_set):
        if (len(component_name_set) == 0):
            return
        logger.info('更新 Component [count={}]'.format(len(component_name_set)))

        component_update_sql = '''UPDATE component
            SET c_first=%s, c_type=%s, `desc`=%s, producer=%s, properties=%s, updated_at=%s
            WHERE c_name=%s'''

        logger.info('准备要更新的 Component 数据')
        now = datetime.datetime.now()
        name_infos = [
            name_info for name_info in [(n, get_product_info(n))
                                        for n in component_name_set]
            if name_info[1] is not None
        ]

        cursor = self.cnx.cursor()
        count = 0

        for (n, info) in name_infos:
            progress(count, len(name_infos), '更新组件')
            count += 1
            info['c_name'] = n
            info['updated_at'] = now

            try:
                cursor.execute(component_update_sql, [
                    info.get(k) for k in [
                        'name_pinyin_first', 'type', 'desc', 'producer',
                        'properties', 'updated_at', 'c_name'
                    ]
                ])
            except Exception as e:
                logger.warn('Component 更新失败: {} {}\n{}'.format(n, info, e))

        self.cnx.commit()
        logger.info('成功更新 Component [count={}]'.format(
            len(component_name_set)))
Beispiel #19
0
    def insert_component(self, component_name_set):
        if (len(component_name_set) == 0):
            return
        logger.info('开始插入 Component [count={}]'.format(
            len(component_name_set)))
        component_insert_sql = '''INSERT INTO component
            (c_id, c_name, c_first, c_type, `desc`, producer,
             properties, created_at, updated_at)
            VALUES(%s, %s, %s, %s, %s, %s, %s, %s, %s)'''

        logger.info('准备要插入的 Component 数据')
        now = datetime.datetime.now()
        name_infos = [
            name_info for name_info in [(n, get_product_info(n))
                                        for n in component_name_set]
            if name_info[1] is not None
        ]

        cursor = self.cnx.cursor()
        i = 0
        for (n, info) in name_infos:
            progress(i, len(name_infos), '插入组件')
            i += 1
            info['c_id'] = str(uuid.uuid4())
            info['c_name'] = n
            info['created_at'] = now
            info['updated_at'] = now
            try:
                cursor.execute(component_insert_sql, [
                    info.get(k) for k in [
                        'c_id', 'c_name', 'name_pinyin_first', 'type', 'desc',
                        'producer', 'properties', 'created_at', 'updated_at'
                    ]
                ])
            except Exception as e:
                logger.warn('组件插入失败: {} {}\n{}'.format(n, info, e))
        self.cnx.commit()
        logger.info('成功插入 Component [count={}]'.format(
            len(component_name_set)))
Beispiel #20
0
    def update_vuln(self, vuln_id_set):
        if (len(vuln_id_set) == 0):
            return
        logger.info('开始更新漏洞 [count={}]'.format(len(vuln_id_set)))
        vuln_update_sql = '''UPDATE vuln
            SET vuln_name=%s, vuln_type=%s, c_id=%s, c_version=%s, cve_id=%s, disclosure_date=%s, level=%s, source=%s, detail=%s, updated_at=%s
            WHERE vuln_id=%s'''

        logger.info('准备要更新的 Vuln 数据')
        vuln_infos = [
            info
            for info in [self.vuln_ind[vuln_id] for vuln_id in vuln_id_set]
            if info is not None
        ]
        now = datetime.datetime.now()
        count = 0
        cursor = self.cnx.cursor()

        for vuln_info in vuln_infos:
            progress(count, len(vuln_infos), '更新漏洞')
            count += 1
            c_id = self.get_component_id(vuln_info['product'])
            vuln_info['c_id'] = c_id
            vuln_info['updated_at'] = now
            try:
                cursor.execute(vuln_update_sql, [
                    vuln_info.get(k) for k in [
                        'name', 'type', 'c_id', 'product_version', 'cve_id',
                        'disclosure_date', 'level', 'ref', 'desc',
                        'updated_at', 'vuln_id'
                    ]
                ])
            except Exception as e:
                logger.warn('Vuln 更新失败: {}\n{}'.format(vuln_info, e))

        self.cnx.commit()
        logger.info('成功更新漏洞 [count={}]'.format(len(vuln_id_set)))
Beispiel #21
0
 def sync_vuln_detail(self,
                      vuln_detail_dir,
                      vuln_detail_static_dir,
                      vuln_ids=None):
     '''
     :param vuln_detail_dir: 漏洞详情存放目录
        - htmls/...
        - imgs/...
     :param vuln_detail_static_dir: Cscan 站点漏洞静态资源目录
     :param vuln_ids: 为空/空列表时同步所有,为列表时只同步列表中指定的漏洞 ID
     '''
     logger.info('同步漏洞详情')
     vuln_update_sql = '''UPDATE vuln SET exploit=%s WHERE vuln_id=%s'''
     cursor = self.cnx.cursor()
     for f in Path(path.join(vuln_detail_dir, 'htmls')).glob('**/*.html'):
         vuln_id = f.name.rstrip('.html')
         if vuln_ids and vuln_id not in vuln_ids:
             continue
         logger.info('同步 %s' % f)
         try:
             cursor.execute(vuln_update_sql, (f.read_text(), vuln_id))
         except Exception as e:
             logger.error('更新失败 %s' % f, e)
     self.cnx.commit()
     if vuln_detail_static_dir:
         logger.info('同步静态资源')
         src_path = path.join(vuln_detail_dir, 'imgs')
         img_path = path.join(vuln_detail_static_dir, 'imgs')
         if not path.exists(img_path):
             os.makedirs(img_path)
         for i in os.listdir(src_path):
             fp = path.join(src_path, i)
             if not path.isfile(fp):
                 continue
             logger.debug('同步 %s' % i)
             copyfile(fp, path.join(img_path, i))