Пример #1
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))
Пример #2
0
class TicketRecords(object):
    def __init__(self):
        self.es = ElasticHelper()
        self.redis = RedisHelper()

    def save_ticket(self, ticket_doc):
        # 首先将当前票据保存到redis缓存中
        self.redis.set_str_value(ticket_doc["ticket_data"]["ticket_hash"],
                                 ticket_doc["ticket_type"],
                                 expire=60 * 60 *
                                 main_config.TGT_maximum_lifetime)

        index = ElasticConfig.krb5_ticket_write_index_prefix + datetime_to_log_date(
            datetime_now_obj())
        # 保存到ES中
        self.es.delay_index(body=ticket_doc,
                            index=index,
                            doc_type=ElasticConfig.krb5_ticket_doc_type)

    def exist_ticket_by_hash(self, ticket_hash: str, ticket_type: str) -> bool:
        result = self.redis.get_str_value(ticket_hash)
        if result and result == ticket_type:
            return True
        else:
            return False

    def set_username_by_tgt_hash(self, ticket_hash: str, username: str):
        key = ticket_hash + REDIS_TICKET_HASH_USERNAME_SUFFIX
        return self.redis.set_str_value(key, username, expire=60 * 60 * 24 * 7)

    def get_username_by_tgt_hash(self, ticket_hash: str) -> str:
        key = ticket_hash + REDIS_TICKET_HASH_USERNAME_SUFFIX
        username = self.redis.get_str_value(key)
        if not username:
            return "unknown"
        else:
            return username

    def terms_by_custom(self, query: dict, aggs_field: str, aggs_size) -> list:
        body = {
            "query": query,
            "size": 0,
            "aggs": get_aggs_statement("abc", "terms", aggs_field, aggs_size)
        }
        rsp = self.es.search(body=body,
                             index=ElasticConfig.krb5_ticket_index,
                             doc_type=ElasticConfig.krb5_ticket_doc_type)
        if rsp:
            return rsp["aggregations"]["abc"]["buckets"]
        else:
            return []

    @staticmethod
    def sec_tools_match(options: str) -> str:
        if options == "0x40800010":
            return "kekeo, Rubeus"
        elif options == "0x50800000":
            return "impacket"
        else:
            return "unknown"
Пример #3
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))
Пример #4
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))
Пример #5
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))
Пример #6
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"])
Пример #7
0
class AccountInfo(object):
    def __init__(self):
        self.redis = RedisHelper()
        self.account_history = AccountHistory()
        self.es = ElasticHelper()

    def check_target_is_admin_by_sid(self, sid: str, domain: str) -> bool:
        """
            检查一个账户是否拥有管理员权限
        """
        key = sid + REDIS_KEY_SID_IS_ADMIN_SUFFIX
        record = self.redis.get_str_value(key)
        # 存在redis缓存记录
        if record:
            if record == "true":
                return True
            else:
                return False
        # 不存在 则通过ldap查询,再更新redis缓存
        else:
            ldap = LDAPSearch(domain)
            user_entry = ldap.search_by_sid(sid=sid, attributes=["adminCount"])
            if user_entry:
                entry_attributes = user_entry.entry_attributes_as_dict
                if len(entry_attributes["adminCount"]
                       ) > 0 and entry_attributes["adminCount"][0] == 1:
                    self.redis.set_str_value(
                        key, "true", expire=ACCOUNT_INFO_REDIS_EXPIRE_TIME)
                    return True
            self.redis.set_str_value(key,
                                     "false",
                                     expire=ACCOUNT_INFO_REDIS_EXPIRE_TIME)
            return False

    def check_target_is_user_by_sid(self, sid: str, domain: str) -> bool:
        """
            检查目标账号是否为 OU=Users
        """
        key = sid + REDIS_KEY_SID_IS_USERS_SUFFIX
        record = self.redis.get_str_value(key)
        # 存在redis缓存记录
        if record:
            if record == "true":
                return True
            else:
                return False
        # 不存在 则通过ldap查询,再更新redis缓存
        else:
            ldap = LDAPSearch(domain)
            user_entry = ldap.search_by_sid(sid=sid, attributes=["cn"])
            if user_entry:
                dn = user_entry.entry_dn
                if "OU=Users" in dn:
                    self.redis.set_str_value(
                        key, "true", expire=ACCOUNT_INFO_REDIS_EXPIRE_TIME)
                    return True
            self.redis.set_str_value(key,
                                     "false",
                                     expire=ACCOUNT_INFO_REDIS_EXPIRE_TIME)
            return False

    def check_target_is_user_by_name(self, user: str, domain: str) -> bool:
        """
            检查目标账号是否为 OU=Users
        """
        key = user + REDIS_KEY_USERNAME_IS_USERS_SUFFIX
        record = self.redis.get_str_value(key)
        # 存在redis缓存记录
        if record:
            if record == "true":
                return True
            else:
                return False
        # 不存在 则通过ldap查询,再更新redis缓存
        else:
            ldap = LDAPSearch(domain)
            user_entry = ldap.search_by_name(user=user, attributes=["cn"])
            if user_entry:
                dn = str(user_entry.entry_dn)
                if "OU=Users".lower() in dn.lower() or "CN=Users".lower(
                ) in dn.lower():
                    self.redis.set_str_value(
                        key, "true", expire=ACCOUNT_INFO_REDIS_EXPIRE_TIME)
                    return True
            self.redis.set_str_value(key,
                                     "false",
                                     expire=ACCOUNT_INFO_REDIS_EXPIRE_TIME)
            return False

    def get_user_info_by_name(self, user_name: str, domain: str) -> User:
        key = user_name + REDIS_KEY_USERNAME_SID_SUFFIX
        # 先查redis
        user_sid = self.redis.get_str_value(key)
        # redis 缓存未命中 再查mongo
        if not user_sid:
            ldap = LDAPSearch(domain)
            user_entry = ldap.search_by_name(user_name,
                                             attributes=["objectSid"])
            if not user_entry:
                return
            user_sid = user_entry.entry_attributes_as_dict["objectSid"][0]
            self.redis.set_str_value(key,
                                     user_sid,
                                     expire=ACCOUNT_INFO_REDIS_EXPIRE_TIME)
        user = User({
            "user_name": user_name,
            "user_sid": user_sid,
            "logon_id": "",
            "domain_name": domain
        })
        return user

    def get_user_info_by_sid(self, sid: str, domain: str) -> User:
        key = sid + REDIS_KEY_SID_USERNAME_SUFFIX
        # 先查redis
        user_name = self.redis.get_str_value(key)
        if not user_name:
            ldap = LDAPSearch(domain)
            user_entry = ldap.search_by_sid(sid, attributes=["sAMAccountName"])
            if not user_entry:
                return None
            user_name = user_entry.entry_attributes_as_dict["sAMAccountName"][
                0]
            self.redis.set_str_value(key,
                                     user_name,
                                     expire=ACCOUNT_INFO_REDIS_EXPIRE_TIME)
        user = User({
            "user_name": user_name,
            "user_sid": sid,
            "logon_id": "",
            "domain_name": domain
        })
        return user

    def check_target_is_aes_support(self, name: str, domain: str) -> bool:
        key = name + REDIS_KEY_USERNAME_AES_SUPPORT_SUFFIX
        # 先查redis
        is_support = self.redis.get_str_value(key)
        #
        if is_support is not None:
            return is_support == "true"
        else:
            ldap = LDAPSearch(domain)
            user_entry = ldap.search_by_name(
                name, attributes=["msDS-SupportedEncryptionTypes"])
            if not user_entry:
                return False
            support_types = user_entry.entry_attributes_as_dict[
                "msDS-SupportedEncryptionTypes"]
            if len(support_types) == 0:
                return False
            support_types = support_types[0]
            # 等于8 支持AES128加密
            if support_types >= 8:
                self.redis.set_str_value(key, "true")
                return True
            else:
                self.redis.set_str_value(key, "false")
                return False

    def user_is_sensitive_by_sid(self, sid: str, domain: str) -> bool:
        """
            检查某个用户是否为敏感用户

            1. adminCount 1
            2. 属于敏感组
            3. 蜜罐账户
            4. 自定义敏感用户
        """
        # 蜜罐账户
        for user in main_config.honeypot_account:
            if user["sid"] == sid:
                return True

        # 自定义敏感用户
        for user in main_config.sensitive_users:
            if user["sid"] == sid:
                return True

        ldap = LDAPSearch(domain)
        user_entry = ldap.search_by_sid(sid,
                                        attributes=["adminCount", "memberOf"])
        if not user_entry:
            return False

        # adminCount
        if len(user_entry.entry_attributes_as_dict["adminCount"]) > 0 and \
                user_entry.entry_attributes_as_dict["adminCount"][0] == 1:
            return True

        # 敏感组
        groups = user_entry.entry_attributes_as_dict["memberOf"]
        sensitive_groups = list(
            map(lambda x: x["name"], main_config.sensitive_groups))
        for g in groups:
            g_name = get_cn_from_dn(g)
            if g_name in sensitive_groups:
                return True
        return False

    def computer_is_sensitive_by_name(self, name: str, domain: str) -> bool:
        """
            检查某个计算机是否为敏感

            1. 域控服务器
            2. 自定义敏感主机
        """
        domain = get_netbios_domain(domain)
        # 域控服务器
        if name.upper() in main_config.dc_name_list[domain]:
            return True

        # 敏感计算机
        sensitive_computers = list(
            map(lambda x: x["name"], main_config.sensitive_computers))
        if name.upper() in sensitive_computers:
            return True

        return False
Пример #8
0
class AccountHistory(object):
    def __init__(self):
        self.es = ElasticHelper()
        self.redis = RedisHelper()

    def set_workstation_by_ip(self, ip: str, workstation: str):
        key = ip + REDIS_KEY_LAST_WORKSTATION_IP_SUFFIX
        self.redis.set_str_value(key, workstation, expire=60 * 60 * 24)

    def set_ip_by_workstation(self, ip: str, workstation: str):
        key = workstation + REDIS_KEY_LAST_IP_WORKSTATION_SUFFIX
        self.redis.set_str_value(key, ip, expire=60 * 60 * 24)

    def get_last_workstation_by_ip(self, ip: str) -> str:
        key = ip + REDIS_KEY_LAST_WORKSTATION_IP_SUFFIX
        workstation = self.redis.get_str_value(key)
        if workstation:
            return workstation
        else:
            return self.search_last_workstation_by_ip(ip)

    def get_last_ip_by_workstation(self, workstation: str) -> str:
        key = workstation + REDIS_KEY_LAST_IP_WORKSTATION_SUFFIX
        ip = self.redis.get_str_value(key)
        if ip:
            return ip
        else:
            return self.search_last_ip_by_workstation(workstation)

    def search_last_workstation_by_ip(self, ip: str) -> str:
        query = {
            "query":
            get_must_statement(
                get_term_statement("event_id", 4768),
                get_wildcard_statement("event_data.TargetUserName.keyword",
                                       "*$"),
                get_term_statement("event_data.IpAddress.keyword",
                                   "::ffff:" + ip),
                get_term_statement("event_data.Status.keyword", "0x0"),
            ),
            "_source":
            ["event_data.TargetUserName", "event_data.TargetDomainName"],
            "size":
            1,
            "sort": {
                "@timestamp": "desc"
            }
        }
        rsp = self.es.search(body=query,
                             index=ElasticConfig.event_log_index,
                             doc_type=ElasticConfig.event_log_doc_type)
        if rsp and rsp["hits"]["total"] > 0:
            data = rsp["hits"]["hits"][0]["_source"]
            workstation = data["event_data"]["TargetUserName"]
            return workstation[:-1]
        else:
            return "unknown"

    def search_last_ip_by_workstation(self, workstation: str) -> str:
        query = {
            "query":
            get_must_statement(
                get_term_statement("event_id", 4768),
                get_wildcard_statement("event_data.TargetUserName.keyword",
                                       workstation + "$"),
                get_term_statement("event_data.Status.keyword", "0x0"),
                get_must_statement(
                    get_must_not_statement(
                        get_term_statement("event_data.IpAddress.keyword",
                                           "::1")),
                    get_must_not_statement(
                        get_term_statement("event_data.IpAddress.keyword",
                                           "::ffff:127.0.0.1")))),
            "_source": ["event_data.IpAddress"],
            "size":
            1,
            "sort": {
                "@timestamp": "desc"
            }
        }
        rsp = self.es.search(body=query,
                             index=ElasticConfig.event_log_index,
                             doc_type=ElasticConfig.event_log_doc_type)
        if rsp and rsp["hits"]["total"] > 0:
            data = rsp["hits"]["hits"][0]["_source"]
            ip = data["event_data"]["IpAddress"]
            return ip.replace("::ffff:", "")
        else:
            return "unknown"
Пример #9
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))