Example #1
0
class Invasion(object):
    def __init__(self):
        self.mongo = MongoHelper(MongoConfig.uri, db=MongoConfig.db, collection=MongoConfig.invasions_collection)

    def new(self, *activities) -> ObjectId:
        """
            新建入侵事件 返回入侵事件ID
        """
        source_ip = activities[0]["form_data"]["source_ip"]
        title = "来自于{ip}的入侵事件".format(ip=source_ip)

        doc = {
            "title": title,
            "level": _get_max_level(list(map(lambda x: x["level"], activities))),
            "start_time": activities[0]["start_time"],
            "end_time": activities[-1]["end_time"],
            "source_ip": source_ip,
            "status": "pending"
        }

        return self.mongo.insert_one(doc).inserted_id

    def add_activity(self, invasion_id: ObjectId, activity_doc: dict):
        """
            向当前入侵事件添加一条新的威胁活动
        """
        query = {
            "_id": invasion_id
        }
        invasion = self.mongo.find_one(query=query)
        level = _get_max_level([invasion["level"], activity_doc["level"]])
        end_time = activity_doc["end_time"]
        if end_time > invasion["end_time"]:
            self.update(invasion_id, {
                "$set": {
                    "level": level,
                    "end_time": end_time
                }
            })
        else:
            self.update(invasion_id, {
                "$set": {
                    "level": level
                }
            })

    def find_record(self, source_ip, start_time, **kwargs):
        """
            根据 source_ip 查找一段时间内的相同来源的入侵事件
        """
        return self.mongo.find_one({
            "source_ip": source_ip,
            "end_time": {"$gte": start_time + timedelta(hours=-main_config.merge_invasion_time)},
            **kwargs
        })

    def update(self, _id, doc):
        self.mongo.update_one({
            "_id": _id
        }, doc=doc)
Example #2
0
def init_sensitive_groups(domain):
    logger.info("init sensitive groups.")
    domain = get_netbios_domain(domain)
    ldap_search = LDAPSearch(domain)
    redis = RedisHelper()
    mongo = MongoHelper(uri=MongoConfig.uri,
                        db=MongoConfig.db,
                        collection=MongoConfig.settings_collection)
    sensitive_groups = []
    for item in default_sensitive_groups(domain):
        if len(item["sid"]) > 0:
            sensitive_groups.append(item)
        else:
            entry = ldap_search.search_by_name(item["name"],
                                               attributes=["objectSid"])
            if not entry or len(
                    entry.entry_attributes_as_dict["objectSid"]) == 0:
                continue
            sid = entry.entry_attributes_as_dict["objectSid"][0]
            item["sid"] = sid
            sensitive_groups.append(item)
    logger.info(",".join(list(map(lambda x: x["name"], sensitive_groups))))
    sensitive_entry = mongo.find_one({"name": "sensitive_entry"})["value"]
    sensitive_entry["group"] = sensitive_groups
    mongo.update_one({"name": "sensitive_entry"},
                     {"$set": {
                         "value": sensitive_entry
                     }},
                     upsert=True)
    redis.set_str_value("sensitive_entry" + REDIS_KEY_SUFFIX,
                        simplejson.dumps(sensitive_entry))
Example #3
0
def check_mongo_connection() -> bool:
    mongo = MongoHelper(MongoConfig.uri)
    if not mongo.check_connection():
        logger.error(
            "Can't connect to the MongoDB, please reconfirm the settings.")
        return False
    logger.info("Connect to the MongoDB successfully, OK.")
    return True
Example #4
0
 def __init__(self, code: str, title: str, desc: str):
     self.code = code
     self.title = title
     self.desc = desc
     self.log = None
     self.krb = None
     self.domain = None
     self.mongo = MongoHelper(MongoConfig.uri, MongoConfig.db,
                              MongoConfig.delay_run_collection)
Example #5
0
def set_learning_end_time_setting():
    value = move_n_days(datetime_utc_now_obj(), 10)
    logger.info("set learning end time: " + str(value))
    name = "learning_end_time"
    redis = RedisHelper()
    mongo = MongoHelper(uri=MongoConfig.uri,
                        db=MongoConfig.db,
                        collection=MongoConfig.settings_collection)
    mongo.update_one(filter={"name": name},
                     doc={"$set": {
                         "value": value
                     }},
                     upsert=True)
    key = name + REDIS_KEY_SUFFIX
    redis.set_str_value(key, datetime_to_common_str(value))
Example #6
0
def init_ldap_settings(domain, server, user, password):
    logger.info("init the ldap configuration.")
    if not server.startswith("ldap://"):
        server = "ldap://" + server
    mongo = MongoHelper(uri=MongoConfig.uri,
                        db=MongoConfig.db,
                        collection=MongoConfig.settings_collection)
    query = {"name": "ldap"}
    doc = {
        domain: {
            "server": server,
            "user": user,
            "password": password,
            "dn": get_dn_domain_name(domain)
        }
    }
    mongo.update_one(filter=query, doc={"$set": {"value": doc}}, upsert=True)
    redis = RedisHelper()
    redis.set_str_value("ldap" + REDIS_KEY_SUFFIX, simplejson.dumps(doc))
Example #7
0
def init_default_settings(domain):
    logger.info("init other settings.")
    redis = RedisHelper()
    mongo = MongoHelper(uri=MongoConfig.uri,
                        db=MongoConfig.db,
                        collection=MongoConfig.settings_collection)
    for name, value in default_settings.items():
        if name == "domain_list":
            value = [domain]
        mongo.update_one(filter={"name": name},
                         doc={"$set": {
                             "value": value
                         }},
                         upsert=True)
        key = name + REDIS_KEY_SUFFIX
        if name in [
                "domain_list", "VPN_ip_part",
                "detail_file_share_white_list_setting"
        ]:
            if len(value) != 0:
                redis.set_list(key, *value)
        elif name in [
                "raw_data_expire", "honeypot_account", "alarms_merge",
                "sensitive_entry", "kerberos"
        ]:
            redis.set_str_value(key, simplejson.dumps(value))
        elif name in ["brute_force_max"]:
            redis.set_str_value(key, str(value))
        elif isinstance(value, list):
            if len(value) > 0 and isinstance(value[0], dict):
                redis.set_str_value(key, simplejson.dumps(value))
            else:
                if len(value) != 0:
                    redis.set_list(key, *value)
        elif isinstance(value, str):
            redis.set_str_value(key, value)
        elif isinstance(value, dict):
            redis.set_str_value(key, simplejson.dumps(value))
        elif isinstance(value, int):
            redis.set_str_value(key, str(value))
Example #8
0
def load_settings():
    """
        加载Mongo中保存的配置信息到redis中
    """
    mongo = MongoHelper(MongoConfig.uri, MongoConfig.db,
                        MongoConfig.settings_collection)
    redis = RedisHelper()
    fetcher = mongo.find_all({})
    for each in fetcher:
        key = each["name"] + "_setting"
        # 再录入
        if isinstance(each["value"], list):
            if len(each["value"]) == 0:
                continue
            elif isinstance(each["value"][0], dict):
                redis.set_str_value(key, simplejson.dumps(each["value"]))
                continue
            redis.set_list(key, *each["value"])
        elif isinstance(each["value"], dict):
            redis.set_str_value(key, simplejson.dumps(each["value"]))
        else:
            redis.set_str_value(key, each["value"])
Example #9
0
def get_all_dc_names(domain: str):
    """
        将DC列表入库
    """
    domain = get_netbios_domain(domain)
    logger.info("Search all domain controllers using LDAP.")
    dc_name_list = []
    ldap_search = LDAPSearch(domain)
    dc_list = ldap_search.search_domain_controller()
    for each in dc_list:
        dc_name = str(each["cn"])
        dc_name_list.append(dc_name)
    mongo = MongoHelper(MongoConfig.uri, MongoConfig.db,
                        MongoConfig.settings_collection)
    doc = {domain: dc_name_list}
    logger.info(",".join(dc_name_list))
    logger.info(
        "domain controller count: {count}".format(count=len(dc_name_list)))
    logger.info("Save all domain controllers to settings.")
    mongo.update_one({"name": "dc_name_list"}, {"$set": {"value": doc}}, True)
    redis = RedisHelper()
    redis.set_str_value("dc_name_list" + REDIS_KEY_SUFFIX,
                        simplejson.dumps(doc))
Example #10
0
class Delegation(object):
    def __init__(self):
        self.mongo = MongoHelper(MongoConfig.uri, MongoConfig.db,
                                 MongoConfig.delegation_collection)

    def new_delegation_record(self,
                              user: User,
                              delegation_type: str,
                              allowed_to=None):
        if delegation_type not in [
                CONSTRAINED_DELEGATION, UNCONSTRAINED_DELEGATION,
                RES_BASED_CONSTRAINED_DELEGATION
        ]:
            raise NoSuchDelegationType()

        self.mongo.insert_one({
            "name": user.user_name,
            "sid": user.user_sid,
            "domain": user.domain_name,
            "delegation_type": delegation_type,
            "allowed_to": allowed_to
        })

    def find_constrained_delegation_by_sid(self, sid: str):
        return self.mongo.find_one({
            "sid": sid,
            "delegation_type": CONSTRAINED_DELEGATION
        })

    def find_res_constrained_delegation_by_name(self, name: str):
        return self.mongo.find_one({
            "name":
            name,
            "delegation_type":
            RES_BASED_CONSTRAINED_DELEGATION
        })

    def find_one_delegation(self, query: dict):
        return self.mongo.find_one(query)

    def update_delegation(self, sid, delegation_type, allowed_to):
        self.mongo.update_one({
            "sid": sid,
            "delegation_type": delegation_type
        }, {"allowed_to": allowed_to})
Example #11
0
 def __init__(self, rules_table):
     self.mongo = MongoHelper(MongoConfig.uri, MongoConfig.db, rules_table)
Example #12
0
class MatchRules(object):
    def __init__(self, rules_table):
        self.mongo = MongoHelper(MongoConfig.uri, MongoConfig.db, rules_table)

    def match(self, event_doc: dict):
        alert_code = event_doc["alert_code"]
        form_data = event_doc["form_data"]
        all_rules = self.mongo.find_all({"alert_code": alert_code})
        for rule in all_rules:
            try:
                rule = Rule(rule)
                # 成功匹配规则 则返回被匹配上的规则ID
                if self._match_one(rule, form_data):
                    return rule.id
            except Exception as e:
                return False
        return False

    def _match_one(self, rule: Rule, form_data):
        """
            一条忽略内容的多条规则,全部匹配才算成功
        """
        for rule_content in rule.rules:
            if rule_content.field_type == "string":
                if not self._match_string(form_data[rule_content.field_name],
                                          rule_content.value,
                                          rule_content.match_type):
                    return False
            elif rule_content.field_type == "ip":
                if not self._match_ip(form_data[rule_content.field_name],
                                      rule_content.value):
                    return False
            elif rule_content.field_type == "list":
                if not self._match_list(form_data[rule_content.field_name],
                                        rule_content.value,
                                        rule_content.match_type):
                    return False
        return True

    def _match_string(self, alert_value, rule_value, match_type) -> bool:
        """
            匹配字符串,将告警字段内容和忽略规则的内容匹配
        """
        if match_type == "term":
            if isinstance(alert_value, list):
                for each in alert_value:
                    if each == rule_value:
                        return True
                return False
            else:
                return alert_value == rule_value
        # 正则匹配
        elif match_type == "regex":
            if isinstance(alert_value, list):
                for each in alert_value:
                    if re.match(rule_value, each):
                        return True
                return False
            else:
                return True if re.match(rule_value, alert_value) else False

    def _match_ip(self, alert_ip, rule_ip) -> bool:
        """
            匹配IP类型
        """
        # CIDR
        if "/" in rule_ip:
            return IP(alert_ip) in IP(rule_ip)
        else:
            return alert_ip == rule_ip

    def _match_list(self, alert_value, rule_value, match_type):
        """
            匹配列表
        """
        for each in rule_value:
            if match_type == "ip" and self._match_ip(alert_value, each):
                return True
            elif match_type == "string" or match_type == "regex":
                if self._match_string(alert_value, each, match_type):
                    return True
        return False
Example #13
0
 def __init__(self):
     self.alert_mongo = MongoHelper(MongoConfig.uri, MongoConfig.db, MongoConfig.alerts_collection)
     self.activity = Activity()
     self.ignore_rule = MatchRules(MongoConfig.ignore_collection)
     self.exclude_rule = MatchRules(MongoConfig.exclude_collection)
Example #14
0
class Alert(object):
    def __init__(self):
        self.alert_mongo = MongoHelper(MongoConfig.uri, MongoConfig.db, MongoConfig.alerts_collection)
        self.activity = Activity()
        self.ignore_rule = MatchRules(MongoConfig.ignore_collection)
        self.exclude_rule = MatchRules(MongoConfig.exclude_collection)

    def generate(self, doc):
        """
            生成告警,发送邮件并入库
        """
        # 计算告警表单内容的唯一ID
        form_data_id = _get_form_data_md5(doc["form_data"])
        doc["form_data_id"] = form_data_id

        # 误报排除规则过滤,不再产生记录
        if self._auto_exclude(doc):
            return

        # 忽略规则过滤
        doc = self._auto_ignore(doc)

        # 首先尝试合并相同来源且相同类型的告警到同一个威胁活动, 即unique_id重复的告警
        if self._merge_alert(doc):
            return

        # 新增,生成威胁活动
        activity_id = self.activity.new(doc)
        # 记录下威胁活动的ID以后,告警入库
        doc["activity_id"] = activity_id
        self.alert_mongo.insert_one(doc)

    def _merge_alert(self, alert_doc):
        """
            合并告警到同一个威胁活动
        """

        # 查找是否已经生成了威胁活动,没有的话直接退出,然后新增
        activity = self.activity.find_record(alert_doc["unique_id"], alert_doc["start_time"])
        if not activity:
            return False

        alert_doc["activity_id"] = activity["_id"]

        # 尝试合并告警表单内容完全重复的告警,增加重复次数
        if self._merge_repeat_count(alert_doc):
            self.activity.update(activity["_id"], {
                "$set": {
                    "end_time": alert_doc["end_time"]
                }
            })
        # 无完全重复,在该威胁活动下新增一条告警
        else:
            self.activity.add_alert(activity, alert_doc)
            self.alert_mongo.insert_one(alert_doc)
        return True

    def _merge_repeat_count(self, alert_doc: dict) -> bool:
        """
            完全重复的告警内容 不再入库 直接统计次数
        """
        query = {
            "activity_id": alert_doc["activity_id"],
            "form_data_id": alert_doc["form_data_id"]
        }
        record = self.alert_mongo.find_one(query)
        if record:
            # 账号爆破特殊处理一下
            if alert_doc["alert_code"] == "301":
                self.alert_mongo.update_one(
                    {"_id": record["_id"]},
                    {
                        "$set": {
                            "form_data.brute_force_target_users": alert_doc["form_data"]["brute_force_target_users"]
                        }
                    }
                )
                return True
            self.alert_mongo.update_one(
                {"_id": record["_id"]},
                {
                    "$inc": {"repeat_count": 1},
                    "$set": {"end_time": alert_doc["end_time"]}
                }
            )
            return True
        else:
            return False

    def _auto_exclude(self, doc):
        """
            根据预先设定的规则,自动排除误报

            和忽略的区别是,排除的误报不再产生记录,直接忽略
        """
        rule_id = self.exclude_rule.match(doc)
        if rule_id:
            return True
        else:
            return False

    def _auto_ignore(self, doc):
        """
            根据预先设定的规则,自动忽略告警
            忽略的告警也需要合并
        """
        rule_id = self.ignore_rule.match(doc)
        if rule_id:
            doc["status"] = "auto_ignore"
            doc["ignore_rule_id"] = rule_id
        return doc
Example #15
0
 def __init__(self):
     self.mongo = MongoHelper(MongoConfig.uri, db=MongoConfig.db, collection=MongoConfig.invasions_collection)
Example #16
0
 def __init__(self):
     self.event_log_modules_map = None
     # self.traffic_kerberos_modules_map = None
     self.mongo = MongoHelper(MongoConfig.uri, MongoConfig.db,
                              MongoConfig.delay_run_collection)
     self.alert = Alert()
Example #17
0
class Engine(object):
    def __init__(self):
        self.event_log_modules_map = None
        # self.traffic_kerberos_modules_map = None
        self.mongo = MongoHelper(MongoConfig.uri, MongoConfig.db,
                                 MongoConfig.delay_run_collection)
        self.alert = Alert()

    def load(self):
        # 加载事件日志检测模块
        logger.info("loading detect modules based on event_log")
        self.event_log_modules_map = self._load_module("event_log", "EVENT_ID")

        # 加载kerberos流量检测模块
        # logger.info("loading detect modules based on traffic_kerberos")
        # self.traffic_kerberos_modules_map = self._load_module("traffic_kerberos", "MSG_TYPE")

    def start(self):
        """
            引擎启动主入口
        """
        self.load()

        # 启动消费者
        c = Consumer()
        # 注册回调
        logger.info("start MQ consumer and register callback func.")
        logger.info("status: main process running")
        c.run(self.do_analyze)

    def delay_run(self):
        """
            延迟检测

            ** 请单进程运行! **
        """
        self.load()
        logger.info("status: delay process running")
        while True:
            time.sleep(5)
            data_list = self._get_delay_data()
            for data in data_list:
                alert_code = data["_delay_info"]["alert_code"]
                # if data["type"] == "krb5":
                #     krb = Kerberos(data)
                #     self._run_analyze(data=krb, data_type=krb.msg_type, modules_map=self.traffic_kerberos_modules_map,
                #                       alert_code=alert_code)
                if data["type"] == "wineventlog":
                    log = Log(data)
                    self._run_analyze(data=log,
                                      data_type=log.event_id,
                                      modules_map=self.event_log_modules_map,
                                      alert_code=alert_code)
            # 删除完成检测数据
            self._clear_confirmed_data(data_list)

    def do_analyze(self, data: dict):
        # 解析krb5流量
        # if data["type"] == "krb5":
        #     krb = Kerberos(data)
        #     if krb.msg_type not in self.traffic_kerberos_modules_map:
        #         return
        #     self._run_analyze(data=krb, data_type=krb.msg_type, modules_map=self.traffic_kerberos_modules_map)
        # 解析事件日志
        if data["type"] == "wineventlog":
            if data["event_id"] == 4662:
                return
            if "event_data" not in data and data["event_id"] != 1100:
                return
            log = Log(data)
            if log.event_id not in self.event_log_modules_map:
                return
            self._run_analyze(data=log,
                              data_type=log.event_id,
                              modules_map=self.event_log_modules_map)

    def _run_analyze(self,
                     data,
                     data_type,
                     modules_map: dict,
                     alert_code=None):
        """
            运行检测模块
        :param data: 数据字典
        :param data_type: log.event_id 的值或者 krb.msg_type
        :param modules_map: 加载了检测模块的字典
        :param alert_code:  可选,具体检测的告警代码,指定了之后只运行该模块
        :return:
        """
        module_list = modules_map[data_type]
        for module in module_list:
            code = module["code"]
            if alert_code and alert_code != code:
                continue
            m_object = module["object"]
            # 运行检测模块的语句
            alert_doc = m_object.run(data)
            if alert_doc:
                # 存在问题,告警
                self.alert.generate(alert_doc)

    def _load_module(self, name: str, data_type: str) -> dict:
        modules_map = {}

        def _register_module(d_type, m):
            if d_type not in modules_map:
                modules_map[d_type] = [m]
            else:
                modules_map[d_type].append(m)

        file_list = get_walk_files(project_dir + "/modules/detect/" + name)

        for f in file_list:
            f = f.replace(project_dir, ".")
            module_path, f = format_module_path(f)
            module = __import__(module_path, fromlist=[f])
            logger.info("loaded module: " + module_path)
            data_types = getattr(module, data_type)
            assert isinstance(data_types, list)
            for d_type in data_types:
                _register_module(
                    d_type, {
                        "code":
                        getattr(module, "ALERT_CODE") if hasattr(
                            module, "ALERT_CODE") else None,
                        "object":
                        getattr(module, f)()
                    })
        return modules_map

    def _get_delay_data(self):
        query = {"_delay_info.time": {"$lte": datetime_now_obj()}}
        return [each for each in self.mongo.find_all(query)]

    def _clear_confirmed_data(self, data_list):
        id_list = []
        for data in data_list:
            id_list.append(data["_id"])
        query = {"_id": {"$in": id_list}}
        self.mongo.delete_many(query)
Example #18
0
 def __init__(self):
     self.mongo = MongoHelper(MongoConfig.uri, MongoConfig.db,
                              MongoConfig.delegation_collection)
Example #19
0
class DetectBase(object):
    def __init__(self, code: str, title: str, desc: str):
        self.code = code
        self.title = title
        self.desc = desc
        self.log = None
        self.krb = None
        self.domain = None
        self.mongo = MongoHelper(MongoConfig.uri, MongoConfig.db,
                                 MongoConfig.delay_run_collection)

    def init(self, log=None, krb=None):
        if log is None and krb is None:
            raise NoDataInitEvent()
        if log and krb:
            raise NoDataInitEvent()
        if log:
            assert isinstance(log, Log)
            self.domain = ".".join(log.dc_computer_name.split(".")[1:])
        else:
            assert isinstance(krb, Kerberos)
            self.domain = krb.req.req_body.realm
        self.log = log
        self.krb = krb
        self._format_domain()

    def delay_confirm_krb(self, secs=10):
        doc = copy.deepcopy(self.krb.record)
        doc["_delay_info"] = {
            "time": move_n_sec(datetime_now_obj(), -secs),
            "data_type": "traffic_kerberos",
            "alert_code": self.code
        }
        self.mongo.insert_one(doc)

    def delay_confirm_log(self, secs=60):
        doc = copy.deepcopy(self.log.record)
        doc["_delay_info"] = {
            "time": move_n_sec(datetime_now_obj(), -secs),
            "data_type": "event_log",
            "alert_code": self.code
        }
        self.mongo.insert_one(doc)

    def _format_domain(self):
        if not self.domain:
            self.domain = ""
            self.netbios_name = ""
            self.fqdn_name = ""
        elif "." in self.domain:
            self.fqdn_name = self.domain
            self.netbios_name = _get_netbios_name(self.domain)
        elif self.domain and self.domain != "-":
            self.netbios_name = self.domain.upper()
            self.fqdn_name = _get_fqdn_name(self.domain)
        else:
            self.netbios_name = ""
            self.fqdn_name = ""

    def _get_unique_id(self, *args) -> str:
        _str = ""
        for each in args:
            _str += each
        return md5(_str)

    def _get_log_doc(self):
        if self.log is None:
            return {}
        return self.log.record

    def _get_krb_doc(self):
        if self.krb is None:
            return {}
        return self.krb.record

    def _get_dc_computer_name(self):
        if self.log:
            return self.log.dc_computer_name
        else:
            return self.krb.dc_host_name

    def _get_dc_hostname(self):
        if self.log:
            return self.log.dc_host_name
        else:
            return self.krb.dc_host_name

    def _get_detect_by(self):
        if self.log:
            return "event_log"
        else:
            return "krb_traffic"

    def _get_time(self):
        if self.log:
            return utc_to_datetime(self.log.utc_log_time)
        else:
            return utc_to_datetime(self.krb.utc_time)

    def _get_base_doc(self, **kwargs):
        return {
            "alert_code": self.code,
            "title": self.title,
            "description": self.desc,
            "classify": self._get_classify(),
            "dc_computer_name": self._get_dc_computer_name(),
            "dc_hostname": self._get_dc_hostname(),
            "domain": self.netbios_name,
            "status": "pending",
            "start_time": self._get_time(),
            "end_time": self._get_time(),
            "raw_log": self._get_log_doc(),
            "raw_krb": self._get_krb_doc(),
            "detect_by": self._get_detect_by(),
            "repeat_count": 1,
            **kwargs
        }

    def _get_classify(self):
        if self.code.startswith("1"):
            return "信息探测"
        elif self.code.startswith("2"):
            return "凭证盗取"
        elif self.code.startswith("3"):
            return "横向移动"
        elif self.code.startswith("4"):
            return "权限提升"
        elif self.code.startswith("5"):
            return "权限维持"
        elif self.code.startswith("6"):
            return "防御绕过"
        else:
            return "未知分类"

    def _get_workstation_by_source_ip(self, source_ip) -> str:
        """
            查找最近该IP认证主机名

            返回主机名和域名
        """
        account_history = AccountHistory()
        return account_history.get_last_workstation_by_ip(source_ip)

    def _get_source_ip_by_workstation(self, source_ip) -> str:
        """
        """
        account_history = AccountHistory()
        return account_history.get_last_ip_by_workstation(source_ip)

    def _get_source_ip_by_logon_id(self, logon_id: str, user_name: str) -> str:
        id_term = get_term_statement("event_id", 4624)
        logon_id_term = get_term_statement("event_data.TargetLogonId.keyword",
                                           logon_id)
        user_term = get_term_statement("event_data.TargetUserName.keyword",
                                       user_name)

        query = {
            "query": get_must_statement(id_term, logon_id_term, user_term),
            "_source": ["event_data.IpAddress"],
            "size": 1
        }
        es = ElasticHelper()

        rsp = es.search(body=query,
                        index=ElasticConfig.event_log_index,
                        doc_type=ElasticConfig.event_log_doc_type)
        if rsp and len(rsp["hits"]["hits"]) > 0:
            return rsp["hits"]["hits"][0]["_source"]["event_data"]["IpAddress"]
        else:
            return "unknown"

    @abstractmethod
    def _generate_alert_doc(self, **kwargs) -> dict:
        pass

    @abstractmethod
    def _get_level(self) -> str:
        pass
Example #20
0
 def __init__(self):
     self.activity_mongo = MongoHelper(MongoConfig.uri, MongoConfig.db, MongoConfig.activities_collection)
     self.invasion = Invasion()
Example #21
0
class Activity(object):
    def __init__(self):
        self.activity_mongo = MongoHelper(MongoConfig.uri, MongoConfig.db, MongoConfig.activities_collection)
        self.invasion = Invasion()

    def new(self, activity_doc: dict) -> ObjectId:
        """
            新增威胁活动记录

            同时尝试生成入侵事件记录
        """
        invasion_id = self._generate_invasion(activity_doc)
        if invasion_id:
            activity_doc["invasion_id"] = invasion_id
        return self.activity_mongo.insert_one(activity_doc).inserted_id

    def add_alert(self, activity_doc, alert_doc: dict):
        doc = {
            "$set": {}
        }
        if alert_doc["end_time"] > activity_doc["end_time"]:
            doc["$set"]["end_time"] = alert_doc["end_time"]
        if alert_doc["level"] > activity_doc["level"]:
            doc["$set"]["level"] = alert_doc["level"]
        if len(doc["$set"].keys()) == 0:
            return
        self.activity_mongo.update_one({
            "_id": activity_doc["_id"]
        }, doc)

    def update(self, _id, doc):
        self.activity_mongo.update_one({
            "_id": _id
        }, doc=doc)

    def find_record(self, uid, start_time):
        """
            根据 unique_id 查找一段时间内相同的威胁活动
        """
        return self.activity_mongo.find_one({
            "unique_id": uid,
            "end_time": {"$gte": start_time + timedelta(hours=-main_config.merge_activity_time)}
        })

    def _generate_invasion(self, activity_doc) -> ObjectId:
        """
            生成入侵事件
            多个相同来源IP 不同类型的威胁活动 可以生成一个入侵事件

            返回入侵事件的ID
        """
        # 首先查找是否已存在对应的入侵事件,尝试合并
        invasion_id = self._merge_activity(activity_doc)
        if invasion_id:
            assert isinstance(invasion_id, ObjectId)
            return invasion_id

        # 没有已存在的入侵事件,则按照条件,查找是否已存在不同类型的威胁活动
        query = {
            "form_data.source_ip": activity_doc["form_data"]["source_ip"],
            "end_time": {"$gte": activity_doc["start_time"] + timedelta(hours=-main_config.merge_invasion_time)},
            "alert_code": {"$ne": activity_doc["alert_code"]}
        }

        # 如果存在不同类型的威胁活动
        another_activities = list(self.activity_mongo.find_all(query).sort("start_time", ASCENDING))
        if len(another_activities) > 0:
            invasion_id = self.invasion.new(*another_activities, activity_doc)
            # 创建完入侵事件之后,将之前查询的到威胁活动全部加上对应的ID
            for activity in another_activities:
                self.update(activity["_id"], {
                    "$set": {
                        "invasion_id": invasion_id
                    }
                })

    def _merge_activity(self, activity_doc):
        source_ip = activity_doc["form_data"]["source_ip"]
        invasion = self.invasion.find_record(source_ip, activity_doc["start_time"])
        if not invasion:
            return False

        # 向存在的入侵事件添加当前威胁活动
        self.invasion.add_activity(invasion["_id"], activity_doc)
        return invasion["_id"]