Exemplo n.º 1
0
def init():
    """
    启动的时候初始化,主要是新建一些日志目录之类的
    :return: 
    """
    logger.propagate = False
    logger.setLevel(logging.DEBUG)
    # logger.setLevel(logging.WARN)
    logger.info(celery_logo)
    load_default_checkers(True)
    modify_default_checkers()
Exemplo n.º 2
0
def scan(package, task_id, create_user, status):
    """
    :param package: 
    :param task_id: 
    :param create_user: 
    :param status: 
    :return: 
    """
    logger.info("hunter task has started")
    # 加载插件,只有一个插件
    checkers = load_default_checkers()
    logger.info('loading package success')
    logger.info('loading plugin success')
    try:
        if checkers["xsseye"].useable == PluginSwith.ON:
            xssfork_process = XssForkProcess(package, task_id)
            xssfork_process.engine_start()
            while not xssfork_process.engine_has_terminated(
            ) and xssfork_process.process is not None:
                logger.info("xsseye program is runing")
                time.sleep(5)
            xssfork_process.engine_kill()
            logger.warn("xsseye program runs to completion")
    except KeyboardInterrupt as e:
        logger.exception("scan error")
    finally:
        logger.info("hunter task has done")
Exemplo n.º 3
0
def download_checkers():
    """
    下载所有的插件,不做鉴权
    :return: 
    """
    checker_name = request.args.get("name")

    if not checker_name:
        zip_floder_skip(target_file="%stmp/plugins.zip" % PLUGIN_PATH,
                        origin_folder=PLUGIN_PATH,
                        is_regular=True,
                        skip_list=["*DS_Store", "*__pycache__*", "tmp/*"])
        return send_file(filename_or_fp="%stmp/plugins.zip" % PLUGIN_PATH,
                         as_attachment=True,
                         cache_timeout=0)

    checkers = load_default_checkers()
    if checker_name not in checkers:
        return jsonify(status=400,
                       message="下载失败",
                       data={"extra_info": "不存在名字为%s的插件" % checker_name})

    return send_file(filename_or_fp=checkers[checker_name].plugin_file_path,
                     as_attachment=True,
                     cache_timeout=0)
Exemplo n.º 4
0
def modify_plugin():
    """
    禁用指定的插件,
    服务端:1.从CHECKER_INSTANCE_DICT指定插件设置disable 2.并向MQ中发送一条消息
    引擎端:1.等到引擎消费到指令从CHECKER_INSTANCE_DICT,也将该插件的disable设置为True
    :return: 
    """
    from plugins.base.vuln_enum import PluginSwith
    from common.plugins_util import modify_default_checkers
    post_data = request.get_json(force=True)
    param_list = ["name", "switch"]
    if has_dict_value_blank(post_data, param_list):
        return jsonify(
            status=400,
            message="更新失败",
            data={"extra_info": "请保证%s任一参数值不为空" % ','.join(param_list)})
    try:
        post_checker_name = post_data.get("name")
        post_switch = post_data.get("switch")
        plugin_switch = PluginSwith.ON if post_switch else PluginSwith.OFF
        checkers = load_default_checkers()
        if post_checker_name not in checkers:
            return jsonify(
                status=400,
                message="更新失败",
                data={"extra_info": "不存在名为%s的插件" % post_checker_name})

        PluginInfoService.update(
            fields=({
                PluginInfo.useable: plugin_switch
            }),
            where=(PluginInfo.plugin_name == post_checker_name))

        RedisService.modify_plugin_switch(checkers[post_checker_name],
                                          plugin_switch)

        system_notice_celery.delay(
            broadcast={
                "type": BroadCastType.PLUGIN,
                "action": BroadCastAction.MODIFY_PLUGIN,
                "data": {
                    "name": post_checker_name,
                    "switch": plugin_switch
                }
            })
        modify_default_checkers()
        return jsonify(status=200,
                       message="更新成功",
                       data={
                           "extra_info":
                           "{}插件{}".format("启用" if plugin_switch else "禁用",
                                           post_checker_name)
                       })
    except Exception as e:
        logger.exception("modify_plugin raise error")
        return jsonify(status=500,
                       message="未知异常",
                       data={"extra_info": "修改插件信息时出现未知异常,请联系管理员查看异常日志"})
Exemplo n.º 5
0
def download_newest_checkers():
    """
    第一次启动时同步插件,从服务端下载最新的插件,
    :return: 
    """
    logger.info("download newest checkers when the system starts up")
    try:
        master_checkers_url = get_system_config()["front_end"]["master_checkers_url"]
        download_file(url=master_checkers_url, save_fp=PLUGIN_ZIP_PATH)
        unzip_file(origin_file=PLUGIN_ZIP_PATH, target_folder=PLUGIN_PATH)
        logger.info("download newest checkers successfully, it still using newest checkers")
    except Exception as e:
        if isinstance(e, requests.exceptions.ConnectTimeout):
            logger.warn("sorry,download newest checkers timeout, it still using old checkers")
        else:
            logger.warn("sorry,download newest checkers error, it still using old checkers")
    finally:
        load_default_checkers(True)
        modify_default_checkers()
Exemplo n.º 6
0
def remove_checker(broadcast):
    """
    移除插件,不做物理删除,只从内存中移除

    {"type": "plugin", "action": "modify", "data": {"name": checker_name, "switch": PluginSwith.ON}
    :param broadcast: 
    :return: 
    """
    checker_name = broadcast["data"]["name"]
    checkers_dict = load_default_checkers()
    if checker_name in checkers_dict:
        logger.info('从插件列表中移除插件{}'.format(checker_name))
        checkers_dict.pop(checker_name)
Exemplo n.º 7
0
def modify_checker(broadcast):
    """
    修改本地插件配置信息,只修改本地配置文件
    
    {"type": "plugin", "action": "modify", "data": {"name": checker_name, "switch": PluginSwith.ON}
    :param broadcast: 
    :return: 
    """
    checker_name = broadcast["data"]["name"]
    switch = broadcast["data"]["switch"]
    checkers_dict = load_default_checkers()
    if checker_name in checkers_dict:
        logger.info('接收到修改插件{}状态为{}的请求'.format(checker_name, switch))
        LocalFilePluginConfig().modify_plugin_config(checker_name, "useable", switch)
        modify_default_checkers()
Exemplo n.º 8
0
    def parse_plugin_file(plugin_file_path):
        """
        warnning: 插件文件路径,这里会存在安全隐患,请按照实际需求考虑是否用imp.load_source
        :param plugin_file_path: 
        :return: 
        """
        import imp
        from exception.hunter_web_exception import BaseHunterException

        # 解析插件并且分类
        base_checker = imp.load_source('BaseChecker', plugin_file_path)
        checker_instance = base_checker.Checker()
        checker_instance.check_plugin_info()
        # 检测插件是否重名
        checker_name = checker_instance.info["name"]
        if checker_name in load_default_checkers():
            raise BaseHunterException("插件%s已经存在,请重新命名" % checker_name)
        return checker_instance
Exemplo n.º 9
0
def scan(package, task_id, create_user, status):
    """
    
    :param package: 
    :param task_id: 
    :param create_user: 
    :param status: 
    :return: 
    """
    from model.url import UrlService, Url

    # logger.setLevel(logging.DEBUG)

    classification_url, classification_data = parse_package(package)
    # 保存URL
    url_task = UrlService.save(status=TaskStatus.WAITING, origin_data=package, task_id=task_id,
                               classification_url=classification_url, classification_data=classification_data)

    result_queue = queue.Queue()  # 结果队列
    logger.info("hunter task has started")
    # 加载插件
    checker_list = load_default_checkers()
    # checker_list = load_checkers(modle_names)
    logger.info('loading package success')
    logger.info('loading plugin success')
    try:
        future_tasks = list()
        for checker_name, checker_instance in checker_list.items():
            future_tasks.append(asyncio.ensure_future(run_plugin(package, checker_instance, result_queue)))
        # 更新URL数据库状态
        UrlService.update(fields=({Url.status: TaskStatus.WORKING}), where=(Url.id == url_task.id))
        loop = asyncio.get_event_loop()
        loop.run_until_complete(asyncio.wait(future_tasks))
        # loop.close()
    except KeyboardInterrupt as e:
        logger.exception("scan error")
    finally:
        UrlService.update(fields=({Url.status: TaskStatus.DONE}), where=(Url.id == url_task.id))
        # UrlService.update_url_status(TaskStatus.DONE, url_task.id)
        logger.info("hunter task has done")
        print_result(url_task, result_queue)
Exemplo n.º 10
0
def init_plugin_info():
    """
    初始化插件信息到数据库中
    :return: 
    """
    # 初始化redis配置信息
    RedisService.init_plugin_config()
    for checker_name, checker_instance in load_default_checkers().items():
        if PluginInfoService.count(
                where=(PluginInfo.plugin_name == checker_name)) == 0:
            PluginInfoService.save(
                author=checker_instance.info["author"],
                plugin_name=checker_instance.info["name"],
                plugin_tag=checker_instance.info["tag"],
                imp_version=checker_instance.info["imp_version"],
                description=checker_instance.info["description"],
                repair=checker_instance.info["repair"],
                type=checker_instance.info["type"]["fullname"],
                chinese_type=checker_instance.info["type"]["fullchinesename"],
                level=checker_instance.info["type"]["level"],
            )
Exemplo n.º 11
0
 def init_plugin_config():
     """
     初始化插件开关
     :return: 
     """
     from common.plugins_util import load_default_checkers
     try:
         checker_dict = load_default_checkers(True)
         for (plugin_name, checker_instance) in checker_dict.items():
             plugin_config_info = json.dumps({
                 "tag":
                 checker_instance.info["tag"],
                 "useable":
                 PluginSwith.ON,
                 "removed":
                 False
             })
             RedisManage.get_redis_client().hset(
                 RedisService.HUNTER_PLUGIN_SWITCH, plugin_name,
                 plugin_config_info)
     except Exception:
         RedisService.logger.exception("RedisService update_plugin error")
Exemplo n.º 12
0
 def init_plugin_info():
     """
     初始化插件信息,2.0 废弃
     :return: 
     """
     from common.plugins_util import load_default_checkers
     try:
         checker_dict = load_default_checkers()
         for (plugin_name, checker_instance) in checker_dict.items():
             plugin_instance_info = {
                 "name": plugin_name,
                 "tag": checker_instance.info["tag"],
                 "imp_version": checker_instance.info["imp_version"],
                 "type": checker_instance.info["type"]["fullchinesename"],
                 "level": checker_instance.info["type"]["level"],
                 "description": checker_instance.info["description"],
                 "useable": PluginSwith.ON
             }
             RedisManage.get_redis_client().hmset(
                 RedisService.HUNTER_PLUGIN + plugin_name,
                 plugin_instance_info)
     except Exception:
         RedisService.logger.exception(
             "RedisService init_plugin_info error")
Exemplo n.º 13
0
def insert_plugin():
    """
    新增插件,
    服务端:1.保存插件到本地,先上传到tmp目录,然后解析插件是否满足格式出tag并移动到tag目录,刷新插件列表 2.向MQ发送一条消息包含插件
    引擎端:2.消费到MQ发送消息,并下载最新插件并新增到CHECKER_INSTANCE_DICT
    :return: 
    """
    import shutil
    from common.system_util import mkdir
    from common.path import PLUGIN_PATH
    from common.plugins_util import load_default_checkers

    def allowed_file(filename):
        """
        检测是否为python文件
        :param filename: 
        :return: 
        """
        return '.' in filename and filename.rsplit('.', 1)[1] in ["py"]

    def parse_plugin_file(plugin_file_path):
        """
        warnning: 插件文件路径,这里会存在安全隐患,请按照实际需求考虑是否用imp.load_source
        :param plugin_file_path: 
        :return: 
        """
        import imp
        from exception.hunter_web_exception import BaseHunterException

        # 解析插件并且分类
        base_checker = imp.load_source('BaseChecker', plugin_file_path)
        checker_instance = base_checker.Checker()
        checker_instance.check_plugin_info()
        # 检测插件是否重名
        checker_name = checker_instance.info["name"]
        if checker_name in load_default_checkers():
            raise BaseHunterException("插件%s已经存在,请重新命名" % checker_name)
        return checker_instance

    def move_plugin(tmp_plugin_file_path, checker_instance, filename):
        """
        :param checker_instance: 
        :return: 
        """
        # 移动插件到指定目录
        tag = checker_instance.info["tag"]
        mkdir(PLUGIN_PATH + tag)
        formal_plugin_file_path = os.path.join(PLUGIN_PATH + tag, filename)
        shutil.move(tmp_plugin_file_path, formal_plugin_file_path)

    def save_plugin_info(checker_instance):
        if PluginInfoService.count(where=(
                PluginInfo.plugin_name == checker_instance.info["name"])) == 0:
            PluginInfoService.save(
                author=checker_instance.info["author"],
                plugin_name=checker_instance.info["name"],
                plugin_tag=checker_instance.info["tag"],
                imp_version=checker_instance.info["imp_version"],
                description=checker_instance.info["description"],
                repair=checker_instance.info["repair"],
                type=checker_instance.info["type"]["fullname"],
                chinese_type=checker_instance.info["type"]["fullchinesename"],
                level=checker_instance.info["type"]["level"],
            )

    try:
        file = request.files['file']
        if file and allowed_file(file.filename):
            filename = file.filename
            tmp_plugin_file_path = os.path.join(PLUGIN_PATH + "tmp/", filename)
            file.save(tmp_plugin_file_path)
            # 解析插件
            checker_instance = parse_plugin_file(tmp_plugin_file_path)
            move_plugin(tmp_plugin_file_path, checker_instance, filename)
            # 保存到数据
            save_plugin_info(checker_instance)
            load_default_checkers(True)
            RedisService.modify_plugin_switch(checker_instance, PluginSwith.ON)
            system_notice_celery.delay(
                broadcast={
                    "type": BroadCastType.PLUGIN,
                    "action": BroadCastAction.INSERT_PLUGIN,
                    "data": {
                        "name": checker_instance.info["name"]
                    }
                })
            return jsonify(status=200,
                           message="上传成功",
                           data={"extra_info": "您可以刷新网页后使用新插件"})
        return jsonify(status=500,
                       message="上传失败",
                       data={"extra_info": "您上传的插件不是py文件"})
    except Exception as e:
        logger.exception("create_plugin raise error")
        # 解析插件是否满足格式
        return jsonify(status=500, message="上传失败", data={"extra_info": str(e)})