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
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
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)
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 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"])