def _get_recursive_groups(self, group_list) -> list: result = [] group_result = [] search_group = group_list recursive_count = 2 while True: temp = [] condition = "" for user in search_group: cn = get_cn_from_dn(user) cn = escape_ldap_filter(cn) condition += "(cn={cn})".format(cn=cn) condition = "(|{cond})".format(cond=condition) entries = self.ldap.search_by_custom(condition, attributes=["memberOf"]) for entry in entries: for g in entry.entry_attributes_as_dict["memberOf"]: if g in group_list or g in group_result or g in temp: continue temp.append(g) if len(temp) == 0: break temp_result = self._multi_entry_data(temp) for each in temp_result: each["recursive_count"] = recursive_count result.append(each) recursive_count += 1 group_result.extend(temp) return result
def user_is_sensitive(self, sid, admin_count=None, member_of=None) -> bool: # 蜜罐账户 for user in main_config.honeypot_user: if user["sid"] == sid: return True # 自定义敏感用户 for user in main_config.sensitive_users: if user["sid"] == sid: return True if admin_count is None and member_of is None: ldap = LDAPSearch(self.domain) user_entry = ldap.search_by_sid(sid, attributes=["adminCount", "memberOf"]) if not user_entry: return False admin_count = user_entry.entry_attributes_as_dict["adminCount"] member_of = user_entry.entry_attributes_as_dict["memberOf"] # adminCount if len(admin_count) > 0 and admin_count[0] == 1: return True # 敏感组 groups = member_of for g in groups: g_name = get_cn_from_dn(g) g_domain = get_domain_from_dn(g) for g_entry in main_config.sensitive_groups: if g_entry["domain"] == g_domain and g_entry["name"] == g_name: return True return False
def detail_user_data(self, name): result = {} fields = ["sAMAccountName", "objectSid", "userPrincipalName", "distinguishedName", "servicePrincipalName", "whenCreated", "userAccountControl", "memberOf", "manager", "directReports", "msDS-AllowedToDelegateTo", "cn"] entry = self.ldap.search_by_name(name, attributes=fields) if entry: for key, value in entry.entry_attributes_as_dict.items(): if len(value) == 0: result[key] = None continue elif key == "whenCreated": result[key] = datetime_to_utc(value[0]) elif key == "manager": m = get_cn_from_dn(value[0]) if m: result[key] = self.user_entry_data(m) else: result[key] = "" elif key == "userAccountControl": result[key] = self.uac_parser.parse_security(value[0]) result["is_disabled"] = self.uac_parser.has_one_flag(value[0], "ACCOUNT_DISABLE") elif key == "directReports": result[key] = self._multi_entry_data(value) elif key == "memberOf": result[key] = self._multi_entry_data(value) result["recursive_groups"] = self._get_recursive_groups(value) elif key == "servicePrincipalName" or key == "msDS-AllowedToDelegateTo": result[key] = value elif len(value) == 1: result[key] = value[0] else: result[key] = value return result
def group_entry_data(self, name): result = {"domain": self.domain} fields = ["description", "adminCount", "groupType", "member", "whenCreated", "sAMAccountName", "managedBy", "cn", "objectSid"] entry = self.ldap.search_by_name(name, attributes=fields) if entry: for key, value in entry.entry_attributes_as_dict.items(): if key == "whenCreated" or key == "whenChanged": result[key] = datetime_to_utc(value[0]) elif key == "adminCount": result["is_sensitive"] = self.group_is_sensitive(name, domain=self.domain, admin_count=value) elif key == "groupType": result["scope"], result["type"] = self.group_type_parser.parse(value[0]) elif key == "member": result["member_count"] = len(value) elif key == "objectSid": result["objectSid"] = value[0] elif key == "managedBy": if len(value) > 0: result["managedBy"] = get_cn_from_dn(value[0]) else: result["managedBy"] = "" elif len(value) == 1: result[key] = value[0] else: result[key] = value return result
def user_entry_data(self, name): result = {"domain": self.domain, "name": name} fields = [ "department", "displayName", "mail", "manager", "title", "whenCreated", "sAMAccountName", "objectSid", "description", "employeeNumber", "cn", "userAccountControl", "memberOf", "adminCount" ] entry = self.ldap.search_by_name(name, attributes=fields) if entry: entry_attributes = entry.entry_attributes_as_dict for key, value in entry_attributes.items(): if len(value) == 0: result[key] = "" continue elif key == "adminCount" or key == "memberOf": continue elif key == "whenCreated": result[key] = datetime_to_utc(value[0]) elif key == "manager": m = get_cn_from_dn(value[0]) if m: result[key] = m else: result[key] = "" elif key == "userAccountControl": result["is_disabled"] = self.uac_parser.has_one_flag( value[0], "ACCOUNT_DISABLE") elif key == "objectSid": result["objectSid"] = value[0] result["is_sensitive"] = self.user_is_sensitive( value[0], admin_count=entry_attributes["adminCount"], member_of=entry_attributes["memberOf"]) elif len(value) == 1: result[key] = value[0] elif len(value) > 1: result[key] = "、".join(value) else: result[key] = "" return result
def _multi_entry_data(self, entry_list) -> list: result = [] if len(entry_list) == 0: return result condition = [] for entry in entry_list: cn = get_cn_from_dn(entry) cn = escape_ldap_filter(cn) condition.append("(CN={cn})".format(cn=cn)) if len(condition) >= 2: condition = "(|{cond})".format(cond="".join(condition)) else: condition = condition[0] entries = self.ldap.search_by_custom(condition, attributes=["department", "displayName", "mail", "manager", "title", "whenCreated", "sAMAccountName", "objectSid", "description", "employeeNumber", "cn", "adminCount", "userAccountControl", "adminCount", "memberOf", "groupType", "member", "managedBy", "objectClass", "distinguishedName", "operatingSystem", "operatingSystemServicePack", "operatingSystemVersion"]) if not entries: return result for entry in entries: temp = {"domain": self.domain} entry_attributes = entry.entry_attributes_as_dict if "computer" in entry_attributes["objectClass"]: temp["entry_type"] = "computer" temp["is_sensitive"] = self.computer_is_sensitive(name=entry_attributes["cn"][0], domain=self.domain, admin_count=entry_attributes["adminCount"]) elif "group" in entry_attributes["objectClass"]: temp["entry_type"] = "group" temp["is_sensitive"] = self.group_is_sensitive(name=entry_attributes["cn"][0], domain=self.domain, admin_count=entry_attributes["adminCount"]) temp["userAccountControl"] = self.uac_parser.parse_security(0) elif "user" in entry_attributes["objectClass"]: temp["entry_type"] = "user" temp["is_sensitive"] = self.user_is_sensitive(sid=entry_attributes["objectSid"][0], admin_count=entry_attributes["adminCount"], member_of=entry_attributes["memberOf"]) else: continue for key, value in entry_attributes.items(): if len(value) == 0: temp[key] = "" continue elif key == "adminCount" or key == "memberOf": continue elif key == "whenCreated": temp[key] = datetime_to_utc(value[0]) elif key == "manager": m = get_cn_from_dn(value[0]) if m: temp[key] = m else: temp[key] = "" elif key == "userAccountControl": temp["is_disabled"] = self.uac_parser.has_one_flag(value[0], "ACCOUNT_DISABLE") elif key == "groupType": temp["scope"], temp["type"] = self.group_type_parser.parse(value[0]) elif key == "member": temp["member_count"] = len(value) elif key == "managedBy": temp["managedBy"] = get_cn_from_dn(value[0]) elif len(value) == 1: temp[key] = value[0] elif len(value) > 1: temp[key] = "、".join(value) else: temp[key] = "" result.append(temp) return result