/// <summary> /// Processes an LDAP entry to resolve PrimaryGroup/MemberOf properties /// </summary> /// <param name="entry">LDAP entry</param> /// <param name="resolvedEntry">The resolved object with the name/type of the entry</param> /// <param name="domainSid">SID for the domain being enumerated. Used to resolve PrimaryGroupID</param> /// <returns></returns> public static IEnumerable <GroupMember> ProcessAdObject(SearchResultEntry entry, ResolvedEntry resolvedEntry, string domainSid) { var principalDisplayName = resolvedEntry.BloodHoundDisplay; var principalDomainName = Utils.ConvertDnToDomain(entry.DistinguishedName); //If this object is a group, add it to our DN cache if (resolvedEntry.ObjectType.Equals("group")) { _cache.AddMapValue(entry.DistinguishedName, "group", principalDisplayName); } var members = entry.GetPropArray("member"); if (members.Length == 0) { var tempMembers = new List <string>(); var finished = false; var bottom = 0; while (!finished) { var top = bottom + 1499; var range = $"member;range={bottom}-{top}"; bottom += 1500; //Try ranged retrieval foreach (var result in _utils.DoSearch("(objectclass=*)", SearchScope.Base, new[] { range }, principalDomainName, entry.DistinguishedName)) { if (result.Attributes.AttributeNames == null) { continue; } var en = result.Attributes.AttributeNames.GetEnumerator(); //If the enumerator fails, that means theres really no members at all if (!en.MoveNext()) { finished = true; break; } if (en.Current == null) { continue; } var attrib = en.Current.ToString(); if (attrib.EndsWith("-*")) { finished = true; } tempMembers.AddRange(result.GetPropArray(attrib)); } } members = tempMembers.ToArray(); } foreach (var dn in members) { //Check our cache first if (!_cache.GetMapValueUnknownType(dn, out var principal)) { if (dn.Contains("ForeignSecurityPrincipals") && dn.Contains("CN=S-1-5-21")) { var sid = dn.Split(',')[0].Substring(3); principal = _utils.UnknownSidTypeToDisplay(sid, _utils.SidToDomainName(sid), Props); } else { var objEntry = _utils .DoSearch("(objectclass=*)", SearchScope.Base, Props, Utils.ConvertDnToDomain(dn), dn) .DefaultIfEmpty(null).FirstOrDefault(); if (objEntry == null) { principal = null; } else { var resolvedObj = objEntry.ResolveAdEntry(); if (resolvedObj == null) { principal = null; } else { _cache.AddMapValue(dn, resolvedObj.ObjectType, resolvedObj.BloodHoundDisplay); principal = new MappedPrincipal ( resolvedObj.BloodHoundDisplay, resolvedObj.ObjectType ); } } } } if (principal != null) { yield return(new GroupMember { AccountName = principal.PrincipalName, GroupName = principalDisplayName, ObjectType = principal.ObjectType }); } } var pgi = entry.GetProp("primarygroupid"); if (pgi == null) { yield break; } var pgsid = $"{domainSid}-{pgi}"; var primaryGroupName = _utils.SidToDisplay(pgsid, principalDomainName, Props, "group"); if (primaryGroupName != null) { yield return new GroupMember { AccountName = resolvedEntry.BloodHoundDisplay, GroupName = primaryGroupName, ObjectType = resolvedEntry.ObjectType } } ; }
public static void GetGroupInfo(SearchResultEntry entry, ResolvedEntry resolved, string domainSid, ref Group u) { if (!Utils.IsMethodSet(ResolvedCollectionMethod.Group)) { return; } var fMembers = new List <GroupMember>(); var principalDisplayName = resolved.BloodHoundDisplay; var principalDomainName = Utils.ConvertDnToDomain(entry.DistinguishedName); if (resolved.ObjectType == "group") { _cache.AddMapValue(entry.DistinguishedName, "group", principalDisplayName); } var members = entry.GetPropArray("member"); if (members.Length == 0) { var tempMembers = new List <string>(); var finished = false; var bottom = 0; while (!finished) { var top = bottom + 1499; var range = $"member;range={bottom}-{top}"; bottom += 1500; //Try ranged retrieval foreach (var result in _utils.DoSearch("(objectclass=*)", SearchScope.Base, new[] { range }, principalDomainName, entry.DistinguishedName)) { if (result.Attributes.AttributeNames == null) { continue; } var en = result.Attributes.AttributeNames.GetEnumerator(); //If the enumerator fails, that means theres really no members at all if (!en.MoveNext()) { finished = true; break; } if (en.Current == null) { continue; } var attrib = en.Current.ToString(); if (attrib.EndsWith("-*")) { finished = true; } tempMembers.AddRange(result.GetPropArray(attrib)); } } members = tempMembers.ToArray(); } foreach (var dn in members) { //Check our cache first if (!_cache.GetMapValueUnknownType(dn, out var principal)) { if (dn.Contains("ForeignSecurityPrincipals")) { var sid = dn.Split(',')[0].Substring(3); if (dn.Contains("CN=S-1-5-21")) { var domain = _utils.SidToDomainName(sid); if (domain == null) { Utils.Verbose($"Unable to resolve domain for FSP {dn}"); continue; } principal = _utils.UnknownSidTypeToDisplay(sid, domain, Props); } else { if (!MappedPrincipal.GetCommon(sid, out principal)) { continue; } principal.PrincipalName = $"{principal.PrincipalName}@{principalDomainName}"; } } else { var objEntry = _utils .DoSearch("(objectclass=*)", SearchScope.Base, Props, Utils.ConvertDnToDomain(dn), dn) .DefaultIfEmpty(null).FirstOrDefault(); if (objEntry == null) { principal = null; } else { var resolvedObj = objEntry.ResolveAdEntry(); if (resolvedObj == null || resolvedObj.ObjectType == "domain") { principal = null; } else { _cache.AddMapValue(dn, resolvedObj.ObjectType, resolvedObj.BloodHoundDisplay); principal = new MappedPrincipal ( resolvedObj.BloodHoundDisplay, resolvedObj.ObjectType ); } } } } if (principal != null) { fMembers.Add(new GroupMember { MemberName = principal.PrincipalName, MemberType = principal.ObjectType }); } } u.Members = fMembers.Distinct().ToArray(); }
/// <summary> /// Processes an LDAP entry to resolve PrimaryGroup/MemberOf properties /// </summary> /// <param name="entry">LDAP entry</param> /// <param name="resolvedEntry">The resolved object with the name/type of the entry</param> /// <param name="domainSid">SID for the domain being enumerated. Used to resolve PrimaryGroupID</param> /// <returns></returns> public static IEnumerable <GroupMember> ProcessAdObject(SearchResultEntry entry, ResolvedEntry resolvedEntry, string domainSid) { var principalDisplayName = resolvedEntry.BloodHoundDisplay; var principalDomainName = Utils.ConvertDnToDomain(entry.DistinguishedName); //If this object is a group, add it to our DN cache if (resolvedEntry.ObjectType.Equals("group")) { _cache.AddMapValue(entry.DistinguishedName, "group", principalDisplayName); } foreach (var dn in entry.GetPropArray("member")) { //Check our cache first if (!_cache.GetMapValueUnknownType(dn, out var principal)) { if (dn.Contains("ForeignSecurityPrincipals") && !dn.StartsWith("CN=S-1-5-21")) { if (dn.Contains("S-1-5-21")) { var sid = entry.GetProp("cn"); principal = _utils.UnknownSidTypeToDisplay(sid, _utils.SidToDomainName(sid), Props); } else { principal = null; } } else { var objEntry = _utils .DoSearch("(objectclass=*)", SearchScope.Base, Props, Utils.ConvertDnToDomain(dn), dn) .DefaultIfEmpty(null).FirstOrDefault(); if (objEntry == null) { principal = null; } else { var resolvedObj = objEntry.ResolveAdEntry(); _cache.AddMapValue(dn, resolvedObj.ObjectType, resolvedObj.BloodHoundDisplay); principal = new MappedPrincipal ( resolvedObj.BloodHoundDisplay, resolvedObj.ObjectType ); } } } if (principal != null) { yield return(new GroupMember { AccountName = principal.PrincipalName, GroupName = principalDisplayName, ObjectType = principal.ObjectType }); } } var pgi = entry.GetProp("primarygroupid"); if (pgi == null) { yield break; } var pgsid = $"{domainSid}-{pgi}"; var primaryGroupName = _utils.SidToDisplay(pgsid, principalDomainName, Props, "group"); if (primaryGroupName != null) { yield return new GroupMember { AccountName = resolvedEntry.BloodHoundDisplay, GroupName = primaryGroupName, ObjectType = resolvedEntry.ObjectType } } ; }
/// <summary> /// Processes an LDAP entry to resolve PrimaryGroup/MemberOf properties /// </summary> /// <param name="entry">LDAP entry</param> /// <param name="resolvedEntry">The resolved object with the name/type of the entry</param> /// <param name="domainSid">SID for the domain being enumerated. Used to resolve PrimaryGroupID</param> /// <returns></returns> public static IEnumerable <GroupMember> ProcessAdObject(SearchResultEntry entry, ResolvedEntry resolvedEntry, string domainSid) { var principalDomainName = Utils.ConvertDnToDomain(entry.DistinguishedName); var principalDisplayName = resolvedEntry.BloodHoundDisplay; var objectType = resolvedEntry.ObjectType; //If this object is a group, add it to our DN cache if (objectType.Equals("group")) { _cache.AddMapValue(entry.DistinguishedName, "group", principalDisplayName); } foreach (var dn in entry.GetPropArray("memberof")) { //Check our cache first if (!_cache.GetMapValue(dn, "group", out var groupName)) { //Search for the object directly var groupEntry = _utils .DoSearch("(objectclass=group)", SearchScope.Base, Props, Utils.ConvertDnToDomain(dn), dn) .DefaultIfEmpty(null).FirstOrDefault(); if (groupEntry == null) { //Our search didn't return anything so fallback //Try convertadname first groupName = ConvertAdName(dn, AdsTypes.AdsNameTypeDn, AdsTypes.AdsNameTypeNt4); //If convertadname is null, just screw with the distinguishedname to get the group groupName = groupName != null ? groupName.Split('\\').Last() : dn.Substring(0, dn.IndexOf(",", StringComparison.Ordinal)).Split('=').Last(); } else { //We got an object back! groupName = groupEntry.ResolveAdEntry().BloodHoundDisplay; } //If we got a group back, add it to the cache for later use if (groupName != null) { _cache.AddMapValue(dn, "group", groupName); } } //We got our group! Return it if (groupName != null) { yield return new GroupMember { AccountName = principalDisplayName, GroupName = groupName, ObjectType = objectType } } ; } var primaryGroupId = entry.GetProp("primarygroupid"); if (primaryGroupId == null) { yield break; } //As far as I know you cant belong to a primary group of another domain var pgsid = $"{domainSid}-{primaryGroupId}"; var primaryGroupName = _utils.SidToDisplay(pgsid, principalDomainName, Props, "group"); if (primaryGroupName != null) { yield return new GroupMember { AccountName = principalDisplayName, GroupName = primaryGroupName, ObjectType = objectType } } ; }