Exemple #1
0
    def run(self, log: Log):
        if log.event_data["AttributeLDAPDisplayName"] != "servicePrincipalName":
            return

        if log.event_data["ObjectClass"] != "user":
            return

        if log.event_data["OperatorType"] not in ["%%14675", "%%14674"]:
            return

        domain = log.event_data["DSName"]
        target_user_name = get_cn_from_dn(log.object_info.dn)
        target_user_info = self.account_info.get_user_info_by_name(
            target_user_name, domain)

        form_data = {
            "operator": {
                "user_name": log.subject_info.user_name,
                "sid": log.subject_info.user_sid,
                "logon_id": log.subject_info.logon_id
            },
            "operator_type":
            "add" if log.event_data["OperatorType"] == "%%14674" else "remove",
            "value":
            log.event_data["AttributeValue"],
            "object_dn":
            log.object_info.dn
        }

        self.account_activity.save_activity(domain=log.event_data["DSName"],
                                            user_name=target_user_name,
                                            sid=target_user_info.user_sid,
                                            dc_name=log.dc_host_name,
                                            timestamp=log.utc_log_time,
                                            data=form_data)
 def _generate_alert_doc(self, **kwargs) -> dict:
     source_ip = self._get_source_ip_by_logon_id(
         self.log.subject_info.logon_id,
         self.log.subject_info.full_user_name)
     form_data = {
         "source_ip": source_ip,
         "source_workstation":
         self._get_workstation_by_source_ip(source_ip),
         "group_name": self.log.target_info.user_name,
         "group_sid": self.log.event_data["TargetSid"],
         "target_user_name":
         get_cn_from_dn(self.log.event_data["MemberName"]),
         "target_user_dn": self.log.event_data["MemberName"],
         "target_user_sid": self.log.event_data["MemberSid"],
         "target_domain": self.log.target_info.domain_name,
         "source_user_name": self.log.subject_info.user_name,
         "source_user_sid": self.log.subject_info.user_sid,
         "source_logon_id": self.log.subject_info.logon_id,
         "source_domain": self.log.subject_info.domain_name,
         "privilege_list": self.log.event_data["PrivilegeList"]
     }
     doc = self._get_base_doc(level=self._get_level(),
                              unique_id=self._get_unique_id(
                                  self.code,
                                  self.log.subject_info.user_name),
                              form_data=form_data)
     return doc
Exemple #3
0
    def user_is_sensitive_by_sid(self, sid: str, domain: str) -> bool:
        """
            检查某个用户是否为敏感用户

            1. adminCount 1
            2. 属于敏感组
            3. 蜜罐账户
            4. 自定义敏感用户

            LDAP查询是性能瓶颈,需要使用redis进行缓存加速

        """
        # 蜜罐账户
        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

        # 先查缓存
        _cache_is_sensitive = self.get_target_sensitive_cache(sid)
        if _cache_is_sensitive is not None:
            return _cache_is_sensitive == "true"

        # LDAP 查询较慢,性能瓶颈
        ldap = LDAPSearch(domain)
        user_entry = ldap.search_by_sid(sid,
                                        attributes=["adminCount", "memberOf"])
        if not user_entry:
            self.set_target_sensitive_cache(sid, "false")
            return False

        # adminCount
        if len(user_entry.entry_attributes_as_dict["adminCount"]) > 0 and \
                user_entry.entry_attributes_as_dict["adminCount"][0] == 1:
            self.set_target_sensitive_cache(sid, "true")
            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:
                self.set_target_sensitive_cache(sid, "true")
                return True
        self.set_target_sensitive_cache(sid, "false")
        return False
Exemple #4
0
    def run(self, log: Log):
        if log.event_id in [4728, 4732, 4756]:
            operator_type = "add"
        else:
            operator_type = "remove"

        target_user_name = get_cn_from_dn(log.event_data["MemberName"])
        target_user_sid = log.event_data["MemberSid"]
        group_name = log.event_data["TargetUserName"]
        domain = log.subject_info.domain_name

        form_data = {"group_name": group_name, "operator_type": operator_type}

        self.account_activity.save_activity(domain=domain,
                                            user_name=target_user_name,
                                            sid=target_user_sid,
                                            dc_name=log.dc_host_name,
                                            timestamp=log.utc_log_time,
                                            data=form_data)
Exemple #5
0
    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
Exemple #6
0
    def run(self, log: Log):
        self.init(log=log)

        if log.event_data[
                "AttributeLDAPDisplayName"] != "msDS-AllowedToActOnBehalfOfOtherIdentity":
            return

        # 只检测敏感计算机
        account = get_cn_from_dn(log.object_info.dn)
        domain = get_domain_from_dn(log.object_info.dn)
        if not self.account_info.computer_is_sensitive_by_name(
                account, domain=get_netbios_domain(domain)):
            return

        ldap = LDAPSearch(domain=domain)
        entry = ldap.search_by_cn(
            cn=account,
            attributes=["sid", "msDS-AllowedToActOnBehalfOfOtherIdentity"])
        if entry is None:
            return
        entry_sid = str(entry["sid"])

        sd = SR_SECURITY_DESCRIPTOR(entry.entry_attributes_as_dict[
            "msDS-AllowedToActOnBehalfOfOtherIdentity"][0])
        # 拥有特殊DACL权限的SID列表
        ace_list = []
        for ace in sd["Dacl"].aces:
            ace_list.append({
                "type_name": ace["TypeName"],
                "sid": ace['Ace']['Sid'].formatCanonical()
            })
        sid_list = list(map(lambda ace: ace["sid"], ace_list))
        sid_list = sorted(list(set(sid_list)))

        target_account_info = User({
            "user_name": account,
            "user_sid": entry_sid
        })

        # 查询历史委派记录
        record = self.delegation.find_res_constrained_delegation_by_name(
            name=account)
        # 不存在记录 则新建 并直接告警
        if not record:
            self.delegation.new_delegation_record(
                user=target_account_info,
                delegation_type=RES_BASED_CONSTRAINED_DELEGATION,
                allowed_to=sid_list)
            return self._generate_alert_doc(
                target_computer=account,
                target_user_name=target_account_info.user_name,
                target_user_sid=target_account_info.user_sid,
                add_allowed_sid=sid_list,
                old_allowed_sid=[])

        # 存在记录且不变,退出
        if sid_list == record["allowed_to"]:
            return

        # 存在记录 对比历史的sid 无新增 更新记录 退出
        new_sids = self._get_new_sid(new_list=sid_list,
                                     old_list=record["allowed_to"])
        if len(new_sids) == 0:
            self.delegation.update_delegation(
                sid=entry_sid,
                delegation_type=RES_BASED_CONSTRAINED_DELEGATION,
                allowed_to=sid_list)
            return

        # 存在记录 有新增 更新记录 告警
        if len(new_sids) > 0:
            self.delegation.update_delegation(
                sid=entry_sid,
                delegation_type=RES_BASED_CONSTRAINED_DELEGATION,
                allowed_to=sid_list)
            return self._generate_alert_doc(
                target_computer=account,
                target_user_name=target_account_info.user_name,
                target_user_sid=target_account_info.user_sid,
                add_allowed_sid=new_sids,
                old_allowed_sid=record["allowed_to"])